Coverage Report

Created: 2025-08-28 06:43

/src/capstonenext/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
#include "capstone/capstone.h"
7
#include "cs_priv.h"
8
#include "utils.h"
9
10
// create a cache for fast id lookup
11
static unsigned short *make_id2insn(const insn_map *insns, unsigned int size)
12
43.2k
{
13
  // NOTE: assume that the max id is always put at the end of insns array
14
43.2k
  unsigned short max_id = insns[size - 1].id;
15
43.2k
  unsigned int i;
16
17
43.2k
  unsigned short *cache =
18
43.2k
    (unsigned short *)cs_mem_calloc(max_id + 1, sizeof(*cache));
19
20
110M
  for (i = 1; i < size; i++)
21
110M
    cache[insns[i].id] = i;
22
23
43.2k
  return cache;
24
43.2k
}
25
26
// look for @id in @insns, given its size in @max. first time call will update
27
// @cache. return 0 if not found
28
unsigned short insn_find(const insn_map *insns, unsigned int max,
29
       unsigned int id, unsigned short **cache)
30
3.71M
{
31
3.71M
  if (id > insns[max - 1].id)
32
0
    return 0;
33
34
3.71M
  if (*cache == NULL)
35
43.2k
    *cache = make_id2insn(insns, max);
36
37
3.71M
  return (*cache)[id];
38
3.71M
}
39
40
// Gives the id for the given @name if it is saved in @map.
41
// Returns the id or -1 if not found.
42
int name2id(const name_map *map, int max, const char *name)
43
79.6k
{
44
79.6k
  CS_ASSERT_RET_VAL(map && name, -1);
45
79.6k
  int i;
46
47
11.6M
  for (i = 0; i < max; i++) {
48
11.5M
    if (!map[i].name) {
49
4.41k
      return -1;
50
4.41k
    }
51
11.5M
    if (!strcmp(map[i].name, name)) {
52
72.3k
      return map[i].id;
53
72.3k
    }
54
11.5M
  }
55
56
  // nothing match
57
2.94k
  return -1;
58
79.6k
}
59
60
// Gives the name for the given @id if it is saved in @map.
61
// Returns the name or NULL if not found.
62
const char *id2name(const name_map *map, int max, const unsigned int id)
63
5.00M
{
64
5.00M
  int i;
65
66
156M
  for (i = 0; i < max; i++) {
67
156M
    if (map[i].id == id) {
68
4.99M
      return map[i].name;
69
4.99M
    }
70
156M
  }
71
72
  // nothing match
73
10.4k
  return NULL;
74
5.00M
}
75
76
/// Adds a register to the implicit write register list.
77
/// It will not add the same register twice.
78
void map_add_implicit_write(MCInst *MI, uint32_t Reg)
79
384k
{
80
384k
  if (!MI->flat_insn->detail)
81
0
    return;
82
83
384k
  uint16_t *regs_write = MI->flat_insn->detail->regs_write;
84
387k
  for (int i = 0; i < MAX_IMPL_W_REGS; ++i) {
85
387k
    if (i == MI->flat_insn->detail->regs_write_count) {
86
367k
      regs_write[i] = Reg;
87
367k
      MI->flat_insn->detail->regs_write_count++;
88
367k
      return;
89
367k
    }
90
20.4k
    if (regs_write[i] == Reg)
91
17.3k
      return;
92
20.4k
  }
93
384k
}
94
95
/// Adds a register to the implicit read register list.
96
/// It will not add the same register twice.
97
void map_add_implicit_read(MCInst *MI, uint32_t Reg)
98
189k
{
99
189k
  if (!MI->flat_insn->detail)
100
0
    return;
101
102
189k
  uint16_t *regs_read = MI->flat_insn->detail->regs_read;
103
198k
  for (int i = 0; i < MAX_IMPL_R_REGS; ++i) {
104
198k
    if (i == MI->flat_insn->detail->regs_read_count) {
105
170k
      regs_read[i] = Reg;
106
170k
      MI->flat_insn->detail->regs_read_count++;
107
170k
      return;
108
170k
    }
109
28.0k
    if (regs_read[i] == Reg)
110
19.4k
      return;
111
28.0k
  }
112
189k
}
113
114
/// Removes a register from the implicit write register list.
115
void map_remove_implicit_write(MCInst *MI, uint32_t Reg)
116
30.0k
{
117
30.0k
  if (!MI->flat_insn->detail)
118
0
    return;
119
120
30.0k
  uint16_t *regs_write = MI->flat_insn->detail->regs_write;
121
30.0k
  bool shorten_list = false;
122
33.8k
  for (int i = 0; i < MAX_IMPL_W_REGS; ++i) {
123
33.8k
    if (shorten_list) {
124
3.81k
      regs_write[i - 1] = regs_write[i];
125
3.81k
    }
126
33.8k
    if (i >= MI->flat_insn->detail->regs_write_count)
127
30.0k
      return;
128
129
3.81k
    if (regs_write[i] == Reg) {
130
3.81k
      MI->flat_insn->detail->regs_write_count--;
131
      // The register should exist only once in the list.
132
3.81k
      CS_ASSERT_RET(!shorten_list);
133
3.81k
      shorten_list = true;
134
3.81k
    }
135
3.81k
  }
136
30.0k
}
137
138
/// Copies the implicit read registers of @imap to @MI->flat_insn.
139
/// Already present registers will be preserved.
140
void map_implicit_reads(MCInst *MI, const insn_map *imap)
141
1.81M
{
142
1.81M
#ifndef CAPSTONE_DIET
143
1.81M
  if (!MI->flat_insn->detail)
144
0
    return;
145
146
1.81M
  cs_detail *detail = MI->flat_insn->detail;
147
1.81M
  unsigned Opcode = MCInst_getOpcode(MI);
148
1.81M
  unsigned i = 0;
149
1.81M
  uint16_t reg = imap[Opcode].regs_use[i];
150
1.94M
  while (reg != 0) {
151
128k
    if (i >= MAX_IMPL_R_REGS ||
152
128k
        detail->regs_read_count >= MAX_IMPL_R_REGS) {
153
0
      printf("ERROR: Too many implicit read register defined in "
154
0
             "instruction mapping.\n");
155
0
      return;
156
0
    }
157
128k
    detail->regs_read[detail->regs_read_count++] = reg;
158
128k
    if (i + 1 < MAX_IMPL_R_REGS) {
159
      // Select next one
160
128k
      reg = imap[Opcode].regs_use[++i];
161
128k
    }
162
128k
  }
163
1.81M
#endif // CAPSTONE_DIET
164
1.81M
}
165
166
/// Copies the implicit write registers of @imap to @MI->flat_insn.
167
/// Already present registers will be preserved.
168
void map_implicit_writes(MCInst *MI, const insn_map *imap)
169
1.81M
{
170
1.81M
#ifndef CAPSTONE_DIET
171
1.81M
  if (!MI->flat_insn->detail)
172
0
    return;
173
174
1.81M
  cs_detail *detail = MI->flat_insn->detail;
175
1.81M
  unsigned Opcode = MCInst_getOpcode(MI);
176
1.81M
  unsigned i = 0;
177
1.81M
  uint16_t reg = imap[Opcode].regs_mod[i];
178
2.11M
  while (reg != 0) {
179
305k
    if (i >= MAX_IMPL_W_REGS ||
180
305k
        detail->regs_write_count >= MAX_IMPL_W_REGS) {
181
0
      printf("ERROR: Too many implicit write register defined in "
182
0
             "instruction mapping.\n");
183
0
      return;
184
0
    }
185
305k
    detail->regs_write[detail->regs_write_count++] = reg;
186
305k
    if (i + 1 < MAX_IMPL_W_REGS) {
187
      // Select next one
188
305k
      reg = imap[Opcode].regs_mod[++i];
189
305k
    }
190
305k
  }
191
1.81M
#endif // CAPSTONE_DIET
192
1.81M
}
193
194
/// Adds a given group to @MI->flat_insn.
195
/// A group is never added twice.
196
void add_group(MCInst *MI, unsigned /* arch_group */ group)
197
93.9k
{
198
93.9k
#ifndef CAPSTONE_DIET
199
93.9k
  if (!MI->flat_insn->detail)
200
0
    return;
201
202
93.9k
  cs_detail *detail = MI->flat_insn->detail;
203
93.9k
  if (detail->groups_count >= MAX_NUM_GROUPS) {
204
0
    printf("ERROR: Too many groups defined.\n");
205
0
    return;
206
0
  }
207
211k
  for (int i = 0; i < detail->groups_count; ++i) {
208
117k
    if (detail->groups[i] == group) {
209
207
      return;
210
207
    }
211
117k
  }
212
93.7k
  detail->groups[detail->groups_count++] = group;
213
93.7k
#endif // CAPSTONE_DIET
214
93.7k
}
215
216
/// Copies the groups from @imap to @MI->flat_insn.
217
/// Already present groups will be preserved.
218
void map_groups(MCInst *MI, const insn_map *imap)
219
1.81M
{
220
1.81M
#ifndef CAPSTONE_DIET
221
1.81M
  if (!MI->flat_insn->detail)
222
0
    return;
223
224
1.81M
  cs_detail *detail = MI->flat_insn->detail;
225
1.81M
  unsigned Opcode = MCInst_getOpcode(MI);
226
1.81M
  unsigned i = 0;
227
1.81M
  uint16_t group = imap[Opcode].groups[i];
228
3.87M
  while (group != 0) {
229
2.05M
    if (detail->groups_count >= MAX_NUM_GROUPS) {
230
0
      printf("ERROR: Too many groups defined in instruction mapping.\n");
231
0
      return;
232
0
    }
233
2.05M
    detail->groups[detail->groups_count++] = group;
234
2.05M
    group = imap[Opcode].groups[++i];
235
2.05M
  }
236
1.81M
#endif // CAPSTONE_DIET
237
1.81M
}
238
239
/// Returns the pointer to the supllementary information in
240
/// the instruction mapping table @imap or NULL in case of failure.
241
const void *map_get_suppl_info(MCInst *MI, const insn_map *imap)
242
1.40M
{
243
1.40M
#ifndef CAPSTONE_DIET
244
1.40M
  if (!MI->flat_insn->detail)
245
0
    return NULL;
246
247
1.40M
  unsigned Opcode = MCInst_getOpcode(MI);
248
1.40M
  return &imap[Opcode].suppl_info;
249
#else
250
  return NULL;
251
#endif // CAPSTONE_DIET
252
1.40M
}
253
254
// Search for the CS instruction id for the given @MC_Opcode in @imap.
255
// return -1 if none is found.
256
unsigned int find_cs_id(unsigned MC_Opcode, const insn_map *imap,
257
      unsigned imap_size)
