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);
}
Exemple #2
0
		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
		}