Skip to content

Commit 1804d11

Browse files
committed
Update the E9Patch trampoline language.
Make it more consistent with E9Tool: - "$continue" -> "$break" ".Lcontinue" -> ".Lbreak" - "$instruction" -> "$instr" ".Linstruction" -> ".Linstr" - Add a fat "$BREAK" (vs. thin "$break"). The fat break can be optimized using an epilogue, whereas thin break must use a jump. Also refactor some code.
1 parent 4dde018 commit 1804d11

10 files changed

Lines changed: 271 additions & 154 deletions

File tree

examples/plugins/example.cpp

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
* examples/plugins/example.cpp -I . -I capstone/include/
3434
*
3535
* To use:
36-
* $ ./e9tool -M 'plugin[example]' -A 'plugin[example]' program
36+
* $ ./e9tool -M 'plugin(example).match()' \
37+
* -P 'plugin(example).patch()' program
3738
* $ ./a.out
3839
* Trace/breakpoint trap
3940
*/
@@ -54,6 +55,10 @@ using namespace e9frontend;
5455
*/
5556
extern void *e9_plugin_init_v1(FILE *out, const ELF *elf)
5657
{
58+
// The e9_plugin_init_v1() is called once per plugin by E9Tool. This can
59+
// be used to emit additional E9Patch messages, such as address space
60+
// reservations and trampoline templates.
61+
5762
/*
5863
* This example uses 3 counters (one for calls/jumps/returns).
5964
* We allocate and initialize the counters to UINT16_MAX (or the value
@@ -97,49 +102,38 @@ extern void *e9_plugin_init_v1(FILE *out, const ELF *elf)
97102
code << 0x9f << ',';
98103
code << 0x50 << ',';
99104

100-
// Increment the counter and branch if <= 0:
105+
// Increment the counter and trap if <= 0:
101106
//
102107
// mov counter(%rip),%rax
103108
// sub $0x1,%rax
104109
// mov %rax,counter(%rip)
105-
// jle .Ltrap
110+
// jg .Lok
111+
// int3
106112
//
107113
code << 0x48 << ',' << 0x8b << ',' << 0x05 << ",\"$counter\",";
108114
code << 0x48 << ',' << 0x83 << ',' << 0xe8 << ',' << 0x01 << ',';
109115
code << 0x48 << ',' << 0x89 << ',' << 0x05 << ",\"$counter\",";
110-
code << 0x7e << ",{\"rel8\":\".Ltrap\"},";
116+
code << 0x7f << ",{\"rel8\":\".Lok\"},";
117+
code << 0xcc << ',';
111118

112119
// Restore state & return from trampoline:
113120
//
114-
// .Lcont:
121+
// .Lok:
115122
// pop %rax
116123
// add $0x7f,%al
117124
// sahf
118125
// pop %rax
119126
// lea 0x4000(%rsp),%rsp
120-
// $instruction
121-
// $continue
122127
//
123-
code << "\".Lcont\",";
128+
code << "\".Lok\",";
124129
code << 0x58 << ',';
125130
code << 0x04 << ',' << 0x7f << ',';
126131
code << 0x9e << ',';
127132
code << 0x58 << ',';
128133
code << 0x48 << ',' << 0x8d << ',' << 0xa4 << ',' << 0x24 << ','
129-
<< 0x00 << ',' << 0x40 << ',' << 0x00 << ',' << 0x00 << ',';
130-
code << "\"$instruction\",";
131-
code << "\"$continue\",";
134+
<< 0x00 << ',' << 0x40 << ',' << 0x00 << ',' << 0x00;
132135

133-
// Trap:
134-
//
135-
// .Ltrap:
136-
// int3
137-
// jmp .Lcont
138-
code << "\".Ltrap\",";
139-
code << 0xcc << ',';
140-
code << 0xeb << ",{\"rel8\":\".Lcont\"}";
141-
142-
sendTrampolineMessage(out, "$cflimit", code.str().c_str());
136+
sendTrampolineMessage(out, "$limit", code.str().c_str());
143137

144138
return nullptr;
145139
}
@@ -149,6 +143,12 @@ extern void *e9_plugin_init_v1(FILE *out, const ELF *elf)
149143
*/
150144
extern intptr_t e9_plugin_match_v1(FILE *out, const Context *cxt, void *arg)
151145
{
146+
// The e9_plugin_match_v1() function is invoked once by E9Tool for each
147+
// disassembled instruction. The function should return a value that is
148+
// used for matching.
149+
150+
// For this example we return a non-zero value for all
151+
// control-flow-transfer instructions:
152152
switch (cxt->I->mnemonic)
153153
{
154154
case MNEMONIC_RET:
@@ -175,15 +175,41 @@ extern intptr_t e9_plugin_match_v1(FILE *out, const Context *cxt, void *arg)
175175
extern void e9_plugin_patch_v1(FILE *out, Phase phase, const Context *cxt,
176176
void *arg)
177177
{
178+
// The e9_plugin_patch_v1() function is invoked by E9Tool in order to
179+
// build "patch" messages for E9Patch. This function is invoked in three
180+
// main phases: CODE, DATA and METADATA, as described below.
181+
//
182+
// Patching phases:
183+
//
184+
// - CODE : Called once per trampoline template.
185+
// Specifies the "code" part of the trampoline template that
186+
// will be executed for each matching instruction.
187+
//
188+
// - DATA : Called once per trampoline template.
189+
// Specifies the "data" part of the trampoline template that
190+
// can be referenced/used by the code part. The data must be
191+
// read-only. The data part is optional.
192+
//
193+
// - METADATA: Called once per patched instruction.
194+
// Specifies the "metadata" which instantiates any macros
195+
// in the trampoline template (both code or data). Data
196+
// that is instruction-specific should be specified as
197+
// metadata. The metadata is optional.
198+
178199
switch (phase)
179200
{
180201
case PHASE_CODE:
181-
fputs("\"$cflimit\",", out);
202+
// The trampoline code simply invokes the $limit template
203+
// (defined above):
204+
fputs("\"$limit\",", out);
182205
return;
183206
case PHASE_DATA:
207+
// There is no trampoline data:
184208
return;
185209
case PHASE_METADATA:
186210
{
211+
// The trampoline metadata instantiates the $counter macro with
212+
// the counter address corresponding to the instruction type:
187213
intptr_t counter = e9_plugin_match_v1(nullptr, cxt, arg);
188214
counter = COUNTERS + (counter - 1) * sizeof(size_t);
189215
fprintf(out, "\"$counter\":{\"rel32\":\"0x%lx\"},", counter);

src/e9patch/e9json.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -590,17 +590,23 @@ static Entry makeMacroEntry(const char *macro)
590590
// Check for built-in macros:
591591
switch (macro[1])
592592
{
593+
case 'B':
594+
if (strcmp(macro, "$BREAK") == 0)
595+
{
596+
entry.kind = ENTRY_BREAK;
597+
entry.optimize = true;
598+
return entry;
599+
}
600+
break;
593601
case 'b':
594602
if (strcmp(macro, "$bytes") == 0)
595603
{
596604
entry.kind = ENTRY_INSTRUCTION_BYTES;
597605
return entry;
598606
}
599-
break;
600-
case 'c':
601-
if (strcmp(macro, "$continue") == 0)
607+
else if (strcmp(macro, "$break") == 0)
602608
{
603-
entry.kind = ENTRY_CONTINUE;
609+
entry.kind = ENTRY_BREAK;
604610
return entry;
605611
}
606612
break;
@@ -769,7 +775,7 @@ static Entry makeDataEntry(Parser &parser)
769775
if (token == TOKEN_STRING && parser.s[0] == '.' &&
770776
parser.s[1] == 'L')
771777
{
772-
entry.use_label = true;
778+
entry.use = true;
773779
entry.label = dupString(parser.s);
774780
}
775781
else
@@ -808,12 +814,12 @@ static Entry makeDataEntry(Parser &parser)
808814
if (token == TOKEN_STRING && parser.s[0] == '.' &&
809815
parser.s[1] == 'L')
810816
{
811-
entry.use_label = true;
817+
entry.use = true;
812818
entry.label = dupString(parser.s);
813819
}
814820
else
815821
{
816-
entry.use_label = false;
822+
entry.use = false;
817823
if (token == TOKEN_NUMBER)
818824
entry.uint64 = (uint64_t)parser.i;
819825
else
@@ -874,14 +880,14 @@ static Trampoline *parseTrampoline(Parser &parser, bool debug = false)
874880
entries.push_back(makeMacroEntry(parser.s));
875881
break;
876882
case '.':
877-
entries.push_back(makeLabelEntry(parser.s));
878-
break;
883+
if (parser.s[1] == 'L')
884+
{
885+
entries.push_back(makeLabelEntry(parser.s));
886+
break;
887+
}
888+
// Fallthrough:
879889
default:
880-
// String constant:
881-
for (unsigned i = 0; parser.s[i] != '\0'; i++)
882-
bytes.push_back((uint8_t)parser.s[i]);
883-
bytes.push_back((uint8_t)'\0');
884-
break;
890+
unexpectedToken(parser, "template entry", token);
885891
}
886892
break;
887893

src/e9patch/e9patch.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ enum EntryKind
150150
ENTRY_INT64,
151151
ENTRY_INSTRUCTION,
152152
ENTRY_INSTRUCTION_BYTES,
153-
ENTRY_CONTINUE,
153+
ENTRY_BREAK,
154154
ENTRY_TAKEN,
155155
};
156156

@@ -163,7 +163,8 @@ struct Entry
163163
union
164164
{
165165
unsigned length; // Entry length
166-
bool use_label; // Use label for rel8/rel32?
166+
bool use; // Label use
167+
bool optimize; // Optimize break?
167168
};
168169
union
169170
{

0 commit comments

Comments
 (0)