1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_disasm.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,210 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 + 1.8 +#include "libdis.h" 1.9 +#include "ia32_insn.h" 1.10 +#include "ia32_invariant.h" 1.11 +#include "x86_operand_list.h" 1.12 + 1.13 + 1.14 +#ifdef _MSC_VER 1.15 + #define snprintf _snprintf 1.16 + #define inline __inline 1.17 +#endif 1.18 + 1.19 +unsigned int x86_disasm( unsigned char *buf, unsigned int buf_len, 1.20 + uint32_t buf_rva, unsigned int offset, 1.21 + x86_insn_t *insn ){ 1.22 + int len, size; 1.23 + unsigned char bytes[MAX_INSTRUCTION_SIZE]; 1.24 + 1.25 + if ( ! buf || ! insn || ! buf_len ) { 1.26 + /* caller screwed up somehow */ 1.27 + return 0; 1.28 + } 1.29 + 1.30 + 1.31 + /* ensure we are all NULLed up */ 1.32 + memset( insn, 0, sizeof(x86_insn_t) ); 1.33 + insn->addr = buf_rva + offset; 1.34 + insn->offset = offset; 1.35 + /* default to invalid insn */ 1.36 + insn->type = insn_invalid; 1.37 + insn->group = insn_none; 1.38 + 1.39 + if ( offset >= buf_len ) { 1.40 + /* another caller screwup ;) */ 1.41 + x86_report_error(report_disasm_bounds, (void*)(long)buf_rva+offset); 1.42 + return 0; 1.43 + } 1.44 + 1.45 + len = buf_len - offset; 1.46 + 1.47 + /* copy enough bytes for disassembly into buffer : this 1.48 + * helps prevent buffer overruns at the end of a file */ 1.49 + memset( bytes, 0, MAX_INSTRUCTION_SIZE ); 1.50 + memcpy( bytes, &buf[offset], (len < MAX_INSTRUCTION_SIZE) ? len : 1.51 + MAX_INSTRUCTION_SIZE ); 1.52 + 1.53 + /* actually do the disassembly */ 1.54 + /* TODO: allow switching when more disassemblers are added */ 1.55 + size = ia32_disasm_addr( bytes, len, insn); 1.56 + 1.57 + /* check and see if we had an invalid instruction */ 1.58 + if (! size ) { 1.59 + x86_report_error(report_invalid_insn, (void*)(long)buf_rva+offset ); 1.60 + return 0; 1.61 + } 1.62 + 1.63 + /* check if we overran the end of the buffer */ 1.64 + if ( size > len ) { 1.65 + x86_report_error( report_insn_bounds, (void*)(long)buf_rva + offset ); 1.66 + MAKE_INVALID( insn, bytes ); 1.67 + return 0; 1.68 + } 1.69 + 1.70 + /* fill bytes field of insn */ 1.71 + memcpy( insn->bytes, bytes, size ); 1.72 + 1.73 + return size; 1.74 +} 1.75 + 1.76 +unsigned int x86_disasm_range( unsigned char *buf, uint32_t buf_rva, 1.77 + unsigned int offset, unsigned int len, 1.78 + DISASM_CALLBACK func, void *arg ) { 1.79 + x86_insn_t insn; 1.80 + unsigned int buf_len, size, count = 0, bytes = 0; 1.81 + 1.82 + /* buf_len is implied by the arguments */ 1.83 + buf_len = len + offset; 1.84 + 1.85 + while ( bytes < len ) { 1.86 + size = x86_disasm( buf, buf_len, buf_rva, offset + bytes, 1.87 + &insn ); 1.88 + if ( size ) { 1.89 + /* invoke callback if it exists */ 1.90 + if ( func ) { 1.91 + (*func)( &insn, arg ); 1.92 + } 1.93 + bytes += size; 1.94 + count ++; 1.95 + } else { 1.96 + /* error */ 1.97 + bytes++; /* try next byte */ 1.98 + } 1.99 + 1.100 + x86_oplist_free( &insn ); 1.101 + } 1.102 + 1.103 + return( count ); 1.104 +} 1.105 + 1.106 +static inline int follow_insn_dest( x86_insn_t *insn ) { 1.107 + if ( insn->type == insn_jmp || insn->type == insn_jcc || 1.108 + insn->type == insn_call || insn->type == insn_callcc ) { 1.109 + return(1); 1.110 + } 1.111 + return(0); 1.112 +} 1.113 + 1.114 +static inline int insn_doesnt_return( x86_insn_t *insn ) { 1.115 + return( (insn->type == insn_jmp || insn->type == insn_return) ? 1: 0 ); 1.116 +} 1.117 + 1.118 +static int32_t internal_resolver( x86_op_t *op, x86_insn_t *insn ){ 1.119 + int32_t next_addr = -1; 1.120 + if ( x86_optype_is_address(op->type) ) { 1.121 + next_addr = op->data.sdword; 1.122 + } else if ( op->type == op_relative_near ) { 1.123 + next_addr = insn->addr + insn->size + op->data.relative_near; 1.124 + } else if ( op->type == op_relative_far ) { 1.125 + next_addr = insn->addr + insn->size + op->data.relative_far; 1.126 + } 1.127 + return( next_addr ); 1.128 +} 1.129 + 1.130 +unsigned int x86_disasm_forward( unsigned char *buf, unsigned int buf_len, 1.131 + uint32_t buf_rva, unsigned int offset, 1.132 + DISASM_CALLBACK func, void *arg, 1.133 + DISASM_RESOLVER resolver, void *r_arg ){ 1.134 + x86_insn_t insn; 1.135 + x86_op_t *op; 1.136 + int32_t next_addr; 1.137 + uint32_t next_offset; 1.138 + unsigned int size, count = 0, bytes = 0, cont = 1; 1.139 + 1.140 + while ( cont && bytes < buf_len ) { 1.141 + size = x86_disasm( buf, buf_len, buf_rva, offset + bytes, 1.142 + &insn ); 1.143 + 1.144 + if ( size ) { 1.145 + /* invoke callback if it exists */ 1.146 + if ( func ) { 1.147 + (*func)( &insn, arg ); 1.148 + } 1.149 + bytes += size; 1.150 + count ++; 1.151 + } else { 1.152 + /* error */ 1.153 + bytes++; /* try next byte */ 1.154 + } 1.155 + 1.156 + if ( follow_insn_dest(&insn) ) { 1.157 + op = x86_get_dest_operand( &insn ); 1.158 + next_addr = -1; 1.159 + 1.160 + /* if caller supplied a resolver, use it to determine 1.161 + * the address to disassemble */ 1.162 + if ( resolver ) { 1.163 + next_addr = resolver(op, &insn, r_arg); 1.164 + } else { 1.165 + next_addr = internal_resolver(op, &insn); 1.166 + } 1.167 + 1.168 + if (next_addr != -1 ) { 1.169 + next_offset = next_addr - buf_rva; 1.170 + /* if offset is in this buffer... */ 1.171 + if ( next_addr >= buf_rva && 1.172 + next_offset < buf_len ) { 1.173 + /* go ahead and disassemble */ 1.174 + count += x86_disasm_forward( buf, 1.175 + buf_len, 1.176 + buf_rva, 1.177 + next_offset, 1.178 + func, arg, 1.179 + resolver, r_arg ); 1.180 + } else { 1.181 + /* report unresolved address */ 1.182 + x86_report_error( report_disasm_bounds, 1.183 + (void*)(long)next_addr ); 1.184 + } 1.185 + } 1.186 + } /* end follow_insn */ 1.187 + 1.188 + if ( insn_doesnt_return(&insn) ) { 1.189 + /* stop disassembling */ 1.190 + cont = 0; 1.191 + } 1.192 + 1.193 + x86_oplist_free( &insn ); 1.194 + } 1.195 + return( count ); 1.196 +} 1.197 + 1.198 +/* invariant instruction representation */ 1.199 +size_t x86_invariant_disasm( unsigned char *buf, int buf_len, 1.200 + x86_invariant_t *inv ){ 1.201 + if (! buf || ! buf_len || ! inv ) { 1.202 + return(0); 1.203 + } 1.204 + 1.205 + return ia32_disasm_invariant(buf, buf_len, inv); 1.206 +} 1.207 +size_t x86_size_disasm( unsigned char *buf, unsigned int buf_len ) { 1.208 + if (! buf || ! buf_len ) { 1.209 + return(0); 1.210 + } 1.211 + 1.212 + return ia32_disasm_size(buf, buf_len); 1.213 +}