PageRenderTime 63ms CodeModel.GetById 47ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 1ms

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