summaryrefslogtreecommitdiff
path: root/src/minibfd
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2007-12-07 10:19:36 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2007-12-07 10:20:52 +0000
commitc105c57086a59379662fff621da5c29ca2789f4f (patch)
tree0e4239c26f4260feadefee88c1fc6025e96af934 /src/minibfd
parent0aa0ab0a0a08b36013b037a35d34dd869bf1bcd0 (diff)
Add symbol line lookup to the minibfd.
Diffstat (limited to 'src/minibfd')
-rw-r--r--src/minibfd/binfile.c25
-rw-r--r--src/minibfd/binfile.h8
-rw-r--r--src/minibfd/binparser.c45
-rw-r--r--src/minibfd/binparser.h4
-rw-r--r--src/minibfd/dwarf2.h801
-rw-r--r--src/minibfd/elfparser.c729
-rw-r--r--src/minibfd/elfparser.h12
7 files changed, 1562 insertions, 62 deletions
diff --git a/src/minibfd/binfile.c b/src/minibfd/binfile.c
index 0e58215..f03baca 100644
--- a/src/minibfd/binfile.c
+++ b/src/minibfd/binfile.c
@@ -220,17 +220,25 @@ bin_file_fini (BinFile *bf)
g_free (bf->filename);
}
-const BinSymbol *
+gboolean
bin_file_lookup_symbol (BinFile *bf,
- gulong address)
+ gulong address,
+ const char **function,
+ const char **filename,
+ const char **path,
+ guint *line)
{
if (bf->elf != NULL) {
address -= bf->text_offset;
- return (const BinSymbol *) elf_parser_lookup_symbol (bf->elf, address);
+ return elf_parser_lookup_symbol (bf->elf, address,
+ function,
+ filename,
+ path,
+ line);
}
- return NULL;
+ return FALSE;
}
gboolean
@@ -254,12 +262,3 @@ bin_file_check_inode (BinFile *bf,
return FALSE;
}
-
-const char *
-bin_symbol_get_name (BinFile *file, const BinSymbol *symbol)
-{
- if (symbol == NULL)
- return NULL;
-
- return elf_parser_get_sym_name (file->elf, (const ElfSym *)symbol);
-}
diff --git a/src/minibfd/binfile.h b/src/minibfd/binfile.h
index a8e3098..e8550d5 100644
--- a/src/minibfd/binfile.h
+++ b/src/minibfd/binfile.h
@@ -49,8 +49,12 @@ void bin_file_open (BinFile *bin_file);
void bin_file_close (BinFile *bin_file);
void bin_file_fini (BinFile *bin_file);
-const BinSymbol *bin_file_lookup_symbol (BinFile *bin_file,
- gulong address);
+gboolean bin_file_lookup_symbol (BinFile *bf,
+ gulong address,
+ const char **function,
+ const char **filename,
+ const char **path,
+ guint *line);
gboolean bin_file_check_inode (BinFile *bin_file,
ino_t inode);
diff --git a/src/minibfd/binparser.c b/src/minibfd/binparser.c
index 3ed7a4d..cef1807 100644
--- a/src/minibfd/binparser.c
+++ b/src/minibfd/binparser.c
@@ -236,6 +236,41 @@ bin_parser_get_uint (BinParser *parser, int width)
return r;
}
+guint64
+bin_parser_get_uleb128 (BinParser *parser)
+{
+ guint64 result = 0;
+ guint shift = 0;
+ guint8 byte;
+
+ do {
+ byte = *(const guint8 *) (parser->data + parser->offset++);
+ result |= ((guint64) (byte & 0x7f)) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+
+ return result;
+}
+
+gint64
+bin_parser_get_sleb128 (BinParser *parser)
+{
+ guint64 result = 0;
+ guint shift = 0;
+ guint8 byte;
+
+ do {
+ byte = *(const guint8 *) (parser->data + parser->offset++);
+ result |= ((guint64) (byte & 0x7f)) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+
+ if (shift < 64 && (byte & 0x40))
+ result |= (guint64) -1 << shift;
+
+ return (gint64) result;
+}
+
const char *
bin_parser_get_string (BinParser *parser)
{
@@ -243,10 +278,8 @@ bin_parser_get_string (BinParser *parser)
/* FIXME: check that the string is within the file */
- result = (const char *)parser->data + parser->offset;
-
+ result = (const char *) parser->data + parser->offset;
parser->offset += strlen (result) + 1;
-
return result;
}
@@ -267,3 +300,9 @@ bin_parser_get_uint_field (BinParser *parser,
return convert_uint (pos, parser->endian, field->width);
}
+
+void
+bin_parser_advance (BinParser *parser, gint64 offset)
+{
+ parser->offset += offset;
+}
diff --git a/src/minibfd/binparser.h b/src/minibfd/binparser.h
index 8923853..bb135a7 100644
--- a/src/minibfd/binparser.h
+++ b/src/minibfd/binparser.h
@@ -152,10 +152,14 @@ void bin_parser_seek_record (BinParser *parser,
int n_records);
void bin_parser_save (BinParser *parser);
void bin_parser_restore (BinParser *parser);
+void bin_parser_advance (BinParser *parser,
+ gint64 offset);
/* retrieve data */
guint64 bin_parser_get_uint (BinParser *parser,
int width);
+guint64 bin_parser_get_uleb128 (BinParser *parser);
+gint64 bin_parser_get_sleb128 (BinParser *parser);
const char * bin_parser_get_string (BinParser *parser);
G_END_DECLS
diff --git a/src/minibfd/dwarf2.h b/src/minibfd/dwarf2.h
new file mode 100644
index 0000000..7b7b42c
--- /dev/null
+++ b/src/minibfd/dwarf2.h
@@ -0,0 +1,801 @@
+/* Declarations and definitions of codes relating to the DWARF2 and
+ DWARF3 symbolic debugging information formats.
+ Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
+ 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+
+ Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
+ Office (AJPO), Florida State University and Silicon Graphics Inc.
+ provided support for this effort -- June 21, 1995.
+
+ Derived from the DWARF 1 implementation written by Ron Guilmette
+ (rfg@netcom.com), November 1990.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* This file is derived from the DWARF specification (a public document)
+ Revision 2.0.0 (July 27, 1993) developed by the UNIX International
+ Programming Languages Special Interest Group (UI/PLSIG) and distributed
+ by UNIX International. Copies of this specification are available from
+ UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
+
+ This file also now contains definitions from the DWARF 3 specification. */
+
+/* This file is shared between GCC and GDB, and should not contain
+ prototypes. */
+
+#ifndef _ELF_DWARF2_H
+#define _ELF_DWARF2_H
+
+/* Structure found in the .debug_line section. */
+typedef struct {
+ unsigned char li_length [4];
+ unsigned char li_version [2];
+ unsigned char li_prologue_length [4];
+ unsigned char li_min_insn_length [1];
+ unsigned char li_default_is_stmt [1];
+ unsigned char li_line_base [1];
+ unsigned char li_line_range [1];
+ unsigned char li_opcode_base [1];
+} DWARF2_External_LineInfo;
+
+typedef struct {
+ unsigned long li_length;
+ unsigned short li_version;
+ unsigned int li_prologue_length;
+ unsigned char li_min_insn_length;
+ unsigned char li_default_is_stmt;
+ int li_line_base;
+ unsigned char li_line_range;
+ unsigned char li_opcode_base;
+} DWARF2_Internal_LineInfo;
+
+/* Structure found in .debug_pubnames section. */
+typedef struct {
+ unsigned char pn_length [4];
+ unsigned char pn_version [2];
+ unsigned char pn_offset [4];
+ unsigned char pn_size [4];
+} DWARF2_External_PubNames;
+
+typedef struct {
+ unsigned long pn_length;
+ unsigned short pn_version;
+ unsigned long pn_offset;
+ unsigned long pn_size;
+} DWARF2_Internal_PubNames;
+
+/* Structure found in .debug_info section. */
+typedef struct {
+ unsigned char cu_length [4];
+ unsigned char cu_version [2];
+ unsigned char cu_abbrev_offset [4];
+ unsigned char cu_pointer_size [1];
+} DWARF2_External_CompUnit;
+
+typedef struct {
+ unsigned long cu_length;
+ unsigned short cu_version;
+ unsigned long cu_abbrev_offset;
+ unsigned char cu_pointer_size;
+} DWARF2_Internal_CompUnit;
+
+typedef struct {
+ unsigned char ar_length [4];
+ unsigned char ar_version [2];
+ unsigned char ar_info_offset [4];
+ unsigned char ar_pointer_size [1];
+ unsigned char ar_segment_size [1];
+} DWARF2_External_ARange;
+
+typedef struct {
+ unsigned long ar_length;
+ unsigned short ar_version;
+ unsigned long ar_info_offset;
+ unsigned char ar_pointer_size;
+ unsigned char ar_segment_size;
+} DWARF2_Internal_ARange;
+
+
+/* Tag names and codes. */
+enum dwarf_tag {
+ DW_TAG_padding = 0x00,
+ DW_TAG_array_type = 0x01,
+ DW_TAG_class_type = 0x02,
+ DW_TAG_entry_point = 0x03,
+ DW_TAG_enumeration_type = 0x04,
+ DW_TAG_formal_parameter = 0x05,
+ DW_TAG_imported_declaration = 0x08,
+ DW_TAG_label = 0x0a,
+ DW_TAG_lexical_block = 0x0b,
+ DW_TAG_member = 0x0d,
+ DW_TAG_pointer_type = 0x0f,
+ DW_TAG_reference_type = 0x10,
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_string_type = 0x12,
+ DW_TAG_structure_type = 0x13,
+ DW_TAG_subroutine_type = 0x15,
+ DW_TAG_typedef = 0x16,
+ DW_TAG_union_type = 0x17,
+ DW_TAG_unspecified_parameters = 0x18,
+ DW_TAG_variant = 0x19,
+ DW_TAG_common_block = 0x1a,
+ DW_TAG_common_inclusion = 0x1b,
+ DW_TAG_inheritance = 0x1c,
+ DW_TAG_inlined_subroutine = 0x1d,
+ DW_TAG_module = 0x1e,
+ DW_TAG_ptr_to_member_type = 0x1f,
+ DW_TAG_set_type = 0x20,
+ DW_TAG_subrange_type = 0x21,
+ DW_TAG_with_stmt = 0x22,
+ DW_TAG_access_declaration = 0x23,
+ DW_TAG_base_type = 0x24,
+ DW_TAG_catch_block = 0x25,
+ DW_TAG_const_type = 0x26,
+ DW_TAG_constant = 0x27,
+ DW_TAG_enumerator = 0x28,
+ DW_TAG_file_type = 0x29,
+ DW_TAG_friend = 0x2a,
+ DW_TAG_namelist = 0x2b,
+ DW_TAG_namelist_item = 0x2c,
+ DW_TAG_packed_type = 0x2d,
+ DW_TAG_subprogram = 0x2e,
+ DW_TAG_template_type_param = 0x2f,
+ DW_TAG_template_value_param = 0x30,
+ DW_TAG_thrown_type = 0x31,
+ DW_TAG_try_block = 0x32,
+ DW_TAG_variant_part = 0x33,
+ DW_TAG_variable = 0x34,
+ DW_TAG_volatile_type = 0x35,
+ /* DWARF 3. */
+ DW_TAG_dwarf_procedure = 0x36,
+ DW_TAG_restrict_type = 0x37,
+ DW_TAG_interface_type = 0x38,
+ DW_TAG_namespace = 0x39,
+ DW_TAG_imported_module = 0x3a,
+ DW_TAG_unspecified_type = 0x3b,
+ DW_TAG_partial_unit = 0x3c,
+ DW_TAG_imported_unit = 0x3d,
+ DW_TAG_condition = 0x3f,
+ DW_TAG_shared_type = 0x40,
+ /* SGI/MIPS Extensions. */
+ DW_TAG_MIPS_loop = 0x4081,
+ /* HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz . */
+ DW_TAG_HP_array_descriptor = 0x4090,
+ /* GNU extensions. */
+ DW_TAG_format_label = 0x4101, /* For FORTRAN 77 and Fortran 90. */
+ DW_TAG_function_template = 0x4102, /* For C++. */
+ DW_TAG_class_template = 0x4103, /* For C++. */
+ DW_TAG_GNU_BINCL = 0x4104,
+ DW_TAG_GNU_EINCL = 0x4105,
+ /* Extensions for UPC. See: http://upc.gwu.edu/~upc. */
+ DW_TAG_upc_shared_type = 0x8765,
+ DW_TAG_upc_strict_type = 0x8766,
+ DW_TAG_upc_relaxed_type = 0x8767,
+ /* PGI (STMicroelectronics) extensions. No documentation available. */
+ DW_TAG_PGI_kanji_type = 0xA000,
+ DW_TAG_PGI_interface_block = 0xA020
+};
+
+#define DW_TAG_lo_user 0x4080
+#define DW_TAG_hi_user 0xffff
+
+/* Flag that tells whether entry has a child or not. */
+#define DW_children_no 0
+#define DW_children_yes 1
+
+/* Form names and codes. */
+enum dwarf_form {
+ DW_FORM_addr = 0x01,
+ DW_FORM_block2 = 0x03,
+ DW_FORM_block4 = 0x04,
+ DW_FORM_data2 = 0x05,
+ DW_FORM_data4 = 0x06,
+ DW_FORM_data8 = 0x07,
+ DW_FORM_string = 0x08,
+ DW_FORM_block = 0x09,
+ DW_FORM_block1 = 0x0a,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_flag = 0x0c,
+ DW_FORM_sdata = 0x0d,
+ DW_FORM_strp = 0x0e,
+ DW_FORM_udata = 0x0f,
+ DW_FORM_ref_addr = 0x10,
+ DW_FORM_ref1 = 0x11,
+ DW_FORM_ref2 = 0x12,
+ DW_FORM_ref4 = 0x13,
+ DW_FORM_ref8 = 0x14,
+ DW_FORM_ref_udata = 0x15,
+ DW_FORM_indirect = 0x16
+};
+
+/* Attribute names and codes. */
+enum dwarf_attribute {
+ DW_AT_sibling = 0x01,
+ DW_AT_location = 0x02,
+ DW_AT_name = 0x03,
+ DW_AT_ordering = 0x09,
+ DW_AT_subscr_data = 0x0a,
+ DW_AT_byte_size = 0x0b,
+ DW_AT_bit_offset = 0x0c,
+ DW_AT_bit_size = 0x0d,
+ DW_AT_element_list = 0x0f,
+ DW_AT_stmt_list = 0x10,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+ DW_AT_member = 0x14,
+ DW_AT_discr = 0x15,
+ DW_AT_discr_value = 0x16,
+ DW_AT_visibility = 0x17,
+ DW_AT_import = 0x18,
+ DW_AT_string_length = 0x19,
+ DW_AT_common_reference = 0x1a,
+ DW_AT_comp_dir = 0x1b,
+ DW_AT_const_value = 0x1c,
+ DW_AT_containing_type = 0x1d,
+ DW_AT_default_value = 0x1e,
+ DW_AT_inline = 0x20,
+ DW_AT_is_optional = 0x21,
+ DW_AT_lower_bound = 0x22,
+ DW_AT_producer = 0x25,
+ DW_AT_prototyped = 0x27,
+ DW_AT_return_addr = 0x2a,
+ DW_AT_start_scope = 0x2c,
+ DW_AT_stride_size = 0x2e,
+ DW_AT_upper_bound = 0x2f,
+ DW_AT_abstract_origin = 0x31,
+ DW_AT_accessibility = 0x32,
+ DW_AT_address_class = 0x33,
+ DW_AT_artificial = 0x34,
+ DW_AT_base_types = 0x35,
+ DW_AT_calling_convention = 0x36,
+ DW_AT_count = 0x37,
+ DW_AT_data_member_location = 0x38,
+ DW_AT_decl_column = 0x39,
+ DW_AT_decl_file = 0x3a,
+ DW_AT_decl_line = 0x3b,
+ DW_AT_declaration = 0x3c,
+ DW_AT_discr_list = 0x3d,
+ DW_AT_encoding = 0x3e,
+ DW_AT_external = 0x3f,
+ DW_AT_frame_base = 0x40,
+ DW_AT_friend = 0x41,
+ DW_AT_identifier_case = 0x42,
+ DW_AT_macro_info = 0x43,
+ DW_AT_namelist_items = 0x44,
+ DW_AT_priority = 0x45,
+ DW_AT_segment = 0x46,
+ DW_AT_specification = 0x47,
+ DW_AT_static_link = 0x48,
+ DW_AT_type = 0x49,
+ DW_AT_use_location = 0x4a,
+ DW_AT_variable_parameter = 0x4b,
+ DW_AT_virtuality = 0x4c,
+ DW_AT_vtable_elem_location = 0x4d,
+ /* DWARF 3 values. */
+ DW_AT_allocated = 0x4e,
+ DW_AT_associated = 0x4f,
+ DW_AT_data_location = 0x50,
+ DW_AT_stride = 0x51,
+ DW_AT_entry_pc = 0x52,
+ DW_AT_use_UTF8 = 0x53,
+ DW_AT_extension = 0x54,
+ DW_AT_ranges = 0x55,
+ DW_AT_trampoline = 0x56,
+ DW_AT_call_column = 0x57,
+ DW_AT_call_file = 0x58,
+ DW_AT_call_line = 0x59,
+ DW_AT_description = 0x5a,
+ DW_AT_binary_scale = 0x5b,
+ DW_AT_decimal_scale = 0x5c,
+ DW_AT_small = 0x5d,
+ DW_AT_decimal_sign = 0x5e,
+ DW_AT_digit_count = 0x5f,
+ DW_AT_picture_string = 0x60,
+ DW_AT_mutable = 0x61,
+ DW_AT_threads_scaled = 0x62,
+ DW_AT_explicit = 0x63,
+ DW_AT_object_pointer = 0x64,
+ DW_AT_endianity = 0x65,
+ DW_AT_elemental = 0x66,
+ DW_AT_pure = 0x67,
+ DW_AT_recursive = 0x68,
+ /* SGI/MIPS extensions. */
+ DW_AT_MIPS_fde = 0x2001,
+ DW_AT_MIPS_loop_begin = 0x2002,
+ DW_AT_MIPS_tail_loop_begin = 0x2003,
+ DW_AT_MIPS_epilog_begin = 0x2004,
+ DW_AT_MIPS_loop_unroll_factor = 0x2005,
+ DW_AT_MIPS_software_pipeline_depth = 0x2006,
+ DW_AT_MIPS_linkage_name = 0x2007,
+ DW_AT_MIPS_stride = 0x2008,
+ DW_AT_MIPS_abstract_name = 0x2009,
+ DW_AT_MIPS_clone_origin = 0x200a,
+ DW_AT_MIPS_has_inlines = 0x200b,
+ /* HP extensions. */
+ DW_AT_HP_block_index = 0x2000,
+ DW_AT_HP_unmodifiable = 0x2001, /* Same as DW_AT_MIPS_fde. */
+ DW_AT_HP_actuals_stmt_list = 0x2010,
+ DW_AT_HP_proc_per_section = 0x2011,
+ DW_AT_HP_raw_data_ptr = 0x2012,
+ DW_AT_HP_pass_by_reference = 0x2013,
+ DW_AT_HP_opt_level = 0x2014,
+ DW_AT_HP_prof_version_id = 0x2015,
+ DW_AT_HP_opt_flags = 0x2016,
+ DW_AT_HP_cold_region_low_pc = 0x2017,
+ DW_AT_HP_cold_region_high_pc = 0x2018,
+ DW_AT_HP_all_variables_modifiable = 0x2019,
+ DW_AT_HP_linkage_name = 0x201a,
+ DW_AT_HP_prof_flags = 0x201b, /* In comp unit of procs_info for -g. */
+ /* GNU extensions. */
+ DW_AT_sf_names = 0x2101,
+ DW_AT_src_info = 0x2102,
+ DW_AT_mac_info = 0x2103,
+ DW_AT_src_coords = 0x2104,
+ DW_AT_body_begin = 0x2105,
+ DW_AT_body_end = 0x2106,
+ DW_AT_GNU_vector = 0x2107,
+ /* VMS extensions. */
+ DW_AT_VMS_rtnbeg_pd_address = 0x2201,
+ /* UPC extension. */
+ DW_AT_upc_threads_scaled = 0x3210,
+ /* PGI (STMicroelectronics) extensions. */
+ DW_AT_PGI_lbase = 0x3a00,
+ DW_AT_PGI_soffset = 0x3a01,
+ DW_AT_PGI_lstride = 0x3a02
+};
+
+#define DW_AT_lo_user 0x2000 /* Implementation-defined range start. */
+#define DW_AT_hi_user 0x3ff0 /* Implementation-defined range end. */
+
+/* Location atom names and codes. */
+enum dwarf_location_atom {
+ DW_OP_addr = 0x03,
+ DW_OP_deref = 0x06,
+ DW_OP_const1u = 0x08,
+ DW_OP_const1s = 0x09,
+ DW_OP_const2u = 0x0a,
+ DW_OP_const2s = 0x0b,
+ DW_OP_const4u = 0x0c,
+ DW_OP_const4s = 0x0d,
+ DW_OP_const8u = 0x0e,
+ DW_OP_const8s = 0x0f,
+ DW_OP_constu = 0x10,
+ DW_OP_consts = 0x11,
+ DW_OP_dup = 0x12,
+ DW_OP_drop = 0x13,
+ DW_OP_over = 0x14,
+ DW_OP_pick = 0x15,
+ DW_OP_swap = 0x16,
+ DW_OP_rot = 0x17,
+ DW_OP_xderef = 0x18,
+ DW_OP_abs = 0x19,
+ DW_OP_and = 0x1a,
+ DW_OP_div = 0x1b,
+ DW_OP_minus = 0x1c,
+ DW_OP_mod = 0x1d,
+ DW_OP_mul = 0x1e,
+ DW_OP_neg = 0x1f,
+ DW_OP_not = 0x20,
+ DW_OP_or = 0x21,
+ DW_OP_plus = 0x22,
+ DW_OP_plus_uconst = 0x23,
+ DW_OP_shl = 0x24,
+ DW_OP_shr = 0x25,
+ DW_OP_shra = 0x26,
+ DW_OP_xor = 0x27,
+ DW_OP_bra = 0x28,
+ DW_OP_eq = 0x29,
+ DW_OP_ge = 0x2a,
+ DW_OP_gt = 0x2b,
+ DW_OP_le = 0x2c,
+ DW_OP_lt = 0x2d,
+ DW_OP_ne = 0x2e,
+ DW_OP_skip = 0x2f,
+ DW_OP_lit0 = 0x30,
+ DW_OP_lit1 = 0x31,
+ DW_OP_lit2 = 0x32,
+ DW_OP_lit3 = 0x33,
+ DW_OP_lit4 = 0x34,
+ DW_OP_lit5 = 0x35,
+ DW_OP_lit6 = 0x36,
+ DW_OP_lit7 = 0x37,
+ DW_OP_lit8 = 0x38,
+ DW_OP_lit9 = 0x39,
+ DW_OP_lit10 = 0x3a,
+ DW_OP_lit11 = 0x3b,
+ DW_OP_lit12 = 0x3c,
+ DW_OP_lit13 = 0x3d,
+ DW_OP_lit14 = 0x3e,
+ DW_OP_lit15 = 0x3f,
+ DW_OP_lit16 = 0x40,
+ DW_OP_lit17 = 0x41,
+ DW_OP_lit18 = 0x42,
+ DW_OP_lit19 = 0x43,
+ DW_OP_lit20 = 0x44,
+ DW_OP_lit21 = 0x45,
+ DW_OP_lit22 = 0x46,
+ DW_OP_lit23 = 0x47,
+ DW_OP_lit24 = 0x48,
+ DW_OP_lit25 = 0x49,
+ DW_OP_lit26 = 0x4a,
+ DW_OP_lit27 = 0x4b,
+ DW_OP_lit28 = 0x4c,
+ DW_OP_lit29 = 0x4d,
+ DW_OP_lit30 = 0x4e,
+ DW_OP_lit31 = 0x4f,
+ DW_OP_reg0 = 0x50,
+ DW_OP_reg1 = 0x51,
+ DW_OP_reg2 = 0x52,
+ DW_OP_reg3 = 0x53,
+ DW_OP_reg4 = 0x54,
+ DW_OP_reg5 = 0x55,
+ DW_OP_reg6 = 0x56,
+ DW_OP_reg7 = 0x57,
+ DW_OP_reg8 = 0x58,
+ DW_OP_reg9 = 0x59,
+ DW_OP_reg10 = 0x5a,
+ DW_OP_reg11 = 0x5b,
+ DW_OP_reg12 = 0x5c,
+ DW_OP_reg13 = 0x5d,
+ DW_OP_reg14 = 0x5e,
+ DW_OP_reg15 = 0x5f,
+ DW_OP_reg16 = 0x60,
+ DW_OP_reg17 = 0x61,
+ DW_OP_reg18 = 0x62,
+ DW_OP_reg19 = 0x63,
+ DW_OP_reg20 = 0x64,
+ DW_OP_reg21 = 0x65,
+ DW_OP_reg22 = 0x66,
+ DW_OP_reg23 = 0x67,
+ DW_OP_reg24 = 0x68,
+ DW_OP_reg25 = 0x69,
+ DW_OP_reg26 = 0x6a,
+ DW_OP_reg27 = 0x6b,
+ DW_OP_reg28 = 0x6c,
+ DW_OP_reg29 = 0x6d,
+ DW_OP_reg30 = 0x6e,
+ DW_OP_reg31 = 0x6f,
+ DW_OP_breg0 = 0x70,
+ DW_OP_breg1 = 0x71,
+ DW_OP_breg2 = 0x72,
+ DW_OP_breg3 = 0x73,
+ DW_OP_breg4 = 0x74,
+ DW_OP_breg5 = 0x75,
+ DW_OP_breg6 = 0x76,
+ DW_OP_breg7 = 0x77,
+ DW_OP_breg8 = 0x78,
+ DW_OP_breg9 = 0x79,
+ DW_OP_breg10 = 0x7a,
+ DW_OP_breg11 = 0x7b,
+ DW_OP_breg12 = 0x7c,
+ DW_OP_breg13 = 0x7d,
+ DW_OP_breg14 = 0x7e,
+ DW_OP_breg15 = 0x7f,
+ DW_OP_breg16 = 0x80,
+ DW_OP_breg17 = 0x81,
+ DW_OP_breg18 = 0x82,
+ DW_OP_breg19 = 0x83,
+ DW_OP_breg20 = 0x84,
+ DW_OP_breg21 = 0x85,
+ DW_OP_breg22 = 0x86,
+ DW_OP_breg23 = 0x87,
+ DW_OP_breg24 = 0x88,
+ DW_OP_breg25 = 0x89,
+ DW_OP_breg26 = 0x8a,
+ DW_OP_breg27 = 0x8b,
+ DW_OP_breg28 = 0x8c,
+ DW_OP_breg29 = 0x8d,
+ DW_OP_breg30 = 0x8e,
+ DW_OP_breg31 = 0x8f,
+ DW_OP_regx = 0x90,
+ DW_OP_fbreg = 0x91,
+ DW_OP_bregx = 0x92,
+ DW_OP_piece = 0x93,
+ DW_OP_deref_size = 0x94,
+ DW_OP_xderef_size = 0x95,
+ DW_OP_nop = 0x96,
+ /* DWARF 3 extensions. */
+ DW_OP_push_object_address = 0x97,
+ DW_OP_call2 = 0x98,
+ DW_OP_call4 = 0x99,
+ DW_OP_call_ref = 0x9a,
+ DW_OP_form_tls_address = 0x9b,
+ DW_OP_call_frame_cfa = 0x9c,
+ DW_OP_bit_piece = 0x9d,
+ /* GNU extensions. */
+ DW_OP_GNU_push_tls_address = 0xe0,
+ DW_OP_GNU_uninit = 0xf0,
+ /* HP extensions. */
+ DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */
+ DW_OP_HP_is_value = 0xe1,
+ DW_OP_HP_fltconst4 = 0xe2,
+ DW_OP_HP_fltconst8 = 0xe3,
+ DW_OP_HP_mod_range = 0xe4,
+ DW_OP_HP_unmod_range = 0xe5,
+ DW_OP_HP_tls = 0xe6
+};
+
+#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */
+#define DW_OP_hi_user 0xff /* Implementation-defined range end. */
+
+/* Type encodings. */
+enum dwarf_type {
+ DW_ATE_void = 0x0,
+ DW_ATE_address = 0x1,
+ DW_ATE_boolean = 0x2,
+ DW_ATE_complex_float = 0x3,
+ DW_ATE_float = 0x4,
+ DW_ATE_signed = 0x5,
+ DW_ATE_signed_char = 0x6,
+ DW_ATE_unsigned = 0x7,
+ DW_ATE_unsigned_char = 0x8,
+ /* DWARF 3. */
+ DW_ATE_imaginary_float = 0x9,
+ DW_ATE_packed_decimal = 0xa,
+ DW_ATE_numeric_string = 0xb,
+ DW_ATE_edited = 0xc,
+ DW_ATE_signed_fixed = 0xd,
+ DW_ATE_unsigned_fixed = 0xe,
+ DW_ATE_decimal_float = 0xf,
+ /* HP extensions. */
+ DW_ATE_HP_float80 = 0x80, /* Floating-point (80 bit). */
+ DW_ATE_HP_complex_float80 = 0x81, /* Complex floating-point (80 bit). */
+ DW_ATE_HP_float128 = 0x82, /* Floating-point (128 bit). */
+ DW_ATE_HP_complex_float128 = 0x83, /* Complex floating-point (128 bit). */
+ DW_ATE_HP_floathpintel = 0x84, /* Floating-point (82 bit IA64). */
+ DW_ATE_HP_imaginary_float80 = 0x85,
+ DW_ATE_HP_imaginary_float128 = 0x86
+};
+
+#define DW_ATE_lo_user 0x80
+#define DW_ATE_hi_user 0xff
+
+/* Decimal sign encodings. */
+enum dwarf_decimal_sign_encoding {
+ /* DWARF 3. */
+ DW_DS_unsigned = 0x01,
+ DW_DS_leading_overpunch = 0x02,
+ DW_DS_trailing_overpunch = 0x03,
+ DW_DS_leading_separate = 0x04,
+ DW_DS_trailing_separate = 0x05
+};
+
+/* Endianity encodings. */
+enum dwarf_endianity_encoding {
+ /* DWARF 3. */
+ DW_END_default = 0x00,
+ DW_END_big = 0x01,
+ DW_END_little = 0x02
+};
+
+#define DW_END_lo_user 0x40
+#define DW_END_hi_user 0xff
+
+/* Array ordering names and codes. */
+enum dwarf_array_dim_ordering {
+ DW_ORD_row_major = 0,
+ DW_ORD_col_major = 1
+};
+
+/* Access attribute. */
+enum dwarf_access_attribute {
+ DW_ACCESS_public = 1,
+ DW_ACCESS_protected = 2,
+ DW_ACCESS_private = 3
+};
+
+/* Visibility. */
+enum dwarf_visibility_attribute {
+ DW_VIS_local = 1,
+ DW_VIS_exported = 2,
+ DW_VIS_qualified = 3
+};
+
+/* Virtuality. */
+enum dwarf_virtuality_attribute {
+ DW_VIRTUALITY_none = 0,
+ DW_VIRTUALITY_virtual = 1,
+ DW_VIRTUALITY_pure_virtual = 2
+};
+
+/* Case sensitivity. */
+enum dwarf_id_case {
+ DW_ID_case_sensitive = 0,
+ DW_ID_up_case = 1,
+ DW_ID_down_case = 2,
+ DW_ID_case_insensitive = 3
+};
+
+/* Calling convention. */
+enum dwarf_calling_convention {
+ DW_CC_normal = 0x1,
+ DW_CC_program = 0x2,
+ DW_CC_nocall = 0x3,
+ DW_CC_GNU_renesas_sh = 0x40
+};
+
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xff
+
+/* Inline attribute. */
+enum dwarf_inline_attribute {
+ DW_INL_not_inlined = 0,
+ DW_INL_inlined = 1,
+ DW_INL_declared_not_inlined = 2,
+ DW_INL_declared_inlined = 3
+};
+
+/* Discriminant lists. */
+enum dwarf_discrim_list {
+ DW_DSC_label = 0,
+ DW_DSC_range = 1
+};
+
+/* Line number opcodes. */
+enum dwarf_line_number_ops {
+ DW_LNS_extended_op = 0,
+ DW_LNS_copy = 1,
+ DW_LNS_advance_pc = 2,
+ DW_LNS_advance_line = 3,
+ DW_LNS_set_file = 4,
+ DW_LNS_set_column = 5,
+ DW_LNS_negate_stmt = 6,
+ DW_LNS_set_basic_block = 7,
+ DW_LNS_const_add_pc = 8,
+ DW_LNS_fixed_advance_pc = 9,
+ /* DWARF 3. */
+ DW_LNS_set_prologue_end = 10,
+ DW_LNS_set_epilogue_begin = 11,
+ DW_LNS_set_isa = 12
+};
+
+/* Line number extended opcodes. */
+enum dwarf_line_number_x_ops {
+ DW_LNE_end_sequence = 1,
+ DW_LNE_set_address = 2,
+ DW_LNE_define_file = 3,
+ /* HP extensions. */
+ DW_LNE_HP_negate_is_UV_update = 0x11,
+ DW_LNE_HP_push_context = 0x12,
+ DW_LNE_HP_pop_context = 0x13,
+ DW_LNE_HP_set_file_line_column = 0x14,
+ DW_LNE_HP_set_routine_name = 0x15,
+ DW_LNE_HP_set_sequence = 0x16,
+ DW_LNE_HP_negate_post_semantics = 0x17,
+ DW_LNE_HP_negate_function_exit = 0x18,
+ DW_LNE_HP_negate_front_end_logical = 0x19,
+ DW_LNE_HP_define_proc = 0x20
+};
+
+#define DW_LNE_lo_user 0x80
+#define DW_LNE_hi_user 0xff
+
+/* Call frame information. */
+enum dwarf_call_frame_info {
+ DW_CFA_advance_loc = 0x40,
+ DW_CFA_offset = 0x80,
+ DW_CFA_restore = 0xc0,
+ DW_CFA_nop = 0x00,
+ DW_CFA_set_loc = 0x01,
+ DW_CFA_advance_loc1 = 0x02,
+ DW_CFA_advance_loc2 = 0x03,
+ DW_CFA_advance_loc4 = 0x04,
+ DW_CFA_offset_extended = 0x05,
+ DW_CFA_restore_extended = 0x06,
+ DW_CFA_undefined = 0x07,
+ DW_CFA_same_value = 0x08,
+ DW_CFA_register = 0x09,
+ DW_CFA_remember_state = 0x0a,
+ DW_CFA_restore_state = 0x0b,
+ DW_CFA_def_cfa = 0x0c,
+ DW_CFA_def_cfa_register = 0x0d,
+ DW_CFA_def_cfa_offset = 0x0e,
+ /* DWARF 3. */
+ DW_CFA_def_cfa_expression = 0x0f,
+ DW_CFA_expression = 0x10,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_def_cfa_sf = 0x12,
+ DW_CFA_def_cfa_offset_sf = 0x13,
+ DW_CFA_val_offset = 0x14,
+ DW_CFA_val_offset_sf = 0x15,
+ DW_CFA_val_expression = 0x16,
+ /* SGI/MIPS specific. */
+ DW_CFA_MIPS_advance_loc8 = 0x1d,
+ /* GNU extensions. */
+ DW_CFA_GNU_window_save = 0x2d,
+ DW_CFA_GNU_args_size = 0x2e,
+ DW_CFA_GNU_negative_offset_extended = 0x2f
+};
+
+#define DW_CIE_ID 0xffffffff
+#define DW_CIE_VERSION 1
+
+#define DW_CFA_extended 0
+#define DW_CFA_lo_user 0x1c
+#define DW_CFA_hi_user 0x3f
+
+#define DW_CHILDREN_no 0x00
+#define DW_CHILDREN_yes 0x01
+
+#define DW_ADDR_none 0
+
+/* Source language names and codes. */
+enum dwarf_source_language {
+ DW_LANG_C89 = 0x0001,
+ DW_LANG_C = 0x0002,
+ DW_LANG_Ada83 = 0x0003,
+ DW_LANG_C_plus_plus = 0x0004,
+ DW_LANG_Cobol74 = 0x0005,
+ DW_LANG_Cobol85 = 0x0006,
+ DW_LANG_Fortran77 = 0x0007,
+ DW_LANG_Fortran90 = 0x0008,
+ DW_LANG_Pascal83 = 0x0009,
+ DW_LANG_Modula2 = 0x000a,
+ /* DWARF 3. */
+ DW_LANG_Java = 0x000b,
+ DW_LANG_C99 = 0x000c,
+ DW_LANG_Ada95 = 0x000d,
+ DW_LANG_Fortran95 = 0x000e,
+ DW_LANG_PLI = 0x000f,
+ DW_LANG_ObjC = 0x0010,
+ DW_LANG_ObjC_plus_plus = 0x0011,
+ DW_LANG_UPC = 0x0012,
+ DW_LANG_D = 0x0013,
+ /* MIPS. */
+ DW_LANG_Mips_Assembler = 0x8001,
+ /* UPC. */
+ DW_LANG_Upc = 0x8765
+};
+
+#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */
+#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */
+
+/* Names and codes for macro information. */
+enum dwarf_macinfo_record_type {
+ DW_MACINFO_define = 1,
+ DW_MACINFO_undef = 2,
+ DW_MACINFO_start_file = 3,
+ DW_MACINFO_end_file = 4,
+ DW_MACINFO_vendor_ext = 255
+};
+
+/* @@@ For use with GNU frame unwind information. */
+
+#define DW_EH_PE_absptr 0x00
+#define DW_EH_PE_omit 0xff
+
+#define DW_EH_PE_uleb128 0x01
+#define DW_EH_PE_udata2 0x02
+#define DW_EH_PE_udata4 0x03
+#define DW_EH_PE_udata8 0x04
+#define DW_EH_PE_sleb128 0x09
+#define DW_EH_PE_sdata2 0x0A
+#define DW_EH_PE_sdata4 0x0B
+#define DW_EH_PE_sdata8 0x0C
+#define DW_EH_PE_signed 0x08
+
+#define DW_EH_PE_pcrel 0x10
+#define DW_EH_PE_textrel 0x20
+#define DW_EH_PE_datarel 0x30
+#define DW_EH_PE_funcrel 0x40
+#define DW_EH_PE_aligned 0x50
+
+#define DW_EH_PE_indirect 0x80
+
+#endif /* _ELF_DWARF2_H */
diff --git a/src/minibfd/elfparser.c b/src/minibfd/elfparser.c
index 2ae1660..dffae2e 100644
--- a/src/minibfd/elfparser.c
+++ b/src/minibfd/elfparser.c
@@ -1,4 +1,8 @@
-/* Sysprof -- Sampling, systemwide CPU profiler
+/* odin
+ * Copyright 2007 Chris Wilson
+ *
+ * Based on:
+ * Sysprof -- Sampling, systemwide CPU profiler
* Copyright 2006, 2007, Soeren Sandmann
*
* This program is free software; you can redistribute it and/or modify
@@ -19,8 +23,14 @@
#include <string.h>
#include <elf.h>
#include <sys/mman.h>
+
#include "binparser.h"
#include "elfparser.h"
+#include "dwarf2.h"
+
+typedef struct _line_info LineInfo;
+typedef struct _line Line;
+typedef struct _unit_info UnitInfo;
struct _elf_sym {
gulong offset;
@@ -36,6 +46,27 @@ typedef struct _section {
guint type;
} Section;
+struct _unit_info {
+ guint offset_size;
+ guint addr_size;
+ const char *compilation_directory;
+ guint64 line_offset;
+};
+
+struct _line_info {
+ gboolean initialised;
+ guint n_lines;
+ Line *lines;
+};
+
+struct _line {
+ const char *file;
+ const char *directory;
+ guint line;
+ guint size;
+ gulong address;
+};
+
struct _elf_parser {
BinParser parser;
@@ -48,6 +79,8 @@ struct _elf_parser {
ElfSym *symbols;
gsize sym_strings;
+ LineInfo line_info;
+
GMappedFile *file;
const Section *text_section;
@@ -72,7 +105,7 @@ get_string_indirect (BinParser *parser,
int field_ident,
gsize str_table)
{
- const char *result = NULL;
+ const char *result;
gsize index;
bin_parser_save (parser); {
@@ -86,6 +119,25 @@ get_string_indirect (BinParser *parser,
return result;
}
+static const char *
+get_string_at_offset (BinParser *parser,
+ const Section *section,
+ guint64 offset)
+{
+ guint64 old_offset;
+ const char *str;
+
+ if (section == NULL)
+ return NULL;
+
+ old_offset = bin_parser_get_offset (parser);
+ bin_parser_set_offset (parser, section->offset + offset);
+ str = bin_parser_get_string (parser);
+ bin_parser_set_offset (parser, old_offset);
+
+ return str;
+}
+
static void
section_init (Section *section,
BinParser *parser,
@@ -161,7 +213,12 @@ elf_parser_new_from_data (const guchar *data, gsize length)
parser->file = NULL;
parser->symbols = NULL;
parser->header = header;
- parser->shn_entry = bin_parser_create_record (&bin_parser, shn_entry);
+
+ parser->line_info.initialised = FALSE;
+ parser->line_info.n_lines = 0;
+ parser->line_info.lines = NULL;
+
+ parser->shn_entry = bin_parser_create_record (&bin_parser, shn_entry);
parser->sym_format = bin_parser_create_record (&bin_parser, sym_format);
@@ -311,6 +368,7 @@ elf_parser_free (ElfParser *parser)
g_mapped_file_free (parser->file);
g_free (parser->symbols);
+ g_free (parser->line_info.lines);
bin_parser_fini (&parser->parser);
@@ -342,6 +400,8 @@ read_table (ElfParser *parser,
int sym_size = bin_record_get_size (parser->sym_format);
int i;
int n_functions;
+ gulong last_addr = 0;
+ gboolean need_sort = FALSE;
parser->n_symbols = sym_table->size / sym_size;
parser->symbols = g_new (ElfSym, parser->n_symbols);
@@ -366,6 +426,9 @@ read_table (ElfParser *parser,
(info >> 4) == STB_LOCAL ||
(info >> 4) == STB_WEAK))
{
+ if (addr < last_addr)
+ need_sort = TRUE;
+ last_addr = addr;
parser->symbols[n_functions].address = addr;
parser->symbols[n_functions].offset = offset;
n_functions++;
@@ -378,7 +441,10 @@ read_table (ElfParser *parser,
parser->n_symbols = n_functions;
parser->symbols = g_renew (ElfSym, parser->symbols, parser->n_symbols);
- qsort (parser->symbols, parser->n_symbols, sizeof (ElfSym), compare_sym);
+ if (need_sort)
+ qsort (parser->symbols,
+ parser->n_symbols, sizeof (ElfSym),
+ compare_sym);
}
static void
@@ -401,8 +467,567 @@ read_symbols (ElfParser *parser)
parser->symbols = g_new (ElfSym, 1);
}
+struct abbrev {
+ guint64 name, form;
+};
+static struct abbrev *
+read_abbrevs (ElfParser *parser, const Section *section, guint64 offset, guint64 target, guint *n_abbrev)
+{
+ guint64 id;
+ guint count;
+
+ g_assert (offset < section->size);
+
+ bin_parser_set_offset (&parser->parser, section->offset + offset);
+
+ id = bin_parser_get_uleb128 (&parser->parser);
+ while (id) {
+ guint64 name, form;
+
+ bin_parser_get_uleb128 (&parser->parser); /* tag */
+ bin_parser_get_uint (&parser->parser, 1); /* has_children */
+
+ count = 0;
+ offset = bin_parser_get_offset (&parser->parser);
+ name = bin_parser_get_uleb128 (&parser->parser);
+ form = bin_parser_get_uleb128 (&parser->parser);
+ while (name) {
+ count++;
+ name = bin_parser_get_uleb128 (&parser->parser);
+ form = bin_parser_get_uleb128 (&parser->parser);
+ }
+
+ if (id == target) {
+ struct abbrev *abbrev;
+
+ if (count == 0)
+ return NULL;
+
+ abbrev = g_new (struct abbrev, count);
+
+ count = 0;
+ bin_parser_set_offset (&parser->parser, offset);
+ name = bin_parser_get_uleb128 (&parser->parser);
+ form = bin_parser_get_uleb128 (&parser->parser);
+ while (name) {
+ abbrev[count].name = name;
+ abbrev[count].form = form;
+ count++;
+
+ name = bin_parser_get_uleb128 (&parser->parser);
+ form = bin_parser_get_uleb128 (&parser->parser);
+ }
+
+ *n_abbrev = count;
+ return abbrev;
+ }
+
+ id = bin_parser_get_uleb128 (&parser->parser);
+ }
+
+ return NULL;
+}
+
+union attribute {
+ guint64 val;
+ const gchar *str;
+};
+static void
+read_attribute (ElfParser *parser,
+ UnitInfo *unit_info,
+ const Section *debug_str,
+ union attribute *attr,
+ unsigned form)
+{
+ guint64 len;
+
+ switch (form){
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr:
+ attr->val = bin_parser_get_uint (&parser->parser, unit_info->addr_size);
+ break;
+
+ case DW_FORM_block2:
+ len = bin_parser_get_uint (&parser->parser, 2);
+ bin_parser_advance (&parser->parser, len);
+ break;
+
+ case DW_FORM_block4:
+ len = bin_parser_get_uint (&parser->parser, 4);
+ bin_parser_advance (&parser->parser, len);
+ break;
+
+ case DW_FORM_data2:
+ attr->val = bin_parser_get_uint (&parser->parser, 2);
+ break;
+
+ case DW_FORM_data4:
+ attr->val = bin_parser_get_uint (&parser->parser, 4);
+ break;
+
+ case DW_FORM_data8:
+ attr->val = bin_parser_get_uint (&parser->parser, 8);
+ break;
+
+ case DW_FORM_string:
+ attr->str = bin_parser_get_string (&parser->parser);
+ break;
+
+ case DW_FORM_strp:
+ len = bin_parser_get_uint (&parser->parser, unit_info->offset_size);
+ attr->str = get_string_at_offset (&parser->parser, debug_str, len);
+ break;
+
+ case DW_FORM_block:
+ len = bin_parser_get_uleb128 (&parser->parser);
+ bin_parser_advance (&parser->parser, len);
+ break;
+
+ case DW_FORM_block1:
+ len = bin_parser_get_uint (&parser->parser, 1);
+ bin_parser_advance (&parser->parser, len);
+ break;
+
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ attr->val = bin_parser_get_uint (&parser->parser, 1);
+ break;
+
+ case DW_FORM_sdata:
+ attr->val = bin_parser_get_sleb128 (&parser->parser);
+ break;
+
+ case DW_FORM_udata:
+ attr->val = bin_parser_get_uleb128 (&parser->parser);
+ break;
+
+ case DW_FORM_ref1:
+ attr->val = bin_parser_get_uint (&parser->parser, 1);
+ break;
+
+ case DW_FORM_ref2:
+ attr->val = bin_parser_get_uint (&parser->parser, 2);
+ break;
+
+ case DW_FORM_ref4:
+ attr->val = bin_parser_get_uint (&parser->parser, 4);
+ break;
+
+ case DW_FORM_ref8:
+ attr->val = bin_parser_get_uint (&parser->parser, 8);
+ break;
+
+ case DW_FORM_ref_udata:
+ attr->val = bin_parser_get_uleb128 (&parser->parser);
+ break;
+
+ case DW_FORM_indirect:
+ form = bin_parser_get_uleb128 (&parser->parser);
+ read_attribute (parser, unit_info, debug_str, attr, form);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+
+static guint64
+elf_parser_get_length (ElfParser *parser, guint *offset_size)
+{
+ guint64 length = bin_parser_get_uint (&parser->parser, 4);
+
+ if (length == 0xffffffff) {
+ length = bin_parser_get_uint (&parser->parser, 8);
+ *offset_size = 8;
+ } else if (length == 0) {
+ g_assert_not_reached ();
+ *offset_size = 8;
+ } else {
+ *offset_size = 4;
+ }
+
+ return length;
+}
+
+static void
+read_unit_info (ElfParser *parser,
+ const Section *debug_abbrev,
+ const Section *debug_str,
+ UnitInfo *unit_info)
+{
+ guint64 offset;
+ guint64 abbrev;
+ struct abbrev *abbrevs;
+ guint n_abbrevs;
+ guint n;
+
+ offset = bin_parser_get_uint (&parser->parser, unit_info->offset_size);
+ unit_info->addr_size = bin_parser_get_uint (&parser->parser, 1);
+ abbrev = bin_parser_get_uleb128 (&parser->parser);
+
+ bin_parser_save (&parser->parser); {
+ /* read the attribute dictionary to find the abbrev for line_offset */
+ abbrevs = read_abbrevs (parser,
+ debug_abbrev,
+ offset,
+ abbrev, &n_abbrevs);
+ if (abbrevs == NULL)
+ return;
+ } bin_parser_restore (&parser->parser);
+
+ unit_info->line_offset = (guint64) -1;
+ unit_info->compilation_directory = NULL;
+
+ for (n = 0; n < n_abbrevs; n++) {
+ union attribute attr;
+ read_attribute (parser, unit_info, debug_str, &attr, abbrevs[n].form);
+ switch (abbrevs[n].name) {
+ case DW_AT_stmt_list:
+ unit_info->line_offset = attr.val;
+ break;
+ case DW_AT_comp_dir:
+ unit_info->compilation_directory = attr.str;
+ break;
+ }
+ }
+ g_free (abbrevs);
+}
+
+static void
+add_line (LineInfo *line_info,
+ const char *file,
+ const char *dir,
+ gulong this,
+ gulong next,
+ guint line)
+{
+ guint n;
+ guint size;
+
+ if (this == next)
+ return;
+
+ size = next - this;
+ if (next < this)
+ size = 1;
+
+ n = line_info->n_lines;
+ if ((n & 1023) == 0) {
+ line_info->lines = g_renew (Line,
+ line_info->lines,
+ line_info->n_lines + 1024);
+ }
+
+ line_info->lines[n].file = file;
+ line_info->lines[n].directory = dir;
+ line_info->lines[n].line = line;
+ line_info->lines[n].address = this;
+ line_info->lines[n].size = size;
+ line_info->n_lines++;
+}
+
+static int
+line_cmp_by_addr (gconstpointer A, gconstpointer B)
+{
+ const Line *a = A, *b = B;
+ if (a->address < b->address)
+ return -1;
+ else if (a->address > b->address)
+ return 1;
+ else
+ return 0;
+}
+
+static void
+fixup_line_sizes (Line *lines, guint n_lines)
+{
+ while (--n_lines) {
+ if (lines[0].address + lines[0].size > lines[1].address)
+ lines[0].size = lines[1].address - lines[0].address;
+ lines++;
+ }
+}
+
+static void
+read_line_info (ElfParser *parser)
+{
+ const Section *debug_info;
+ const Section *debug_abbrev;
+ const Section *debug_str;
+ const Section *debug_line;
+
+ guint64 debug_info_offset;
+ UnitInfo unit_info;
+ guint64 total_length, end;
+ gushort version;
+ guint offset_size;
+ guint opcode_base, max_opcode_base = 0;
+ guchar *opcode_lengths = NULL;
+ guint max_dir_index = 0, dir_index;
+ const gchar **directories = NULL;
+ guint max_file_index = 0, file_index;
+ const gchar **files = NULL;
+ guint *fi2di = NULL;
+ const gchar *str;
+ guint i;
+ gboolean need_sort = FALSE;
+ gint8 min_instruction_length;
+ gint8 default_is_stmt;
+ gint8 line_base;
+ guint8 line_range;
+
+ parser->line_info.initialised = TRUE;
+
+ debug_info = find_section (parser, ".debug_info", SHT_PROGBITS);
+ debug_abbrev = find_section (parser, ".debug_abbrev", SHT_PROGBITS);
+ debug_str = find_section (parser, ".debug_str", SHT_PROGBITS),
+ debug_line = find_section (parser, ".debug_line", SHT_PROGBITS);
+ if (debug_info == NULL ||
+ debug_abbrev == NULL ||
+ debug_str == NULL ||
+ debug_line == NULL)
+ return;
+
+ debug_info_offset = debug_info->offset;
+ while (debug_info_offset < debug_info->offset + debug_info->size) {
+ /* compilation unit */
+ bin_parser_set_offset (&parser->parser, debug_info_offset);
+ total_length = elf_parser_get_length (parser, &unit_info.offset_size);
+ debug_info_offset = bin_parser_get_offset (&parser->parser) +
+ total_length;
+
+ version = bin_parser_get_uint (&parser->parser, 2);
+ g_return_if_fail (version == 2);
+
+ read_unit_info (parser, debug_abbrev, debug_str, &unit_info);
+ if (unit_info.line_offset == (guint64) -1)
+ continue;
+
+ g_return_if_fail (unit_info.line_offset < debug_line->size);
+
+
+ /* line block */
+ bin_parser_set_offset (&parser->parser,
+ debug_line->offset + unit_info.line_offset);
+ total_length = elf_parser_get_length (parser, &offset_size);
+ end = bin_parser_get_offset (&parser->parser) + total_length;
+
+ version = bin_parser_get_uint (&parser->parser, 2);
+ g_return_if_fail (version == 2);
+ bin_parser_get_uint (&parser->parser, offset_size); /* prologue_length */
+
+ min_instruction_length = bin_parser_get_uint (&parser->parser, 1);
+ default_is_stmt = bin_parser_get_uint (&parser->parser, 1);
+
+ line_base = (gint8) bin_parser_get_uint (&parser->parser, 1);
+ line_range = bin_parser_get_uint (&parser->parser, 1);
+
+ opcode_base = bin_parser_get_uint (&parser->parser, 1);
+ if (opcode_base > max_opcode_base) {
+ max_opcode_base = opcode_base;
+ opcode_lengths = g_newa (guchar, opcode_base);
+ opcode_lengths[0] = 1;
+ }
+ for (i = 1; i < opcode_base; i++)
+ opcode_lengths[i] = bin_parser_get_uint (&parser->parser, 1);
+
+ /* read directory table */
+ bin_parser_save (&parser->parser); {
+ i = 1;
+ while (*bin_parser_get_string (&parser->parser) != '\0')
+ i++;
+ } bin_parser_restore (&parser->parser);
+ if (i > max_dir_index) {
+ max_dir_index = i;
+ directories = g_newa (const gchar *, max_dir_index);
+ }
+ i = 1;
+ directories[0] = unit_info.compilation_directory;
+ while (*(str = bin_parser_get_string (&parser->parser)) != '\0')
+ directories[i++] = str;
+ dir_index = i;
+
+ /* read file table */
+ bin_parser_save (&parser->parser); {
+ i = 1;
+ while (*bin_parser_get_string (&parser->parser) != '\0') {
+ /* dir */ bin_parser_get_uleb128 (&parser->parser);
+ /* size */ bin_parser_get_uleb128 (&parser->parser);
+ /* time */ bin_parser_get_uleb128 (&parser->parser);
+ i++;
+ }
+ } bin_parser_restore (&parser->parser);
+ if (i > max_file_index) {
+ max_file_index = i;
+ files = g_newa (const gchar *, max_file_index);
+ files[0] = NULL;
+ fi2di = g_newa (guint, max_file_index);
+ fi2di[0] = 0;
+ }
+ i = 1;
+ while (*(str = bin_parser_get_string (&parser->parser)) != '\0') {
+ fi2di[i] = bin_parser_get_uleb128 (&parser->parser);
+ /* size */ bin_parser_get_uleb128 (&parser->parser);
+ /* time */ bin_parser_get_uleb128 (&parser->parser);
+ files[i] = str;
+ i++;
+ }
+ file_index = i;
+
+ while (bin_parser_get_offset (&parser->parser) < end) {
+ gboolean end_sequence = FALSE;
+ guint opcode, extended_op;
+ gulong address = 0, last_address = 0;
+ guint line = 1, last_line = 1;
+ gint file = 1, last_file = 1;
+ int is_stmt = default_is_stmt;
+
+ while (! end_sequence) {
+ opcode = bin_parser_get_uint (&parser->parser, 1);
+ if (opcode >= opcode_base) { /* special operand */
+ opcode -= opcode_base;
+ address += (opcode / line_range) * min_instruction_length;
+ line += (opcode % line_range) + line_base;
+
+ if (is_stmt) {
+ if (last_address) {
+ add_line (&parser->line_info,
+ files[last_file],
+ directories[fi2di[last_file]],
+ last_address, address, last_line);
+ need_sort |= last_address > address;
+ }
+ last_address = address;
+ last_file = file;
+ last_line = line;
+ }
+ } else switch (opcode) {
+ case DW_LNS_extended_op:
+ bin_parser_get_uleb128 (&parser->parser); /* len */
+ extended_op = bin_parser_get_uint (&parser->parser, 1);
+ switch (extended_op) {
+ case DW_LNE_end_sequence:
+ if (is_stmt) {
+ add_line (&parser->line_info,
+ files[last_file],
+ directories[fi2di[last_file]],
+ last_address, address, last_line);
+ need_sort |= last_address > address;
+ }
+ end_sequence = TRUE;
+ break;
+ case DW_LNE_set_address:
+ address = bin_parser_get_uint (&parser->parser,
+ unit_info.addr_size);
+ break;
+ case DW_LNE_define_file:
+ if (file_index >= max_file_index) {
+ const gchar **new_files;
+ guint *new_fi2di;
+
+ max_file_index = file_index + 4;
+
+ new_files = g_newa (const gchar *, max_file_index);
+ memcpy (new_files, files,
+ sizeof (const gchar *) * file_index);
+ new_fi2di = g_newa (guint, max_file_index);
+ memcpy (new_fi2di, fi2di,
+ sizeof (guint) * file_index);
+
+ files = new_files;
+ fi2di = new_fi2di;
+ }
+ files[file_index] = bin_parser_get_string (&parser->parser);
+ fi2di[file_index] = bin_parser_get_uleb128 (&parser->parser);
+ /* size */ bin_parser_get_uleb128 (&parser->parser);
+ /* time */ bin_parser_get_uleb128 (&parser->parser);
+ file_index++;
+ break;
+
+ default:
+ g_return_if_reached ();
+ break;
+ }
+ break;
+
+ case DW_LNS_copy:
+ if (is_stmt) {
+ if (last_address) {
+ add_line (&parser->line_info,
+ files[last_file],
+ directories[fi2di[last_file]],
+ last_address, address, last_line);
+ need_sort |= last_address > address;
+ }
+ last_address = address;
+ last_file = file;
+ last_line = line;
+ }
+ break;
+
+ case DW_LNS_advance_pc:
+ address += min_instruction_length *
+ bin_parser_get_uleb128 (&parser->parser);
+ break;
+
+ case DW_LNS_advance_line:
+ line += bin_parser_get_sleb128 (&parser->parser);
+ break;
+
+ case DW_LNS_set_file:
+ file = bin_parser_get_uleb128 (&parser->parser);
+ break;
+
+ case DW_LNS_set_column:
+ bin_parser_get_uleb128 (&parser->parser);
+ break;
+
+ case DW_LNS_negate_stmt:
+ is_stmt = ! is_stmt;
+ break;
+
+ case DW_LNS_set_basic_block:
+ break;
+
+ case DW_LNS_const_add_pc:
+ address += (255 - opcode_base) / line_range *
+ min_instruction_length;
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ address += bin_parser_get_uint (&parser->parser, 2);
+ break;
+
+ case DW_LNS_set_prologue_end:
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ break;
+
+ case DW_LNS_set_isa:
+ bin_parser_get_uleb128 (&parser->parser);
+ break;
+
+ default:
+ for (i = 0; i < opcode_lengths[opcode]; i++)
+ bin_parser_get_uleb128 (&parser->parser);
+ break;
+ }
+ }
+ }
+ }
+
+ if (need_sort)
+ qsort (parser->line_info.lines,
+ parser->line_info.n_lines, sizeof (Line),
+ line_cmp_by_addr);
+ fixup_line_sizes (parser->line_info.lines, parser->line_info.n_lines);
+}
+
+
static ElfSym *
-do_lookup (ElfSym *symbols, gulong address, int first, int last)
+do_sym_lookup (ElfSym *symbols, gulong address, int first, int last)
{
do {
if (address >= symbols[last].address) {
@@ -426,35 +1051,83 @@ do_lookup (ElfSym *symbols, gulong address, int first, int last)
} while (TRUE);
}
+static Line *
+do_line_lookup (Line *lines, gulong address, int first, int last)
+{
+ gulong a_mid_lo, a_mid_hi;
+ guint mid;
+ do {
+ mid = (first + last) / 2;
+ a_mid_lo = lines[mid].address;
+ a_mid_hi = lines[mid].address + lines[mid].size - 1;
+
+ if (address < a_mid_lo)
+ last = mid - 1;
+ else if (address > a_mid_hi)
+ first = mid + 1;
+ else
+ return &lines[mid];
+ } while (first <= last);
+
+ return NULL;
+}
+
/* Address should be given in 'offset into text segment' */
-const ElfSym *
-elf_parser_lookup_symbol (ElfParser *parser, gulong address)
+gboolean
+elf_parser_lookup_symbol (ElfParser *parser, gulong address,
+ const char **function,
+ const char **file,
+ const char **directory,
+ guint *lineno)
{
- const ElfSym *result;
+ const ElfSym *sym;
+ gboolean ret = FALSE;
+
+ if (!parser->text_section)
+ return FALSE;
if (parser->symbols == NULL)
read_symbols (parser);
-
if (parser->n_symbols == 0)
- return NULL;
+ return FALSE;
- if (!parser->text_section)
- return NULL;
+ if (parser->line_info.initialised == 0)
+ read_line_info (parser);
address += parser->text_section->load_address;
- result = do_lookup (parser->symbols, address, 0, parser->n_symbols - 1);
- if (result) {
+ sym = do_sym_lookup (parser->symbols, address, 0, parser->n_symbols - 1);
+ if (sym != NULL) {
gulong size;
- bin_parser_set_offset (&parser->parser, result->offset);
+ bin_parser_set_offset (&parser->parser, sym->offset);
size = bin_parser_get_uint_field (
&parser->parser, parser->sym_format, st_size);
- if (size > 0 && result->address + size <= address)
- result = NULL;
+ if (size > 0 && sym->address + size <= address)
+ sym = NULL;
+
}
- return result;
+ if (sym != NULL) {
+ bin_parser_set_offset (&parser->parser, sym->offset);
+ *function = get_string_indirect (&parser->parser, parser->sym_format,
+ st_name, parser->sym_strings);
+
+ if (parser->line_info.n_lines) {
+ const Line *line;
+ line = do_line_lookup (parser->line_info.lines, address,
+ 0, parser->line_info.n_lines);
+ if (line != NULL) {
+ *file = line->file;
+ *directory = line->directory;
+ *lineno = line->line;
+ }
+ }
+
+ ret = TRUE;
+ }
+
+ return ret;
}
gulong
@@ -502,26 +1175,6 @@ elf_parser_get_eh_frame (ElfParser *parser)
return bin_parser_get_data (&parser->parser) + eh_frame->offset;
}
-const char *
-elf_parser_get_sym_name (ElfParser *parser, const ElfSym *sym)
-{
- const char *result;
-
- g_return_val_if_fail (parser != NULL, NULL);
-
- bin_parser_set_offset (&parser->parser, sym->offset);
- result = get_string_indirect (&parser->parser, parser->sym_format,
- st_name, parser->sym_strings);
-
- return result;
-}
-
-gulong
-elf_parser_get_sym_address (ElfParser *parser, const ElfSym *sym)
-{
- return sym->address;
-}
-
/*
* Utility functions
*/
diff --git a/src/minibfd/elfparser.h b/src/minibfd/elfparser.h
index 56a99ce..1ccc0f4 100644
--- a/src/minibfd/elfparser.h
+++ b/src/minibfd/elfparser.h
@@ -49,12 +49,12 @@ gulong elf_parser_get_text_offset (ElfParser *parser);
* of the file would have been mapped, so a - (m - o) is the position
* in the file of a.
*/
-const ElfSym *elf_parser_lookup_symbol (ElfParser *parser,
- gulong address);
-const char *elf_parser_get_sym_name (ElfParser *parser,
- const ElfSym *sym);
-gulong elf_parser_get_sym_address (ElfParser *parser,
- const ElfSym *sym);
+gboolean
+elf_parser_lookup_symbol (ElfParser *parser, gulong address,
+ const char **function,
+ const char **file,
+ const char **directory,
+ guint *lineno);
G_END_DECLS