Skip to content

Commit 27aeee5

Browse files
committed
Make trampolines composable.
Previously, there could only be ONE trampoline per matching instruction. E.g.: ./e9tool -M m1 -A print -M m2 -A 'call ...' If an instruction I matches *both* m1 and m2, then E9Tool will only choose the FIRST trampoline (i.e., print), and call trampoline will not be used. This commit changes the semantics so that the instruction I will be instrumented with *both* the print AND call trampolines executed in order. This makes it easy to compose instrumations, e.g., AFL instrumentation can be composed with print instrumentation for debugging, etc. Previously it was highly non-trivial to compose trampolines. This is a complex change and a WIP. The current commit breaks some features, like plugins, which need to be redesigned and fixed later.
1 parent 938649f commit 27aeee5

9 files changed

Lines changed: 499 additions & 246 deletions

File tree

src/e9tool/e9frontend.cpp

Lines changed: 33 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,9 +1420,19 @@ void e9frontend::sendMetadataFooter(FILE *out)
14201420
/*
14211421
* Send definition header.
14221422
*/
1423-
void e9frontend::sendDefinitionHeader(FILE *out, const char *name)
1423+
void e9frontend::sendDefinitionHeader(FILE *out, const char *patch,
1424+
const char *name)
14241425
{
1425-
fprintf(out, "\"$%s\":", name);
1426+
fprintf(out, "\"$%s@%s\":[", name, patch);
1427+
}
1428+
1429+
/*
1430+
* Send definition footer.
1431+
*/
1432+
void e9frontend::sendDefinitionFooter(FILE *out, bool last)
1433+
{
1434+
putc(']', out);
1435+
sendSeparator(out, last);
14261436
}
14271437

