Skip to content

Commit 0e44268

Browse files
committed
Add --trap=ADDR option for fine grained debugging
1 parent e642563 commit 0e44268

6 files changed

Lines changed: 81 additions & 16 deletions

File tree

src/e9patch/e9api.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,11 @@ static void parseInstruction(Binary *B, const Message &msg)
323323
else
324324
pcrel32_idx = pcrel_idx; // Must be pcrel32
325325
}
326+
bool debug = (option_trap_all ||
327+
option_trap.find(address) != option_trap.end());
326328
Instr *I = new Instr(offset, address, length, B->original.bytes + offset,
327329
B->patched.bytes + offset, B->patched.state + offset, pcrel32_idx,
328-
pcrel8_idx, B->elf.pic);
330+
pcrel8_idx, B->elf.pic, debug);
329331
insertInstruction(B, I);
330332
}
331333

src/e9patch/e9json.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,18 @@ static Entry makeLabelEntry(const char *label)
569569
return entry;
570570
}
571571

572+
/*
573+
* Create a DEBUG template entry.
574+
*/
575+
static Entry makeDebugEntry(void)
576+
{
577+
Entry entry;
578+
entry.kind = ENTRY_DEBUG;
579+
entry.length = 0;
580+
entry.macro = nullptr;
581+
return entry;
582+
}
583+
572584
/*
573585
* Convert an integer.
574586
*/
@@ -714,13 +726,13 @@ static Entry makeDataEntry(Parser &parser)
714726
/*
715727
* Parse a template object.
716728
*/
717-
static Trampoline *parseTrampoline(Parser &parser, bool int3 = false)
729+
static Trampoline *parseTrampoline(Parser &parser, bool debug = false)
718730
{
719731
std::vector<uint8_t> bytes;
720732
std::vector<Entry> entries;
721733

722-
if (int3)
723-
bytes.push_back(0xCC); // INT3 instruction
734+
if (debug)
735+
entries.push_back(makeDebugEntry());
724736

725737
char token = getToken(parser);
726738
bool once = true;
@@ -1017,8 +1029,7 @@ static void parseParams(Parser &parser, Message &msg)
10171029
value.string = dupString(parser.s);
10181030
break;
10191031
case PARAM_TEMPLATE:
1020-
value.trampoline = parseTrampoline(parser,
1021-
option_trap_all);
1032+
value.trampoline = parseTrampoline(parser, /*debug=*/true);
10221033
break;
10231034
case PARAM_METADATA:
10241035
value.metadata = parseMetadata(parser);

src/e9patch/e9patch.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ intptr_t option_mem_ub = INTPTR_MAX;
4848
size_t option_mem_mapping_size = PAGE_SIZE;
4949
bool option_mem_multi_page = true;
5050
bool option_static_loader = false;
51+
std::set<intptr_t> option_trap;
5152
bool option_trap_all = false;
5253
static std::string option_input("-");
5354
static std::string option_output("-");
@@ -252,10 +253,14 @@ static void usage(FILE *stream, const char *progname)
252253
"\t\tEnable [disables] backward jumps for tactic T3.\n"
253254
"\t\tDefault: true (enabled)\n"
254255
"\n"
256+
"\t--trap=ADDR\n"
257+
"\t\tInsert a trap (int3) instruction at the trampoline entry for\n"
258+
"\t\tthe instruction at address ADDR. This can be used to debug\n"
259+
"\t\tthe trampoline using GDB.\n"
260+
"\n"
255261
"\t--trap-all[=false]\n"
256262
"\t\tEnable [disable] the insertion of a trap (int3) instruction at\n"
257-
"\t\teach trampoline entry. This can be used to debug trampoline\n"
258-
"\t\tusing gdb.\n"
263+
"\t\tall trampoline entries.\n"
259264
"\t\tDefault: false (disabled)\n"
260265
"\n", progname, PAGE_SIZE, PAGE_SIZE);
261266
}
@@ -286,6 +291,7 @@ enum Option
286291
OPTION_TACTIC_T2,
287292
OPTION_TACTIC_T3,
288293
OPTION_TACTIC_BACKWARD_T3,
294+
OPTION_TRAP,
289295
OPTION_TRAP_ALL,
290296
};
291297

