Skip to content

Commit 3c71df4

Browse files
committed
Refactor: Emit JSON composite trampolines upfront.
1 parent ff9caa3 commit 3c71df4

4 files changed

Lines changed: 236 additions & 102 deletions

File tree

src/e9tool/e9tool.cpp

Lines changed: 137 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ static const char *parseFunctionName(Parser &parser)
11511151
/*
11521152
* Parse a patch.
11531153
*/
1154-
static Patch *parsePatch(const ELF &elf, const char *str)
1154+
static const Patch *parsePatch(const ELF &elf, const char *str)
11551155
{
11561156
PatchKind kind;
11571157
Parser parser(str, "patch", elf);
@@ -1466,6 +1466,7 @@ static Patch *parsePatch(const ELF &elf, const char *str)
14661466

14671467
// Build the patch:
14681468
std::string name;
1469+
static size_t id = 1;
14691470
switch (kind)
14701471
{
14711472
case PATCH_PRINT:
@@ -1478,47 +1479,17 @@ static Patch *parsePatch(const ELF &elf, const char *str)
14781479
return new Patch("$trap", PATCH_TRAP, pos);
14791480
case PATCH_CALL:
14801481
name += "$call_";
1481-
switch (pos)
1482-
{
1483-
case POS_BEFORE:
1484-
name += 'B'; break;
1485-
case POS_REPLACE:
1486-
name += 'R'; break;
1487-
case POS_AFTER:
1488-
name += 'A'; break;
1489-
}
1490-
switch (abi)
1491-
{
1492-
case ABI_CLEAN:
1493-
name += 'C'; break;
1494-
case ABI_NAKED:
1495-
name += 'N'; break;
1496-
}
1497-
switch (jmp)
1498-
{
1499-
case JUMP_NONE:
1500-
name += 'N'; break;
1501-
case JUMP_BREAK:
1502-
name += 'B'; break;
1503-
case JUMP_GOTO:
1504-
name += 'G'; break;
1505-
}
1506-
name += '_';
1507-
name += symbol;
1508-
name += '_';
1509-
name += filename;
1482+
name += std::to_string(id++);
15101483
return new Patch(strDup(name.c_str()), PATCH_CALL, pos, abi, jmp,
15111484
symbol, std::move(args), filename);
15121485
case PATCH_EXIT:
15131486
name += "$exit_";
15141487
name += std::to_string(status);
15151488
return new Patch(strDup(name.c_str()), PATCH_EXIT, pos, status);
15161489
case PATCH_PLUGIN:
1517-
{
15181490
name += "$plugin_";
1519-
name += filename;
1491+
name += std::to_string(id++);
15201492
return new Patch(strDup(name.c_str()), PATCH_PLUGIN, pos, plugin);
1521-
}
15221493
default:
15231494
return nullptr;
15241495
}
@@ -2042,7 +2013,7 @@ static bool matchEval(const MatchExpr *expr, const Targets &targets,
20422013
*/
20432014
struct Matching
20442015
{
2045-
const std::vector<Action *> actions;
2016+
std::vector<Action *> actions;
20462017

20472018
Matching(std::vector<Action *> &&actions) : actions(std::move(actions))
20482019
{
@@ -2051,26 +2022,25 @@ struct Matching
20512022
};
20522023
struct MatchingCmp
20532024
{
2054-
bool operator()(const Matching &m1, const Matching &m2)
2025+
bool operator()(const Matching *m1, const Matching *m2)
20552026
{
20562027
for (size_t i = 0; ; i++)
20572028
{
2058-
if (i >= m1.actions.size())
2059-
return (i < m2.actions.size());
2060-
else if (i >= m2.actions.size())
2029+
if (i >= m1->actions.size())
2030+
return (i < m2->actions.size());
2031+
else if (i >= m2->actions.size())
20612032
return false;
2062-
if (m1.actions[i] < m2.actions[i])
2033+
if (m1->actions[i] < m2->actions[i])
20632034
return true;
2064-
if (m1.actions[i] > m2.actions[i])
2035+
if (m1->actions[i] > m2->actions[i])
20652036
return false;
20662037
}
20672038
}
20682039
};
20692040
struct MatchingCache
20702041
{
2071-
std::map<const Matching, size_t, MatchingCmp> cache;
2042+
std::map<const Matching *, size_t, MatchingCmp> cache;
20722043
std::vector<const Matching *> matchings;
2073-
20742044
};
20752045

20762046
/*
@@ -2090,15 +2060,41 @@ static void match(const std::vector<Action *> &actions, const Targets &targets,
20902060
/*
20912061
* Save matching.
20922062
*/
2093-
static size_t saveMatching(std::vector<Action *> &matching, MatchingCache &Ms)
2063+
static size_t saveMatching(std::vector<Action *> &matching, const InstrInfo *I,
2064+
MatchingCache &Ms)
20942065
{
2066+
// Check for existing:
20952067
Matching M(std::move(matching));
2096-
auto i = Ms.cache.find(M);
2068+
auto i = Ms.cache.find(&M);
20972069
if (i != Ms.cache.end())
20982070
return i->second;
2071+
2072+
// Check if valid (at most one replace):
2073+
bool seen_replace = false, seen_break = false;
2074+
for (const auto *action: matching)
2075+
for (const auto *patch: action->patch)
2076+
seen_break = seen_break ||
2077+
(patch->kind == PATCH_BREAK && patch->pos == POS_BEFORE);
2078+
for (const auto *action: matching)
2079+
{
2080+
for (const auto *patch: action->patch)
2081+
{
2082+
if (patch->pos != POS_REPLACE)
2083+
continue;
2084+
if (seen_replace && !seen_break)
2085+
error("multiple matching \"replace\" trampolines detected "
2086+
"for instruction \"%s\" at address 0x%lx", I->string.instr,
2087+
I->address);
2088+
seen_replace = true;
2089+
seen_break = seen_break || (patch->kind == PATCH_BREAK);
2090+
}
2091+
}
2092+
2093+
// Add to cache:
20992094
size_t idx = Ms.matchings.size();
2100-
auto j = Ms.cache.insert({M, idx});
2101-
Ms.matchings.push_back(&j.first->first);
2095+
Matching *N = new Matching(std::move(M.actions));
2096+
Ms.cache.insert({N, idx});
2097+
Ms.matchings.push_back(N);
21022098
return idx;
21032099
}
21042100

@@ -2671,7 +2667,7 @@ int main(int argc, char **argv)
26712667
std::vector<const Patch *> patch;
26722668
for (const auto &str: entry.patch)
26732669
{
2674-
Patch *P = parsePatch(elf, str.c_str());
2670+
const Patch *P = parsePatch(elf, str.c_str());
26752671
patch.push_back(P);
26762672
if (P->kind == PATCH_BREAK)
26772673
break;
@@ -3015,8 +3011,7 @@ int main(int argc, char **argv)
30153011
section, filename, section);
30163012
}
30173013
Is.shrink_to_fit();
3018-
notifyPlugins(out, &elf, Is.data(), Is.size(),
3019-
EVENT_DISASSEMBLY_COMPLETE);
3014+
notifyPlugins(out, &elf, Is.data(), Is.size(), EVENT_DISASSEMBLY_COMPLETE);
30203015
size_t count = Is.size();
30213016

30223017
// Step (1a): CFG Analysis (if necessary).
@@ -3038,9 +3033,9 @@ int main(int argc, char **argv)
30383033
if (matched)
30393034
{
30403035
Is[i].patch = true;
3041-
Is[i].matching = saveMatching(matching, Ms);
3036+
Is[i].matching = saveMatching(matching, &I, Ms);
30423037
}
3043-
debug("%s0x%lx%s: %s%s%s%s",
3038+
debug("%s0x%lx%s: match %s%s%s%s",
30443039
(option_is_tty? "\33[31m": ""),
30453040
I.address,
30463041
(option_is_tty? "\33[0m": ""),
@@ -3053,52 +3048,24 @@ int main(int argc, char **argv)
30533048
(I.category & CATEGORY_CALL) != 0))
30543049
Is[i].jump = true;
30553050
}
3056-
notifyPlugins(out, &elf, Is.data(), Is.size(),
3057-
EVENT_MATCHING_COMPLETE);
3051+
notifyPlugins(out, &elf, Is.data(), Is.size(), EVENT_MATCHING_COMPLETE);
30583052

3059-
/*
3060-
* Send instructions & patches. Note: this MUST be done in reverse!
3061-
*/
3062-
intptr_t id = -1;
3053+
// Step (3): Send all composite trampolines:
3054+
size_t tid = 0;
3055+
std::map<const Matching *, size_t, MatchingCmp> tmps;
30633056
std::vector<Metadata> metadata;
3064-
for (ssize_t i = (ssize_t)count - 1; i >= 0; i--)
3057+
std::vector<std::vector<Metadata>> metadatas;
3058+
Context cxt = {&elf, Is.data(), count, -1, nullptr, -1};
3059+
for (const auto *M: Ms.matchings)
30653060
{
3066-
switch (option_optimization_level)
3067-
{
3068-
case '2': case '3': case 's':
3069-
if (!Is[i].emitted && Is[i].jump)
3070-
{
3071-
// Always emits jump/calls for -Opeephole
3072-
Is[i].emitted = true;
3073-
sendInstructionMessage(out, Is[i].address,
3074-
Is[i].size, Is[i].offset);
3075-
}
3076-
break;
3077-
}
3078-
if (!Is[i].patch)
3079-
continue;
3080-
3081-
// Disassmble the instruction again.
3082-
RawInstr raw;
3083-
InstrInfo I;
3084-
getInstrInfo(&elf, &Is[i], &I, &raw);
3085-
bool done = false;
3086-
for (ssize_t j = i; !done && j >= 0; j--)
3087-
done = !sendInstructionMessage(out, Is[j], Is[i].address);
3088-
done = false;
3089-
for (size_t j = i + 1; !done && j < count; j++)
3090-
done = !sendInstructionMessage(out, Is[j], Is[i].address);
3091-
3092-
// Send the "patch" message.
3093-
id++;
3094-
Context cxt = {&elf, Is.data(), count, i, &I, id};
3095-
sendMessageHeader(out, "patch");
3096-
sendParamHeader(out, "trampoline");
3061+
sendMessageHeader(out, "trampoline");
3062+
sendParamHeader(out, "name");
3063+
fprintf(out, "\"$tmp_%zu\"", tid);
3064+
sendSeparator(out);
3065+
sendParamHeader(out, "template");
30973066
fputs("[\".Ltrampoline\",", out);
3098-
const Matching *M = Ms.matchings[Is[i].matching];
30993067

31003068
// BEFORE trampolines:
3101-
metadata.clear();
31023069
bool seen_break = false;
31033070
for (const auto *action: M->actions)
31043071
{
@@ -3118,10 +3085,6 @@ int main(int argc, char **argv)
31183085
{
31193086
if (action->patch[j]->pos != POS_REPLACE || seen_break)
31203087
continue;
3121-
if (seen_replace)
3122-
error("multiple matching \"replace\" trampolines for "
3123-
"instruction \"%s\" at address 0x%lx", I.string.instr,
3124-
I.address);
31253088
seen_replace = true;
31263089
seen_break = sendTrampoline(out, action, j, &cxt, metadata);
31273090
}
@@ -3155,25 +3118,97 @@ int main(int argc, char **argv)
31553118
fprintf(out, "\"$DATA@%s\",", patch->name+1);
31563119
}
31573120
fputc(']', out);
3158-
sendSeparator(out);
3121+
sendSeparator(out, /*last=*/true);
3122+
sendMessageFooter(out, /*sync=*/true);
3123+
3124+
metadatas.emplace_back();
3125+
metadatas[tid].swap(metadata);
3126+
tmps.insert({M, tid});
3127+
tid++;
3128+
}
31593129

3160-
if (metadata.size() > 0)
3130+
/*
3131+
* Send instructions & patches. Note: this MUST be done in reverse!
3132+
*/
3133+
debug("--------------------------------------");
3134+
intptr_t id = -1;
3135+
for (ssize_t i = (ssize_t)count - 1; i >= 0; i--)
3136+
{
3137+
switch (option_optimization_level)
3138+
{
3139+
case '2': case '3': case 's':
3140+
if (!Is[i].emitted && Is[i].jump)
3141+
{
3142+
// Always emits jump/calls for -Opeephole
3143+
Is[i].emitted = true;
3144+
sendInstructionMessage(out, Is[i].address,
3145+
Is[i].size, Is[i].offset);
3146+
}
3147+
break;
3148+
}
3149+
if (!Is[i].patch)
3150+
continue;
3151+
3152+
// Disassmble the instruction again.
3153+
RawInstr raw;
3154+
InstrInfo I;
3155+
getInstrInfo(&elf, &Is[i], &I, &raw);
3156+
bool done = false;
3157+
for (ssize_t j = i; !done && j >= 0; j--)
3158+
done = !sendInstructionMessage(out, Is[j], Is[i].address);
3159+
done = false;
3160+
for (size_t j = i + 1; !done && j < count; j++)
3161+
done = !sendInstructionMessage(out, Is[j], Is[i].address);
3162+
3163+
// Send the "patch" message.
3164+
id++;
3165+
Context cxt = {&elf, Is.data(), count, i, &I, id};
3166+
const Matching *M = Ms.matchings[Is[i].matching];
3167+
size_t tid = tmps[M];
3168+
3169+
if (option_debug)
3170+
{
3171+
std::string s;
3172+
bool prev = false;
3173+
for (const auto *action: M->actions)
3174+
{
3175+
for (size_t j = 0, n = action->patch.size(); j < n; j++)
3176+
{
3177+
if (prev)
3178+
s += ',';
3179+
prev = true;
3180+
s += action->patch[j]->name;
3181+
}
3182+
}
3183+
debug("%s0x%lx%s: patch %s%s%s [%s] #%zu",
3184+
(option_is_tty? "\33[31m": ""),
3185+
I.address,
3186+
(option_is_tty? "\33[0m": ""),
3187+
(option_is_tty? "\33[32m": ""),
3188+
I.string.instr,
3189+
(option_is_tty? "\33[0m": ""),
3190+
s.c_str(), tid);
3191+
}
3192+
3193+
sendMessageHeader(out, "patch");
3194+
sendParamHeader(out, "trampoline");
3195+
fprintf(out, "\"$tmp_%zu\",", tid);
3196+
if (metadatas[tid].size() > 0)
31613197
{
31623198
sendParamHeader(out, "metadata");
31633199
sendMetadataHeader(out);
3164-
for (const auto &entry: metadata)
3165-
sendMetadata(out, &elf, entry.action, entry.idx, &I, id, &cxt);
3200+
for (const auto &entry: metadatas[tid])
3201+
sendMetadata(out, &elf, entry.action, entry.idx, &I, id,
3202+
&cxt);
31663203
sendMetadataFooter(out);
31673204
sendSeparator(out);
31683205
}
3169-
31703206
sendParamHeader(out, "offset");
31713207
sendInteger(out, I.offset);
31723208
sendSeparator(out, /*last=*/true);
31733209
sendMessageFooter(out, /*sync=*/true);
31743210
}
3175-
notifyPlugins(out, &elf, Is.data(), Is.size(),
3176-
EVENT_PATCHING_COMPLETE);
3211+
notifyPlugins(out, &elf, Is.data(), Is.size(), EVENT_PATCHING_COMPLETE);
31773212
Is.clear();
31783213

31793214
/*

0 commit comments

Comments
 (0)