Skip to content

Commit 1a4a5b6

Browse files
committed
Fixed the broken trace generation
1 parent 7275520 commit 1a4a5b6

File tree

2 files changed

+125
-145
lines changed

2 files changed

+125
-145
lines changed

scripts/trace_dump.py

Lines changed: 0 additions & 69 deletions
This file was deleted.

src/extractor/pt_extractor.cpp

Lines changed: 125 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,50 @@ static void bb_hit(std::map<uint64_t, uint64_t>& hitmap, uint64_t address)
137137
}
138138
}
139139

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+
140184
int pt_process(std::string perf_path, std::string binary_path,
141185
std::string output_path)
142186
{
@@ -188,98 +232,77 @@ int pt_process(std::string perf_path, std::string binary_path,
188232

189233
// Begin processing the trace
190234
int status = 0;
191-
CodeBranch next_jump;
192-
struct pt_block block;
193-
int emptycount = 0;
235+
CodeBranch prev_jump;
194236

195-
next_jump.type = CodeBranchType::Invalid;
237+
uint64_t bb_low = 0;
238+
uint64_t bb_high = 0;
196239

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;
214241

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);
219244

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)
223247
break;
224-
}
225248

226-
// Handling event skipping
227-
if(status & pts_event_pending) {
228-
struct pt_event evt;
229-
int evt_status = 0;
230249

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);
236253

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;
242262

243-
// Now handling jumps
244-
if(disas.is_mapped(block.ip)) {
245-
CodeBranch br = disas.get_next_branch(block.ip);
246263
trace::BranchEvent* evt = nullptr;
247264

248-
bb_hit(bb_hitcount, block.ip);
265+
bb_hit(bb_hitcount, bb_addr);
249266

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;
255272
}
256273

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);
261279
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);
265289
evt->set_type(trace::BranchType::CONDJUMP);
266290
}
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);
283306
}
284307

285308
// We serialize the message
@@ -291,7 +314,33 @@ int pt_process(std::string perf_path, std::string binary_path,
291314
trace_evt.SerializeToCodedStream(&branch_os);
292315
}
293316

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;
295344
}
296345
}
297346

0 commit comments

Comments
 (0)