void print_in_readelf_style(std::ostream& s, const core::Cie& cie) { // first line is section-offset, length-not-including-length-field, zeroes, "CIE" s.width(8); s.fill('0'); s << setw(8) << setfill('0') << std::hex << cie.get_offset() << ' ' << setw(16) << setfill('0') << std::hex << cie.get_bytes_in_cie() << ' ' << setw(8) << setfill('0') << 0 << std::dec << " CIE" << endl; // cie fields come next s << " Version: " << (int) cie.get_version() << endl << " Augmentation: \"" << cie.get_augmenter() << "\"" << endl << " Code alignment factor: " << cie.get_code_alignment_factor() << endl << " Data alignment factor: " << cie.get_data_alignment_factor() << endl << " Return address column: " << cie.get_return_address_register_rule() << endl << " Augmentation data: "; auto augbytes = cie.get_augmentation_bytes(); for (auto i_byte = augbytes.begin(); i_byte != augbytes.end(); ++i_byte) { if (i_byte != augbytes.begin()) s << ' '; s << std::hex << setw(2) << setfill('0') << (unsigned) *i_byte; } s << std::dec << endl; s << endl; /* Now we need to print the "initial instructions". */ encap::frame_instrlist initial_instrs(cie, /* FIXME */ 8, cie.initial_instructions_seq()); print_in_readelf_style(s, initial_instrs, -1); }
frame_instrlist::frame_instrlist(const core::Cie& cie, int addrlen, const pair<unsigned char*, unsigned char*>& seq, bool use_host_byte_order /* = true */) { // unsigned char *instrs_start = seq.first; const unsigned char *pos = seq.first; const unsigned char *const limit = seq.second; while (pos < limit) { Dwarf_Frame_Op3 decoded = { 0, 0, 0, 0, 0, 0 }; /* See DWARF4 page 181 for the summary of opcode encoding and arguments. * This macro masks out any argument part of the basic opcodes. */ #define opcode_from_byte(b) (((b) & 0xc0) ? (b) & 0xc0 : (b)) unsigned char opcode_byte = *pos++; decoded.fp_base_op = opcode_byte >> 6; decoded.fp_extended_op = (decoded.fp_base_op == 0) ? opcode_byte & ~0xc0 : 0; switch (opcode_from_byte(opcode_byte)) { // "packed" two-bit opcodes case DW_CFA_advance_loc: decoded.fp_offset_or_block_len = opcode_byte & ~0xc0; break; case DW_CFA_offset: decoded.fp_register = opcode_byte & ~0xc0; // NOTE: here we are writing a signed value into an unsigned location decoded.fp_offset_or_block_len = cie.get_data_alignment_factor() * read_uleb128(&pos, seq.second); // ... so assert something that says we can read it back if (cie.get_data_alignment_factor() < 0) { assert((Dwarf_Signed) decoded.fp_offset_or_block_len <= 0); } break; case DW_CFA_restore: decoded.fp_register = opcode_byte & ~0xc0; break; // DW_CFA_extended and DW_CFA_nop are the same value, BUT case DW_CFA_nop: goto no_args; // this is a full zero byte // extended opcodes follow case DW_CFA_remember_state: goto no_args; case DW_CFA_restore_state: goto no_args; no_args: break; case DW_CFA_set_loc: decoded.fp_offset_or_block_len = read_addr(addrlen, &pos, seq.second, use_host_byte_order); break; case DW_CFA_advance_loc1: decoded.fp_offset_or_block_len = *pos++; break; case DW_CFA_advance_loc2: decoded.fp_offset_or_block_len = (host_is_big_endian() ^ use_host_byte_order) ? read_2byte_le(&pos, limit) : read_2byte_be(&pos, limit); break; case DW_CFA_advance_loc4: decoded.fp_offset_or_block_len = (host_is_big_endian() ^ use_host_byte_order) ? read_4byte_le(&pos, limit) : read_4byte_be(&pos, limit); // case DW_CFA_offset: // already dealt with, above case DW_CFA_restore_extended: goto uleb128_register_only; case DW_CFA_undefined: goto uleb128_register_only; case DW_CFA_same_value: goto uleb128_register_only; case DW_CFA_def_cfa_register: goto uleb128_register_only; uleb128_register_only: decoded.fp_register = read_uleb128(&pos, limit); break; case DW_CFA_offset_extended: goto uleb128_register_and_factored_offset; case DW_CFA_register: goto uleb128_register_and_factored_offset; uleb128_register_and_factored_offset:// FIXME: second register goes where? I've put it in fp_offset_or_block_len decoded.fp_register = read_uleb128(&pos, limit); decoded.fp_offset_or_block_len = cie.get_data_alignment_factor() * read_uleb128(&pos, limit); break; case DW_CFA_def_cfa: goto uleb128_register_and_offset; uleb128_register_and_offset:// FIXME: second register goes where? I've put it in fp_offset_or_block_len decoded.fp_register = read_uleb128(&pos, limit); decoded.fp_offset_or_block_len = read_uleb128(&pos, limit); break; case DW_CFA_offset_extended_sf: goto uleb128_register_sleb128_offset; case DW_CFA_def_cfa_sf: goto uleb128_register_sleb128_offset; uleb128_register_sleb128_offset: decoded.fp_register = read_uleb128(&pos, limit); decoded.fp_offset_or_block_len = cie.get_data_alignment_factor() * read_sleb128(&pos, limit); break; case DW_CFA_def_cfa_offset: goto uleb128_offset_only; uleb128_offset_only: decoded.fp_offset_or_block_len = read_uleb128(&pos, limit); break; case DW_CFA_def_cfa_offset_sf: goto sleb128_offset_only; sleb128_offset_only: decoded.fp_offset_or_block_len = cie.get_data_alignment_factor() * read_sleb128(&pos, limit); break; case DW_CFA_expression: decoded.fp_register = read_uleb128(&pos, limit); decoded.fp_offset_or_block_len = read_uleb128(&pos, limit); decoded.fp_expr_block = const_cast<Dwarf_Small*>(pos); pos += decoded.fp_offset_or_block_len; break; case DW_CFA_def_cfa_expression: decoded.fp_offset_or_block_len = read_uleb128(&pos, limit); decoded.fp_expr_block = const_cast<Dwarf_Small*>(pos); pos += decoded.fp_offset_or_block_len; break; case DW_CFA_val_offset: decoded.fp_register = read_uleb128(&pos, limit); decoded.fp_offset_or_block_len = cie.get_data_alignment_factor() * read_sleb128(&pos, limit); break; case DW_CFA_val_offset_sf: decoded.fp_register = read_uleb128(&pos, limit); decoded.fp_offset_or_block_len = cie.get_data_alignment_factor() * read_uleb128(&pos, limit); break; case DW_CFA_val_expression: decoded.fp_register = read_uleb128(&pos, limit); decoded.fp_offset_or_block_len = read_uleb128(&pos, limit); decoded.fp_expr_block = const_cast<Dwarf_Small*>(pos); pos += decoded.fp_offset_or_block_len; break; /* HACK: somewhere better to put the vendor-specific stuff? */ case DW_CFA_GNU_args_size: /* from LSB 3.1.1: * "The DW_CFA_GNU_args_size instruction takes an unsigned LEB128 operand * representing an argument size. This instruction specifies the total * of the size of the arguments which have been pushed onto the stack. */ decoded.fp_offset_or_block_len = read_uleb128(&pos, limit); break; default: assert(false); } // end switch // push the current row push_back(frame_instr(cie.get_owner().get_dbg().raw_handle(), decoded)); #undef opcode_from_byte } // end while }