@@ -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 */
20432014struct 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};
20522023struct 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};
20692040struct 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