/* ARGSUSED */ Dwarf_Unsigned _dwarf_length_of_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned offset, Dwarf_Bool is_info) { int local_length_size = 0; int local_extension_size = 0; Dwarf_Unsigned length = 0; Dwarf_Unsigned final_size = 0; Dwarf_Small *cuptr = is_info? dbg->de_debug_info.dss_data + offset: dbg->de_debug_types.dss_data+ offset; READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, cuptr, local_length_size, local_extension_size); final_size = local_extension_size + /* initial extension, if present */ local_length_size + /* Size of cu length field. */ sizeof(Dwarf_Half) + /* Size of version stamp field. */ local_length_size + /* Size of abbrev offset field. */ sizeof(Dwarf_Small); /* Size of address size field. */ if (!is_info) { final_size += /* type signature size */ sizeof (Dwarf_Sig8) + /* type offset size */ local_length_size; } return final_size; }
/* Read in the common cie/fde prefix, including reading * the cie-value which shows which this is: cie or fde. * */ int dwarf_read_cie_fde_prefix(Dwarf_Debug dbg, Dwarf_Small * frame_ptr_in, Dwarf_Small * section_ptr_in, Dwarf_Unsigned section_index_in, Dwarf_Unsigned section_length_in, struct cie_fde_prefix_s *data_out, Dwarf_Error * error) { Dwarf_Unsigned length = 0; int local_length_size = 0; int local_extension_size = 0; Dwarf_Small *frame_ptr = frame_ptr_in; Dwarf_Small *cie_ptr_addr = 0; Dwarf_Unsigned cie_id = 0; /* READ_AREA_LENGTH updates frame_ptr for consumed bytes */ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, frame_ptr, local_length_size, local_extension_size); if (length % local_length_size != 0) { _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD); return (DW_DLV_ERROR); } if (length == 0) { /* nul bytes at end of section, seen at end of egcs eh_frame sections (in a.out). Take this as meaning no more CIE/FDE data. We should be very close to end of section. */ return DW_DLV_NO_ENTRY; } cie_ptr_addr = frame_ptr; READ_UNALIGNED(dbg, cie_id, Dwarf_Unsigned, frame_ptr, local_length_size); SIGN_EXTEND(cie_id, local_length_size); frame_ptr += local_length_size; data_out->cf_start_addr = frame_ptr_in; data_out->cf_addr_after_prefix = frame_ptr; data_out->cf_length = length; data_out->cf_local_length_size = local_length_size; data_out->cf_local_extension_size = local_extension_size; data_out->cf_cie_id = cie_id; data_out->cf_cie_id_addr = cie_ptr_addr; data_out->cf_section_ptr = section_ptr_in; data_out->cf_section_index = section_index_in; data_out->cf_section_length = section_length_in; return DW_DLV_OK; }
/* ARGSUSED */ Dwarf_Unsigned _dwarf_length_of_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned offset) { int local_length_size = 0; int local_extension_size = 0; Dwarf_Unsigned length = 0; Dwarf_Small *cuptr = dbg->de_debug_info.dss_data + offset; READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, cuptr, local_length_size, local_extension_size); return local_extension_size + /* initial extesion, if present */ local_length_size + /* Size of cu length field. */ sizeof(Dwarf_Half) + /* Size of version stamp field. */ local_length_size + /* Size of abbrev offset field. */ sizeof(Dwarf_Small); /* Size of address size field. */ }
/* Common code for two user-visible routines to share. Errors here result in memory leaks, but errors here are serious (making aranges unusable) so we assume callers will not repeat the error often or mind the leaks. */ static int dwarf_get_aranges_list(Dwarf_Debug dbg, Dwarf_Chain * chain_out, Dwarf_Signed * chain_count_out, Dwarf_Error * error) { /* Sweeps through the arange. */ Dwarf_Small *arange_ptr = 0; Dwarf_Small *arange_ptr_start = 0; /* Start of arange header. Used for rounding offset of arange_ptr to twice the tuple size. Libdwarf requirement. */ Dwarf_Small *header_ptr = 0; /* Version of .debug_aranges header. */ Dwarf_Half version = 0; /* Offset of current set of aranges into .debug_info. */ Dwarf_Off info_offset = 0; /* Size in bytes of addresses in target. */ Dwarf_Small address_size = 0; /* Size in bytes of segment offsets in target. */ Dwarf_Small segment_size = 0; /* Count of total number of aranges. */ Dwarf_Unsigned arange_count = 0; Dwarf_Arange arange = 0; /* Used to chain Dwarf_Aranges structs. */ Dwarf_Chain curr_chain = NULL; Dwarf_Chain prev_chain = NULL; Dwarf_Chain head_chain = NULL; if (!dbg->de_debug_aranges.dss_size) { return (DW_DLV_NO_ENTRY); } arange_ptr = dbg->de_debug_aranges.dss_data; arange_ptr_start = arange_ptr; do { /* Length of current set of aranges. */ Dwarf_Unsigned length = 0; Dwarf_Small remainder = 0; Dwarf_Small *arange_ptr_past_end = 0; Dwarf_Unsigned range_entry_size = 0; int local_length_size; /*REFERENCED*/ /* Not used in this instance of the macro */ int local_extension_size = 0; header_ptr = arange_ptr; /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, arange_ptr, local_length_size, local_extension_size); arange_ptr_past_end = arange_ptr + length; READ_UNALIGNED(dbg, version, Dwarf_Half, arange_ptr, sizeof(Dwarf_Half)); arange_ptr += sizeof(Dwarf_Half); length = length - sizeof(Dwarf_Half); if (version != CURRENT_VERSION_STAMP) { _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, info_offset, Dwarf_Off, arange_ptr, local_length_size); arange_ptr += local_length_size; length = length - local_length_size; /* This applies to debug_info only, not to debug_types. */ if (info_offset >= dbg->de_debug_info.dss_size) { FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset, "arange info offset.a"); if (info_offset >= dbg->de_debug_info.dss_size) { _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD); return (DW_DLV_ERROR); } } address_size = *(Dwarf_Small *) arange_ptr; if(address_size > sizeof(Dwarf_Addr)) { _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR); return DW_DLV_ERROR; } if(address_size == 0) { _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR); return DW_DLV_ERROR; } /* It is not an error if the sizes differ. Unusual, but not an error. */ arange_ptr = arange_ptr + sizeof(Dwarf_Small); length = length - sizeof(Dwarf_Small); /* Even DWARF2 had a segment_size field here, meaning size in bytes of a segment descriptor on the target system. */ segment_size = *(Dwarf_Small *) arange_ptr; if(segment_size > sizeof(Dwarf_Addr)) { _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD); return (DW_DLV_ERROR); } arange_ptr = arange_ptr + sizeof(Dwarf_Small); length = length - sizeof(Dwarf_Small); range_entry_size = 2*address_size + segment_size; /* Round arange_ptr offset to next multiple of address_size. */ remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) % (range_entry_size); if (remainder != 0) { arange_ptr = arange_ptr + (2 * address_size) - remainder; length = length - ((2 * address_size) - remainder); } do { Dwarf_Addr range_address = 0; Dwarf_Unsigned segment_selector = 0; Dwarf_Unsigned range_length = 0; /* For segmented address spaces, the first field to read is a segment selector (new in DWARF4). Surprising since the segment_size was always there in the table header! */ if(version == 4 && segment_size != 0) { READ_UNALIGNED(dbg, segment_selector, Dwarf_Unsigned, arange_ptr, segment_size); arange_ptr += address_size; length = length - address_size; } READ_UNALIGNED(dbg, range_address, Dwarf_Addr, arange_ptr, address_size); arange_ptr += address_size; length = length - address_size; READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned, arange_ptr, address_size); arange_ptr += address_size; length = length - address_size; { /* We used to suppress all-zero entries, but now we return all aranges entries so we show the entire content. March 31, 2010. */ arange = (Dwarf_Arange) _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); if (arange == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } arange->ar_segment_selector = segment_selector; arange->ar_segment_selector_size = segment_size; arange->ar_address = range_address; arange->ar_length = range_length; arange->ar_info_offset = info_offset; arange->ar_dbg = dbg; arange_count++; curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (curr_chain == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain->ch_item = arange; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { prev_chain->ch_next = curr_chain; prev_chain = curr_chain; } } /* The current set of ranges is terminated by range_address 0 and range_length 0, but that does not necessarily terminate the ranges for this CU! There can be multiple sets in that DWARF does not explicitly forbid multiple sets. DWARF2,3,4 section 7.20 We stop short to avoid overrun of the end of the CU. */ } while (arange_ptr_past_end >= (arange_ptr + range_entry_size)); /* A compiler could emit some padding bytes here. dwarf2/3 (dwarf4 sec 7.20) does not clearly make extra padding bytes illegal. */ if (arange_ptr_past_end < arange_ptr) { char buf[200]; Dwarf_Unsigned pad_count = arange_ptr - arange_ptr_past_end; Dwarf_Unsigned offset = arange_ptr - arange_ptr_start; snprintf(buf,sizeof(buf),"DW_DLE_ARANGE_LENGTH_BAD." " 0x%" DW_PR_XZEROS DW_PR_DUx " pad bytes at offset 0x%" DW_PR_XZEROS DW_PR_DUx " in .debug_aranges", pad_count, offset); dwarf_insert_harmless_error(dbg,buf); } /* For most compilers, arange_ptr == arange_ptr_past_end at this point. But not if there were padding bytes */ arange_ptr = arange_ptr_past_end; } while (arange_ptr < dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size); if (arange_ptr != dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size) { _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR); return (DW_DLV_ERROR); } *chain_out = head_chain; *chain_count_out = arange_count; return DW_DLV_OK; }
/* This function returns the count of the number of aranges in the .debug_aranges section. It sets aranges to point to a block of Dwarf_Arange's describing the arange's. It returns DW_DLV_ERROR on error. Must be identical in most aspects to dwarf_get_aranges_addr_offsets! */ int dwarf_get_aranges(Dwarf_Debug dbg, Dwarf_Arange ** aranges, Dwarf_Signed * returned_count, Dwarf_Error * error) { /* Sweeps the .debug_aranges section. */ Dwarf_Small *arange_ptr; /* Start of arange header. Used for rounding offset of arange_ptr to twice the tuple size. Libdwarf requirement. */ Dwarf_Small *header_ptr; /* Version of .debug_aranges header. */ Dwarf_Half version; /* Offset of current set of aranges into .debug_info. */ Dwarf_Off info_offset; /* Size in bytes of addresses in target. */ Dwarf_Small address_size; /* Size in bytes of segment offsets in target. */ Dwarf_Small segment_size; Dwarf_Small remainder; /* Count of total number of aranges. */ Dwarf_Unsigned arange_count = 0; /* Start address of arange. */ Dwarf_Addr range_address; /* Length of arange. */ Dwarf_Unsigned range_length; Dwarf_Arange arange, *arange_block; Dwarf_Unsigned i; /* Used to chain Dwarf_Aranges structs. */ Dwarf_Chain curr_chain, prev_chain, head_chain = NULL; int res; /* ***** BEGIN CODE ***** */ if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } res = _dwarf_load_section(dbg, dbg->de_debug_aranges_index, &dbg->de_debug_aranges, error); if (res != DW_DLV_OK) { return res; } arange_ptr = dbg->de_debug_aranges; do { /* Length of current set of aranges. */ Dwarf_Unsigned length; Dwarf_Small *arange_ptr_past_end = 0; int local_length_size; /*REFERENCED*/ /* Not used in this instance of the macro */ int local_extension_size; header_ptr = arange_ptr; /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, arange_ptr, local_length_size, local_extension_size); arange_ptr_past_end = arange_ptr + length; READ_UNALIGNED(dbg, version, Dwarf_Half, arange_ptr, sizeof(Dwarf_Half)); arange_ptr += sizeof(Dwarf_Half); length = length - sizeof(Dwarf_Half); if (version != CURRENT_VERSION_STAMP) { _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, info_offset, Dwarf_Off, arange_ptr, local_length_size); arange_ptr += local_length_size; length = length - local_length_size; if (info_offset >= dbg->de_debug_info_size) { _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD); return (DW_DLV_ERROR); } address_size = *(Dwarf_Small *) arange_ptr; if (address_size != dbg->de_pointer_size) { /* Internal error of some kind */ _dwarf_error(dbg, error, DW_DLE_BADBITC); return (DW_DLV_ERROR); } arange_ptr = arange_ptr + sizeof(Dwarf_Small); length = length - sizeof(Dwarf_Small); segment_size = *(Dwarf_Small *) arange_ptr; arange_ptr = arange_ptr + sizeof(Dwarf_Small); length = length - sizeof(Dwarf_Small); if (segment_size != 0) { _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD); return (DW_DLV_ERROR); } /* Round arange_ptr offset to next multiple of address_size. */ remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) % (2 * address_size); if (remainder != 0) { arange_ptr = arange_ptr + (2 * address_size) - remainder; length = length - ((2 * address_size) - remainder); } do { READ_UNALIGNED(dbg, range_address, Dwarf_Addr, arange_ptr, address_size); arange_ptr += address_size; length = length - address_size; READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned, arange_ptr, address_size); arange_ptr += address_size; length = length - address_size; if (range_address != 0 || range_length != 0) { arange = (Dwarf_Arange) _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); if (arange == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } arange->ar_address = range_address; arange->ar_length = range_length; arange->ar_info_offset = info_offset; arange->ar_dbg = dbg; arange_count++; curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (curr_chain == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain->ch_item = arange; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { prev_chain->ch_next = curr_chain; prev_chain = curr_chain; } } } while (range_address != 0 || range_length != 0); /* A compiler could emit some padding bytes here. dwarf2/3 (dwarf3 draft8 sec 7.20) does not clearly make extra padding bytes illegal. */ if(arange_ptr_past_end < arange_ptr) { _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD); return (DW_DLV_ERROR); } /* For most compilers, arange_ptr == arange_ptr_past_end at this point. But not if there were padding bytes */ arange_ptr = arange_ptr_past_end; } while (arange_ptr < dbg->de_debug_aranges + dbg->de_debug_aranges_size); if (arange_ptr != dbg->de_debug_aranges + dbg->de_debug_aranges_size) { _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR); return (DW_DLV_ERROR); } arange_block = (Dwarf_Arange *) _dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count); if (arange_block == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain = head_chain; for (i = 0; i < arange_count; i++) { *(arange_block + i) = curr_chain->ch_item; prev_chain = curr_chain; curr_chain = curr_chain->ch_next; dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); } *aranges = arange_block; *returned_count = (arange_count); return DW_DLV_OK; }
/* This function returns DW_DLV_OK if it succeeds and DW_DLV_ERR or DW_DLV_OK otherwise. count is set to the number of addresses in the .debug_aranges section. For each address, the corresponding element in an array is set to the address itself(aranges) and the section offset (offsets). Must be identical in most aspects to dwarf_get_aranges! */ int _dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrs, Dwarf_Off ** offsets, Dwarf_Signed * count, Dwarf_Error * error) { /* Sweeps the .debug_aranges section. */ Dwarf_Small *arange_ptr; Dwarf_Small *arange_start_ptr; /* Start of arange header. Used for rounding offset of arange_ptr to twice the tuple size. Libdwarf requirement. */ Dwarf_Small *header_ptr; /* Length of current set of aranges. */ Dwarf_Unsigned length; /* Version of .debug_aranges header. */ Dwarf_Half version; /* Offset of current set of aranges into .debug_info. */ Dwarf_Off info_offset; /* Size in bytes of addresses in target. */ Dwarf_Small address_size; /* Size in bytes of segment offsets in target. */ Dwarf_Small segment_size; Dwarf_Small remainder; /* Count of total number of aranges. */ Dwarf_Unsigned arange_count = 0; /* Start address of arange. */ Dwarf_Addr range_address; /* Length of arange. */ Dwarf_Unsigned range_length; Dwarf_Arange arange; Dwarf_Unsigned i; /* Used to chain Dwarf_Aranges structs. */ Dwarf_Chain curr_chain, prev_chain, head_chain = NULL; Dwarf_Addr *arange_addrs; Dwarf_Off *arange_offsets; int res; /* ***** BEGIN CODE ***** */ if (error != NULL) *error = NULL; if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } res = _dwarf_load_section(dbg, dbg->de_debug_aranges_index, &dbg->de_debug_aranges, error); if (res != DW_DLV_OK) { return res; } arange_ptr = dbg->de_debug_aranges; do { int local_length_size; /*REFERENCED*/ /* not used in this instance of the macro */ int local_extension_size; header_ptr = arange_ptr; /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, arange_ptr, local_length_size, local_extension_size); READ_UNALIGNED(dbg, version, Dwarf_Half, arange_ptr, sizeof(Dwarf_Half)); arange_ptr += sizeof(Dwarf_Half); length = length - sizeof(Dwarf_Half); if (version != CURRENT_VERSION_STAMP) { _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, info_offset, Dwarf_Off, arange_ptr, local_length_size); arange_ptr += local_length_size; length = length - local_length_size; if (info_offset >= dbg->de_debug_info_size) { _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD); return (DW_DLV_ERROR); } address_size = *(Dwarf_Small *) arange_ptr; arange_ptr = arange_ptr + sizeof(Dwarf_Small); length = length - sizeof(Dwarf_Small); segment_size = *(Dwarf_Small *) arange_ptr; arange_ptr = arange_ptr + sizeof(Dwarf_Small); length = length - sizeof(Dwarf_Small); if (segment_size != 0) { _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD); return (DW_DLV_ERROR); } /* Round arange_ptr offset to next multiple of address_size. */ remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) % (2 * address_size); if (remainder != 0) { arange_ptr = arange_ptr + (2 * address_size) - remainder; length = length - ((2 * address_size) - remainder); } do { arange_start_ptr = arange_ptr; READ_UNALIGNED(dbg, range_address, Dwarf_Addr, arange_ptr, dbg->de_pointer_size); arange_ptr += dbg->de_pointer_size; length = length - dbg->de_pointer_size; READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned, arange_ptr, local_length_size); arange_ptr += local_length_size; length = length - local_length_size; if (range_address != 0 || range_length != 0) { arange = (Dwarf_Arange) _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); if (arange == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } arange->ar_address = range_address; arange->ar_length = range_length; arange->ar_info_offset = arange_start_ptr - dbg->de_debug_aranges; arange->ar_dbg = dbg; arange_count++; curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (curr_chain == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain->ch_item = arange; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { prev_chain->ch_next = curr_chain; prev_chain = curr_chain; } } } while (range_address != 0 || range_length != 0); if (length != 0) { _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD); return (DW_DLV_ERROR); } } while (arange_ptr < dbg->de_debug_aranges + dbg->de_debug_aranges_size); if (arange_ptr != dbg->de_debug_aranges + dbg->de_debug_aranges_size) { _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR); return (DW_DLV_ERROR); } arange_addrs = (Dwarf_Addr *) _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); if (arange_addrs == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } arange_offsets = (Dwarf_Off *) _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); if (arange_offsets == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain = head_chain; for (i = 0; i < arange_count; i++) { Dwarf_Arange ar = curr_chain->ch_item; arange_addrs[i] = ar->ar_address; arange_offsets[i] = ar->ar_info_offset; prev_chain = curr_chain; curr_chain = curr_chain->ch_next; dwarf_dealloc(dbg, ar, DW_DLA_ARANGE); dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); } *count = arange_count; *offsets = arange_offsets; *addrs = arange_addrs; return (DW_DLV_OK); }
/* return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR */ int _dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error) { /* This pointer is used to scan the portion of the .debug_line section for the current cu. */ Dwarf_Small *line_ptr; Dwarf_Small *orig_line_ptr; /* This points to the last byte of the .debug_line portion for the current cu. */ Dwarf_Small *line_ptr_end; /* This points to the end of the statement program prologue for the current cu, and serves to check that the prologue was correctly decoded. */ Dwarf_Small *check_line_ptr; /* Pointer to a DW_AT_stmt_list attribute in case it exists in the die. */ Dwarf_Attribute stmt_list_attr; /* Pointer to DW_AT_comp_dir attribute in die. */ Dwarf_Attribute comp_dir_attr; /* Pointer to name of compilation directory. */ Dwarf_Small *comp_dir = NULL; /* Offset into .debug_line specified by a DW_AT_stmt_list attribute. */ Dwarf_Unsigned line_offset; /* These are the fields of the statement program header. */ Dwarf_Unsigned total_length; Dwarf_Half version; Dwarf_Unsigned prologue_length; Dwarf_Small minimum_instruction_length; Dwarf_Small default_is_stmt; Dwarf_Sbyte line_base; Dwarf_Small line_range; Dwarf_Small opcode_base; Dwarf_Small *opcode_length; /* These are the state machine state variables. */ Dwarf_Addr address; Dwarf_Word file; Dwarf_Word line; Dwarf_Word column; Dwarf_Bool is_stmt; Dwarf_Bool basic_block; Dwarf_Bool end_sequence; Dwarf_Sword i, file_entry_count, include_directories_count; /* This is the current opcode read from the statement program. */ Dwarf_Small opcode; /* Pointer to a Dwarf_Line_Context_s structure that contains the context such as file names and include directories for the set of lines being generated. */ Dwarf_Line_Context line_context; /* These variables are used to decode leb128 numbers. Leb128_num holds the decoded number, and leb128_length is its length in bytes. */ Dwarf_Word leb128_num; Dwarf_Word leb128_length; Dwarf_Sword advance_line; /* This is the operand of the latest fixed_advance_pc extended opcode. */ Dwarf_Half fixed_advance_pc; /* This is the length of an extended opcode instr. */ Dwarf_Word instr_length; Dwarf_Small ext_opcode; int local_length_size; /*REFERENCED*/ /* Not used in this instance of the macro */ int local_extension_size; /* The Dwarf_Debug this die belongs to. */ Dwarf_Debug dbg; int resattr; int lres; int res; /* ***** BEGIN CODE ***** */ if (error != NULL) *error = NULL; CHECK_DIE(die, DW_DLV_ERROR) dbg = die->di_cu_context->cc_dbg; res = _dwarf_load_section(dbg, dbg->de_debug_line_index, &dbg->de_debug_line, error); if (res != DW_DLV_OK) { return res; } resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error); if (resattr != DW_DLV_OK) { return resattr; } lres = dwarf_formudata(stmt_list_attr, &line_offset, error); if (lres != DW_DLV_OK) { return lres; } if (line_offset >= dbg->de_debug_line_size) { _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); return (DW_DLV_ERROR); } orig_line_ptr = dbg->de_debug_line; line_ptr = dbg->de_debug_line + line_offset; dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); /* If die has DW_AT_comp_dir attribute, get the string that names the compilation directory. */ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error); if (resattr == DW_DLV_ERROR) { return resattr; } if (resattr == DW_DLV_OK) { int cres; char *cdir; cres = dwarf_formstring(comp_dir_attr, &cdir, error); if (cres == DW_DLV_ERROR) { return cres; } else if (cres == DW_DLV_OK) { comp_dir = (Dwarf_Small *) cdir; } } if (resattr == DW_DLV_OK) { dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR); } /* Following is a straightforward decoding of the statement program prologue information. */ /* READ_AREA_LENGTH updates line_ptr for consumed bytes */ READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned, line_ptr, local_length_size, local_extension_size); line_ptr_end = line_ptr + total_length; if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) { _dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD); return (DW_DLV_ERROR); } printf("total line info length %ld bytes, " "line offset 0x%llx %lld\n", (long) total_length, (long long) line_offset, (long long) line_offset); printf("compilation_directory %s\n", comp_dir ? ((char *) comp_dir) : ""); READ_UNALIGNED(dbg, version, Dwarf_Half, line_ptr, sizeof(Dwarf_Half)); line_ptr += sizeof(Dwarf_Half); if (version != CURRENT_VERSION_STAMP) { _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned, line_ptr, local_length_size); line_ptr += local_length_size; check_line_ptr = line_ptr; minimum_instruction_length = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); default_is_stmt = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); line_base = *(Dwarf_Sbyte *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Sbyte); line_range = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); opcode_base = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); printf(" min instruction length %d\n", (int) minimum_instruction_length); printf(" default is stmt %d\n", (int) default_is_stmt); printf(" line base %d\n", (int) line_base); printf(" line_range %d\n", (int) line_range); opcode_length = (Dwarf_Small *) alloca(sizeof(Dwarf_Small) * opcode_base); for (i = 1; i < opcode_base; i++) { opcode_length[i] = *(Dwarf_Small *) line_ptr; printf(" opcode[%d] length %d\n", (int) i, (int) opcode_length[i]); line_ptr = line_ptr + sizeof(Dwarf_Small); } include_directories_count = 0; while ((*(char *) line_ptr) != '\0') { printf(" include dir[%d] %s\n", (int) include_directories_count, line_ptr); line_ptr = line_ptr + strlen((char *) line_ptr) + 1; include_directories_count++; } line_ptr++; file_entry_count = 0; while (*(char *) line_ptr != '\0') { Dwarf_Unsigned tlm2; Dwarf_Unsigned di; Dwarf_Unsigned fl; printf(" file[%d] %s\n", (int) file_entry_count, (char *) line_ptr); line_ptr = line_ptr + strlen((char *) line_ptr) + 1; di = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; tlm2 = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; fl = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; printf(" dir index %d\n", (int) di); { time_t tt = (time_t) tlm2; printf(" last time 0x%x %s", /* ctime supplies newline */ (unsigned) tlm2, ctime(&tt)); } printf(" file length %ld 0x%lx\n", (long) fl, (unsigned long) fl); file_entry_count++; } line_ptr++; if (line_ptr != check_line_ptr + prologue_length) { _dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD); return (DW_DLV_ERROR); } /* Set up context structure for this set of lines. */ line_context = (Dwarf_Line_Context) _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1); if (line_context == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } printf(" statement prog offset in section: %lld 0x%llx\n", (long long) (line_ptr - orig_line_ptr), (long long) (line_ptr - orig_line_ptr)); /* Initialize the state machine. */ address = 0; file = 1; line = 1; column = 0; is_stmt = default_is_stmt; basic_block = false; end_sequence = false; print_line_header(); /* Start of statement program. */ while (line_ptr < line_ptr_end) { int type; printf(" [0x%06llx] ", (long long) (line_ptr - orig_line_ptr)); opcode = *(Dwarf_Small *) line_ptr; line_ptr++; /* 'type' is the output */ WHAT_IS_OPCODE(type, opcode, opcode_base, opcode_length, line_ptr); if (type == LOP_DISCARD) { /* do nothing, necessary ops done */ } else if (type == LOP_SPECIAL) { /* This op code is a special op in the object, no matter that it might fall into the standard op range in this compile Thatis, these are special opcodes between special_opcode_base and MAX_LINE_OP_CODE. (including special_opcode_base and MAX_LINE_OP_CODE) */ char special[50]; unsigned origop = opcode; opcode = opcode - opcode_base; address = address + minimum_instruction_length * (opcode / line_range); line = line + line_base + opcode % line_range; sprintf(special, "Specialop %3u", origop); print_line_detail(special, opcode, address, (int) file, line, column, is_stmt, basic_block, end_sequence); basic_block = false; } else if (type == LOP_STANDARD) { switch (opcode) { case DW_LNS_copy:{ if (opcode_length[DW_LNS_copy] != 0) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } print_line_detail("DW_LNS_copy", opcode, address, file, line, column, is_stmt, basic_block, end_sequence); basic_block = false; break; } case DW_LNS_advance_pc:{ Dwarf_Unsigned utmp2; if (opcode_length[DW_LNS_advance_pc] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } DECODE_LEB128_UWORD(line_ptr, utmp2) printf("DW_LNS_advance_pc val %lld 0x%llx\n", (long long) (Dwarf_Word) utmp2, (long long) (Dwarf_Word) utmp2); leb128_num = (Dwarf_Word) utmp2; address = address + minimum_instruction_length * leb128_num; break; } case DW_LNS_advance_line:{ Dwarf_Signed stmp; if (opcode_length[DW_LNS_advance_line] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } DECODE_LEB128_SWORD(line_ptr, stmp) advance_line = (Dwarf_Sword) stmp; printf("DW_LNS_advance_line val %lld 0x%llx\n", (long long) advance_line, (long long) advance_line); line = line + advance_line; break; } case DW_LNS_set_file:{ Dwarf_Unsigned utmp2; if (opcode_length[DW_LNS_set_file] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } DECODE_LEB128_UWORD(line_ptr, utmp2) file = (Dwarf_Word) utmp2; printf("DW_LNS_set_file %ld\n", (long) file); break; } case DW_LNS_set_column:{ Dwarf_Unsigned utmp2; if (opcode_length[DW_LNS_set_column] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } DECODE_LEB128_UWORD(line_ptr, utmp2) column = (Dwarf_Word) utmp2; printf("DW_LNS_set_column val %lld 0x%llx\n", (long long) column, (long long) column); break; } case DW_LNS_negate_stmt:{ if (opcode_length[DW_LNS_negate_stmt] != 0) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } is_stmt = !is_stmt; printf("DW_LNS_negate_stmt\n"); break; } case DW_LNS_set_basic_block:{ if (opcode_length[DW_LNS_set_basic_block] != 0) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } printf("DW_LNS_set_basic_block\n"); basic_block = true; break; } case DW_LNS_const_add_pc:{ opcode = MAX_LINE_OP_CODE - opcode_base; address = address + minimum_instruction_length * (opcode / line_range); printf("DW_LNS_const_add_pc new address 0x%llx\n", (long long) address); break; } case DW_LNS_fixed_advance_pc:{ if (opcode_length[DW_LNS_fixed_advance_pc] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half, line_ptr, sizeof(Dwarf_Half)); line_ptr += sizeof(Dwarf_Half); address = address + fixed_advance_pc; printf("DW_LNS_fixed_advance_pc val %lld 0x%llx" " new address 0x%llx\n", (long long) fixed_advance_pc, (long long) fixed_advance_pc, (long long) address); break; } } } else if (type == LOP_EXTENDED) { Dwarf_Unsigned utmp3; DECODE_LEB128_UWORD(line_ptr, utmp3) instr_length = (Dwarf_Word) utmp3; ext_opcode = *(Dwarf_Small *) line_ptr; line_ptr++; switch (ext_opcode) { case DW_LNE_end_sequence:{ end_sequence = true; print_line_detail("DW_LNE_end_sequence extended", opcode, address, file, line, column, is_stmt, basic_block, end_sequence); address = 0; file = 1; line = 1; column = 0; is_stmt = default_is_stmt; basic_block = false; end_sequence = false; break; } case DW_LNE_set_address:{ if (instr_length - 1 == dbg->de_pointer_size) { READ_UNALIGNED(dbg, address, Dwarf_Addr, line_ptr, dbg->de_pointer_size); line_ptr += dbg->de_pointer_size; printf("DW_LNE_set_address address 0x%llx\n", (long long) address); } else { _dwarf_error(dbg, error, DW_DLE_LINE_SET_ADDR_ERROR); return (DW_DLV_ERROR); } break; } case DW_LNE_define_file:{ Dwarf_Small *fn; Dwarf_Signed di; Dwarf_Signed tlm; Dwarf_Unsigned fl; fn = (Dwarf_Small *) line_ptr; line_ptr = line_ptr + strlen((char *) line_ptr) + 1; di = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; tlm = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; fl = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; printf("DW_LNE_define_file %s \n", fn); printf(" dir index %d\n", (int) di); { time_t tt3 = (time_t) tlm; /* ctime supplies newline */ printf(" last time 0x%x %s", (unsigned) tlm, ctime(&tt3)); } printf(" file length %ld 0x%lx\n", (long) fl, (unsigned long) fl); break; } default:{ _dwarf_error(dbg, error, DW_DLE_LINE_EXT_OPCODE_BAD); return (DW_DLV_ERROR); } } } } return (DW_DLV_OK); }
/* Although source files is supposed to return the source files in the compilation-unit, it does not look for any in the statement program. In other words, it ignores those defined using the extended opcode DW_LNE_define_file. */ int dwarf_srcfiles(Dwarf_Die die, char ***srcfiles, Dwarf_Signed * srcfilecount, Dwarf_Error * error) { /* This pointer is used to scan the portion of the .debug_line section for the current cu. */ Dwarf_Small *line_ptr; /* This points to the last byte of the .debug_line portion for the current cu. */ Dwarf_Small *line_ptr_end; /* This points to the end of the statement program prologue for the current cu, and serves to check that the prologue was correctly decoded. */ Dwarf_Small *check_line_ptr; /* Pointer to a DW_AT_stmt_list attribute in case it exists in the die. */ Dwarf_Attribute stmt_list_attr; /* Pointer to DW_AT_comp_dir attribute in die. */ Dwarf_Attribute comp_dir_attr; /* Pointer to name of compilation directory. */ Dwarf_Small *comp_dir = 0; /* Offset into .debug_line specified by a DW_AT_stmt_list attribute. */ Dwarf_Unsigned line_offset = 0; /* Some of the fields of the statement program header. */ Dwarf_Unsigned total_length = 0; Dwarf_Half version = 0; Dwarf_Unsigned prologue_length = 0; Dwarf_Small special_opcode_base= 0; /* File name excluding included directory. */ char *file_name = 0; /* Name of directory that the file is in. */ char *dir_name = 0; /* Name concatenating both directory and file name. */ char *full_name = 0; /* This is the directory index for the file. The compilation directory is 0, and the first included directory is 1. */ Dwarf_Sword dir_index = 0; Dwarf_Small *include_directories = 0; Dwarf_Sword i = 0; Dwarf_Sword file_count = 0; Dwarf_Sword directories_count = 0; /* This is the current opcode read from the statement program. */ Dwarf_Word leb128_length; /* This is the length of an extended opcode instr. */ /* This points to a block of char *'s, each of which points to a file name. */ char **ret_files = 0; /* The Dwarf_Debug this die belongs to. */ Dwarf_Debug dbg; /* Used to chain the file names. */ Dwarf_Chain curr_chain, prev_chain, head_chain = NULL; int resattr; int lres; int local_length_size = 0; /*REFERENCED*/ /* Not used in this instance of the macro */ int local_extension_size = 0; int res; /* ***** BEGIN CODE ***** */ /* Reset error. */ if (error != NULL) *error = NULL; CHECK_DIE(die, DW_DLV_ERROR) dbg = die->di_cu_context->cc_dbg; resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error); if (resattr != DW_DLV_OK) { return resattr; } if (dbg->de_debug_line_index == 0) { _dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_NULL); return (DW_DLV_ERROR); } res = _dwarf_load_section(dbg, dbg->de_debug_line_index, &dbg->de_debug_line, error); if (res != DW_DLV_OK) { return res; } lres = dwarf_formudata(stmt_list_attr, &line_offset, error); if (lres != DW_DLV_OK) { return lres; } if (line_offset >= dbg->de_debug_line_size) { _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); return (DW_DLV_ERROR); } line_ptr = dbg->de_debug_line + line_offset; dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); /* If die has DW_AT_comp_dir attribute, get the string that names the compilation directory. */ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error); if (resattr == DW_DLV_ERROR) { return resattr; } if (resattr == DW_DLV_OK) { int cres; char *cdir; cres = dwarf_formstring(comp_dir_attr, &cdir, error); if (cres == DW_DLV_ERROR) { return cres; } else if (cres == DW_DLV_OK) { comp_dir = (Dwarf_Small *) cdir; } } if (resattr == DW_DLV_OK) { dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR); } /* Following is a straightforward decoding of the statement program prologue information. */ /* READ_AREA_LENGTH updates line_ptr for consumed bytes */ READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned, line_ptr, local_length_size, local_extension_size); line_ptr_end = line_ptr + total_length; if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) { _dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, version, Dwarf_Half, line_ptr, sizeof(Dwarf_Half)); line_ptr += sizeof(Dwarf_Half); if (version != CURRENT_VERSION_STAMP && version != CURRENT_VERSION_STAMP3) { _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned, line_ptr, local_length_size); line_ptr += local_length_size; check_line_ptr = line_ptr; /* Skip over minimum instruction length. */ line_ptr = line_ptr + sizeof(Dwarf_Small); /* Skip over default_is_stmt. */ line_ptr = line_ptr + sizeof(Dwarf_Small); /* Skip over line_base. */ line_ptr = line_ptr + sizeof(Dwarf_Sbyte); /* Skip over line_ptr. */ line_ptr = line_ptr + sizeof(Dwarf_Small); special_opcode_base = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); for (i = 1; i < special_opcode_base; i++) { /* Skip over opcode lengths for standard opcodes. */ line_ptr = line_ptr + sizeof(Dwarf_Small); } directories_count = 0; include_directories = line_ptr; while ((*(char *) line_ptr) != '\0') { line_ptr = line_ptr + strlen((char *) line_ptr) + 1; directories_count++; } line_ptr++; file_count = 0; while (*(char *) line_ptr != '\0') { Dwarf_Unsigned utmp; file_name = (char *) line_ptr; line_ptr = line_ptr + strlen((char *) line_ptr) + 1; DECODE_LEB128_UWORD(line_ptr, utmp) dir_index = (Dwarf_Sword) utmp; if (dir_index > directories_count) { _dwarf_error(dbg, error, DW_DLE_DIR_INDEX_BAD); return (DW_DLV_ERROR); } if (dir_index == 0) dir_name = (char *) comp_dir; else { dir_name = (char *) include_directories; for (i = 1; i < dir_index; i++) /* FIX: this is probably very slow: redoing strlen! davea 9/94 */ dir_name = dir_name + strlen(dir_name) + 1; } /* dir_name can be NULL if there is no DW_AT_comp_dir */ if ((*file_name) == '/' || dir_name == 0) full_name = file_name; else { full_name = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING, strlen(dir_name) + 1 + strlen(file_name) + 1); if (full_name == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } strcpy(full_name, dir_name); strcat(full_name, "/"); strcat(full_name, file_name); } /* Skip over time of last modification. */ _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; /* Skip over file length. */ _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (curr_chain == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain->ch_item = full_name; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { prev_chain->ch_next = curr_chain; prev_chain = curr_chain; } file_count++; } line_ptr++; if (line_ptr != check_line_ptr + prologue_length) { _dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD); return (DW_DLV_ERROR); } if (file_count == 0) { *srcfiles = NULL; *srcfilecount = 0; return (DW_DLV_NO_ENTRY); } ret_files = (char **) _dwarf_get_alloc(dbg, DW_DLA_LIST, file_count); if (ret_files == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain = head_chain; for (i = 0; i < file_count; i++) { *(ret_files + i) = curr_chain->ch_item; prev_chain = curr_chain; curr_chain = curr_chain->ch_next; dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); } *srcfiles = ret_files; *srcfilecount = file_count; return (DW_DLV_OK); }
/* return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR */ int _dwarf_internal_srclines(Dwarf_Die die, Dwarf_Line ** linebuf, Dwarf_Signed * count, Dwarf_Bool doaddrs, Dwarf_Bool dolines, Dwarf_Error * error) { /* This pointer is used to scan the portion of the .debug_line section for the current cu. */ Dwarf_Small *line_ptr; /* This points to the last byte of the .debug_line portion for the current cu. */ Dwarf_Small *line_ptr_end; /* This points to the end of the statement program prologue for the current cu, and serves to check that the prologue was correctly decoded. */ Dwarf_Small *check_line_ptr; /* Pointer to a DW_AT_stmt_list attribute in case it exists in the die. */ Dwarf_Attribute stmt_list_attr; /* Pointer to DW_AT_comp_dir attribute in die. */ Dwarf_Attribute comp_dir_attr; /* Pointer to name of compilation directory. */ Dwarf_Small *comp_dir = NULL; /* Offset into .debug_line specified by a DW_AT_stmt_list attribute. */ Dwarf_Unsigned line_offset; /* These are the fields of the statement program header. */ Dwarf_Unsigned total_length; Dwarf_Half version; Dwarf_Unsigned prologue_length; Dwarf_Small minimum_instruction_length; Dwarf_Small default_is_stmt; Dwarf_Sbyte line_base; Dwarf_Small line_range; Dwarf_Small special_opcode_base; Dwarf_Small *opcode_length; Dwarf_Small *include_directories; Dwarf_File_Entry file_entries; /* These are the state machine state variables. */ Dwarf_Addr address; Dwarf_Word file; Dwarf_Word line; Dwarf_Word column; Dwarf_Bool is_stmt; Dwarf_Bool basic_block; Dwarf_Bool end_sequence; /* These pointers are used to build the list of files names by this cu. cur_file_entry points to the file name being added, and prev_file_entry to the previous one. */ Dwarf_File_Entry cur_file_entry, prev_file_entry; Dwarf_Sword i, file_entry_count, include_directories_count; /* This is the current opcode read from the statement program. */ Dwarf_Small opcode; /* Pointer to a Dwarf_Line_Context_s structure that contains the context such as file names and include directories for the set of lines being generated. */ Dwarf_Line_Context line_context; /* This is a pointer to the current line being added to the line matrix. */ Dwarf_Line curr_line; /* These variables are used to decode leb128 numbers. Leb128_num holds the decoded number, and leb128_length is its length in bytes. */ Dwarf_Word leb128_num; Dwarf_Word leb128_length; Dwarf_Sword advance_line; /* This is the operand of the latest fixed_advance_pc extended opcode. */ Dwarf_Half fixed_advance_pc; /* Counts the number of lines in the line matrix. */ Dwarf_Sword line_count = 0; /* This is the length of an extended opcode instr. */ Dwarf_Word instr_length; Dwarf_Small ext_opcode; /* Used to chain together pointers to line table entries that are later used to create a block of Dwarf_Line entries. */ Dwarf_Chain chain_line, head_chain = NULL, curr_chain; /* This points to a block of Dwarf_Lines, a pointer to which is returned in linebuf. */ Dwarf_Line *block_line; /* The Dwarf_Debug this die belongs to. */ Dwarf_Debug dbg; int resattr; int lres; int local_length_size = 0; /*REFERENCED*/ /* Not used in this instance of the macro */ int local_extension_size = 0; int res; /* ***** BEGIN CODE ***** */ if (error != NULL) *error = NULL; CHECK_DIE(die, DW_DLV_ERROR) dbg = die->di_cu_context->cc_dbg; res = _dwarf_load_section(dbg, dbg->de_debug_line_index, &dbg->de_debug_line, error); if (res != DW_DLV_OK) { return res; } resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error); if (resattr != DW_DLV_OK) { return resattr; } lres = dwarf_formudata(stmt_list_attr, &line_offset, error); if (lres != DW_DLV_OK) { return lres; } if (line_offset >= dbg->de_debug_line_size) { _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); return (DW_DLV_ERROR); } line_ptr = dbg->de_debug_line + line_offset; dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); /* If die has DW_AT_comp_dir attribute, get the string that names the compilation directory. */ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error); if (resattr == DW_DLV_ERROR) { return resattr; } if (resattr == DW_DLV_OK) { int cres; char *cdir; cres = dwarf_formstring(comp_dir_attr, &cdir, error); if (cres == DW_DLV_ERROR) { return cres; } else if (cres == DW_DLV_OK) { comp_dir = (Dwarf_Small *) cdir; } } if (resattr == DW_DLV_OK) { dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR); } /* Following is a straightforward decoding of the statement program prologue information. */ /* READ_AREA_LENGTH updates line_ptr for consumed bytes */ READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned, line_ptr, local_length_size, local_extension_size); line_ptr_end = line_ptr + total_length; if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) { _dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, version, Dwarf_Half, line_ptr, sizeof(Dwarf_Half)); line_ptr += sizeof(Dwarf_Half); if (version != CURRENT_VERSION_STAMP && version != CURRENT_VERSION_STAMP3) { _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned, line_ptr, local_length_size); line_ptr += local_length_size; check_line_ptr = line_ptr; minimum_instruction_length = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); default_is_stmt = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); line_base = *(Dwarf_Sbyte *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Sbyte); line_range = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); special_opcode_base = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); opcode_length = (Dwarf_Small *) alloca(sizeof(Dwarf_Small) * special_opcode_base); for (i = 1; i < special_opcode_base; i++) { opcode_length[i] = *(Dwarf_Small *) line_ptr; line_ptr = line_ptr + sizeof(Dwarf_Small); } include_directories_count = 0; include_directories = line_ptr; while ((*(char *) line_ptr) != '\0') { line_ptr = line_ptr + strlen((char *) line_ptr) + 1; include_directories_count++; } line_ptr++; file_entry_count = 0; file_entries = prev_file_entry = NULL; while (*(char *) line_ptr != '\0') { cur_file_entry = (Dwarf_File_Entry) _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1); if (cur_file_entry == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } cur_file_entry->fi_file_name = (Dwarf_Small *) line_ptr; line_ptr = line_ptr + strlen((char *) line_ptr) + 1; cur_file_entry->fi_dir_index = (Dwarf_Sword) _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; cur_file_entry->fi_time_last_mod = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; cur_file_entry->fi_file_length = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; if (file_entries == NULL) file_entries = cur_file_entry; else prev_file_entry->fi_next = cur_file_entry; prev_file_entry = cur_file_entry; file_entry_count++; } line_ptr++; if (line_ptr != check_line_ptr + prologue_length) { _dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD); return (DW_DLV_ERROR); } /* Set up context structure for this set of lines. */ line_context = (Dwarf_Line_Context) _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1); if (line_context == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } /* Initialize the state machine. */ address = 0; file = 1; line = 1; column = 0; is_stmt = default_is_stmt; basic_block = false; end_sequence = false; /* Start of statement program. */ while (line_ptr < line_ptr_end) { int type; opcode = *(Dwarf_Small *) line_ptr; line_ptr++; /* 'type' is the output */ WHAT_IS_OPCODE(type, opcode, special_opcode_base, opcode_length, line_ptr); if (type == LOP_DISCARD) { /* do nothing, necessary ops done */ } else if (type == LOP_SPECIAL) { /* This op code is a special op in the object, no matter that it might fall into the standard op range in this compile Thatis, these are special opcodes between special_opcode_base and MAX_LINE_OP_CODE. (including special_opcode_base and MAX_LINE_OP_CODE) */ opcode = opcode - special_opcode_base; address = address + minimum_instruction_length * (opcode / line_range); line = line + line_base + opcode % line_range; if (dolines) { curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1); if (curr_line == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_line->li_address = address; curr_line->li_addr_line.li_l_data.li_file = (Dwarf_Sword) file; curr_line->li_addr_line.li_l_data.li_line = (Dwarf_Sword) line; curr_line->li_addr_line.li_l_data.li_column = (Dwarf_Half) column; curr_line->li_addr_line.li_l_data.li_is_stmt = is_stmt; curr_line->li_addr_line.li_l_data.li_basic_block = basic_block; curr_line->li_addr_line.li_l_data.li_end_sequence = end_sequence; curr_line->li_context = line_context; line_count++; chain_line = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (chain_line == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } chain_line->ch_item = curr_line; if (head_chain == NULL) head_chain = curr_chain = chain_line; else { curr_chain->ch_next = chain_line; curr_chain = chain_line; } } basic_block = false; } else if (type == LOP_STANDARD) { switch (opcode) { case DW_LNS_copy:{ if (opcode_length[DW_LNS_copy] != 0) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } if (dolines) { curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1); if (curr_line == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_line->li_address = address; curr_line->li_addr_line.li_l_data.li_file = (Dwarf_Sword) file; curr_line->li_addr_line.li_l_data.li_line = (Dwarf_Sword) line; curr_line->li_addr_line.li_l_data.li_column = (Dwarf_Half) column; curr_line->li_addr_line.li_l_data.li_is_stmt = is_stmt; curr_line->li_addr_line.li_l_data. li_basic_block = basic_block; curr_line->li_addr_line.li_l_data. li_end_sequence = end_sequence; curr_line->li_context = line_context; line_count++; chain_line = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (chain_line == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } chain_line->ch_item = curr_line; if (head_chain == NULL) head_chain = curr_chain = chain_line; else { curr_chain->ch_next = chain_line; curr_chain = chain_line; } } basic_block = false; break; } case DW_LNS_advance_pc:{ Dwarf_Unsigned utmp2; if (opcode_length[DW_LNS_advance_pc] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } DECODE_LEB128_UWORD(line_ptr, utmp2) leb128_num = (Dwarf_Word) utmp2; address = address + minimum_instruction_length * leb128_num; break; } case DW_LNS_advance_line:{ Dwarf_Signed stmp; if (opcode_length[DW_LNS_advance_line] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } DECODE_LEB128_SWORD(line_ptr, stmp) advance_line = (Dwarf_Sword) stmp; line = line + advance_line; break; } case DW_LNS_set_file:{ Dwarf_Unsigned utmp2; if (opcode_length[DW_LNS_set_file] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } DECODE_LEB128_UWORD(line_ptr, utmp2) file = (Dwarf_Word) utmp2; break; } case DW_LNS_set_column:{ Dwarf_Unsigned utmp2; if (opcode_length[DW_LNS_set_column] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } DECODE_LEB128_UWORD(line_ptr, utmp2) column = (Dwarf_Word) utmp2; break; } case DW_LNS_negate_stmt:{ if (opcode_length[DW_LNS_negate_stmt] != 0) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } is_stmt = !is_stmt; break; } case DW_LNS_set_basic_block:{ if (opcode_length[DW_LNS_set_basic_block] != 0) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } basic_block = true; break; } case DW_LNS_const_add_pc:{ opcode = MAX_LINE_OP_CODE - special_opcode_base; address = address + minimum_instruction_length * (opcode / line_range); break; } case DW_LNS_fixed_advance_pc:{ if (opcode_length[DW_LNS_fixed_advance_pc] != 1) { _dwarf_error(dbg, error, DW_DLE_LINE_NUM_OPERANDS_BAD); return (DW_DLV_ERROR); } READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half, line_ptr, sizeof(Dwarf_Half)); line_ptr += sizeof(Dwarf_Half); address = address + fixed_advance_pc; break; } } } else if (type == LOP_EXTENDED) { Dwarf_Unsigned utmp3; DECODE_LEB128_UWORD(line_ptr, utmp3) instr_length = (Dwarf_Word) utmp3; /* Dwarf_Small is a ubyte and the extended opcode is a ubyte, though not stated as clearly in the 2.0.0 spec as one might hope. */ ext_opcode = *(Dwarf_Small *) line_ptr; line_ptr++; switch (ext_opcode) { case DW_LNE_end_sequence:{ end_sequence = true; if (dolines) { curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1); if (curr_line == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_line->li_address = address; curr_line->li_addr_line.li_l_data.li_file = (Dwarf_Sword) file; curr_line->li_addr_line.li_l_data.li_line = (Dwarf_Sword) line; curr_line->li_addr_line.li_l_data.li_column = (Dwarf_Half) column; curr_line->li_addr_line.li_l_data.li_is_stmt = default_is_stmt; curr_line->li_addr_line.li_l_data. li_basic_block = basic_block; curr_line->li_addr_line.li_l_data. li_end_sequence = end_sequence; curr_line->li_context = line_context; line_count++; chain_line = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (chain_line == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } chain_line->ch_item = curr_line; if (head_chain == NULL) head_chain = curr_chain = chain_line; else { curr_chain->ch_next = chain_line; curr_chain = chain_line; } } address = 0; file = 1; line = 1; column = 0; is_stmt = default_is_stmt; basic_block = false; end_sequence = false; break; } case DW_LNE_set_address:{ if (instr_length - 1 == dbg->de_pointer_size) { READ_UNALIGNED(dbg, address, Dwarf_Addr, line_ptr, dbg->de_pointer_size); if (doaddrs) { curr_line = (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1); if (curr_line == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_line->li_address = address; curr_line->li_addr_line.li_offset = line_ptr - dbg->de_debug_line; line_count++; chain_line = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (chain_line == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } chain_line->ch_item = curr_line; if (head_chain == NULL) head_chain = curr_chain = chain_line; else { curr_chain->ch_next = chain_line; curr_chain = chain_line; } } line_ptr += dbg->de_pointer_size; } else { _dwarf_error(dbg, error, DW_DLE_LINE_SET_ADDR_ERROR); return (DW_DLV_ERROR); } break; } case DW_LNE_define_file:{ if (dolines) { cur_file_entry = (Dwarf_File_Entry) _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1); if (cur_file_entry == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } cur_file_entry->fi_file_name = (Dwarf_Small *) line_ptr; line_ptr = line_ptr + strlen((char *) line_ptr) + 1; cur_file_entry->fi_dir_index = (Dwarf_Sword) _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; cur_file_entry->fi_time_last_mod = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; cur_file_entry->fi_file_length = _dwarf_decode_u_leb128(line_ptr, &leb128_length); line_ptr = line_ptr + leb128_length; if (file_entries == NULL) file_entries = cur_file_entry; else prev_file_entry->fi_next = cur_file_entry; prev_file_entry = cur_file_entry; file_entry_count++; } break; } default:{ _dwarf_error(dbg, error, DW_DLE_LINE_EXT_OPCODE_BAD); return (DW_DLV_ERROR); } } } } block_line = (Dwarf_Line *) _dwarf_get_alloc(dbg, DW_DLA_LIST, line_count); if (block_line == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain = head_chain; for (i = 0; i < line_count; i++) { *(block_line + i) = curr_chain->ch_item; head_chain = curr_chain; curr_chain = curr_chain->ch_next; dwarf_dealloc(dbg, head_chain, DW_DLA_CHAIN); } line_context->lc_file_entries = file_entries; line_context->lc_file_entry_count = file_entry_count; line_context->lc_include_directories = include_directories; line_context->lc_include_directories_count = include_directories_count; line_context->lc_line_count = line_count; line_context->lc_compilation_directory = comp_dir; line_context->lc_version_number = version; line_context->lc_dbg = dbg; *count = line_count; *linebuf = block_line; return (DW_DLV_OK); }
/* Sweeps the complete section. */ int _dwarf_internal_get_pubnames_like_data( Dwarf_Debug dbg, Dwarf_Small *section_data_ptr, Dwarf_Unsigned section_length, Dwarf_Global **globals, Dwarf_Signed *return_count, Dwarf_Error *error, int allocation_code, int length_err_num, int version_err_num ) { Dwarf_Small *pubnames_like_ptr; /* Points to the context for the current set of global names, and contains information to identify the compilation-unit that the set refers to. */ Dwarf_Global_Context pubnames_context; Dwarf_Half version; /* Offset from the start of compilation-unit for the current global. */ Dwarf_Off die_offset_in_cu; Dwarf_Unsigned global_count = 0; /* Points to the current global read. */ Dwarf_Global global; /* Used to chain the Dwarf_Global_s structs for creating contiguous list of pointers to the structs. */ Dwarf_Chain curr_chain, prev_chain, head_chain = NULL; /* Points to contiguous block of Dwarf_Global's to be returned. */ Dwarf_Global *ret_globals; /* Temporary counter. */ Dwarf_Unsigned i; if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return(DW_DLV_ERROR); } if (section_data_ptr == NULL) { return(DW_DLV_NO_ENTRY); } pubnames_like_ptr = section_data_ptr; do { Dwarf_Unsigned length; int local_extension_size; int local_length_size; pubnames_context = (Dwarf_Global_Context) _dwarf_get_alloc(dbg, allocation_code, 1); if (pubnames_context == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return(DW_DLV_ERROR); } /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed bytes*/ READ_AREA_LENGTH(dbg,length,Dwarf_Unsigned, pubnames_like_ptr,local_length_size,local_extension_size); pubnames_context->pu_length_size = local_length_size; pubnames_context->pu_extension_size = local_extension_size; pubnames_context->pu_dbg = dbg; READ_UNALIGNED(dbg,version, Dwarf_Half, pubnames_like_ptr, sizeof(Dwarf_Half)); pubnames_like_ptr += sizeof(Dwarf_Half); if (version != CURRENT_VERSION_STAMP) { _dwarf_error(dbg, error, version_err_num); return(DW_DLV_ERROR); } /* offset of CU header in debug section */ READ_UNALIGNED(dbg,pubnames_context->pu_offset_of_cu_header, Dwarf_Off, pubnames_like_ptr, pubnames_context->pu_length_size); pubnames_like_ptr += pubnames_context->pu_length_size; READ_UNALIGNED(dbg,pubnames_context->pu_info_length,Dwarf_Unsigned, pubnames_like_ptr, pubnames_context->pu_length_size); pubnames_like_ptr += pubnames_context->pu_length_size; if (pubnames_like_ptr > (section_data_ptr + section_length)) { _dwarf_error(dbg, error, length_err_num); return(DW_DLV_ERROR); } /* read initial offset (of DIE within CU) of a pubname, final entry is not a pair, just a zero offset */ READ_UNALIGNED(dbg,die_offset_in_cu,Dwarf_Off, pubnames_like_ptr, pubnames_context->pu_length_size); pubnames_like_ptr += pubnames_context->pu_length_size; /* loop thru pairs. DIE off with CU followed by string */ while (die_offset_in_cu != 0) { /* Already read offset, pubnames_like_ptr now points to the string */ global = (Dwarf_Global)_dwarf_get_alloc(dbg, DW_DLA_GLOBAL, 1); if (global == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return(DW_DLV_ERROR); } global_count++; global->gl_context = pubnames_context; global->gl_named_die_offset_within_cu = die_offset_in_cu; global->gl_name = pubnames_like_ptr; pubnames_like_ptr = pubnames_like_ptr + strlen((char *)pubnames_like_ptr) + 1; /* finish off current entry chain */ curr_chain = (Dwarf_Chain)_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (curr_chain == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return(DW_DLV_ERROR); } /* Put current global on singly_linked list. */ curr_chain->ch_item = (Dwarf_Global)global; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { prev_chain->ch_next = curr_chain; prev_chain = curr_chain; } /* read offset for the *next* entry */ READ_UNALIGNED(dbg,die_offset_in_cu, Dwarf_Off, pubnames_like_ptr, pubnames_context->pu_length_size); pubnames_like_ptr += pubnames_context->pu_length_size; if (pubnames_like_ptr > (section_data_ptr + section_length)) { _dwarf_error(dbg, error, length_err_num); return(DW_DLV_ERROR); } } } while (pubnames_like_ptr < (section_data_ptr + section_length)); /* Points to contiguous block of Dwarf_Global's. */ ret_globals = (Dwarf_Global *) _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count); if (ret_globals == NULL) {_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return(DW_DLV_ERROR);} /* Store pointers to Dwarf_Global_s structs in contiguous block, and deallocate the chain. */ curr_chain = head_chain; for (i = 0; i < global_count; i++) { *(ret_globals + i) = curr_chain->ch_item; prev_chain = curr_chain; curr_chain = curr_chain->ch_next; dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); } *globals = ret_globals; *return_count = (global_count); return DW_DLV_OK; }
/* This function is used to create a CU Context for a compilation-unit that begins at offset in .debug_info. The CU Context is attached to the list of CU Contexts for this dbg. It is assumed that the CU at offset has not been read before, and so do not call this routine before making sure of this with _dwarf_find_CU_Context(). Returns NULL on error. As always, being an internal routine, assumes a good dbg. This function must always set a dwarf error code before returning NULL. Always. */ static Dwarf_CU_Context _dwarf_make_CU_Context(Dwarf_Debug dbg, Dwarf_Off offset,Dwarf_Bool is_info,Dwarf_Error * error) { Dwarf_CU_Context cu_context = 0; Dwarf_Unsigned length = 0; Dwarf_Signed abbrev_offset = 0; Dwarf_Unsigned typeoffset = 0; Dwarf_Sig8 signaturedata; Dwarf_Unsigned types_extra_len = 0; Dwarf_Byte_Ptr cu_ptr = 0; int local_extension_size = 0; int local_length_size = 0; Dwarf_Debug_InfoTypes dis = is_info? &dbg->de_info_reading: &dbg->de_types_reading; Dwarf_Unsigned section_size = is_info? dbg->de_debug_info.dss_size: dbg->de_debug_types.dss_size; cu_context = (Dwarf_CU_Context) _dwarf_get_alloc(dbg, DW_DLA_CU_CONTEXT, 1); if (cu_context == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (NULL); } cu_context->cc_dbg = dbg; cu_context->cc_is_info = is_info; { Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: dbg->de_debug_types.dss_data; cu_ptr = (Dwarf_Byte_Ptr) (dataptr+offset); } /* READ_AREA_LENGTH updates cu_ptr for consumed bytes */ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, cu_ptr, local_length_size, local_extension_size); cu_context->cc_length_size = local_length_size; cu_context->cc_extension_size = local_extension_size; cu_context->cc_length = (Dwarf_Word) length; READ_UNALIGNED(dbg, cu_context->cc_version_stamp, Dwarf_Half, cu_ptr, sizeof(Dwarf_Half)); cu_ptr += sizeof(Dwarf_Half); READ_UNALIGNED(dbg, abbrev_offset, Dwarf_Signed, cu_ptr, local_length_size); cu_ptr += local_length_size; cu_context->cc_abbrev_offset = (Dwarf_Sword) abbrev_offset; cu_context->cc_address_size = *(Dwarf_Small *) cu_ptr; ++cu_ptr; if(cu_context->cc_address_size > sizeof(Dwarf_Addr)) { _dwarf_error(dbg, error, DW_DLE_CU_ADDRESS_SIZE_BAD); return (NULL); } if(!is_info) { /* debug_types CU headers have extra header bytes. */ types_extra_len = sizeof(signaturedata) + local_length_size; } if ((length < (CU_VERSION_STAMP_SIZE + local_length_size + CU_ADDRESS_SIZE_SIZE + types_extra_len)) || ((offset + length + local_length_size + local_extension_size) > section_size)) { dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); _dwarf_error(dbg, error, DW_DLE_CU_LENGTH_ERROR); return (NULL); } if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP3 && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP4) { dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (NULL); } if (!is_info) { if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP4) { dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); _dwarf_error(dbg, error, DW_DLE_DEBUG_TYPES_ONLY_DWARF4); return (NULL); } /* Now read the debug_types extra header fields of the signature (8 bytes) and the typeoffset. */ memcpy(&signaturedata,cu_ptr,sizeof(signaturedata)); cu_ptr += sizeof(signaturedata); READ_UNALIGNED(dbg, typeoffset, Dwarf_Unsigned, cu_ptr, local_length_size); cu_context->cc_typeoffset = typeoffset; cu_context->cc_signature = signaturedata; Dwarf_Unsigned cu_len = length - (local_length_size + local_extension_size); if(typeoffset >= cu_len) { dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); _dwarf_error(dbg, error, DW_DLE_DEBUG_TYPEOFFSET_BAD); return (NULL); } } if (abbrev_offset >= dbg->de_debug_abbrev.dss_size) { dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT); _dwarf_error(dbg, error, DW_DLE_ABBREV_OFFSET_ERROR); return (NULL); } cu_context->cc_abbrev_hash_table = (Dwarf_Hash_Table) _dwarf_get_alloc(dbg, DW_DLA_HASH_TABLE, 1); if (cu_context->cc_abbrev_hash_table == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (NULL); } cu_context->cc_debug_offset = (Dwarf_Word) offset; dis->de_last_offset = (Dwarf_Word) (offset + length + local_extension_size + local_length_size); if (dis->de_cu_context_list == NULL) { dis->de_cu_context_list = cu_context; dis->de_cu_context_list_end = cu_context; } else { dis->de_cu_context_list_end->cc_next = cu_context; dis->de_cu_context_list_end = cu_context; } return (cu_context); }
/* This function is used to create a CU Context for a compilation-unit that begins at offset in .debug_info. The CU Context is attached to the list of CU Contexts for this dbg. It is assumed that the CU at offset has not been read before, and so do not call this routine before making sure of this with _dwarf_find_CU_Context(). Returns NULL on error. As always, being an internal routine, assumes a good dbg. This function must always set a dwarf error code before returning NULL. Always. */ static Dwarf_CU_Context _dwarf_make_CU_Context(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Error * error) { Dwarf_CU_Context cu_context; Dwarf_Unsigned length; Dwarf_Signed abbrev_offset; Dwarf_Byte_Ptr cu_ptr; int local_extension_size = 0; int local_length_size; cu_context = (Dwarf_CU_Context) _dwarf_get_alloc(dbg, DW_DLA_CU_CONTEXT, 1); if (cu_context == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (NULL); } cu_context->cc_dbg = dbg; cu_ptr = (Dwarf_Byte_Ptr) (dbg->de_debug_info + offset); /* READ_AREA_LENGTH updates cu_ptr for consumed bytes */ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, cu_ptr, local_length_size, local_extension_size); cu_context->cc_length_size = local_length_size; cu_context->cc_extension_size = local_extension_size; cu_context->cc_length = (Dwarf_Word) length; READ_UNALIGNED(dbg, cu_context->cc_version_stamp, Dwarf_Half, cu_ptr, sizeof(Dwarf_Half)); cu_ptr += sizeof(Dwarf_Half); READ_UNALIGNED(dbg, abbrev_offset, Dwarf_Signed, cu_ptr, local_length_size); cu_ptr += local_length_size; cu_context->cc_abbrev_offset = (Dwarf_Sword) abbrev_offset; cu_context->cc_address_size = *(Dwarf_Small *) cu_ptr; if ((length < CU_VERSION_STAMP_SIZE + local_length_size + CU_ADDRESS_SIZE_SIZE) || (offset + length + local_length_size + local_extension_size > dbg->de_debug_info_size)) { _dwarf_error(dbg, error, DW_DLE_CU_LENGTH_ERROR); return (NULL); } if (cu_context->cc_address_size != dbg->de_pointer_size) { _dwarf_error(dbg, error, DW_DLE_CU_ADDRESS_SIZE_BAD); return (NULL); } if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP3) { _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (NULL); } if (abbrev_offset >= dbg->de_debug_abbrev_size) { _dwarf_error(dbg, error, DW_DLE_ABBREV_OFFSET_ERROR); return (NULL); } cu_context->cc_abbrev_hash_table = (Dwarf_Hash_Table) _dwarf_get_alloc(dbg, DW_DLA_HASH_TABLE, 1); if (cu_context->cc_abbrev_hash_table == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (NULL); } cu_context->cc_debug_info_offset = (Dwarf_Word) offset; dbg->de_info_last_offset = (Dwarf_Word) (offset + length + local_extension_size + local_length_size); if (dbg->de_cu_context_list == NULL) { dbg->de_cu_context_list = cu_context; dbg->de_cu_context_list_end = cu_context; } else { dbg->de_cu_context_list_end->cc_next = cu_context; dbg->de_cu_context_list_end = cu_context; } return (cu_context); }