|  | /* | 
|  | * 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 <stdint.h> | 
|  |  | 
|  | #include <deque> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include <android-base/stringprintf.h> | 
|  |  | 
|  | #include <unwindstack/DwarfError.h> | 
|  | #include <unwindstack/DwarfMemory.h> | 
|  | #include <unwindstack/Log.h> | 
|  | #include <unwindstack/Memory.h> | 
|  | #include <unwindstack/Regs.h> | 
|  |  | 
|  | #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 <typename AddressType> | 
|  | const typename DwarfOp<AddressType>::OpHandleFuncPtr DwarfOp<AddressType>::kOpHandleFuncList[] = { | 
|  | [OP_ILLEGAL] = nullptr, | 
|  | [OP_DEREF] = &DwarfOp<AddressType>::op_deref, | 
|  | [OP_DEREF_SIZE] = &DwarfOp<AddressType>::op_deref_size, | 
|  | [OP_PUSH] = &DwarfOp<AddressType>::op_push, | 
|  | [OP_DUP] = &DwarfOp<AddressType>::op_dup, | 
|  | [OP_DROP] = &DwarfOp<AddressType>::op_drop, | 
|  | [OP_OVER] = &DwarfOp<AddressType>::op_over, | 
|  | [OP_PICK] = &DwarfOp<AddressType>::op_pick, | 
|  | [OP_SWAP] = &DwarfOp<AddressType>::op_swap, | 
|  | [OP_ROT] = &DwarfOp<AddressType>::op_rot, | 
|  | [OP_ABS] = &DwarfOp<AddressType>::op_abs, | 
|  | [OP_AND] = &DwarfOp<AddressType>::op_and, | 
|  | [OP_DIV] = &DwarfOp<AddressType>::op_div, | 
|  | [OP_MINUS] = &DwarfOp<AddressType>::op_minus, | 
|  | [OP_MOD] = &DwarfOp<AddressType>::op_mod, | 
|  | [OP_MUL] = &DwarfOp<AddressType>::op_mul, | 
|  | [OP_NEG] = &DwarfOp<AddressType>::op_neg, | 
|  | [OP_NOT] = &DwarfOp<AddressType>::op_not, | 
|  | [OP_OR] = &DwarfOp<AddressType>::op_or, | 
|  | [OP_PLUS] = &DwarfOp<AddressType>::op_plus, | 
|  | [OP_PLUS_UCONST] = &DwarfOp<AddressType>::op_plus_uconst, | 
|  | [OP_SHL] = &DwarfOp<AddressType>::op_shl, | 
|  | [OP_SHR] = &DwarfOp<AddressType>::op_shr, | 
|  | [OP_SHRA] = &DwarfOp<AddressType>::op_shra, | 
|  | [OP_XOR] = &DwarfOp<AddressType>::op_xor, | 
|  | [OP_BRA] = &DwarfOp<AddressType>::op_bra, | 
|  | [OP_EQ] = &DwarfOp<AddressType>::op_eq, | 
|  | [OP_GE] = &DwarfOp<AddressType>::op_ge, | 
|  | [OP_GT] = &DwarfOp<AddressType>::op_gt, | 
|  | [OP_LE] = &DwarfOp<AddressType>::op_le, | 
|  | [OP_LT] = &DwarfOp<AddressType>::op_lt, | 
|  | [OP_NE] = &DwarfOp<AddressType>::op_ne, | 
|  | [OP_SKIP] = &DwarfOp<AddressType>::op_skip, | 
|  | [OP_LIT] = &DwarfOp<AddressType>::op_lit, | 
|  | [OP_REG] = &DwarfOp<AddressType>::op_reg, | 
|  | [OP_REGX] = &DwarfOp<AddressType>::op_regx, | 
|  | [OP_BREG] = &DwarfOp<AddressType>::op_breg, | 
|  | [OP_BREGX] = &DwarfOp<AddressType>::op_bregx, | 
|  | [OP_NOP] = &DwarfOp<AddressType>::op_nop, | 
|  | [OP_NOT_IMPLEMENTED] = &DwarfOp<AddressType>::op_not_implemented, | 
|  | }; | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::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 <typename AddressType> | 
|  | bool DwarfOp<AddressType>::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<AddressType>(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 <typename AddressType> | 
|  | void DwarfOp<AddressType>::GetLogInfo(uint64_t start, uint64_t end, | 
|  | std::vector<std::string>* 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<AddressType>(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 <typename AddressType> | 
|  | bool DwarfOp<AddressType>::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 <typename AddressType> | 
|  | bool DwarfOp<AddressType>::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 <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_push() { | 
|  | // Push all of the operands. | 
|  | for (auto operand : operands_) { | 
|  | stack_.push_front(operand); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_dup() { | 
|  | stack_.push_front(StackAt(0)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_drop() { | 
|  | StackPop(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_over() { | 
|  | stack_.push_front(StackAt(1)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::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 <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_swap() { | 
|  | AddressType old_value = stack_[0]; | 
|  | stack_[0] = stack_[1]; | 
|  | stack_[1] = old_value; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_rot() { | 
|  | AddressType top = stack_[0]; | 
|  | stack_[0] = stack_[1]; | 
|  | stack_[1] = stack_[2]; | 
|  | stack_[2] = top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_abs() { | 
|  | SignedType signed_value = static_cast<SignedType>(stack_[0]); | 
|  | if (signed_value < 0) { | 
|  | signed_value = -signed_value; | 
|  | } | 
|  | stack_[0] = static_cast<AddressType>(signed_value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_and() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] &= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_div() { | 
|  | AddressType top = StackPop(); | 
|  | if (top == 0) { | 
|  | last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
|  | return false; | 
|  | } | 
|  | SignedType signed_divisor = static_cast<SignedType>(top); | 
|  | SignedType signed_dividend = static_cast<SignedType>(stack_[0]); | 
|  | stack_[0] = static_cast<AddressType>(signed_dividend / signed_divisor); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_minus() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] -= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_mod() { | 
|  | AddressType top = StackPop(); | 
|  | if (top == 0) { | 
|  | last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; | 
|  | return false; | 
|  | } | 
|  | stack_[0] %= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_mul() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] *= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_neg() { | 
|  | SignedType signed_value = static_cast<SignedType>(stack_[0]); | 
|  | stack_[0] = static_cast<AddressType>(-signed_value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_not() { | 
|  | stack_[0] = ~stack_[0]; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_or() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] |= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_plus() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] += top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_plus_uconst() { | 
|  | stack_[0] += OperandAt(0); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_shl() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] <<= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_shr() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] >>= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_shra() { | 
|  | AddressType top = StackPop(); | 
|  | SignedType signed_value = static_cast<SignedType>(stack_[0]) >> top; | 
|  | stack_[0] = static_cast<AddressType>(signed_value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_xor() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] ^= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_bra() { | 
|  | // Requires one stack element. | 
|  | AddressType top = StackPop(); | 
|  | int16_t offset = static_cast<int16_t>(OperandAt(0)); | 
|  | uint64_t cur_offset; | 
|  | if (top != 0) { | 
|  | cur_offset = memory_->cur_offset() + offset; | 
|  | } else { | 
|  | cur_offset = memory_->cur_offset() - offset; | 
|  | } | 
|  | memory_->set_cur_offset(cur_offset); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_eq() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] == top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_ge() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] >= top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_gt() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] > top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_le() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] <= top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_lt() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] < top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_ne() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] != top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_skip() { | 
|  | int16_t offset = static_cast<int16_t>(OperandAt(0)); | 
|  | uint64_t cur_offset = memory_->cur_offset() + offset; | 
|  | memory_->set_cur_offset(cur_offset); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_lit() { | 
|  | stack_.push_front(cur_op() - 0x30); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_reg() { | 
|  | is_register_ = true; | 
|  | stack_.push_front(cur_op() - 0x50); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::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 <typename AddressType> | 
|  | bool DwarfOp<AddressType>::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 <typename AddressType> | 
|  | bool DwarfOp<AddressType>::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 <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_nop() { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_not_implemented() { | 
|  | last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Explicitly instantiate DwarfOp. | 
|  | template class DwarfOp<uint32_t>; | 
|  | template class DwarfOp<uint64_t>; | 
|  |  | 
|  | }  // namespace unwindstack |