258
1.81M
{
259
  // binary searching since the IDs are sorted in order
260
1.81M
  unsigned int left, right, m;
261
1.81M
  unsigned int max = imap_size;
262
263
1.81M
  right = max - 1;
264
265
1.81M
  if (MC_Opcode < imap[0].id || MC_Opcode > imap[right].id)
266
    // not found
267
0
    return -1;
268
269
1.81M
  left = 0;
270
271
20.3M
  while (left <= right) {
272
20.3M
    m = (left + right) / 2;
273
20.3M
    if (MC_Opcode == imap[m].id) {
274
1.81M
      return m;
275
1.81M
    }
276
277
18.5M
    if (MC_Opcode < imap[m].id)
278
6.69M
      right = m - 1;
279
11.8M
    else
280
11.8M
      left = m + 1;
281
18.5M
  }
282
283
0
  return -1;
284
1.81M
}
285
286
/// Sets the Capstone instruction id which maps to the @MI opcode.
287
/// If no mapping is found the function returns and prints an error.
288
void map_cs_id(MCInst *MI, const insn_map *imap, unsigned int imap_size)
289
1.81M
{
290
1.81M
  unsigned int i = find_cs_id(MCInst_getOpcode(MI), imap, imap_size);
291
1.81M
  if (i != -1) {
292
1.81M
    MI->flat_insn->id = imap[i].mapid;
293
1.81M
    return;
294
1.81M
  }
295
0
  printf("ERROR: Could not find CS id for MCInst opcode: %d\n",
296
0
         MCInst_getOpcode(MI));
297
0
  return;
298
1.81M
}
299
300
/// Returns the operand type information from the
301
/// mapping table for instruction operands.
302
/// Only usable by `auto-sync` archs!
303
const cs_op_type mapping_get_op_type(MCInst *MI, unsigned OpNum,
304
             const map_insn_ops *insn_ops_map,
305
             size_t map_size)
