/thirdparty/breakpad/third_party/libdisasm/x86_disasm.c

http://github.com/tomahawk-player/tomahawk · C · 210 lines · 153 code · 34 blank · 23 comment · 45 complexity · 0355205209b4734be7dcab875d397cc1 MD5 · raw file

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "libdis.h"
  5. #include "ia32_insn.h"
  6. #include "ia32_invariant.h"
  7. #include "x86_operand_list.h"
  8. #ifdef _MSC_VER
  9. #define snprintf _snprintf
  10. #define inline __inline
  11. #endif
  12. unsigned int x86_disasm( unsigned char *buf, unsigned int buf_len,
  13. uint32_t buf_rva, unsigned int offset,
  14. x86_insn_t *insn ){
  15. int len, size;
  16. unsigned char bytes[MAX_INSTRUCTION_SIZE];
  17. if ( ! buf || ! insn || ! buf_len ) {
  18. /* caller screwed up somehow */
  19. return 0;
  20. }
  21. /* ensure we are all NULLed up */
  22. memset( insn, 0, sizeof(x86_insn_t) );
  23. insn->addr = buf_rva + offset;
  24. insn->offset = offset;
  25. /* default to invalid insn */
  26. insn->type = insn_invalid;
  27. insn->group = insn_none;
  28. if ( offset >= buf_len ) {
  29. /* another caller screwup ;) */
  30. x86_report_error(report_disasm_bounds, (void*)(long)buf_rva+offset);
  31. return 0;
  32. }
  33. len = buf_len - offset;
  34. /* copy enough bytes for disassembly into buffer : this
  35. * helps prevent buffer overruns at the end of a file */
  36. memset( bytes, 0, MAX_INSTRUCTION_SIZE );
  37. memcpy( bytes, &buf[offset], (len < MAX_INSTRUCTION_SIZE) ? len :
  38. MAX_INSTRUCTION_SIZE );
  39. /* actually do the disassembly */
  40. /* TODO: allow switching when more disassemblers are added */
  41. size = ia32_disasm_addr( bytes, len, insn);
  42. /* check and see if we had an invalid instruction */
  43. if (! size ) {
  44. x86_report_error(report_invalid_insn, (void*)(long)buf_rva+offset );
  45. return 0;
  46. }
  47. /* check if we overran the end of the buffer */
  48. if ( size > len ) {
  49. x86_report_error( report_insn_bounds, (void*)(long)buf_rva + offset );
  50. MAKE_INVALID( insn, bytes );
  51. return 0;
  52. }
  53. /* fill bytes field of insn */
  54. memcpy( insn->bytes, bytes, size );
  55. return size;
  56. }
  57. unsigned int x86_disasm_range( unsigned char *buf, uint32_t buf_rva,
  58. unsigned int offset, unsigned int len,
  59. DISASM_CALLBACK func, void *arg ) {
  60. x86_insn_t insn;
  61. unsigned int buf_len, size, count = 0, bytes = 0;
  62. /* buf_len is implied by the arguments */
  63. buf_len = len + offset;
  64. while ( bytes < len ) {
  65. size = x86_disasm( buf, buf_len, buf_rva, offset + bytes,
  66. &insn );
  67. if ( size ) {
  68. /* invoke callback if it exists */
  69. if ( func ) {
  70. (*func)( &insn, arg );
  71. }
  72. bytes += size;
  73. count ++;
  74. } else {
  75. /* error */
  76. bytes++; /* try next byte */
  77. }
  78. x86_oplist_free( &insn );
  79. }
  80. return( count );
  81. }
  82. static inline int follow_insn_dest( x86_insn_t *insn ) {
  83. if ( insn->type == insn_jmp || insn->type == insn_jcc ||
  84. insn->type == insn_call || insn->type == insn_callcc ) {
  85. return(1);
  86. }
  87. return(0);
  88. }
  89. static inline int insn_doesnt_return( x86_insn_t *insn ) {
  90. return( (insn->type == insn_jmp || insn->type == insn_return) ? 1: 0 );
  91. }
  92. static int32_t internal_resolver( x86_op_t *op, x86_insn_t *insn ){
  93. int32_t next_addr = -1;
  94. if ( x86_optype_is_address(op->type) ) {
  95. next_addr = op->data.sdword;
  96. } else if ( op->type == op_relative_near ) {
  97. next_addr = insn->addr + insn->size + op->data.relative_near;
  98. } else if ( op->type == op_relative_far ) {
  99. next_addr = insn->addr + insn->size + op->data.relative_far;
  100. }
  101. return( next_addr );
  102. }
  103. unsigned int x86_disasm_forward( unsigned char *buf, unsigned int buf_len,
  104. uint32_t buf_rva, unsigned int offset,
  105. DISASM_CALLBACK func, void *arg,
  106. DISASM_RESOLVER resolver, void *r_arg ){
  107. x86_insn_t insn;
  108. x86_op_t *op;
  109. int32_t next_addr;
  110. uint32_t next_offset;
  111. unsigned int size, count = 0, bytes = 0, cont = 1;
  112. while ( cont && bytes < buf_len ) {
  113. size = x86_disasm( buf, buf_len, buf_rva, offset + bytes,
  114. &insn );
  115. if ( size ) {
  116. /* invoke callback if it exists */
  117. if ( func ) {
  118. (*func)( &insn, arg );
  119. }
  120. bytes += size;
  121. count ++;
  122. } else {
  123. /* error */
  124. bytes++; /* try next byte */
  125. }
  126. if ( follow_insn_dest(&insn) ) {
  127. op = x86_get_dest_operand( &insn );
  128. next_addr = -1;
  129. /* if caller supplied a resolver, use it to determine
  130. * the address to disassemble */
  131. if ( resolver ) {
  132. next_addr = resolver(op, &insn, r_arg);
  133. } else {
  134. next_addr = internal_resolver(op, &insn);
  135. }
  136. if (next_addr != -1 ) {
  137. next_offset = next_addr - buf_rva;
  138. /* if offset is in this buffer... */
  139. if ( next_offset >= 0 &&
  140. next_offset < buf_len ) {
  141. /* go ahead and disassemble */
  142. count += x86_disasm_forward( buf,
  143. buf_len,
  144. buf_rva,
  145. next_offset,
  146. func, arg,
  147. resolver, r_arg );
  148. } else {
  149. /* report unresolved address */
  150. x86_report_error( report_disasm_bounds,
  151. (void*)(long)next_addr );
  152. }
  153. }
  154. } /* end follow_insn */
  155. if ( insn_doesnt_return(&insn) ) {
  156. /* stop disassembling */
  157. cont = 0;
  158. }
  159. x86_oplist_free( &insn );
  160. }
  161. return( count );
  162. }
  163. /* invariant instruction representation */
  164. size_t x86_invariant_disasm( unsigned char *buf, int buf_len,
  165. x86_invariant_t *inv ){
  166. if (! buf || ! buf_len || ! inv ) {
  167. return(0);
  168. }
  169. return ia32_disasm_invariant(buf, buf_len, inv);
  170. }
  171. size_t x86_size_disasm( unsigned char *buf, unsigned int buf_len ) {
  172. if (! buf || ! buf_len ) {
  173. return(0);
  174. }
  175. return ia32_disasm_size(buf, buf_len);
  176. }