@@ -319,7 +325,8 @@ void parseOptions(int argc, char * const argv[], bool api)
319325
{"tactic-T2", opt_arg, nullptr, OPTION_TACTIC_T2},
320326
{"tactic-T3", opt_arg, nullptr, OPTION_TACTIC_T3},
321327
{"tactic-backward-T3", no_arg, nullptr, OPTION_TACTIC_BACKWARD_T3},
322-
{"trap-all", no_arg, nullptr, OPTION_TRAP_ALL},
328+
{"trap", req_arg, nullptr, OPTION_TRAP},
329+
{"trap-all", opt_arg, nullptr, OPTION_TRAP_ALL},
323330
{nullptr, no_arg, nullptr, 0}
324331
};
325332

@@ -403,6 +410,10 @@ void parseOptions(int argc, char * const argv[], bool api)
403410
option_tactic_backward_T3 =
404411
parseBoolOptArg("--tactic-backward-T3", optarg);
405412
break;
413+
case OPTION_TRAP:
414+
option_trap.insert(parseIntOptArg("--trap", optarg, 0,
415+
INTPTR_MAX));
416+
break;
406417
case OPTION_TRAP_ALL:
407418
option_trap_all = parseBoolOptArg("--trap-all", optarg);
408419
break;

src/e9patch/e9patch.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <deque>
3030
#include <map>
31+
#include <set>
3132
#include <vector>
3233

3334
#define NO_RETURN __attribute__((__noreturn__))
@@ -107,6 +108,7 @@ struct Bounds
107108
*/
108109
enum EntryKind
109110
{
111+
ENTRY_DEBUG,
110112
ENTRY_BYTES,
111113
ENTRY_ZEROES,
112114
ENTRY_LABEL,
@@ -183,6 +185,7 @@ struct Instr
183185
const size_t pcrel32_idx:4; // 32bit PC-relative imm idx (or 0)
184186
const size_t pcrel8_idx:4; // 8bit PC-relative imm idx (or 0)
185187
const size_t pic:1; // PIC? (stored here for convenience)
188+
const size_t debug:1; // Debug trampoline?
186189
size_t evicted:1; // The instruction evicted?
187190
size_t no_optimize:1; // Disable -Ojump-elim?
188191
const intptr_t addr; // The address of the instruction
@@ -216,10 +219,11 @@ struct Instr
216219

217220
Instr(off_t offset, intptr_t addr, size_t size, const uint8_t *original,
218221
uint8_t *bytes, uint8_t *state, size_t pcrel32_idx,
219-
size_t pcrel8_idx, bool pic) :
222+
size_t pcrel8_idx, bool pic, bool debug) :
220223
offset((size_t)offset), addr(addr), size(size), original(original),
221224
patched(bytes, state), pcrel32_idx(pcrel32_idx),
222-
pcrel8_idx(pcrel8_idx), pic(pic), evicted(false), no_optimize(false)
225+
pcrel8_idx(pcrel8_idx), pic(pic), debug(debug), evicted(false),
226+
no_optimize(false)
223227
{
224228
;
225229
}
@@ -374,6 +378,7 @@ extern bool option_tactic_T2;
374378
extern bool option_tactic_T3;
375379
extern bool option_tactic_backward_T3;
376380
extern bool option_static_loader;
381+
extern std::set<intptr_t> option_trap;
377382
extern bool option_trap_all;
378383
extern size_t option_mem_granularity;
379384
extern size_t option_mem_mapping_size;