306
6.79M
{
307
6.79M
  assert(MI);
308
6.79M
  assert(MI->Opcode < map_size);
309
6.79M
  assert(OpNum < sizeof(insn_ops_map[MI->Opcode].ops) /
310
6.79M
             sizeof(insn_ops_map[MI->Opcode].ops[0]));
311
312
6.79M
  return insn_ops_map[MI->Opcode].ops[OpNum].type;
313
6.79M
}
314
315
/// Returns the operand access flags from the
316
/// mapping table for instruction operands.
317
/// Only usable by `auto-sync` archs!
318
const cs_ac_type mapping_get_op_access(MCInst *MI, unsigned OpNum,
319
               const map_insn_ops *insn_ops_map,
320
               size_t map_size)
321
5.43M
{
322
5.43M
  assert(MI);
323
5.43M
  assert(MI->Opcode < map_size);
324
5.43M
  assert(OpNum < sizeof(insn_ops_map[MI->Opcode].ops) /
325
5.43M
             sizeof(insn_ops_map[MI->Opcode].ops[0]));
326
327
5.43M
  cs_ac_type access = insn_ops_map[MI->Opcode].ops[OpNum].access;
328
5.43M
  if (MCInst_opIsTied(MI, OpNum) || MCInst_opIsTying(MI, OpNum))
329
397k
    access |= (access == CS_AC_READ) ? CS_AC_WRITE : CS_AC_READ;
330
5.43M
  return access;
331
5.43M
}
332
333
/// Returns the operand at detail->arch.operands[op_count + offset]
334
/// Or NULL if detail is not set or the offset would be out of bounds.
335
#define DEFINE_get_detail_op(arch, ARCH, ARCH_UPPER) \
336
  cs_##arch##_op *ARCH##_get_detail_op(MCInst *MI, int offset) \