14281438
/*
@@ -1552,35 +1562,6 @@ static unsigned sendInstructionMessage(FILE *out, intptr_t addr,
15521562
return sendMessageFooter(out);
15531563
}
15541564

1555-
/*
1556-
* Send a "patch" message.
1557-
*/
1558-
unsigned e9frontend::sendPatchMessage(FILE *out, const char *trampoline,
1559-
off_t offset, const Metadata *metadata)
1560-
{
1561-
sendMessageHeader(out, "patch");
1562-
sendParamHeader(out, "trampoline");
1563-
sendString(out, trampoline);
1564-
sendSeparator(out);
1565-
if (metadata != nullptr)
1566-
{
1567-
sendParamHeader(out, "metadata");
1568-
sendMetadataHeader(out);
1569-
for (unsigned i = 0; metadata[i].name != nullptr; i++)
1570-
{
1571-
sendDefinitionHeader(out, metadata[i].name);
1572-
sendCode(out, metadata[i].data);
1573-
sendSeparator(out, (metadata[i+1].name == nullptr));
1574-
}
1575-
sendMetadataFooter(out);
1576-
sendSeparator(out);
1577-
}
1578-
sendParamHeader(out, "offset");
1579-
sendInteger(out, (intptr_t)offset);
1580-
sendSeparator(out, /*last=*/true);
1581-
return sendMessageFooter(out, /*sync=*/true);
1582-
}
1583-
15841565
/*
15851566
* Send an "emit" message.
15861567
*/
@@ -1675,8 +1656,7 @@ unsigned e9frontend::sendPassthruTrampolineMessage(FILE *out)
16751656
sendString(out, "$passthru");
16761657
sendSeparator(out);
16771658
sendParamHeader(out, "template");
1678-
putc('[', out);
1679-
fprintf(out, "\"$instruction\",\"$continue\"]");
1659+
fputs("[]", out);
16801660
sendSeparator(out, /*last=*/true);
16811661
return sendMessageFooter(out, /*sync=*/true);
16821662
}
@@ -1720,13 +1700,13 @@ unsigned e9frontend::sendPrintTrampolineMessage(FILE *out,
17201700
fprintf(out, "%u,", 0x52);
17211701
fprintf(out, "%u,%u,", 0x41, 0x53);
17221702

1723-
// leaq .Lstring(%rip), %rsi
1703+
// leaq .Lasm(%rip), %rsi
17241704
// mov $strlen,%edx
17251705
// mov $0x2,%edi # stderr
17261706
// mov $0x1,%eax # SYS_write
1727-
fprintf(out, "%u,%u,%u,{\"rel32\":\".Lstring\"},",
1707+
fprintf(out, "%u,%u,%u,{\"rel32\":\".Lasm@print\"},",
17281708
0x48, 0x8d, 0x35);
1729-
fprintf(out, "%u,\"$asmStrLen\",", 0xba);
1709+
fprintf(out, "%u,\"$ASM_LEN@print\",", 0xba);
17301710
fprintf(out, "%u,{\"int32\":%d},",
17311711
0xbf, 0x02);
17321712
fprintf(out, "%u,{\"int32\":%d},",
@@ -1785,9 +1765,9 @@ unsigned e9frontend::sendPrintTrampolineMessage(FILE *out,
17851765
// push %rdx # Key = NULL
17861766
// push %rdx # ByteOffset = NULL
17871767
// mov $strlen,%eax
1788-
// push %rax # Length=asmStrLen
1789-
// leaq .Lstring(%rip),%rax
1790-
// push %rax # Buffer=asmStr
1768+
// push %rax # Length=ASM_LEN
1769+
// leaq .Lasm(%rip),%rax
1770+
// push %rax # Buffer=ASM
17911771
// lea 0x78(%rsp),%rax
17921772
// push %rax # IoStatusBlock=...
17931773
// lea -0x20(%rsp),%rsp
@@ -1810,10 +1790,10 @@ unsigned e9frontend::sendPrintTrampolineMessage(FILE *out,
18101790
0x41, 0x89, 0xd1);
18111791
fprintf(out, "%u,", 0x52);
18121792
fprintf(out, "%u,", 0x52);
1813-
fprintf(out, "%u,\"$asmStrLen\",",
1793+
fprintf(out, "%u,\"$ASM_LEN@print\",",
18141794
0xb8);
18151795
fprintf(out, "%u,", 0x50);
1816-
fprintf(out, "%u,%u,%u,{\"rel32\":\".Lstring\"},",
1796+
fprintf(out, "%u,%u,%u,{\"rel32\":\".Lasm@print\"},",
18171797
0x48, 0x8d, 0x05);
18181798
fprintf(out, "%u,", 0x50);
18191799
fprintf(out, "%u,%u,%u,%u,{\"int8\":%d},",
@@ -1858,12 +1838,7 @@ unsigned e9frontend::sendPrintTrampolineMessage(FILE *out,
18581838
break;
18591839
}
18601840

1861-
// Execute the displaced instruction, and return from the trampoline:
1862-
fprintf(out, ",\"$instruction\",\"$continue\"");
1863-
1864-
// Place the string representation of the instruction here:
1865-
fprintf(out, ",\".Lstring\",\"$asmStr\"]");
1866-
1841+
fputc(']', out);
18671842
sendSeparator(out, /*last=*/true);
18681843
return sendMessageFooter(out, /*sync=*/true);
18691844
}
@@ -1910,9 +1885,7 @@ unsigned e9frontend::sendTrapTrampolineMessage(FILE *out)
19101885
sendString(out, "$trap");
19111886
sendSeparator(out);
19121887
sendParamHeader(out, "template");
1913-
putc('[', out);
1914-
fprintf(out, "%u,\"$instruction\",\"$continue\"", 0xcc);
1915-
putc(']', out);
1888+
fprintf(out, "[%u]", 0xcc);
19161889
sendSeparator(out, /*last=*/true);
19171890
return sendMessageFooter(out, /*sync=*/true);
19181891
}
@@ -3649,19 +3622,13 @@ unsigned e9frontend::sendCallTrampolineMessage(FILE *out, const char *name,
36493622
break;
36503623
}
36513624

3625+
const char *patch = name+1;
36523626
sendMessageHeader(out, "trampoline");
36533627
sendParamHeader(out, "name");
36543628
sendString(out, name);
36553629
sendSeparator(out);
36563630
sendParamHeader(out, "template");
36573631
putc('[', out);
3658-
3659-
// Put a label at the start of the trampoline:
3660-
fputs("\".Ltrampoline\",", out);
3661-
3662-
// Put instruction here for "after" instrumentation.
3663-
if (pos == POS_AFTER)
3664-
fprintf(out, "\"$instruction\",");
36653632

36663633
// Adjust the stack:
36673634
fprintf(out, "%u,%u,%u,%u,{\"int32\":%d},", // lea -0x4000(%rsp),%rsp
@@ -3683,7 +3650,7 @@ unsigned e9frontend::sendCallTrampolineMessage(FILE *out, const char *name,
36833650
}
36843651

36853652
// Load the arguments:
3686-
fputs("\"$loadArgs\",", out);
3653+
fprintf(out, "\"$ARGS@%s\",", patch);
36873654
if (!sysv)
36883655
{
36893656
// lea -0x20(%rsp),%rsp # MS ABI red-zone
@@ -3692,7 +3659,7 @@ unsigned e9frontend::sendCallTrampolineMessage(FILE *out, const char *name,
36923659
}
36933660

36943661
// Call the function:
3695-
fprintf(out, "%u,\"$function\",", 0xe8); // callq function
3662+
fprintf(out, "%u,\"$FUNC@%s\",", 0xe8, patch); // callq function
36963663

36973664
// Restore the state:
36983665
if (!sysv)
@@ -3701,7 +3668,7 @@ unsigned e9frontend::sendCallTrampolineMessage(FILE *out, const char *name,
37013668
fprintf(out, "%u,%u,%u,%u,{\"int8\":%d},",
37023669
0x48, 0x8d, 0x64, 0x24, 0x20);
37033670
}
3704-
fputs("\"$restoreState\",", out);
3671+
fprintf(out, "\"$RSTOR@%s\",", patch);
37053672

37063673
// If clean & conditional & !state, store result in %rcx, else in %rax
37073674
bool preserve_rax = (conditional || !clean);
@@ -3733,13 +3700,13 @@ unsigned e9frontend::sendCallTrampolineMessage(FILE *out, const char *name,
37333700
// xchg %rax,%rcx
37343701
//
37353702
fprintf(out, "%u,%u,", 0x48, 0x91);
3736-
fprintf(out, "%u,{\"rel8\":\".Lskip\"},", 0xe3);
3703+
fprintf(out, "%u,{\"rel8\":\".Lskip@%s\"},", 0xe3, patch);
37373704
fprintf(out, "%u,%u,", 0x48, 0x91);
37383705
}
37393706
else
37403707
{
37413708
// jrcxz .Lskip
3742-
fprintf(out, "%u,{\"rel8\":\".Lskip\"},", 0xe3);
3709+
fprintf(out, "%u,{\"rel8\":\".Lskip@%s\"},", 0xe3, patch);
37433710
}
37443711

37453712
// The result is non-zero
@@ -3759,7 +3726,7 @@ unsigned e9frontend::sendCallTrampolineMessage(FILE *out, const char *name,
37593726
fprintf(out, "%u,%u,%u,%u,%u,{\"int32\":%d},",
37603727
0x64, 0x48, 0x89, (result_rax? 0x04: 0x0c), 0x25, tls_offset);
37613728
fprintf(out, "%u,", (result_rax? 0x58: 0x59));
3762-
fputs("\"$restoreRSP\",",out);
3729+
fprintf(out, "\"$RSTOR_RSP@%s\",", patch);
37633730

37643731
// jmpq *%fs:0x40
37653732
fprintf(out, "%u,%u,%u,%u,{\"int32\":%d},",
@@ -3768,12 +3735,12 @@ unsigned e9frontend::sendCallTrampolineMessage(FILE *out, const char *name,
37683735
else
37693736
{
37703737
fprintf(out, "%u,", (result_rax? 0x58: 0x59));
3771-
fputs("\"$restoreRSP\",",out);
3738+
fprintf(out, "\"$RSTOR_RSP@%s\",", patch);
37723739
fputs("\"$continue\",", out);
37733740
}
37743741

37753742
// The result is zero...
3776-
fputs("\".Lskip\",", out);
3743+
fprintf(out, "\".Lskip@%s\",", patch);
37773744
if (result_rax)
37783745
{
37793746
// xchg %rax,%rcx
@@ -3783,26 +3750,8 @@ unsigned e9frontend::sendCallTrampolineMessage(FILE *out, const char *name,
37833750
}
37843751

37853752
// Restore the stack pointer.
3786-
fputs("\"$restoreRSP\",",out);
3753+
fprintf(out, "\"$RSTOR_RSP@%s\"]", patch);
37873754

3788-
// Put instruction here for "before" instrumentation:
3789-
switch (pos)
3790-
{
3791-
case POS_BEFORE:
3792-
fputs("\"$instruction\",", out);
3793-
break;
3794-
default:
3795-
break;
3796-
}
3797-
3798-
// Return from trampoline:
3799-
fputs("\"$continue\"", out);
3800-
3801-
// Any additional data:
3802-
if (args.size() > 0)
3803-
fputs(",\"$data\"]", out);
3804-
else
3805-
fputc(']', out);
38063755
sendSeparator(out, /*last=*/true);
38073756
return sendMessageFooter(out, /*sync=*/true);
38083757
}

src/e9tool/e9frontend.h

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,7 @@ enum CallJump
9999
/*
100100
* Metadata.
101101
*/
102-
struct Metadata
103-
{
104-
const char *name; // Metadata name.
105-
const char *data; // Metadata data.
106-
};
102+
typedef std::map<const char *, const char *> Metadata;
107103

108104
/*
109105
* Mnemonics.
@@ -2077,18 +2073,18 @@ struct OpInfo
20772073
*/
20782074
struct Instr
20792075
{
2080-
size_t address:48; // Instruction address
2081-
size_t action:16; // (E9Tool internal)
2076+
size_t offset:40; // Instruction offset in file
2077+
size_t matching:24; // (E9Tool internal)
20822078

2083-
size_t offset:48; // Instruction offset in file
2079+
size_t address:48; // Instruction address
20842080
size_t size:4; // Instruction size
20852081

20862082
size_t data:1; // (E9Tool internal)
20872083
size_t patch:1; // (E9Tool internal)
20882084
size_t emitted:1; // (E9Tool internal)
20892085
size_t jump:1; // (E9Tool internal)
20902086

2091-
Instr() : patch(0), emitted(0), action(0), jump(0)
2087+
Instr() : patch(0), emitted(0), matching(0), jump(0)
20922088
{
20932089
;
20942090
}
@@ -2314,7 +2310,9 @@ extern void sendParamHeader(FILE *out, const char *name);
23142310
extern void sendSeparator(FILE *out, bool last = false);
23152311
extern void sendMetadataHeader(FILE *out);
23162312
extern void sendMetadataFooter(FILE *out);
2317-
extern void sendDefinitionHeader(FILE *out, const char *name);
2313+
extern void sendDefinitionHeader(FILE *out, const char *patch,
2314+
const char *name);
2315+
extern void sendDefinitionFooter(FILE *out, bool last = false);
23182316
extern void sendInteger(FILE *out, intptr_t i);
23192317
extern void sendString(FILE *out, const char *s);
23202318
extern void sendCode(FILE *out, const char *code);
@@ -2323,8 +2321,8 @@ extern void sendCode(FILE *out, const char *code);
23232321
* High-level functions that send complete E9PATCH JSONRPC messages:
23242322
*/
23252323
extern unsigned sendOptionsMessage(FILE *out, std::vector<const char *> &argv);
2326-
extern unsigned sendPatchMessage(FILE *out, const char *trampoline,
2327-
off_t offset, const Metadata *metadata = nullptr);
2324+
// extern unsigned sendPatchMessage(FILE *out, const char *trampoline,
2325+
// off_t offset, const Metadata *metadata = nullptr);
23282326
extern unsigned sendReserveMessage(FILE *out, intptr_t addr, size_t len,
23292327
bool absolute = false);
23302328
extern unsigned sendReserveMessage(FILE *out, intptr_t addr,

0 commit comments

Comments
 (0)