@@ -137,6 +137,50 @@ static void bb_hit(std::map<uint64_t, uint64_t>& hitmap, uint64_t address)
137
137
}
138
138
}
139
139
140
+ static uint64_t get_next_bb_addr (struct pt_block_decoder * dec)
141
+ {
142
+ struct pt_event evt;
143
+ struct pt_block block;
144
+ int status;
145
+
146
+ // Handle block events before requesting a proper block
147
+ do {
148
+ status = pt_blk_event (dec, &evt, sizeof (struct pt_event ));
149
+
150
+ // Trace is enabled, meaning that the event address is the next
151
+ // basic block processed by our program.
152
+ if (status == ptev_enabled)
153
+ return evt.variant .enabled .ip ;
154
+
155
+ } while (status >= 0 );
156
+
157
+ // Requesting the next block
158
+ status = pt_blk_next (dec, &block, sizeof (struct pt_block ));
159
+
160
+ if (status == -pte_eos)
161
+ return 0 ;
162
+
163
+ if (status == -pte_nosync || status == -pte_nomap) {
164
+ std::cerr << " Warning: Trace out of sync, seeking to next PSB\n " ;
165
+ status = pt_blk_sync_forward (dec);
166
+
167
+ if (status == -pte_eos) {
168
+ std::cerr << " No new PSB\n " ;
169
+ return 0 ;
170
+ }
171
+
172
+ if (status < 0 ) {
173
+ log_pt_err (dec, (pt_error_code)-status);
174
+ return 0 ;
175
+ }
176
+
177
+ // TODO: Clean this part of the code
178
+ return get_next_bb_addr (dec);
179
+ }
180
+
181
+ return block.ip ;
182
+ }
183
+
140
184
int pt_process (std::string perf_path, std::string binary_path,
141
185
std::string output_path)
142
186
{
@@ -188,98 +232,77 @@ int pt_process(std::string perf_path, std::string binary_path,
188
232
189
233
// Begin processing the trace
190
234
int status = 0 ;
191
- CodeBranch next_jump;
192
- struct pt_block block;
193
- int emptycount = 0 ;
235
+ CodeBranch prev_jump;
194
236
195
- next_jump.type = CodeBranchType::Invalid;
237
+ uint64_t bb_low = 0 ;
238
+ uint64_t bb_high = 0 ;
196
239
197
- while (status, pte_eos) {
198
- status = pt_blk_next (blk_dec, &block, sizeof (struct pt_block ));
199
-
200
- // Handling eof and out of sync
201
- if (status == -pte_eos) {
202
- break ;
203
- } else if (status == -pte_nosync
204
- || status == -pte_nomap
205
- || emptycount > 10 ) {
206
- std::cerr << " Warning: Trace out of sync, seeking to next PSB\n " ;
207
- status = pt_blk_sync_forward (blk_dec);
208
- emptycount = 0 ;
209
-
210
- if (status == -pte_eos) {
211
- std::cerr << " No new PSB\n " ;
212
- break ;
213
- }
240
+ prev_jump.type = CodeBranchType::Invalid;
214
241
215
- if (status < 0 ) {
216
- log_pt_err (blk_dec, (pt_error_code)-status);
217
- break ;
218
- }
242
+ while (true ) {
243
+ uint64_t bb_addr = get_next_bb_addr (blk_dec);
219
244
220
- continue ;
221
- } else if (status < 0 ) {
222
- log_pt_err (blk_dec, (pt_error_code)-status);
245
+ // We reached eos or an error
246
+ if (bb_addr == 0 )
223
247
break ;
224
- }
225
248
226
- // Handling event skipping
227
- if (status & pts_event_pending) {
228
- struct pt_event evt;
229
- int evt_status = 0 ;
230
249
231
- while (evt_status >= 0 ) {
232
- evt_status = pt_blk_event (blk_dec, &evt,
233
- sizeof (struct pt_event ));
234
- }
235
- }
250
+ // Now handling jumps
251
+ if (disas.is_mapped (bb_addr)) {
252
+ CodeBranch br = disas.get_next_branch (bb_addr);
236
253
237
- // handling empty basic blocks
238
- if (block.ninsn == 0 ) {
239
- emptycount++;
240
- continue ;
241
- }
254
+ // We skip fragmented and duplicate basic blocks
255
+ if (br.address >= bb_low && br.address <= bb_high)
256
+ continue ;
257
+
258
+ // If the current branch is out of the current range we need to
259
+ // update the range.
260
+ bb_low = bb_addr;
261
+ bb_high = br.address ;
242
262
243
- // Now handling jumps
244
- if (disas.is_mapped (block.ip )) {
245
- CodeBranch br = disas.get_next_branch (block.ip );
246
263
trace::BranchEvent* evt = nullptr ;
247
264
248
- bb_hit (bb_hitcount, block. ip );
265
+ bb_hit (bb_hitcount, bb_addr );
249
266
250
- if (next_jump. type == CodeBranchType::Invalid) {
251
- next_jump = br;
252
- next_jump .type = CodeBranchType::Invalid;
253
- } else {
254
- evt = trace_evt. mutable_branch_evt () ;
267
+ // First valid block encountered
268
+ if (prev_jump. type == CodeBranchType::Invalid ||
269
+ prev_jump .type == CodeBranchType::Return) {
270
+ prev_jump = br;
271
+ continue ;
255
272
}
256
273
257
- if (next_jump.type == CodeBranchType::CondJump) {
258
- if (block.ip == next_jump.ok ) {
259
- evt->set_source (next_jump.address );
260
- evt->set_destination (next_jump.ok );
274
+ if (prev_jump.type == CodeBranchType::CondJump) {
275
+ if (bb_addr == prev_jump.ok ) {
276
+ evt = trace_evt.mutable_branch_evt ();
277
+ evt->set_source (prev_jump.address );
278
+ evt->set_destination (prev_jump.ok );
261
279
evt->set_type (trace::BranchType::CONDJUMP);
262
- } else if (block.ip == next_jump.fail ) {
263
- evt->set_source (next_jump.address );
264
- evt->set_destination (next_jump.fail );
280
+ } else {
281
+ // There is a nasty edge case where this doesn't work.
282
+ // If the true branch of a jcc jumps to a block with
283
+ // a return, pt will not generate a basic block event.
284
+ // As such the next bb_addr will be the address after the
285
+ // return.
286
+ evt = trace_evt.mutable_branch_evt ();
287
+ evt->set_source (prev_jump.address );
288
+ evt->set_destination (prev_jump.fail );
265
289
evt->set_type (trace::BranchType::CONDJUMP);
266
290
}
267
- } else if (next_jump.type == CodeBranchType::Call) {
268
- evt->set_source (next_jump.address );
269
- evt->set_destination (next_jump.ok );
270
- evt->set_type (trace::BranchType::CALL);
271
- } else if (next_jump.type == CodeBranchType::IndCall) {
272
- evt->set_source (next_jump.address );
273
- evt->set_destination (block.ip );
274
- evt->set_type (trace::BranchType::INDCALL);
275
- } else if (next_jump.type == CodeBranchType::IndJump) {
276
- evt->set_source (next_jump.address );
277
- evt->set_destination (block.ip );
278
- evt->set_type (trace::BranchType::INDJUMP);
279
- } else if (next_jump.type == CodeBranchType::Jump) {
280
- evt->set_source (next_jump.address );
281
- evt->set_destination (next_jump.ok );
282
- evt->set_type (trace::BranchType::JUMP);
291
+ } else if (prev_jump.type == CodeBranchType::Call) {
292
+ evt = trace_evt.mutable_branch_evt ();
293
+ evt->set_source (prev_jump.address );
294
+ evt->set_destination (prev_jump.ok );
295
+ evt->set_type (trace::BranchType::CALL);
296
+ } else if (prev_jump.type == CodeBranchType::IndCall) {
297
+ evt = trace_evt.mutable_branch_evt ();
298
+ evt->set_source (prev_jump.address );
299
+ evt->set_destination (bb_addr);
300
+ evt->set_type (trace::BranchType::INDCALL);
301
+ } else if (prev_jump.type == CodeBranchType::IndJump) {
302
+ evt = trace_evt.mutable_branch_evt ();
303
+ evt->set_source (prev_jump.address );
304
+ evt->set_destination (bb_addr);
305
+ evt->set_type (trace::BranchType::INDJUMP);
283
306
}
284
307
285
308
// We serialize the message
@@ -291,7 +314,33 @@ int pt_process(std::string perf_path, std::string binary_path,
291
314
trace_evt.SerializeToCodedStream (&branch_os);
292
315
}
293
316
294
- next_jump = br;
317
+ // This is necessary as pt doesn't log the destination of direct
318
+ // jumps (and thus libipt doesn't generate a basic block address).
319
+ while (br.type == CodeBranchType::Jump) {
320
+ evt = trace_evt.mutable_branch_evt ();
321
+ evt->set_source (br.address );
322
+ evt->set_destination (br.ok );
323
+ evt->set_type (trace::BranchType::JUMP);
324
+
325
+ // We generate the event as no basic block event will be
326
+ // generated by ipt.
327
+ bb_hit (bb_hitcount, br.ok );
328
+
329
+ // Sometimes we get duplicates. By setting up the invalid
330
+ // address range we can filter them out.
331
+ bb_low = br.ok ;
332
+ br = disas.get_next_branch (br.ok );
333
+ bb_high = br.address ;
334
+
335
+ branch_os.WriteVarint32 (trace_evt.ByteSize ());
336
+ trace_evt.SerializeToCodedStream (&branch_os);
337
+ }
338
+
339
+ prev_jump = br;
340
+ } else {
341
+ prev_jump.type = CodeBranchType::Invalid;
342
+ bb_low = 0 ;
343
+ bb_high = 0 ;
295
344
}
296
345
}
297
346
0 commit comments