337
21.2M
  { \
338
21.2M
    if (!MI->flat_insn->detail) \
339
21.2M
      return NULL; \
340
21.2M
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
341
21.2M
    if (OpIdx < 0 || OpIdx >= NUM_##ARCH_UPPER##_OPS) { \
342
8.54k
      return NULL; \
343
8.54k
    } \
344
21.2M
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
345
21.2M
  }
ARM_get_detail_op
Line
Count
Source
337
11.6M
  { \
338
11.6M
    if (!MI->flat_insn->detail) \
339
11.6M
      return NULL; \
340
11.6M
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
341
11.6M
    if (OpIdx < 0 || OpIdx >= NUM_##ARCH_UPPER##_OPS) { \
342
0
      return NULL; \
343
0
    } \
344
11.6M
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
345
11.6M
  }
PPC_get_detail_op
Line
Count
Source
337
644k
  { \
338
644k
    if (!MI->flat_insn->detail) \
339
644k
      return NULL; \
340
644k
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
341
644k
    if (OpIdx < 0 || OpIdx >= NUM_##ARCH_UPPER##_OPS) { \
342
0
      return NULL; \
343
0
    } \
344
644k
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
345
644k
  }
Unexecuted instantiation: TriCore_get_detail_op
AArch64_get_detail_op
Line
Count
Source
337
5.43M
  { \
338
5.43M
    if (!MI->flat_insn->detail) \
339
5.43M
      return NULL; \
340
5.43M
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
341
5.43M
    if (OpIdx < 0 || OpIdx >= NUM_##ARCH_UPPER##_OPS) { \
342
0
      return NULL; \
343
0
    } \
344
5.43M
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
345
5.43M
  }
