/src/capstonev5/Mapping.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* Capstone Disassembly Engine */ | 
| 2 |  | /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ | 
| 3 |  | /*    Rot127 <unisono@quyllur.org>, 2022-2023 */ | 
| 4 |  |  | 
| 5 |  | #include "Mapping.h" | 
| 6 |  |  | 
| 7 |  | // create a cache for fast id lookup | 
| 8 |  | static unsigned short *make_id2insn(const insn_map *insns, unsigned int size) | 
| 9 | 14.6k | { | 
| 10 |  |   // NOTE: assume that the max id is always put at the end of insns array | 
| 11 | 14.6k |   unsigned short max_id = insns[size - 1].id; | 
| 12 | 14.6k |   unsigned short i; | 
| 13 |  |  | 
| 14 | 14.6k |   unsigned short *cache = | 
| 15 | 14.6k |     (unsigned short *)cs_mem_calloc(max_id + 1, sizeof(*cache)); | 
| 16 |  |  | 
| 17 | 41.7M |   for (i = 1; i < size; i++) | 
| 18 | 41.7M |     cache[insns[i].id] = i; | 
| 19 |  |  | 
| 20 | 14.6k |   return cache; | 
| 21 | 14.6k | } | 
| 22 |  |  | 
| 23 |  | // look for @id in @insns, given its size in @max. first time call will update | 
| 24 |  | // @cache. return 0 if not found | 
| 25 |  | unsigned short insn_find(const insn_map *insns, unsigned int max, | 
| 26 |  |        unsigned int id, unsigned short **cache) | 
| 27 | 1.06M | { | 
| 28 | 1.06M |   if (id > insns[max - 1].id) | 
| 29 | 0 |     return 0; | 
| 30 |  |  | 
| 31 | 1.06M |   if (*cache == NULL) | 
| 32 | 14.6k |     *cache = make_id2insn(insns, max); | 
| 33 |  |  | 
| 34 | 1.06M |   return (*cache)[id]; | 
| 35 | 1.06M | } | 
| 36 |  |  | 
| 37 |  | // Gives the id for the given @name if it is saved in @map. | 
| 38 |  | // Returns the id or -1 if not found. | 
| 39 |  | int name2id(const name_map *map, int max, const char *name) | 
| 40 | 20.8k | { | 
| 41 | 20.8k |   int i; | 
| 42 |  |  | 
| 43 | 4.18M |   for (i = 0; i < max; i++) { | 
| 44 | 4.17M |     if (!strcmp(map[i].name, name)) { | 
| 45 | 12.3k |       return map[i].id; | 
| 46 | 12.3k |     } | 
| 47 | 4.17M |   } | 
| 48 |  |  | 
| 49 |  |   // nothing match | 
| 50 | 8.55k |   return -1; | 
| 51 | 20.8k | } | 
| 52 |  |  | 
| 53 |  | // Gives the name for the given @id if it is saved in @map. | 
| 54 |  | // Returns the name or NULL if not found. | 
| 55 |  | const char *id2name(const name_map *map, int max, const unsigned int id) | 
| 56 | 993k | { | 
| 57 | 993k |   int i; | 
| 58 |  |  | 
| 59 | 20.4M |   for (i = 0; i < max; i++) { | 
| 60 | 20.4M |     if (map[i].id == id) { | 
| 61 | 993k |       return map[i].name; | 
| 62 | 993k |     } | 
| 63 | 20.4M |   } | 
| 64 |  |  | 
| 65 |  |   // nothing match | 
| 66 | 0 |   return NULL; | 
| 67 | 993k | } | 
| 68 |  |  | 
| 69 |  | /// Adds a register to the implicit write register list. | 
| 70 |  | /// It will not add the same register twice. | 
| 71 |  | void map_add_implicit_write(MCInst *MI, uint32_t Reg) | 
| 72 | 0 | { | 
| 73 | 0 |   if (!MI->flat_insn->detail) | 
| 74 | 0 |     return; | 
| 75 |  |  | 
| 76 | 0 |   uint16_t *regs_write = MI->flat_insn->detail->regs_write; | 
| 77 | 0 |   for (int i = 0; i < MAX_IMPL_W_REGS; ++i) { | 
| 78 | 0 |     if (i == MI->flat_insn->detail->regs_write_count) { | 
| 79 | 0 |       regs_write[i] = Reg; | 
| 80 | 0 |       MI->flat_insn->detail->regs_write_count++; | 
| 81 | 0 |       return; | 
| 82 | 0 |     } | 
| 83 | 0 |     if (regs_write[i] == Reg) | 
| 84 | 0 |       return; | 
| 85 | 0 |   } | 
| 86 | 0 | } | 
| 87 |  |  | 
| 88 |  | /// Copies the implicit read registers of @imap to @MI->flat_insn. | 
| 89 |  | /// Already present registers will be preserved. | 
| 90 |  | void map_implicit_reads(MCInst *MI, const insn_map *imap) | 
| 91 | 0 | { | 
| 92 | 0 | #ifndef CAPSTONE_DIET | 
| 93 | 0 |   if (!MI->flat_insn->detail) | 
| 94 | 0 |     return; | 
| 95 |  |  | 
| 96 | 0 |   cs_detail *detail = MI->flat_insn->detail; | 
| 97 | 0 |   unsigned Opcode = MCInst_getOpcode(MI); | 
| 98 | 0 |   unsigned i = 0; | 
| 99 | 0 |   uint16_t reg = imap[Opcode].regs_use[i]; | 
| 100 | 0 |   while (reg != 0) { | 
| 101 | 0 |     if (i >= MAX_IMPL_R_REGS || | 
| 102 | 0 |         detail->regs_read_count >= MAX_IMPL_R_REGS) { | 
| 103 | 0 |       printf("ERROR: Too many implicit read register defined in " | 
| 104 | 0 |              "instruction mapping.\n"); | 
| 105 | 0 |       return; | 
| 106 | 0 |     } | 
| 107 | 0 |     detail->regs_read[detail->regs_read_count++] = reg; | 
| 108 | 0 |     reg = imap[Opcode].regs_use[++i]; | 
| 109 | 0 |   } | 
| 110 | 0 | #endif // CAPSTONE_DIET | 
| 111 | 0 | } | 
| 112 |  |  | 
| 113 |  | /// Copies the implicit write registers of @imap to @MI->flat_insn. | 
| 114 |  | /// Already present registers will be preserved. | 
| 115 |  | void map_implicit_writes(MCInst *MI, const insn_map *imap) | 
| 116 | 0 | { | 
| 117 | 0 | #ifndef CAPSTONE_DIET | 
| 118 | 0 |   if (!MI->flat_insn->detail) | 
| 119 | 0 |     return; | 
| 120 |  |  | 
| 121 | 0 |   cs_detail *detail = MI->flat_insn->detail; | 
| 122 | 0 |   unsigned Opcode = MCInst_getOpcode(MI); | 
| 123 | 0 |   unsigned i = 0; | 
| 124 | 0 |   uint16_t reg = imap[Opcode].regs_mod[i]; | 
| 125 | 0 |   while (reg != 0) { | 
| 126 | 0 |     if (i >= MAX_IMPL_W_REGS || | 
| 127 | 0 |         detail->regs_write_count >= MAX_IMPL_W_REGS) { | 
| 128 | 0 |       printf("ERROR: Too many implicit write register defined in " | 
| 129 | 0 |              "instruction mapping.\n"); | 
| 130 | 0 |       return; | 
| 131 | 0 |     } | 
| 132 | 0 |     detail->regs_write[detail->regs_write_count++] = reg; | 
| 133 | 0 |     reg = imap[Opcode].regs_mod[++i]; | 
| 134 | 0 |   } | 
| 135 | 0 | #endif // CAPSTONE_DIET | 
| 136 | 0 | } | 
| 137 |  |  | 
| 138 |  | /// Copies the groups from @imap to @MI->flat_insn. | 
| 139 |  | /// Already present groups will be preserved. | 
| 140 |  | void map_groups(MCInst *MI, const insn_map *imap) | 
| 141 | 0 | { | 
| 142 | 0 | #ifndef CAPSTONE_DIET | 
| 143 | 0 |   if (!MI->flat_insn->detail) | 
| 144 | 0 |     return; | 
| 145 |  |  | 
| 146 | 0 |   cs_detail *detail = MI->flat_insn->detail; | 
| 147 | 0 |   unsigned Opcode = MCInst_getOpcode(MI); | 
| 148 | 0 |   unsigned i = 0; | 
| 149 | 0 |   uint16_t group = imap[Opcode].groups[i]; | 
| 150 | 0 |   while (group != 0) { | 
| 151 | 0 |     if (detail->groups_count >= MAX_NUM_GROUPS) { | 
| 152 | 0 |       printf("ERROR: Too many groups defined in instruction mapping.\n"); | 
| 153 | 0 |       return; | 
| 154 | 0 |     } | 
| 155 | 0 |     detail->groups[detail->groups_count++] = group; | 
| 156 | 0 |     group = imap[Opcode].groups[++i]; | 
| 157 | 0 |   } | 
| 158 | 0 | #endif // CAPSTONE_DIET | 
| 159 | 0 | } | 
| 160 |  |  | 
| 161 |  | // Search for the CS instruction id for the given @MC_Opcode in @imap. | 
| 162 |  | // return -1 if none is found. | 
| 163 |  | unsigned int find_cs_id(unsigned MC_Opcode, const insn_map *imap, | 
| 164 |  |       unsigned imap_size) | 
| 165 | 0 | { | 
| 166 |  |   // binary searching since the IDs are sorted in order | 
| 167 | 0 |   unsigned int left, right, m; | 
| 168 | 0 |   unsigned int max = imap_size; | 
| 169 |  | 
 | 
| 170 | 0 |   right = max - 1; | 
| 171 |  | 
 | 
| 172 | 0 |   if (MC_Opcode < imap[0].id || MC_Opcode > imap[right].id) | 
| 173 |  |     // not found | 
| 174 | 0 |     return -1; | 
| 175 |  |  | 
| 176 | 0 |   left = 0; | 
| 177 |  | 
 | 
| 178 | 0 |   while (left <= right) { | 
| 179 | 0 |     m = (left + right) / 2; | 
| 180 | 0 |     if (MC_Opcode == imap[m].id) { | 
| 181 | 0 |       return m; | 
| 182 | 0 |     } | 
| 183 |  |  | 
| 184 | 0 |     if (MC_Opcode < imap[m].id) | 
| 185 | 0 |       right = m - 1; | 
| 186 | 0 |     else | 
| 187 | 0 |       left = m + 1; | 
| 188 | 0 |   } | 
| 189 |  |  | 
| 190 | 0 |   return -1; | 
| 191 | 0 | } | 
| 192 |  |  | 
| 193 |  | /// Sets the Capstone instruction id which maps to the @MI opcode. | 
| 194 |  | /// If no mapping is found the function returns and prints an error. | 
| 195 |  | void map_cs_id(MCInst *MI, const insn_map *imap, unsigned int imap_size) | 
| 196 | 0 | { | 
| 197 | 0 |   unsigned int i = find_cs_id(MCInst_getOpcode(MI), imap, imap_size); | 
| 198 | 0 |   if (i != -1) { | 
| 199 | 0 |     MI->flat_insn->id = imap[i].mapid; | 
| 200 | 0 |     return; | 
| 201 | 0 |   } | 
| 202 | 0 |   printf("ERROR: Could not find CS id for MCInst opcode: %d\n", | 
| 203 | 0 |          MCInst_getOpcode(MI)); | 
| 204 | 0 |   return; | 
| 205 | 0 | } | 
| 206 |  |  | 
| 207 |  | /// Returns the operand type information from the | 
| 208 |  | /// mapping table for instruction operands. | 
| 209 |  | /// Only usable by `auto-sync` archs! | 
| 210 |  | const cs_op_type mapping_get_op_type(MCInst *MI, unsigned OpNum, | 
| 211 |  |              const map_insn_ops *insn_ops_map, | 
| 212 |  |              size_t map_size) | 
| 213 | 0 | { | 
| 214 | 0 |   assert(MI); | 
| 215 | 0 |   assert(MI->Opcode < map_size); | 
| 216 | 0 |   assert(OpNum < sizeof(insn_ops_map[MI->Opcode].ops) / | 
| 217 | 0 |              sizeof(insn_ops_map[MI->Opcode].ops[0])); | 
| 218 |  |  | 
| 219 | 0 |   return insn_ops_map[MI->Opcode].ops[OpNum].type; | 
| 220 | 0 | } | 
| 221 |  |  | 
| 222 |  | /// Returns the operand access flags from the | 
| 223 |  | /// mapping table for instruction operands. | 
| 224 |  | /// Only usable by `auto-sync` archs! | 
| 225 |  | const cs_ac_type mapping_get_op_access(MCInst *MI, unsigned OpNum, | 
| 226 |  |                const map_insn_ops *insn_ops_map, | 
| 227 |  |                size_t map_size) | 
| 228 | 0 | { | 
| 229 | 0 |   assert(MI); | 
| 230 | 0 |   assert(MI->Opcode < map_size); | 
| 231 | 0 |   assert(OpNum < sizeof(insn_ops_map[MI->Opcode].ops) / | 
| 232 | 0 |              sizeof(insn_ops_map[MI->Opcode].ops[0])); | 
| 233 |  |  | 
| 234 | 0 |   cs_ac_type access = insn_ops_map[MI->Opcode].ops[OpNum].access; | 
| 235 | 0 |   if (MCInst_opIsTied(MI, OpNum) || MCInst_opIsTying(MI, OpNum)) | 
| 236 | 0 |     access |= (access == CS_AC_READ) ? CS_AC_WRITE : CS_AC_READ; | 
| 237 | 0 |   return access; | 
| 238 | 0 | } | 
| 239 |  |  | 
| 240 |  | /// Returns the operand at detail->arch.operands[op_count + offset] | 
| 241 |  | /// Or NULL if detail is not set. | 
| 242 |  | #define DEFINE_get_detail_op(arch, ARCH) \ | 
| 243 |  |   cs_##arch##_op *ARCH##_get_detail_op(MCInst *MI, int offset) \ | 
| 244 | 0 |   { \ | 
| 245 | 0 |     if (!MI->flat_insn->detail) \ | 
| 246 | 0 |       return NULL; \ | 
| 247 | 0 |     int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \ | 
| 248 | 0 |     assert(OpIdx >= 0 && OpIdx < MAX_MC_OPS); \ | 
| 249 | 0 |     return &MI->flat_insn->detail->arch.operands[OpIdx]; \ | 
| 250 | 0 |   } Unexecuted instantiation: ARM_get_detail_opUnexecuted instantiation: PPC_get_detail_opUnexecuted instantiation: TriCore_get_detail_op | 
| 251 |  |  | 
| 252 |  | DEFINE_get_detail_op(arm, ARM); | 
| 253 |  | DEFINE_get_detail_op(ppc, PPC); | 
| 254 |  | DEFINE_get_detail_op(tricore, TriCore); |