/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include "DwarfOp.h" namespace unwindstack { enum DwarfOpHandleFunc : uint8_t { OP_ILLEGAL = 0, OP_DEREF, OP_DEREF_SIZE, OP_PUSH, OP_DUP, OP_DROP, OP_OVER, OP_PICK, OP_SWAP, OP_ROT, OP_ABS, OP_AND, OP_DIV, OP_MINUS, OP_MOD, OP_MUL, OP_NEG, OP_NOT, OP_OR, OP_PLUS, OP_PLUS_UCONST, OP_SHL, OP_SHR, OP_SHRA, OP_XOR, OP_BRA, OP_EQ, OP_GE, OP_GT, OP_LE, OP_LT, OP_NE, OP_SKIP, OP_LIT, OP_REG, OP_REGX, OP_BREG, OP_BREGX, OP_NOP, OP_NOT_IMPLEMENTED, }; struct OpCallback { // It may seem tempting to "clean this up" by replacing "const char[26]" with // "const char*", but doing so would place the entire callback table in // .data.rel.ro section, instead of .rodata section, and thus increase // dirty memory usage. Libunwindstack is used by the linker and therefore // loaded for every running process, so every bit of memory counts. // Unlike C standard, C++ standard guarantees this array is big enough to // store the names, or else we would get a compilation error. const char name[26]; // Similarily for this field, we do NOT want to directly store function // pointers here. Not only would that cause the callback table to be placed // in .data.rel.ro section, but it would be duplicated for each AddressType. // Instead, we use DwarfOpHandleFunc enum to decouple the callback table from // the function pointers. DwarfOpHandleFunc handle_func; uint8_t num_required_stack_values; uint8_t num_operands; uint8_t operands[2]; }; constexpr static OpCallback kCallbackTable[256] = { {"", OP_ILLEGAL, 0, 0, {}}, // 0x00 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0x01 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0x02 illegal op { // 0x03 DW_OP_addr "DW_OP_addr", OP_PUSH, 0, 1, {DW_EH_PE_absptr}, }, {"", OP_ILLEGAL, 0, 0, {}}, // 0x04 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0x05 illegal op { // 0x06 DW_OP_deref "DW_OP_deref", OP_DEREF, 1, 0, {}, }, {"", OP_ILLEGAL, 0, 0, {}}, // 0x07 illegal op { // 0x08 DW_OP_const1u "DW_OP_const1u", OP_PUSH, 0, 1, {DW_EH_PE_udata1}, }, { // 0x09 DW_OP_const1s "DW_OP_const1s", OP_PUSH, 0, 1, {DW_EH_PE_sdata1}, }, { // 0x0a DW_OP_const2u "DW_OP_const2u", OP_PUSH, 0, 1, {DW_EH_PE_udata2}, }, { // 0x0b DW_OP_const2s "DW_OP_const2s", OP_PUSH, 0, 1, {DW_EH_PE_sdata2}, }, { // 0x0c DW_OP_const4u "DW_OP_const4u", OP_PUSH, 0, 1, {DW_EH_PE_udata4}, }, { // 0x0d DW_OP_const4s "DW_OP_const4s", OP_PUSH, 0, 1, {DW_EH_PE_sdata4}, }, { // 0x0e DW_OP_const8u "DW_OP_const8u", OP_PUSH, 0, 1, {DW_EH_PE_udata8}, }, { // 0x0f DW_OP_const8s "DW_OP_const8s", OP_PUSH, 0, 1, {DW_EH_PE_sdata8}, }, { // 0x10 DW_OP_constu "DW_OP_constu", OP_PUSH, 0, 1, {DW_EH_PE_uleb128}, }, { // 0x11 DW_OP_consts "DW_OP_consts", OP_PUSH, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x12 DW_OP_dup "DW_OP_dup", OP_DUP, 1, 0, {}, }, { // 0x13 DW_OP_drop "DW_OP_drop", OP_DROP, 1, 0, {}, }, { // 0x14 DW_OP_over "DW_OP_over", OP_OVER, 2, 0, {}, }, { // 0x15 DW_OP_pick "DW_OP_pick", OP_PICK, 0, 1, {DW_EH_PE_udata1}, }, { // 0x16 DW_OP_swap "DW_OP_swap", OP_SWAP, 2, 0, {}, }, { // 0x17 DW_OP_rot "DW_OP_rot", OP_ROT, 3, 0, {}, }, { // 0x18 DW_OP_xderef "DW_OP_xderef", OP_NOT_IMPLEMENTED, 2, 0, {}, }, { // 0x19 DW_OP_abs "DW_OP_abs", OP_ABS, 1, 0, {}, }, { // 0x1a DW_OP_and "DW_OP_and", OP_AND, 2, 0, {}, }, { // 0x1b DW_OP_div "DW_OP_div", OP_DIV, 2, 0, {}, }, { // 0x1c DW_OP_minus "DW_OP_minus", OP_MINUS, 2, 0, {}, }, { // 0x1d DW_OP_mod "DW_OP_mod", OP_MOD, 2, 0, {}, }, { // 0x1e DW_OP_mul "DW_OP_mul", OP_MUL, 2, 0, {}, }, { // 0x1f DW_OP_neg "DW_OP_neg", OP_NEG, 1, 0, {}, }, { // 0x20 DW_OP_not "DW_OP_not", OP_NOT, 1, 0, {}, }, { // 0x21 DW_OP_or "DW_OP_or", OP_OR, 2, 0, {}, }, { // 0x22 DW_OP_plus "DW_OP_plus", OP_PLUS, 2, 0, {}, }, { // 0x23 DW_OP_plus_uconst "DW_OP_plus_uconst", OP_PLUS_UCONST, 1, 1, {DW_EH_PE_uleb128}, }, { // 0x24 DW_OP_shl "DW_OP_shl", OP_SHL, 2, 0, {}, }, { // 0x25 DW_OP_shr "DW_OP_shr", OP_SHR, 2, 0, {}, }, { // 0x26 DW_OP_shra "DW_OP_shra", OP_SHRA, 2, 0, {}, }, { // 0x27 DW_OP_xor "DW_OP_xor", OP_XOR, 2, 0, {}, }, { // 0x28 DW_OP_bra "DW_OP_bra", OP_BRA, 1, 1, {DW_EH_PE_sdata2}, }, { // 0x29 DW_OP_eq "DW_OP_eq", OP_EQ, 2, 0, {}, }, { // 0x2a DW_OP_ge "DW_OP_ge", OP_GE, 2, 0, {}, }, { // 0x2b DW_OP_gt "DW_OP_gt", OP_GT, 2, 0, {}, }, { // 0x2c DW_OP_le "DW_OP_le", OP_LE, 2, 0, {}, }, { // 0x2d DW_OP_lt "DW_OP_lt", OP_LT, 2, 0, {}, }, { // 0x2e DW_OP_ne "DW_OP_ne", OP_NE, 2, 0, {}, }, { // 0x2f DW_OP_skip "DW_OP_skip", OP_SKIP, 0, 1, {DW_EH_PE_sdata2}, }, { // 0x30 DW_OP_lit0 "DW_OP_lit0", OP_LIT, 0, 0, {}, }, { // 0x31 DW_OP_lit1 "DW_OP_lit1", OP_LIT, 0, 0, {}, }, { // 0x32 DW_OP_lit2 "DW_OP_lit2", OP_LIT, 0, 0, {}, }, { // 0x33 DW_OP_lit3 "DW_OP_lit3", OP_LIT, 0, 0, {}, }, { // 0x34 DW_OP_lit4 "DW_OP_lit4", OP_LIT, 0, 0, {}, }, { // 0x35 DW_OP_lit5 "DW_OP_lit5", OP_LIT, 0, 0, {}, }, { // 0x36 DW_OP_lit6 "DW_OP_lit6", OP_LIT, 0, 0, {}, }, { // 0x37 DW_OP_lit7 "DW_OP_lit7", OP_LIT, 0, 0, {}, }, { // 0x38 DW_OP_lit8 "DW_OP_lit8", OP_LIT, 0, 0, {}, }, { // 0x39 DW_OP_lit9 "DW_OP_lit9", OP_LIT, 0, 0, {}, }, { // 0x3a DW_OP_lit10 "DW_OP_lit10", OP_LIT, 0, 0, {}, }, { // 0x3b DW_OP_lit11 "DW_OP_lit11", OP_LIT, 0, 0, {}, }, { // 0x3c DW_OP_lit12 "DW_OP_lit12", OP_LIT, 0, 0, {}, }, { // 0x3d DW_OP_lit13 "DW_OP_lit13", OP_LIT, 0, 0, {}, }, { // 0x3e DW_OP_lit14 "DW_OP_lit14", OP_LIT, 0, 0, {}, }, { // 0x3f DW_OP_lit15 "DW_OP_lit15", OP_LIT, 0, 0, {}, }, { // 0x40 DW_OP_lit16 "DW_OP_lit16", OP_LIT, 0, 0, {}, }, { // 0x41 DW_OP_lit17 "DW_OP_lit17", OP_LIT, 0, 0, {}, }, { // 0x42 DW_OP_lit18 "DW_OP_lit18", OP_LIT, 0, 0, {}, }, { // 0x43 DW_OP_lit19 "DW_OP_lit19", OP_LIT, 0, 0, {}, }, { // 0x44 DW_OP_lit20 "DW_OP_lit20", OP_LIT, 0, 0, {}, }, { // 0x45 DW_OP_lit21 "DW_OP_lit21", OP_LIT, 0, 0, {}, }, { // 0x46 DW_OP_lit22 "DW_OP_lit22", OP_LIT, 0, 0, {}, }, { // 0x47 DW_OP_lit23 "DW_OP_lit23", OP_LIT, 0, 0, {}, }, { // 0x48 DW_OP_lit24 "DW_OP_lit24", OP_LIT, 0, 0, {}, }, { // 0x49 DW_OP_lit25 "DW_OP_lit25", OP_LIT, 0, 0, {}, }, { // 0x4a DW_OP_lit26 "DW_OP_lit26", OP_LIT, 0, 0, {}, }, { // 0x4b DW_OP_lit27 "DW_OP_lit27", OP_LIT, 0, 0, {}, }, { // 0x4c DW_OP_lit28 "DW_OP_lit28", OP_LIT, 0, 0, {}, }, { // 0x4d DW_OP_lit29 "DW_OP_lit29", OP_LIT, 0, 0, {}, }, { // 0x4e DW_OP_lit30 "DW_OP_lit30", OP_LIT, 0, 0, {}, }, { // 0x4f DW_OP_lit31 "DW_OP_lit31", OP_LIT, 0, 0, {}, }, { // 0x50 DW_OP_reg0 "DW_OP_reg0", OP_REG, 0, 0, {}, }, { // 0x51 DW_OP_reg1 "DW_OP_reg1", OP_REG, 0, 0, {}, }, { // 0x52 DW_OP_reg2 "DW_OP_reg2", OP_REG, 0, 0, {}, }, { // 0x53 DW_OP_reg3 "DW_OP_reg3", OP_REG, 0, 0, {}, }, { // 0x54 DW_OP_reg4 "DW_OP_reg4", OP_REG, 0, 0, {}, }, { // 0x55 DW_OP_reg5 "DW_OP_reg5", OP_REG, 0, 0, {}, }, { // 0x56 DW_OP_reg6 "DW_OP_reg6", OP_REG, 0, 0, {}, }, { // 0x57 DW_OP_reg7 "DW_OP_reg7", OP_REG, 0, 0, {}, }, { // 0x58 DW_OP_reg8 "DW_OP_reg8", OP_REG, 0, 0, {}, }, { // 0x59 DW_OP_reg9 "DW_OP_reg9", OP_REG, 0, 0, {}, }, { // 0x5a DW_OP_reg10 "DW_OP_reg10", OP_REG, 0, 0, {}, }, { // 0x5b DW_OP_reg11 "DW_OP_reg11", OP_REG, 0, 0, {}, }, { // 0x5c DW_OP_reg12 "DW_OP_reg12", OP_REG, 0, 0, {}, }, { // 0x5d DW_OP_reg13 "DW_OP_reg13", OP_REG, 0, 0, {}, }, { // 0x5e DW_OP_reg14 "DW_OP_reg14", OP_REG, 0, 0, {}, }, { // 0x5f DW_OP_reg15 "DW_OP_reg15", OP_REG, 0, 0, {}, }, { // 0x60 DW_OP_reg16 "DW_OP_reg16", OP_REG, 0, 0, {}, }, { // 0x61 DW_OP_reg17 "DW_OP_reg17", OP_REG, 0, 0, {}, }, { // 0x62 DW_OP_reg18 "DW_OP_reg18", OP_REG, 0, 0, {}, }, { // 0x63 DW_OP_reg19 "DW_OP_reg19", OP_REG, 0, 0, {}, }, { // 0x64 DW_OP_reg20 "DW_OP_reg20", OP_REG, 0, 0, {}, }, { // 0x65 DW_OP_reg21 "DW_OP_reg21", OP_REG, 0, 0, {}, }, { // 0x66 DW_OP_reg22 "DW_OP_reg22", OP_REG, 0, 0, {}, }, { // 0x67 DW_OP_reg23 "DW_OP_reg23", OP_REG, 0, 0, {}, }, { // 0x68 DW_OP_reg24 "DW_OP_reg24", OP_REG, 0, 0, {}, }, { // 0x69 DW_OP_reg25 "DW_OP_reg25", OP_REG, 0, 0, {}, }, { // 0x6a DW_OP_reg26 "DW_OP_reg26", OP_REG, 0, 0, {}, }, { // 0x6b DW_OP_reg27 "DW_OP_reg27", OP_REG, 0, 0, {}, }, { // 0x6c DW_OP_reg28 "DW_OP_reg28", OP_REG, 0, 0, {}, }, { // 0x6d DW_OP_reg29 "DW_OP_reg29", OP_REG, 0, 0, {}, }, { // 0x6e DW_OP_reg30 "DW_OP_reg30", OP_REG, 0, 0, {}, }, { // 0x6f DW_OP_reg31 "DW_OP_reg31", OP_REG, 0, 0, {}, }, { // 0x70 DW_OP_breg0 "DW_OP_breg0", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x71 DW_OP_breg1 "DW_OP_breg1", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x72 DW_OP_breg2 "DW_OP_breg2", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x73 DW_OP_breg3 "DW_OP_breg3", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x74 DW_OP_breg4 "DW_OP_breg4", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x75 DW_OP_breg5 "DW_OP_breg5", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x76 DW_OP_breg6 "DW_OP_breg6", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x77 DW_OP_breg7 "DW_OP_breg7", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x78 DW_OP_breg8 "DW_OP_breg8", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x79 DW_OP_breg9 "DW_OP_breg9", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x7a DW_OP_breg10 "DW_OP_breg10", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x7b DW_OP_breg11 "DW_OP_breg11", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x7c DW_OP_breg12 "DW_OP_breg12", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x7d DW_OP_breg13 "DW_OP_breg13", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x7e DW_OP_breg14 "DW_OP_breg14", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x7f DW_OP_breg15 "DW_OP_breg15", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x80 DW_OP_breg16 "DW_OP_breg16", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x81 DW_OP_breg17 "DW_OP_breg17", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x82 DW_OP_breg18 "DW_OP_breg18", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x83 DW_OP_breg19 "DW_OP_breg19", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x84 DW_OP_breg20 "DW_OP_breg20", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x85 DW_OP_breg21 "DW_OP_breg21", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x86 DW_OP_breg22 "DW_OP_breg22", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x87 DW_OP_breg23 "DW_OP_breg23", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x88 DW_OP_breg24 "DW_OP_breg24", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x89 DW_OP_breg25 "DW_OP_breg25", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x8a DW_OP_breg26 "DW_OP_breg26", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x8b DW_OP_breg27 "DW_OP_breg27", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x8c DW_OP_breg28 "DW_OP_breg28", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x8d DW_OP_breg29 "DW_OP_breg29", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x8e DW_OP_breg30 "DW_OP_breg30", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x8f DW_OP_breg31 "DW_OP_breg31", OP_BREG, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x90 DW_OP_regx "DW_OP_regx", OP_REGX, 0, 1, {DW_EH_PE_uleb128}, }, { // 0x91 DW_OP_fbreg "DW_OP_fbreg", OP_NOT_IMPLEMENTED, 0, 1, {DW_EH_PE_sleb128}, }, { // 0x92 DW_OP_bregx "DW_OP_bregx", OP_BREGX, 0, 2, {DW_EH_PE_uleb128, DW_EH_PE_sleb128}, }, { // 0x93 DW_OP_piece "DW_OP_piece", OP_NOT_IMPLEMENTED, 0, 1, {DW_EH_PE_uleb128}, }, { // 0x94 DW_OP_deref_size "DW_OP_deref_size", OP_DEREF_SIZE, 1, 1, {DW_EH_PE_udata1}, }, { // 0x95 DW_OP_xderef_size "DW_OP_xderef_size", OP_NOT_IMPLEMENTED, 0, 1, {DW_EH_PE_udata1}, }, { // 0x96 DW_OP_nop "DW_OP_nop", OP_NOP, 0, 0, {}, }, { // 0x97 DW_OP_push_object_address "DW_OP_push_object_address", OP_NOT_IMPLEMENTED, 0, 0, {}, }, { // 0x98 DW_OP_call2 "DW_OP_call2", OP_NOT_IMPLEMENTED, 0, 1, {DW_EH_PE_udata2}, }, { // 0x99 DW_OP_call4 "DW_OP_call4", OP_NOT_IMPLEMENTED, 0, 1, {DW_EH_PE_udata4}, }, { // 0x9a DW_OP_call_ref "DW_OP_call_ref", OP_NOT_IMPLEMENTED, 0, 0, // Has a different sized operand (4 bytes or 8 bytes). {}, }, { // 0x9b DW_OP_form_tls_address "DW_OP_form_tls_address", OP_NOT_IMPLEMENTED, 0, 0, {}, }, { // 0x9c DW_OP_call_frame_cfa "DW_OP_call_frame_cfa", OP_NOT_IMPLEMENTED, 0, 0, {}, }, { // 0x9d DW_OP_bit_piece "DW_OP_bit_piece", OP_NOT_IMPLEMENTED, 0, 2, {DW_EH_PE_uleb128, DW_EH_PE_uleb128}, }, { // 0x9e DW_OP_implicit_value "DW_OP_implicit_value", OP_NOT_IMPLEMENTED, 0, 1, {DW_EH_PE_uleb128}, }, { // 0x9f DW_OP_stack_value "DW_OP_stack_value", OP_NOT_IMPLEMENTED, 1, 0, {}, }, {"", OP_ILLEGAL, 0, 0, {}}, // 0xa0 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xa1 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xa2 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xa3 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xa4 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xa5 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xa6 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xa7 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xa8 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xa9 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xaa illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xab illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xac illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xad illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xae illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xaf illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb0 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb1 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb2 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb3 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb4 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb5 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb6 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb7 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb8 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xb9 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xba illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xbb illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xbc illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xbd illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xbe illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xbf illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc0 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc1 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc2 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc3 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc4 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc5 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc6 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc7 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc8 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xc9 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xca illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xcb illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xcc illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xcd illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xce illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xcf illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd0 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd1 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd2 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd3 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd4 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd5 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd6 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd7 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd8 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xd9 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xda illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xdb illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xdc illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xdd illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xde illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xdf illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xe0 DW_OP_lo_user {"", OP_ILLEGAL, 0, 0, {}}, // 0xe1 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xe2 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xe3 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xe4 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xe5 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xe6 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xe7 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xe8 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xe9 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xea illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xeb illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xec illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xed illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xee illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xef illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf0 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf1 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf2 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf3 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf4 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf5 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf6 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf7 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf8 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xf9 illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xfa illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xfb illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xfc illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xfd illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xfe illegal op {"", OP_ILLEGAL, 0, 0, {}}, // 0xff DW_OP_hi_user }; template const typename DwarfOp::OpHandleFuncPtr DwarfOp::kOpHandleFuncList[] = { [OP_ILLEGAL] = nullptr, [OP_DEREF] = &DwarfOp::op_deref, [OP_DEREF_SIZE] = &DwarfOp::op_deref_size, [OP_PUSH] = &DwarfOp::op_push, [OP_DUP] = &DwarfOp::op_dup, [OP_DROP] = &DwarfOp::op_drop, [OP_OVER] = &DwarfOp::op_over, [OP_PICK] = &DwarfOp::op_pick, [OP_SWAP] = &DwarfOp::op_swap, [OP_ROT] = &DwarfOp::op_rot, [OP_ABS] = &DwarfOp::op_abs, [OP_AND] = &DwarfOp::op_and, [OP_DIV] = &DwarfOp::op_div, [OP_MINUS] = &DwarfOp::op_minus, [OP_MOD] = &DwarfOp::op_mod, [OP_MUL] = &DwarfOp::op_mul, [OP_NEG] = &DwarfOp::op_neg, [OP_NOT] = &DwarfOp::op_not, [OP_OR] = &DwarfOp::op_or, [OP_PLUS] = &DwarfOp::op_plus, [OP_PLUS_UCONST] = &DwarfOp::op_plus_uconst, [OP_SHL] = &DwarfOp::op_shl, [OP_SHR] = &DwarfOp::op_shr, [OP_SHRA] = &DwarfOp::op_shra, [OP_XOR] = &DwarfOp::op_xor, [OP_BRA] = &DwarfOp::op_bra, [OP_EQ] = &DwarfOp::op_eq, [OP_GE] = &DwarfOp::op_ge, [OP_GT] = &DwarfOp::op_gt, [OP_LE] = &DwarfOp::op_le, [OP_LT] = &DwarfOp::op_lt, [OP_NE] = &DwarfOp::op_ne, [OP_SKIP] = &DwarfOp::op_skip, [OP_LIT] = &DwarfOp::op_lit, [OP_REG] = &DwarfOp::op_reg, [OP_REGX] = &DwarfOp::op_regx, [OP_BREG] = &DwarfOp::op_breg, [OP_BREGX] = &DwarfOp::op_bregx, [OP_NOP] = &DwarfOp::op_nop, [OP_NOT_IMPLEMENTED] = &DwarfOp::op_not_implemented, }; template bool DwarfOp::Eval(uint64_t start, uint64_t end) { is_register_ = false; stack_.clear(); memory_->set_cur_offset(start); dex_pc_set_ = false; // Unroll the first Decode calls to be able to check for a special // sequence of ops and values that indicate this is the dex pc. // The pattern is: // OP_const4u (0x0c) 'D' 'E' 'X' '1' // OP_drop (0x13) if (memory_->cur_offset() < end) { if (!Decode()) { return false; } } else { return true; } bool check_for_drop; if (cur_op_ == 0x0c && operands_.back() == 0x31584544) { check_for_drop = true; } else { check_for_drop = false; } if (memory_->cur_offset() < end) { if (!Decode()) { return false; } } else { return true; } if (check_for_drop && cur_op_ == 0x13) { dex_pc_set_ = true; } uint32_t iterations = 2; while (memory_->cur_offset() < end) { if (!Decode()) { return false; } // To protect against a branch that creates an infinite loop, // terminate if the number of iterations gets too high. if (iterations++ == 1000) { last_error_.code = DWARF_ERROR_TOO_MANY_ITERATIONS; return false; } } return true; } template bool DwarfOp::Decode() { last_error_.code = DWARF_ERROR_NONE; if (!memory_->ReadBytes(&cur_op_, 1)) { last_error_.code = DWARF_ERROR_MEMORY_INVALID; last_error_.address = memory_->cur_offset(); return false; } const auto* op = &kCallbackTable[cur_op_]; if (op->handle_func == OP_ILLEGAL) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } const auto handle_func = kOpHandleFuncList[op->handle_func]; // Make sure that the required number of stack elements is available. if (stack_.size() < op->num_required_stack_values) { last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID; return false; } operands_.clear(); for (size_t i = 0; i < op->num_operands; i++) { uint64_t value; if (!memory_->ReadEncodedValue(op->operands[i], &value)) { last_error_.code = DWARF_ERROR_MEMORY_INVALID; last_error_.address = memory_->cur_offset(); return false; } operands_.push_back(value); } return (this->*handle_func)(); } template void DwarfOp::GetLogInfo(uint64_t start, uint64_t end, std::vector* lines) { memory_->set_cur_offset(start); while (memory_->cur_offset() < end) { uint8_t cur_op; if (!memory_->ReadBytes(&cur_op, 1)) { return; } std::string raw_string(android::base::StringPrintf("Raw Data: 0x%02x", cur_op)); std::string log_string; const auto* op = &kCallbackTable[cur_op]; if (op->handle_func == OP_ILLEGAL) { log_string = "Illegal"; } else { log_string = op->name; uint64_t start_offset = memory_->cur_offset(); for (size_t i = 0; i < op->num_operands; i++) { uint64_t value; if (!memory_->ReadEncodedValue(op->operands[i], &value)) { return; } log_string += ' ' + std::to_string(value); } uint64_t end_offset = memory_->cur_offset(); memory_->set_cur_offset(start_offset); for (size_t i = start_offset; i < end_offset; i++) { uint8_t byte; if (!memory_->ReadBytes(&byte, 1)) { return; } raw_string += android::base::StringPrintf(" 0x%02x", byte); } memory_->set_cur_offset(end_offset); } lines->push_back(std::move(log_string)); lines->push_back(std::move(raw_string)); } } template bool DwarfOp::op_deref() { // Read the address and dereference it. AddressType addr = StackPop(); AddressType value; if (!regular_memory()->ReadFully(addr, &value, sizeof(value))) { last_error_.code = DWARF_ERROR_MEMORY_INVALID; last_error_.address = addr; return false; } stack_.push_front(value); return true; } template bool DwarfOp::op_deref_size() { AddressType bytes_to_read = OperandAt(0); if (bytes_to_read > sizeof(AddressType) || bytes_to_read == 0) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } // Read the address and dereference it. AddressType addr = StackPop(); AddressType value = 0; if (!regular_memory()->ReadFully(addr, &value, bytes_to_read)) { last_error_.code = DWARF_ERROR_MEMORY_INVALID; last_error_.address = addr; return false; } stack_.push_front(value); return true; } template bool DwarfOp::op_push() { // Push all of the operands. for (auto operand : operands_) { stack_.push_front(operand); } return true; } template bool DwarfOp::op_dup() { stack_.push_front(StackAt(0)); return true; } template bool DwarfOp::op_drop() { StackPop(); return true; } template bool DwarfOp::op_over() { stack_.push_front(StackAt(1)); return true; } template bool DwarfOp::op_pick() { AddressType index = OperandAt(0); if (index >= StackSize()) { last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID; return false; } stack_.push_front(StackAt(index)); return true; } template bool DwarfOp::op_swap() { AddressType old_value = stack_[0]; stack_[0] = stack_[1]; stack_[1] = old_value; return true; } template bool DwarfOp::op_rot() { AddressType top = stack_[0]; stack_[0] = stack_[1]; stack_[1] = stack_[2]; stack_[2] = top; return true; } template bool DwarfOp::op_abs() { SignedType signed_value = static_cast(stack_[0]); if (signed_value < 0) { signed_value = -signed_value; } stack_[0] = static_cast(signed_value); return true; } template bool DwarfOp::op_and() { AddressType top = StackPop(); stack_[0] &= top; return true; } template bool DwarfOp::op_div() { AddressType top = StackPop(); if (top == 0) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } SignedType signed_divisor = static_cast(top); SignedType signed_dividend = static_cast(stack_[0]); stack_[0] = static_cast(signed_dividend / signed_divisor); return true; } template bool DwarfOp::op_minus() { AddressType top = StackPop(); stack_[0] -= top; return true; } template bool DwarfOp::op_mod() { AddressType top = StackPop(); if (top == 0) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } stack_[0] %= top; return true; } template bool DwarfOp::op_mul() { AddressType top = StackPop(); stack_[0] *= top; return true; } template bool DwarfOp::op_neg() { SignedType signed_value = static_cast(stack_[0]); stack_[0] = static_cast(-signed_value); return true; } template bool DwarfOp::op_not() { stack_[0] = ~stack_[0]; return true; } template bool DwarfOp::op_or() { AddressType top = StackPop(); stack_[0] |= top; return true; } template bool DwarfOp::op_plus() { AddressType top = StackPop(); stack_[0] += top; return true; } template bool DwarfOp::op_plus_uconst() { stack_[0] += OperandAt(0); return true; } template bool DwarfOp::op_shl() { AddressType top = StackPop(); stack_[0] <<= top; return true; } template bool DwarfOp::op_shr() { AddressType top = StackPop(); stack_[0] >>= top; return true; } template bool DwarfOp::op_shra() { AddressType top = StackPop(); SignedType signed_value = static_cast(stack_[0]) >> top; stack_[0] = static_cast(signed_value); return true; } template bool DwarfOp::op_xor() { AddressType top = StackPop(); stack_[0] ^= top; return true; } template bool DwarfOp::op_bra() { // Requires one stack element. AddressType top = StackPop(); if (top == 0) { return true; } int16_t offset = static_cast(OperandAt(0)); uint64_t cur_offset = memory_->cur_offset() + offset; memory_->set_cur_offset(cur_offset); return true; } template bool DwarfOp::op_eq() { AddressType top = StackPop(); stack_[0] = bool_to_dwarf_bool(stack_[0] == top); return true; } template bool DwarfOp::op_ge() { AddressType top = StackPop(); stack_[0] = bool_to_dwarf_bool(stack_[0] >= top); return true; } template bool DwarfOp::op_gt() { AddressType top = StackPop(); stack_[0] = bool_to_dwarf_bool(stack_[0] > top); return true; } template bool DwarfOp::op_le() { AddressType top = StackPop(); stack_[0] = bool_to_dwarf_bool(stack_[0] <= top); return true; } template bool DwarfOp::op_lt() { AddressType top = StackPop(); stack_[0] = bool_to_dwarf_bool(stack_[0] < top); return true; } template bool DwarfOp::op_ne() { AddressType top = StackPop(); stack_[0] = bool_to_dwarf_bool(stack_[0] != top); return true; } template bool DwarfOp::op_skip() { int16_t offset = static_cast(OperandAt(0)); uint64_t cur_offset = memory_->cur_offset() + offset; memory_->set_cur_offset(cur_offset); return true; } template bool DwarfOp::op_lit() { stack_.push_front(cur_op() - 0x30); return true; } template bool DwarfOp::op_reg() { is_register_ = true; stack_.push_front(cur_op() - 0x50); return true; } template bool DwarfOp::op_regx() { is_register_ = true; stack_.push_front(OperandAt(0)); return true; } // It's not clear for breg/bregx, if this op should read the current // value of the register, or where we think that register is located. // For simplicity, the code will read the value before doing the unwind. template bool DwarfOp::op_breg() { uint16_t reg = cur_op() - 0x70; if (reg >= regs_info_->Total()) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } stack_.push_front(regs_info_->Get(reg) + OperandAt(0)); return true; } template bool DwarfOp::op_bregx() { AddressType reg = OperandAt(0); if (reg >= regs_info_->Total()) { last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; return false; } stack_.push_front(regs_info_->Get(reg) + OperandAt(1)); return true; } template bool DwarfOp::op_nop() { return true; } template bool DwarfOp::op_not_implemented() { last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED; return false; } // Explicitly instantiate DwarfOp. template class DwarfOp; template class DwarfOp; } // namespace unwindstack