Unexecuted instantiation: Alpha_get_detail_op
Unexecuted instantiation: HPPA_get_detail_op
Unexecuted instantiation: LoongArch_get_detail_op
Mips_get_detail_op
Line
Count
Source
337
1.20M
  { \
338
1.20M
    if (!MI->flat_insn->detail) \
339
1.20M
      return NULL; \
340
1.20M
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
341
1.20M
    if (OpIdx < 0 || OpIdx >= NUM_##ARCH_UPPER##_OPS) { \
342
0
      return NULL; \
343
0
    } \
344
1.20M
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
345
1.20M
  }
RISCV_get_detail_op
Line
Count
Source
337
529k
  { \
338
529k
    if (!MI->flat_insn->detail) \
339
529k
      return NULL; \
340
529k
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
341
529k
    if (OpIdx < 0 || OpIdx >= NUM_##ARCH_UPPER##_OPS) { \
342
0
      return NULL; \
343
0
    } \
344
529k
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
345
529k
  }
SystemZ_get_detail_op
Line
Count
Source
337
1.20M
  { \
338
1.20M
    if (!MI->flat_insn->detail) \
339
1.20M
      return NULL; \
340
1.20M
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
341
1.20M
    if (OpIdx < 0 || OpIdx >= NUM_##ARCH_UPPER##_OPS) { \
342
0
      return NULL; \
343
0
    } \
344
1.20M
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
345
1.20M
  }
Xtensa_get_detail_op
Line
Count
Source
337
226k
  { \
338
226k
    if (!MI->flat_insn->detail) \
339
226k
      return NULL; \
340
226k
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
341
226k
    if (OpIdx < 0 || OpIdx >= NUM_##ARCH_UPPER##_OPS) { \
342
0
      return NULL; \
343
0
    } \
344
226k
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
345
226k
  }
Unexecuted instantiation: BPF_get_detail_op
Unexecuted instantiation: ARC_get_detail_op
Sparc_get_detail_op
Line
Count
Source
337
333k
  { \
338
333k
    if (!MI->flat_insn->detail) \
339
333k
      return NULL; \
340
333k
    int OpIdx = MI->flat_insn->detail->arch.op_count + offset; \
341
333k
    if (OpIdx < 0 || OpIdx >= NUM_##ARCH_UPPER##_OPS) { \
342
8.54k
      return NULL; \
343
8.54k
    } \
344
333k
    return &MI->flat_insn->detail->arch.operands[OpIdx]; \
345
333k
  }
346
347
DEFINE_get_detail_op(arm, ARM, ARM);
348
DEFINE_get_detail_op(ppc, PPC, PPC);
349
DEFINE_get_detail_op(tricore, TriCore, TRICORE);
350
DEFINE_get_detail_op(aarch64, AArch64, AARCH64);
351
DEFINE_get_detail_op(alpha, Alpha, ALPHA);
352
DEFINE_get_detail_op(hppa, HPPA, HPPA);
353
DEFINE_get_detail_op(loongarch, LoongArch, LOONGARCH);
354
DEFINE_get_detail_op(mips, Mips, MIPS);
355
DEFINE_get_detail_op(riscv, RISCV, RISCV);
356
DEFINE_get_detail_op(systemz, SystemZ, SYSTEMZ);
357
DEFINE_get_detail_op(xtensa, Xtensa, XTENSA);
358
DEFINE_get_detail_op(bpf, BPF, BPF);
359
DEFINE_get_detail_op(arc, ARC, ARC);
360
DEFINE_get_detail_op(sparc, Sparc, SPARC);
361
362
/// Returns true if for this architecture the
363
/// alias operands should be filled.
364
/// TODO: Replace this with a proper option.
365
///       So it can be toggled between disas() calls.
366
bool map_use_alias_details(const MCInst *MI)
367
3.04M
{
368
3.04M
  assert(MI);
369
3.04M
  return (MI->csh->detail_opt & CS_OPT_ON) &&
370
3.04M
         !(MI->csh->detail_opt & CS_OPT_DETAIL_REAL);
371
3.04M
}
372
373
/// Sets the setDetailOps flag to @p Val.
374
/// If detail == NULLit refuses to set the flag to true.
375
void map_set_fill_detail_ops(MCInst *MI, bool Val)
376
2.97M
{
377
2.97M
  CS_ASSERT_RET(MI);
378
2.97M
  if (!detail_is_set(MI)) {
379
0
    MI->fillDetailOps = false;
380
0
    return;
381
0
  }
382
383
2.97M
  MI->fillDetailOps = Val;
384
2.97M
}
385
386
/// Sets the instruction alias flags and the given alias id.
387
void map_set_is_alias_insn(MCInst *MI, bool Val, uint64_t Alias)
388
0
{
389
0
  CS_ASSERT_RET(MI);
390
0
  MI->isAliasInstr = Val;
391
0
  MI->flat_insn->is_alias = Val;
392
0
  MI->flat_insn->alias_id = Alias;
393
0
}
394
395
static inline bool char_ends_mnem(const char c, cs_arch arch)
396
378k
{
397
378k
  switch (arch) {
398
293k
  default:
399
293k
    return (!c || c == ' ' || c == '\t' || c == '.');
400
55.4k
  case CS_ARCH_PPC:
401
55.4k
    return (!c || c == ' ' || c == '\t');
402
29.3k
  case CS_ARCH_SPARC:
403
29.3k
    return (!c || c == ' ' || c == '\t' || c == ',');
404
378k
  }
405
378k
}
406
407
/// Sets an alternative id for some instruction.
408
/// Or -1 if it fails.
409
/// You must add (<ARCH>_INS_ALIAS_BEGIN + 1) to the id to get the real id.
410
void map_set_alias_id(MCInst *MI, const SStream *O,
411
          const name_map *alias_mnem_id_map, int map_size)
