* Flush the patching queue up to the new cursor. */
| 55 | * Flush the patching queue up to the new cursor. |
| 56 | */ |
| 57 | static void queueFlush(Binary *B, intptr_t cursor) |
| 58 | { |
| 59 | if (B->cursor <= cursor) |
| 60 | error("failed to patch instruction at address 0x%lx; \"patch\" " |
| 61 | "messages were not send in reverse order", cursor); |
| 62 | B->cursor = cursor; |
| 63 | |
| 64 | cursor += std::max( |
| 65 | T0_LIMIT * /*max instruction size=*/15, |
| 66 | /*max short jmp=*/ INT8_MAX + 2 + /*max instruction size=*/15) + |
| 67 | /*a bit extra=*/32; |
| 68 | while (!B->Q.empty() && |
| 69 | (B->Q.back().options || B->Q.back().I->addr > cursor)) |
| 70 | { |
| 71 | const auto &entry = B->Q.back(); |
| 72 | if (!entry.options) |
| 73 | { |
| 74 | // Patch entry |
| 75 | Instr *I = entry.I; |
| 76 | const Trampoline *T = entry.T; |
| 77 | switch (I->STATE[0]) |
| 78 | { |
| 79 | case STATE_QUEUED: |
| 80 | for (unsigned i = 0; i < I->size; i++) |
| 81 | { |
| 82 | assert(I->STATE[i] == STATE_QUEUED); |
| 83 | I->STATE[i] = STATE_INSTRUCTION; |
| 84 | } |
| 85 | I->debug = (option_trap_all || |
| 86 | option_trap.find(I->addr) != option_trap.end()); |
| 87 | if (patch(*B, I, T)) |
| 88 | stat_num_patched++; |
| 89 | else |
| 90 | stat_num_failed++; |
| 91 | break; |
| 92 | default: |
| 93 | // For other states we assume T0 was applies: |
| 94 | stat_num_patched++; |
| 95 | stat_num_T0++; |
| 96 | log(COLOR_GREEN, '.'); |
| 97 | break; |
| 98 | } |
| 99 | } |
| 100 | else |
| 101 | { |
| 102 | // Options entry |
| 103 | char * const *argv = entry.argv; |
| 104 | parseOptions(B, argv); |
| 105 | delete[] argv; |
| 106 | } |
| 107 | B->Q.pop_back(); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | /* |
| 112 | * Queue an instruction for patching. |