src/e9patch/e9trampoline.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ static int getTrampolineSize(const Trampoline *T, const Instr *I,
234234
const Entry &entry = T->entries[i];
235235
switch (entry.kind)
236236
{
237+
case ENTRY_DEBUG:
238+
size += (I != nullptr && I->debug? /*sizeof(int3)=*/1: 0);
239+
continue;
237240
case ENTRY_BYTES:
238241
case ENTRY_ZEROES:
239242
size += entry.length;
@@ -321,6 +324,9 @@ static BoundsInfo getTrampolineBounds(const Trampoline *T, const Instr *I,
321324
const Entry &entry = T->entries[i];
322325
switch (entry.kind)
323326
{
327+
case ENTRY_DEBUG:
328+
b.size += (I != nullptr && I->debug? /*sizeof(int3)=*/1: 0);
329+
continue;
324330
case ENTRY_BYTES:
325331
case ENTRY_ZEROES:
326332
b.size += entry.length;
@@ -422,6 +428,8 @@ static off_t buildLabelSet(const Trampoline *T, const Instr *I, off_t offset,
422428
const Entry &entry = T->entries[i];
423429
switch (entry.kind)
424430
{
431+
case ENTRY_DEBUG:
432+
offset += (I != nullptr && I->debug? /*sizeof(int3)=*/1: 0);
425433
case ENTRY_BYTES:
426434
case ENTRY_ZEROES:
427435
offset += entry.length;
@@ -528,14 +536,18 @@ static off_t lookupLabel(const char *label, const Instr *I, int32_t offset32,
528536
/*
529537
* Build the trampoline bytes.
530538
*/
531-
static void buildBytes(const Trampoline *T, const Instr *I,
532-
int32_t offset32, const LabelSet &labels, Buffer &buf)
539+
static void buildBytes(const Trampoline *T, const Instr *I, int32_t offset32,
540+
const LabelSet &labels, Buffer &buf)
533541
{
534542
for (unsigned i = 0; i < T->num_entries; i++)
535543
{
536544
const Entry &entry = T->entries[i];
537545
switch (entry.kind)
538546
{
547+
case ENTRY_DEBUG:
548+
if (I != nullptr && I->debug)
549+
buf.push(/*int3=*/0xcc);
550+
continue;
539551
case ENTRY_BYTES:
540552
buf.push(entry.bytes, entry.length);
541553
continue;

src/e9tool/e9tool.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2051,9 +2051,9 @@ static void usage(FILE *stream, const char *progname)
20512051
"\n"
20522052
"\t\tThe default syntax is \"ATT\".\n"
20532053
"\n"
2054-
"\t--trap-all\n"
2055-
"\t\tInsert a trap (int3) instruction at each trampoline entry.\n"
2056-
"\t\tThis can be used for debugging with gdb.\n"
2054+
"\t--trap=ADDR, --trap-all\n"
2055+
"\t\tInsert a trap (int3) instruction at the corresponding\n"
2056+
"\t\ttrampoline entry. This can be used for debugging with gdb.\n"
20572057
"\n", progname);
20582058
}
20592059

@@ -2079,6 +2079,7 @@ enum Option
20792079
OPTION_STATIC_LOADER,
20802080
OPTION_SYNC,
20812081
OPTION_SYNTAX,
2082+
OPTION_TRAP,
20822083
OPTION_TRAP_ALL,
20832084
};
20842085

@@ -2111,6 +2112,7 @@ int main(int argc, char **argv)
21112112
{"static-loader", no_arg, nullptr, OPTION_STATIC_LOADER},
21122113
{"sync", req_arg, nullptr, OPTION_SYNC},
21132114
{"syntax", req_arg, nullptr, OPTION_SYNTAX},
2115+
{"trap", req_arg, nullptr, OPTION_TRAP},
21142116
{"trap-all", no_arg, nullptr, OPTION_TRAP_ALL},
21152117
{nullptr, no_arg, nullptr, 0}
21162118
};
@@ -2123,6 +2125,7 @@ int main(int argc, char **argv)
21232125
bool option_executable = false, option_shared = false,
21242126
option_static_loader = false;
21252127
std::string option_start(""), option_end(""), option_backend("./e9patch");
2128+
std::set<intptr_t> option_trap;
21262129
MatchExpr *option_match = nullptr;
21272130
while (true)
21282131
{
@@ -2236,6 +2239,18 @@ int main(int argc, char **argv)
22362239
error("bad value \"%s\" for `--syntax' option; "
22372240
"expected \"ATT\" or \"intel\"", optarg);
22382241
break;
2242+
case OPTION_TRAP:
2243+
{
2244+
errno = 0;
2245+
char *end = nullptr;
2246+
unsigned long r = strtoul(optarg, &end, 0);
2247+
if (errno != 0 || end == optarg ||
2248+
(end != nullptr && *end != '\0') || r > INTPTR_MAX)
2249+
error("bad value for \"%s\" for `--trap' option; "
2250+
"expected an address", optarg);
2251+
option_trap.insert(r);
2252+
break;
2253+
}
22392254
case OPTION_TRAP_ALL:
22402255
option_trap_all = true;
22412256
break;
@@ -2367,6 +2382,15 @@ int main(int argc, char **argv)
23672382
options.push_back(option);
23682383
if (options.size() > 0)
23692384
sendOptionMessage(backend.out, options);
2385+
for (auto addr: option_trap)
2386+
{
2387+
options.clear();
2388+
options.push_back("--trap");
2389+
std::string val;
2390+
val += std::to_string(addr);
2391+
options.push_back(val.c_str());
2392+
sendOptionMessage(backend.out, options);
2393+
}
23702394

23712395
/*
23722396
* Initialize all plugins:

0 commit comments

Comments
 (0)