412
1.70M
{
413
1.70M
  if (!MCInst_isAlias(MI))
414
1.62M
    return;
415
416
79.6k
  char alias_mnem[16] = { 0 };
417
79.6k
  int i = 0, j = 0;
418
79.6k
  const char *asm_str_buf = O->buffer;
419
  // Skip spaces and tabs
420
133k
  while (is_blank_char(asm_str_buf[i])) {
421
53.9k
    if (!asm_str_buf[i]) {
422
0
      MI->flat_insn->alias_id = -1;
423
0
      return;
424
0
    }
425
53.9k
    ++i;
426
53.9k
  }
427
378k
  for (; j < sizeof(alias_mnem) - 1; ++j, ++i) {
428
378k
    if (char_ends_mnem(asm_str_buf[i], MI->csh->arch))
429
79.6k
      break;
430
298k
    alias_mnem[j] = asm_str_buf[i];
431
298k
  }
432
433
79.6k
  MI->flat_insn->alias_id =
434
79.6k
    name2id(alias_mnem_id_map, map_size, alias_mnem);
435
79.6k
}
436
437
/// Does a binary search over the given map and searches for @id.
438
/// If @id exists in @map, it sets @found to true and returns
439
/// the value for the @id.
440
/// Otherwise, @found is set to false and it returns UINT64_MAX.
441
///
442
/// Of course it assumes the map is sorted.
443
uint64_t enum_map_bin_search(const cs_enum_id_map *map, size_t map_len,
444
           const char *id, bool *found)
445
0
{
446
0
  size_t l = 0;
447
0
  size_t r = map_len;
448
0
  size_t id_len = strlen(id);
449
450
0
  while (l <= r) {
451
0
    size_t m = (l + r) / 2;
452
0
    size_t j = 0;
453
0
    size_t i = 0;
454
0
    size_t entry_len = strlen(map[m].str);
455
456
0
    while (j < entry_len && i < id_len && id[i] == map[m].str[j]) {
457
0
      ++j, ++i;
458
0
    }
459
0
    if (i == id_len && j == entry_len) {
460
0
      *found = true;
461
0
      return map[m].val;
462
0
    }
463
464
0
    if (id[i] < map[m].str[j]) {
465
0
      r = m - 1;
466
0
    } else if (id[i] > map[m].str[j]) {
467
0
      l = m + 1;
468
0
    }
469
0
    if ((m == 0 && id[i] < map[m].str[j]) ||
470
0
        (l + r) / 2 >= map_len) {
471
      // Break before we go out of bounds.
472
0
      break;
473
0
    }
474
0
  }
475
0
  *found = false;
476
0
  return UINT64_MAX;
477
0
}