toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.c

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 #include <stdlib.h>
michael@0 2 #include <string.h>
michael@0 3
michael@0 4 #include "ia32_invariant.h"
michael@0 5 #include "ia32_insn.h"
michael@0 6 #include "ia32_settings.h"
michael@0 7
michael@0 8 extern ia32_table_desc_t *ia32_tables;
michael@0 9 extern ia32_settings_t ia32_settings;
michael@0 10
michael@0 11 extern size_t ia32_table_lookup( unsigned char *buf, size_t buf_len,
michael@0 12 unsigned int table, ia32_insn_t **raw_insn,
michael@0 13 unsigned int *prefixes );
michael@0 14
michael@0 15
michael@0 16 /* -------------------------------- ModR/M, SIB */
michael@0 17 /* Convenience flags */
michael@0 18 #define MODRM_EA 1 /* ModR/M is an effective addr */
michael@0 19 #define MODRM_reg 2 /* ModR/M is a register */
michael@0 20
michael@0 21 /* ModR/M flags */
michael@0 22 #define MODRM_RM_SIB 0x04 /* R/M == 100 */
michael@0 23 #define MODRM_RM_NOREG 0x05 /* R/B == 101 */
michael@0 24 /* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */
michael@0 25 #define MODRM_MOD_NODISP 0x00 /* mod == 00 */
michael@0 26 #define MODRM_MOD_DISP8 0x01 /* mod == 01 */
michael@0 27 #define MODRM_MOD_DISP32 0x02 /* mod == 10 */
michael@0 28 #define MODRM_MOD_NOEA 0x03 /* mod == 11 */
michael@0 29 /* 16-bit modrm flags */
michael@0 30 #define MOD16_MOD_NODISP 0
michael@0 31 #define MOD16_MOD_DISP8 1
michael@0 32 #define MOD16_MOD_DISP16 2
michael@0 33 #define MOD16_MOD_REG 3
michael@0 34
michael@0 35 #define MOD16_RM_BXSI 0
michael@0 36 #define MOD16_RM_BXDI 1
michael@0 37 #define MOD16_RM_BPSI 2
michael@0 38 #define MOD16_RM_BPDI 3
michael@0 39 #define MOD16_RM_SI 4
michael@0 40 #define MOD16_RM_DI 5
michael@0 41 #define MOD16_RM_BP 6
michael@0 42 #define MOD16_RM_BX 7
michael@0 43
michael@0 44 /* SIB flags */
michael@0 45 #define SIB_INDEX_NONE 0x04
michael@0 46 #define SIB_BASE_EBP 0x05
michael@0 47 #define SIB_SCALE_NOBASE 0x00
michael@0 48
michael@0 49 /* Convenience struct for modR/M bitfield */
michael@0 50 struct modRM_byte {
michael@0 51 unsigned int mod : 2;
michael@0 52 unsigned int reg : 3;
michael@0 53 unsigned int rm : 3;
michael@0 54 };
michael@0 55
michael@0 56 /* Convenience struct for SIB bitfield */
michael@0 57 struct SIB_byte {
michael@0 58 unsigned int scale : 2;
michael@0 59 unsigned int index : 3;
michael@0 60 unsigned int base : 3;
michael@0 61 };
michael@0 62
michael@0 63 #ifdef WIN32
michael@0 64 static void byte_decode(unsigned char b, struct modRM_byte *modrm) {
michael@0 65 #else
michael@0 66 static inline void byte_decode(unsigned char b, struct modRM_byte *modrm) {
michael@0 67 #endif
michael@0 68 /* generic bitfield-packing routine */
michael@0 69
michael@0 70 modrm->mod = b >> 6; /* top 2 bits */
michael@0 71 modrm->reg = (b & 56) >> 3; /* middle 3 bits */
michael@0 72 modrm->rm = b & 7; /* bottom 3 bits */
michael@0 73 }
michael@0 74 static int ia32_invariant_modrm( unsigned char *in, unsigned char *out,
michael@0 75 unsigned int mode_16, x86_invariant_op_t *op) {
michael@0 76 struct modRM_byte modrm;
michael@0 77 struct SIB_byte sib;
michael@0 78 unsigned char *c, *cin;
michael@0 79 unsigned short *s;
michael@0 80 unsigned int *i;
michael@0 81 int size = 0; /* modrm byte is already counted */
michael@0 82
michael@0 83
michael@0 84 byte_decode(*in, &modrm); /* get bitfields */
michael@0 85
michael@0 86 out[0] = in[0]; /* save modrm byte */
michael@0 87 cin = &in[1];
michael@0 88 c = &out[1];
michael@0 89 s = (unsigned short *)&out[1];
michael@0 90 i = (unsigned int *)&out[1];
michael@0 91
michael@0 92 op->type = op_expression;
michael@0 93 op->flags |= op_pointer;
michael@0 94 if ( ! mode_16 && modrm.rm == MODRM_RM_SIB &&
michael@0 95 modrm.mod != MODRM_MOD_NOEA ) {
michael@0 96 size ++;
michael@0 97 byte_decode(*cin, (struct modRM_byte *)(void*)&sib);
michael@0 98
michael@0 99 out[1] = in[1]; /* save sib byte */
michael@0 100 cin = &in[2];
michael@0 101 c = &out[2];
michael@0 102 s = (unsigned short *)&out[2];
michael@0 103 i = (unsigned int *)&out[2];
michael@0 104
michael@0 105 if ( sib.base == SIB_BASE_EBP && ! modrm.mod ) {
michael@0 106 /* disp 32 is variant! */
michael@0 107 memset( i, X86_WILDCARD_BYTE, 4 );
michael@0 108 size += 4;
michael@0 109 }
michael@0 110 }
michael@0 111
michael@0 112 if (! modrm.mod && modrm.rm == 101) {
michael@0 113 if ( mode_16 ) { /* straight RVA in disp */
michael@0 114 memset( s, X86_WILDCARD_BYTE, 2 );
michael@0 115 size += 2;
michael@0 116 } else {
michael@0 117 memset( i, X86_WILDCARD_BYTE, 2 );
michael@0 118 size += 4;
michael@0 119 }
michael@0 120 } else if (modrm.mod && modrm.mod < 3) {
michael@0 121 if (modrm.mod == MODRM_MOD_DISP8) { /* offset in disp */
michael@0 122 *c = *cin;
michael@0 123 size += 1;
michael@0 124 } else if ( mode_16 ) {
michael@0 125 *s = (* ((unsigned short *) cin));
michael@0 126 size += 2;
michael@0 127 } else {
michael@0 128 *i = (*((unsigned int *) cin));
michael@0 129 size += 4;
michael@0 130 }
michael@0 131 } else if ( modrm.mod == 3 ) {
michael@0 132 op->type = op_register;
michael@0 133 op->flags &= ~op_pointer;
michael@0 134 }
michael@0 135
michael@0 136 return (size);
michael@0 137 }
michael@0 138
michael@0 139
michael@0 140 static int ia32_decode_invariant( unsigned char *buf, size_t buf_len,
michael@0 141 ia32_insn_t *t, unsigned char *out,
michael@0 142 unsigned int prefixes, x86_invariant_t *inv) {
michael@0 143
michael@0 144 unsigned int addr_size, op_size, mode_16;
michael@0 145 unsigned int op_flags[3] = { t->dest_flag, t->src_flag, t->aux_flag };
michael@0 146 int x, type, bytes = 0, size = 0, modrm = 0;
michael@0 147
michael@0 148 /* set addressing mode */
michael@0 149 if (ia32_settings.options & opt_16_bit) {
michael@0 150 op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2;
michael@0 151 addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2;
michael@0 152 mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 0 : 1;
michael@0 153 } else {
michael@0 154 op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4;
michael@0 155 addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4;
michael@0 156 mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 1 : 0;
michael@0 157 }
michael@0 158
michael@0 159 for (x = 0; x < 3; x++) {
michael@0 160 inv->operands[x].access = (enum x86_op_access)
michael@0 161 OP_PERM(op_flags[x]);
michael@0 162 inv->operands[x].flags = (enum x86_op_flags)
michael@0 163 (OP_FLAGS(op_flags[x]) >> 12);
michael@0 164
michael@0 165 switch (op_flags[x] & OPTYPE_MASK) {
michael@0 166 case OPTYPE_c:
michael@0 167 size = (op_size == 4) ? 2 : 1;
michael@0 168 break;
michael@0 169 case OPTYPE_a: case OPTYPE_v:
michael@0 170 size = (op_size == 4) ? 4 : 2;
michael@0 171 break;
michael@0 172 case OPTYPE_p:
michael@0 173 size = (op_size == 4) ? 6 : 4;
michael@0 174 break;
michael@0 175 case OPTYPE_b:
michael@0 176 size = 1;
michael@0 177 break;
michael@0 178 case OPTYPE_w:
michael@0 179 size = 2;
michael@0 180 break;
michael@0 181 case OPTYPE_d: case OPTYPE_fs: case OPTYPE_fd:
michael@0 182 case OPTYPE_fe: case OPTYPE_fb: case OPTYPE_fv:
michael@0 183 case OPTYPE_si: case OPTYPE_fx:
michael@0 184 size = 4;
michael@0 185 break;
michael@0 186 case OPTYPE_s:
michael@0 187 size = 6;
michael@0 188 break;
michael@0 189 case OPTYPE_q: case OPTYPE_pi:
michael@0 190 size = 8;
michael@0 191 break;
michael@0 192 case OPTYPE_dq: case OPTYPE_ps: case OPTYPE_ss:
michael@0 193 case OPTYPE_pd: case OPTYPE_sd:
michael@0 194 size = 16;
michael@0 195 break;
michael@0 196 case OPTYPE_m:
michael@0 197 size = (addr_size == 4) ? 4 : 2;
michael@0 198 break;
michael@0 199 default:
michael@0 200 break;
michael@0 201 }
michael@0 202
michael@0 203 type = op_flags[x] & ADDRMETH_MASK;
michael@0 204 switch (type) {
michael@0 205 case ADDRMETH_E: case ADDRMETH_M: case ADDRMETH_Q:
michael@0 206 case ADDRMETH_R: case ADDRMETH_W:
michael@0 207 modrm = 1;
michael@0 208 bytes += ia32_invariant_modrm( buf, out,
michael@0 209 mode_16, &inv->operands[x]);
michael@0 210 break;
michael@0 211 case ADDRMETH_C: case ADDRMETH_D: case ADDRMETH_G:
michael@0 212 case ADDRMETH_P: case ADDRMETH_S: case ADDRMETH_T:
michael@0 213 case ADDRMETH_V:
michael@0 214 inv->operands[x].type = op_register;
michael@0 215 modrm = 1;
michael@0 216 break;
michael@0 217 case ADDRMETH_A: case ADDRMETH_O:
michael@0 218 /* pad with xF4's */
michael@0 219 memset( &out[bytes + modrm], X86_WILDCARD_BYTE,
michael@0 220 size );
michael@0 221 bytes += size;
michael@0 222 inv->operands[x].type = op_offset;
michael@0 223 if ( type == ADDRMETH_O ) {
michael@0 224 inv->operands[x].flags |= op_signed |
michael@0 225 op_pointer;
michael@0 226 }
michael@0 227 break;
michael@0 228 case ADDRMETH_I: case ADDRMETH_J:
michael@0 229 /* grab imm value */
michael@0 230 if ((op_flags[x] & OPTYPE_MASK) == OPTYPE_v) {
michael@0 231 /* assume this is an address */
michael@0 232 memset( &out[bytes + modrm],
michael@0 233 X86_WILDCARD_BYTE, size );
michael@0 234 } else {
michael@0 235 memcpy( &out[bytes + modrm],
michael@0 236 &buf[bytes + modrm], size );
michael@0 237 }
michael@0 238
michael@0 239 bytes += size;
michael@0 240 if ( type == ADDRMETH_J ) {
michael@0 241 if ( size == 1 ) {
michael@0 242 inv->operands[x].type =
michael@0 243 op_relative_near;
michael@0 244 } else {
michael@0 245 inv->operands[x].type =
michael@0 246 op_relative_far;
michael@0 247 }
michael@0 248 inv->operands[x].flags |= op_signed;
michael@0 249 } else {
michael@0 250 inv->operands[x].type = op_immediate;
michael@0 251 }
michael@0 252 break;
michael@0 253 case ADDRMETH_F:
michael@0 254 inv->operands[x].type = op_register;
michael@0 255 break;
michael@0 256 case ADDRMETH_X:
michael@0 257 inv->operands[x].flags |= op_signed |
michael@0 258 op_pointer | op_ds_seg | op_string;
michael@0 259 break;
michael@0 260 case ADDRMETH_Y:
michael@0 261 inv->operands[x].flags |= op_signed |
michael@0 262 op_pointer | op_es_seg | op_string;
michael@0 263 break;
michael@0 264 case ADDRMETH_RR:
michael@0 265 inv->operands[x].type = op_register;
michael@0 266 break;
michael@0 267 case ADDRMETH_II:
michael@0 268 inv->operands[x].type = op_immediate;
michael@0 269 break;
michael@0 270 default:
michael@0 271 inv->operands[x].type = op_unused;
michael@0 272 break;
michael@0 273 }
michael@0 274 }
michael@0 275
michael@0 276 return (bytes + modrm);
michael@0 277 }
michael@0 278
michael@0 279 size_t ia32_disasm_invariant( unsigned char * buf, size_t buf_len,
michael@0 280 x86_invariant_t *inv ) {
michael@0 281 ia32_insn_t *raw_insn = NULL;
michael@0 282 unsigned int prefixes;
michael@0 283 unsigned int type;
michael@0 284 size_t size;
michael@0 285
michael@0 286 /* Perform recursive table lookup starting with main table (0) */
michael@0 287 size = ia32_table_lookup( buf, buf_len, 0, &raw_insn, &prefixes );
michael@0 288 if ( size == INVALID_INSN || size > buf_len ) {
michael@0 289 /* TODO: set errno */
michael@0 290 return 0;
michael@0 291 }
michael@0 292
michael@0 293 /* copy opcode bytes to buffer */
michael@0 294 memcpy( inv->bytes, buf, size );
michael@0 295
michael@0 296 /* set mnemonic type and group */
michael@0 297 type = raw_insn->mnem_flag & ~INS_FLAG_MASK;
michael@0 298 inv->group = (enum x86_insn_group) (INS_GROUP(type)) >> 12;
michael@0 299 inv->type = (enum x86_insn_type) INS_TYPE(type);
michael@0 300
michael@0 301 /* handle operands */
michael@0 302 size += ia32_decode_invariant( buf + size, buf_len - size, raw_insn,
michael@0 303 &buf[size - 1], prefixes, inv );
michael@0 304
michael@0 305 inv->size = size;
michael@0 306
michael@0 307 return size; /* return size of instruction in bytes */
michael@0 308 }
michael@0 309
michael@0 310 size_t ia32_disasm_size( unsigned char *buf, size_t buf_len ) {
michael@0 311 x86_invariant_t inv = { {0} };
michael@0 312 return( ia32_disasm_invariant( buf, buf_len, &inv ) );
michael@0 313 }

mercurial