Stackdb
Stackdb is a stackable, multi-target and -level source debugger and memory forensics library.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
disasm.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011, 2012, 2013, 2014 The University of Utah
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include "disasm.h"
20 #include "target_api.h"
21 #include "alist.h"
22 
23 #include <distorm.h>
24 #include <mnemonics.h>
25 
26 char *inst_names[] = {
27  "NONE",
28  "RET",
29  "IRET",
30  "CALL",
31  "SYSCALL",
32  "SYSRET",
33  "SYSENTER",
34  "SYSEXIT",
35  "INT",
36  "INT3",
37  "INTO",
38  "JMP",
39  "JCC",
40  "CMOV",
41 };
42 
43 const char *disasm_get_inst_name(inst_type_t type) {
44  return inst_names[type];
45 }
46 
48  unsigned char *inst_buf,unsigned int buf_len,
49  struct array_list **idata_list_saveptr,int noabort) {
50  _CodeInfo ci;
51  _DInst di;
52  _DecodedInst inst;
53  unsigned int di_count = 0;
54  struct array_list *tmplist;
55  struct inst_data *idata;
56 
57  if (!idata_list_saveptr) {
58  errno = EINVAL;
59  return -1;
60  }
61 
62  tmplist = array_list_create(0);
63 
64  ci.code = (unsigned char *)inst_buf;
65  ci.codeLen = buf_len;
66  ci.codeOffset = 0;
67  ci.features = DF_NONE;
68  if (target->arch->wordsize == 4)
69  ci.dt = Decode32Bits;
70  else
71  ci.dt = Decode64Bits;
72 
73  while (ci.codeOffset < buf_len) {
74  memset(&di,0,sizeof(di));
75  if (distorm_decompose64(&ci,&di,1,&di_count) == DECRES_INPUTERR) {
76  vwarn("decoding error at offset %"PRIu64"\n",ci.codeOffset);
77  goto inst_err_out;
78  }
79  if (di_count == 0)
80  break;
81 
82  if (di.flags == FLAG_NOT_DECODABLE) {
83  vwarn("bad instruction at offset %"PRIu64"\n",ci.codeOffset);
84  if (!noabort)
85  goto inst_err_out;
86  else {
87  ci.codeOffset += 1;
88  ci.code += 1;
89  continue;
90  }
91  }
92 
93  idata = (struct inst_data *)calloc(1,sizeof(*idata));
94 
95  idata->type = di.opcode;
96  idata->size = di.size;
97  idata->dtype = DECODE_TYPE_NONE;
98  idata->offset = (SMOFFSET)ci.codeOffset;
99 
100  array_list_add(tmplist,idata);
101 
102  memset(&inst,0,sizeof(inst));
103  distorm_format(&ci,&di,&inst);
104  vdebug(3,LA_TARGET,LF_DISASM,"decoded %s %s at %"PRIu64"\n",
105  inst.mnemonic.p,inst.operands.p,ci.codeOffset);
106 
107  /* Setup next iteration. */
108  ci.codeOffset += di.size;
109  ci.code += di.size;
110  }
111 
112  if (ci.codeOffset != buf_len) {
113  vwarn("decoding stopped %"PRIi64" bytes short\n",
114  (uint64_t)buf_len - ci.codeOffset);
115  if (!noabort)
116  goto inst_err_out;
117  }
118 
119  if (idata_list_saveptr)
120  *idata_list_saveptr = tmplist;
121  return 0;
122 
123  inst_err_out:
124  array_list_deep_free(tmplist);
125  return -1;
126 }
127 
128 /*
129  * Returns offsets for a specific instruction.
130  */
132  unsigned char *inst_buf,unsigned int buf_len,
133  struct array_list **offset_list,ADDR base,
134  int noabort) {
135  _CodeInfo ci;
136  _DInst di;
137  _DecodedInst inst;
138  unsigned int di_count = 0;
139  struct array_list *tmplist;
140  struct cf_inst_data *idata;
141 
142  if (!offset_list) {
143  errno = EINVAL;
144  return -1;
145  }
146 
147  tmplist = array_list_create(0);
148 
149  ci.code = (unsigned char *)inst_buf;
150  ci.codeLen = buf_len;
151  ci.codeOffset = 0;
152  ci.features = DF_NONE;
153  if (target->arch->wordsize == 4)
154  ci.dt = Decode32Bits;
155  else
156  ci.dt = Decode64Bits;
157 
158  while (ci.codeOffset < buf_len) {
159  memset(&di,0,sizeof(di));
160  if (distorm_decompose64(&ci,&di,1,&di_count) == DECRES_INPUTERR) {
162  "decoding error at offset %"PRIu64"\n",ci.codeOffset);
163  goto inst_err_out;
164  }
165  if (di_count == 0)
166  break;
167 
168  if (di.flags == FLAG_NOT_DECODABLE) {
170  "bad instruction at offset %"PRIu64"\n",ci.codeOffset);
171  if (!noabort)
172  goto inst_err_out;
173  else {
174  ci.codeOffset += 1;
175  ci.code += 1;
176  continue;
177  }
178  }
179 
180  /*
181  * Only decode RETs; add their offsets to the list when we find them!
182  */
183  memset(&inst,0,sizeof(inst));
184  if ((!flags || flags & INST_CF_RET)
185  && (di.opcode == I_RET || di.opcode == I_RETF)) {
186  idata = calloc(1,sizeof(*idata));
187  memset(idata,0,sizeof(*idata));
188 
189  idata->type = INST_RET;
190  array_list_add(tmplist,idata);
191 
192  goto valid_inst;
193  }
194  else if ((!flags || flags & INST_CF_IRET) && di.opcode == I_IRET) {
195  idata = calloc(1,sizeof(*idata));
196  memset(idata,0,sizeof(*idata));
197 
198  idata->type = INST_IRET;
199  array_list_add(tmplist,idata);
200 
201  goto valid_inst;
202  }
203  else if ((!flags || flags & INST_CF_INT) && di.opcode == I_INT) {
204  idata = calloc(1,sizeof(*idata));
205  memset(idata,0,sizeof(*idata));
206 
207  idata->type = INST_INT;
208  idata->cf.intnum = di.imm.byte;
209  array_list_add(tmplist,idata);
210 
211  goto valid_inst;
212  }
213  else if ((!flags || flags & INST_CF_INT3) && di.opcode == I_INT_3) {
214  idata = calloc(1,sizeof(*idata));
215  memset(idata,0,sizeof(*idata));
216 
217  idata->type = INST_INT3;
218  idata->cf.intnum = 3;
219  array_list_add(tmplist,idata);
220 
221  goto valid_inst;
222  }
223  else if ((!flags || flags & INST_CF_INTO) && di.opcode == I_INTO) {
224  idata = calloc(1,sizeof(*idata));
225  memset(idata,0,sizeof(*idata));
226 
227  idata->type = INST_INTO;
228  idata->cf.intnum = 4;
229  array_list_add(tmplist,idata);
230 
231  goto valid_inst;
232  }
233  else if (((!flags || flags & INST_CF_SYSCALL) && di.opcode == I_SYSCALL)
234  || ((!flags || flags & INST_CF_SYSRET) && di.opcode == I_SYSRET)
235  || ((!flags || flags & INST_CF_SYSENTER) && di.opcode == I_SYSENTER)
236  || ((!flags || flags & INST_CF_SYSEXIT) && di.opcode == I_SYSEXIT)) {
237  idata = calloc(1,sizeof(*idata));
238  memset(idata,0,sizeof(*idata));
239 
240  switch (di.opcode) {
241  case I_SYSCALL:
242  idata->type = INST_SYSCALL;
243  break;
244  case I_SYSRET:
245  idata->type = INST_SYSRET;
246  break;
247  case I_SYSENTER:
248  idata->type = INST_SYSENTER;
249  break;
250  case I_SYSEXIT:
251  idata->type = INST_SYSEXIT;
252  break;
253  default:
254  break;
255  }
256  array_list_add(tmplist,idata);
257 
258  goto valid_inst;
259  }
260  else if ((!flags || flags & INST_CF_JCC) && META_GET_FC(di.meta) == FC_CND_BRANCH) {
261  idata = calloc(1,sizeof(*idata));
262  memset(idata,0,sizeof(*idata));
263 
264  idata->type = INST_JCC;
265  idata->cf.is_relative = 1;
266  idata->cf.reloffset = di.imm.sqword;
267  array_list_add(tmplist,idata);
268 
269  goto valid_inst;
270  }
271  else if (((!flags || flags & INST_CF_CALL)
272  && (di.opcode == I_CALL || di.opcode == I_CALL_FAR))
273  || ((!flags || flags & INST_CF_JMP)
274  && META_GET_FC(di.meta) == FC_UNC_BRANCH)) {
275  idata = calloc(1,sizeof(*idata));
276  memset(idata,0,sizeof(*idata));
277 
278  if (META_GET_FC(di.meta) == FC_UNC_BRANCH)
279  idata->type = INST_JMP;
280  else
281  idata->type = INST_CALL;
282  idata->cf.disp = di.disp;
283 
284  /*
285  * Handle the different addressing modes.
286  */
287  if (di.ops[0].type == O_PC) {
288  idata->cf.reloffset = di.imm.addr; //INSTRUCTION_GET_TARGET(&di);
289  idata->cf.is_relative = 1;
290  }
291  else if (di.ops[0].type == O_IMM && (di.opcode == I_CALL
292  || di.opcode == I_JMP)) {
293  idata->cf.is_relative = 1;
294  idata->cf.reloffset = di.imm.sqword;
295  }
296  /* I think this case doesn't exist, and is really the O_PTR case. */
297  else if (di.ops[0].type == O_IMM && (di.opcode == I_CALL_FAR
298  || di.opcode == I_JMP_FAR)) {
299  idata->cf.addr = di.imm.qword;
300  }
301  else if (di.ops[0].type == O_PTR && (di.opcode == I_CALL_FAR
302  || di.opcode == I_JMP_FAR)) {
303  idata->cf.addr = di.imm.ptr.off;
304  }
305  else if (di.ops[0].type == O_REG) {
306  idata->cf.is_reg = 1;
307  idata->cf.base_reg = di.ops[0].index;
308  idata->cf.index_reg = R_NONE;
309  /* I hope this is is right. */
310  idata->cf.scale = 1;
311  }
312  else if (di.ops[0].type == O_SMEM) {
313  idata->cf.is_reg = 1;
314  idata->cf.base_reg = di.ops[0].index;
315  idata->cf.index_reg = R_NONE;
316  /* I hope this is is right. */
317  idata->cf.scale = 1;
318  }
319  else if (di.ops[0].type == O_MEM) {
320  idata->cf.is_reg = 1;
321  idata->cf.base_reg = di.base;
322  idata->cf.index_reg = di.ops[0].index;
323  idata->cf.scale = di.scale;
324  }
325  else if (di.ops[0].type == O_DISP) {
326  idata->cf.is_mem = 1;
327  /* XXX: is this right? */
328  idata->cf.mem = di.disp;
329  }
330  else {
331  distorm_format(&ci,&di,&inst);
332  vwarn("decoded unknown call inst %s %s at %"PRIu64
333  " (type=%hhu,index=%hhu,size=%hu) -- returning to user"
334  " anyway!)\n",
335  inst.mnemonic.p,inst.operands.p,ci.codeOffset,
336  di.ops[0].type,di.ops[0].index,di.ops[0].size);
337  //goto invalid_inst;
338  }
339 
340  array_list_add(tmplist,idata);
341 
342  goto valid_inst;
343  }
344  else {
345  distorm_format(&ci,&di,&inst);
346  vdebug(6,LA_TARGET,LF_DISASM,"decoded ignored inst %s %s at %"PRIu64"\n",
347  inst.mnemonic.p,inst.operands.p,ci.codeOffset);
348  goto invalid_inst;
349  }
350 
351  valid_inst:
352  idata->size = di.size;
353  idata->offset = ci.codeOffset;
354 
355  if (idata->cf.is_relative) {
356  OFFSET toff = di.size + idata->offset + idata->cf.disp + idata->cf.reloffset;
357  if (toff >= 0 && toff < buf_len)
358  idata->cf.target_in_segment = 1;
359  idata->cf.target = toff + base;
360  idata->cf.target_is_valid = 1;
361  }
362  else if (!idata->cf.is_reg && !idata->cf.is_mem) {
363  idata->cf.target = idata->cf.addr;
364  if (idata->cf.addr >= base && idata->cf.addr < (base + buf_len))
365  idata->cf.target_in_segment = 1;
366  idata->cf.target_is_valid = 1;
367  }
368  else {
369  idata->cf.target_is_valid = 0;
370  idata->cf.target = 0;
371  }
372 
373  distorm_format(&ci,&di,&inst);
374  vdebug(3,LA_TARGET,LF_DISASM,"decoded %s %s at %"PRIu64"\n",
375  inst.mnemonic.p,inst.operands.p,ci.codeOffset);
376 
377  invalid_inst:
378  /* Setup next iteration. */
379  ci.codeOffset += di.size;
380  ci.code += di.size;
381  }
382 
383  if (ci.codeOffset != buf_len) {
385  "decoding stopped %"PRIi64" bytes short\n",
386  (uint64_t)buf_len - ci.codeOffset);
387  if (!noabort)
388  goto inst_err_out;
389  }
390 
391  if (offset_list)
392  *offset_list = tmplist;
393  return 0;
394 
395  inst_err_out:
396  array_list_deep_free(tmplist);
397  return -1;
398 }
399 
400 
401 /*
402  * Returns an integer corresponding to modifications to the stack
403  * pointer. For instance, if you pass it a prologue, we'll likely
404  * return a negative integer as the stack grows downwards -- i.e.,
405  * during pushes, subs, enters.
406  *
407  * On error, we return -1; on success, 0.
408  */
410  unsigned char *inst_buf,unsigned int buf_len,
411  int *sp) {
412  _CodeInfo ci;
413  _DInst di;
414  _DecodedInst inst;
415  unsigned int di_count = 0;
416  int retval = 0;
417  int i;
418 
419  if (!sp) {
420  errno = EINVAL;
421  return -1;
422  }
423 
424  ci.code = (unsigned char *)inst_buf;
425  ci.codeLen = buf_len;
426  ci.codeOffset = 0;
427  /* Make it stop decoding if it encounters
428  * CALL/FAR, RET/IRET/RETF, SYSENTER/SYSEXIT/SYSCALL/SYSRET,
429  * conditional/unconditional branches, INT, CMOV.
430  */
431  ci.features = DF_STOP_ON_FLOW_CONTROL;
432  if (target->arch->wordsize == 4)
433  ci.dt = Decode32Bits;
434  else
435  ci.dt = Decode64Bits;
436 
437  while (ci.codeOffset < buf_len) {
438  memset(&di,0,sizeof(di));
439  if (distorm_decompose64(&ci,&di,1,&di_count) == DECRES_INPUTERR) {
440  vwarn("decoding error at offset %"PRIu64"\n",ci.codeOffset);
441  return -1;
442  }
443  if (di_count == 0)
444  break;
445 
446  if (di.flags == FLAG_NOT_DECODABLE) {
447  vwarn("bad instruction at offset %"PRIu64"\n",ci.codeOffset);
448  return -1;
449  }
450 
451  distorm_format(&ci,&di,&inst);
452  vdebug(3,LA_TARGET,LF_DISASM,"decoded %s %s\n",inst.mnemonic.p,inst.operands.p);
453 
454  /*
455  * XXX: all the inc/decrements for ENTER, POP/PUSH are affected
456  * by the operand-size attribute of the current code segment
457  * and/or stack segment descriptor. We'd have to read the
458  * current CS/SS registers, or if the target is not executing,
459  * we'd have to get their state from elsewhere.
460  *
461  * So just ignore this for now and assume 8-byte stack size
462  * increments for 64-bit, and 4-byte increments for 32-bit
463  * binaries.
464  */
465  switch (di.opcode) {
466  case I_NOP:
467  break;
468  case I_ENTER:
469  /* We only support 32- or 64-bit ENTER. */
470  if (di.ops[0].type != O_IMM1 || di.ops[1].type != O_IMM2) {
471  vwarn("ENTER did not have two imm operands; error!\n");
472  goto inst_err_out;
473  }
474 
475  int size = di.imm.ex.i1;
476  int nestinglevel = di.imm.ex.i2 % 32;
477 
478  /* Handle BP push. */
479  retval -= target->arch->wordsize;
480 
481  /* Push nesting area. */
482  for (i = 1; i < nestinglevel; ++i) {
483  retval -= target->arch->wordsize;
484  }
485 
486  /* Push frame temp. */
487  retval -= target->arch->wordsize;
488 
489  /* Push the size. */
490  retval -= size;
491 
492  break;
493  case I_PUSH:
494  case I_PUSHF:
495  retval -= target->arch->wordsize;
496  break;
497  case I_PUSHA:
498  /* Push all general-purpose regs. */
499  retval -= target->arch->wordsize * 8;
500  break;
501  case I_POP:
502  case I_POPF:
503  retval += target->arch->wordsize;
504  break;
505  case I_POPA:
506  /* Pop all general-purpose regs (except ESP, which is skipped). */
507  retval += target->arch->wordsize * 8;
508  break;
509  case I_ADD:
510  if (di.ops[0].type == O_REG && di.usedRegistersMask & RM_SP) {
511  if (di.ops[1].type == O_IMM)
512  retval += di.imm.sword;
513  else {
514  vwarn("unsupported SP offset op: ADD!\n");
515  goto inst_err_out;
516  }
517  }
518  break;
519  case I_SUB:
520  if (di.ops[0].type == O_REG && di.usedRegistersMask & RM_SP) {
521  if (di.ops[1].type == O_IMM)
522  retval -= di.imm.sword;
523  else {
524  vwarn("unsupported SP offset op: SUB!\n");
525  goto inst_err_out;
526  }
527  }
528  break;
529  /* We assume shifts never operate on a 0-valued ESP!! That
530  * would be silly, but I suppose it could happen.
531  */
532  case I_SAL:
533  case I_SAR:
534  case I_SHL:
535  if (di.ops[0].type == O_REG && di.ops[0].index & RM_SP) {
536  if (di.ops[1].type != O_IMM) {
537  vwarn("unsupported SP offset op: SAL/SAR/SHL!\n");
538  goto inst_err_out;
539  }
540  else {
541  if (di.imm.byte == 0)
542  break;
543  if (di.opcode == I_SAR)
544  retval -= 1 << di.imm.byte;
545  else
546  retval += 1 << di.imm.byte;
547  }
548  }
549  break;
550  case I_SHR:
551  if (di.ops[0].type == O_REG && di.ops[0].index & RM_SP) {
552  vwarn("unsupported SP offset op: SHR!\n");
553  goto inst_err_out;
554  }
555  break;
556  case I_MOV:
557  if (di.ops[0].type == O_REG && di.ops[0].index & RM_SP) {
558  vwarn("unsupported SP offset op: MOV!\n");
559  goto inst_err_out;
560  }
561  break;
562  /* These can never have any effect on ESP since they only
563  * inc/dec by 1 -- and we always inc/dec the SP by at least 2.
564  */
565  case I_DEC:
566  case I_INC:
567  break;
568  /* These have implied destination of EAX, so we can ignore
569  * them.
570  */
571  case I_DIV:
572  case I_MUL:
573  case I_IDIV:
574  break;
575  /* If the first operand (destination) is ESP, we have to give
576  * up, since our offset would be dependent on the current value
577  * of ESP -- which we don't know without actually arriving at
578  * this code point.
579  */
580  case I_IMUL:
581  /* This can take either the MUL one-operand form, or more. */
582  if (di.ops[1].type != O_NONE
583  && di.ops[0].type == O_REG && di.ops[0].index & RM_SP) {
584  vwarn("unsupported SP offset op: IMUL!\n");
585  goto inst_err_out;
586  }
587  break;
588  case I_XOR:
589  if (di.ops[0].type == O_REG && di.ops[0].index & RM_SP) {
590  vwarn("unsupported SP offset op: XOR!\n");
591  goto inst_err_out;
592  }
593  break;
594  case I_AND:
595  if (di.ops[0].type == O_REG && di.ops[0].index & RM_SP) {
596  vwarn("unsupported SP offset op: AND!\n");
597  goto inst_err_out;
598  }
599  break;
600  case I_OR:
601  if (di.ops[0].type == O_REG && di.ops[0].index & RM_SP) {
602  vwarn("unsupported SP offset op: OR!\n");
603  goto inst_err_out;
604  }
605  break;
606  /* One-operand instructions: */
607  case I_NOT:
608  if (di.ops[0].type == O_REG && di.ops[0].index & RM_SP) {
609  vwarn("unsupported SP offset op: NOT!\n");
610  goto inst_err_out;
611  }
612  break;
613  case I_NEG:
614  if (di.ops[0].type == O_REG && di.ops[0].index & RM_SP) {
615  vwarn("unsupported SP offset op: NEG!\n");
616  goto inst_err_out;
617  }
618  break;
619  default:
620  break;
621  }
622 
623  /* Setup next iteration. */
624  ci.codeOffset += di.size;
625  ci.code += di.size;
626  }
627 
628  if (ci.codeOffset != buf_len) {
629  vwarn("decoding stopped %"PRIu64" bytes short; bad prologue?\n",
630  buf_len - ci.codeOffset - 1);
631  return -1;
632  }
633 
634  *sp = retval;
635  return 0;
636 
637  inst_err_out:
638  return -1;
639 }
640 
641 char *const inst_type_names[] = {
642  [INST_NONE] = "NONE",
643  [INST_RET] = "RET",
644  [INST_IRET] = "IRET",
645  [INST_CALL] = "CALL",
646  [INST_SYSCALL] = "SYSCALL",
647  [INST_SYSRET] = "SYSRET",
648  [INST_SYSENTER] = "SYSENTER",
649  [INST_SYSEXIT] = "SYSEXIT",
650  [INST_INT] = "INT",
651  [INST_INT3] = "INT3",
652  [INST_INTO] = "INTO",
653  [INST_JMP] = "JMP",
654  [INST_JCC] = "JCC",
655  [INST_CMOV] = "CMOV"
656 };
uint8_t intnum
Definition: disasm.h:113
SMOFFSET offset
Definition: disasm.h:35
uint8_t size
Definition: disasm.h:38
#define vwarnopt(level, area, flags, format,...)
Definition: log.h:37
int disasm_generic(struct target *target, unsigned char *inst_buf, unsigned int buf_len, struct array_list **idata_list_saveptr, int noabort)
Definition: disasm.c:47
uint8_t size
Definition: disasm.h:101
char * inst_names[]
Definition: disasm.c:26
int is_mem
Definition: disasm.h:104
OFFSET offset
Definition: disasm.h:100
static uint64_t unsigned int i
uint8_t scale
Definition: disasm.h:120
uint64_t disp
Definition: disasm.h:110
inst_type_t type
Definition: disasm.h:99
int is_relative
Definition: disasm.h:104
int32_t SMOFFSET
Definition: common.h:100
int target_in_segment
Definition: disasm.h:104
OFFSET reloffset
Definition: disasm.h:124
int32_t OFFSET
Definition: common.h:65
char *const inst_type_names[]
Definition: disasm.c:641
#define vwarn(format,...)
Definition: log.h:33
dis_reg_t index_reg
Definition: disasm.h:119
int disasm_get_control_flow_offsets(struct target *target, inst_cf_flags_t flags, unsigned char *inst_buf, unsigned int buf_len, struct array_list **offset_list, ADDR base, int noabort)
Definition: disasm.c:131
int target_is_valid
Definition: disasm.h:104
inst_cf_flags_t
Definition: disasm.h:67
#define vdebug(devel, areas, flags, format,...)
Definition: log.h:302
const char * disasm_get_inst_name(inst_type_t type)
Definition: disasm.c:43
int is_reg
Definition: disasm.h:104
struct cf_inst_data::@12 cf
struct arch * arch
Definition: target_api.h:2603
unsigned int wordsize
Definition: arch.h:121
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
ADDR target
Definition: disasm.h:132
Definition: log.h:70
Definition: log.h:176
uint32_t ADDR
Definition: common.h:64
dis_inst_t type
Definition: disasm.h:36
dis_reg_t base_reg
Definition: disasm.h:118
decode_t dtype
Definition: disasm.h:37
inst_type_t
Definition: disasm.h:46
int disasm_get_prologue_stack_size(struct target *target, unsigned char *inst_buf, unsigned int buf_len, int *sp)
Definition: disasm.c:409
ADDR mem
Definition: disasm.h:122
ADDR addr
Definition: disasm.h:126