[RFA] Location list support.

Michal Ludvig
2003-02-01T07:50:15Z

[-- Attachment #1: Type: text/plain, Size: 786 bytes --]

Hi all,
this is a first part of my attempt to enable use of dwarf3 .debug_loc
sections (as generated by GCC's rtlopt-branch) for variable tracking.
With this patch GDB at least doesn't segfault as it did when trying to
debug a binary with .debug_loc section.
It can already read and parse .debug_loc and then use the appropriate
first block found for a given DIE for obtaining the SYMBOL_VALUE() in
newsymbol(). So now it behaves exactly like it did with GCCs that didn't
emit .debug_loc.
I hope to have a full support (ie. SYMBOL_VALUE that depends on PC)
available soon.
This was developped in gdb-5.3 but should be usable with mainline with
no problems.

Comments? Approvals?

Michal Ludvig
--
* SuSE CR, s.r.o * mludvig@suse.cz
* (+420) 296.545.373 * http://www.suse.cz

[-- Attachment #2: loclist-1.diff --]
[-- Type: text/plain, Size: 11627 bytes --]

2003-02-01 Michal Ludvig <mludvig@suse.cz>

* dwarf2read.c (struct loclist_block)
(struct loclist_master): New structures.
(loclist_base, dwarf_loc_buffer): New variables.
(struct dwarf2_pinfo): New items dwarf_loc_buffer and
dwarf_loc_size.
(DWARF_LOC_BUFFER, DWARF_LOC_SIZE): New macros.
(dwarf2_read_loclist, dwarf2_read_loclist_blocks)
(dwarf_alloc_loclist_block, dwarf_alloc_loclist_master)
(dwarf2_loclist_lookup_block): New functions.
(psymtab_to_symtab_1): Call dwarf2_read_loclist().
(new_symbol): Handle .debug_loc references.

Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.66.2.2
diff -u -p -r1.66.2.2 dwarf2read.c
--- dwarf2read.c 25 Nov 2002 21:46:54 -0000 1.66.2.2
+++ dwarf2read.c 31 Jan 2003 18:10:53 -0000
@@ -312,6 +312,22 @@ struct dwarf_block
char *data;
};

+struct loclist_block
+ {
+ CORE_ADDR lowpc, highpc; /* Range where attribute is valid. */
+ struct dwarf_block blk;
+ struct loclist_block *next;
+ };
+
+struct loclist_master
+ {
+ unsigned int offset; /* Offset of this block in .debug_loc. */
+ struct loclist_block *blocks;
+ struct loclist_master *next;
+ };
+
+static struct loclist_master *loclist_base;
+
/* We only hold one compilation unit's abbrevs in
memory at any one time. */
#ifndef ABBREV_HASH_SIZE
@@ -352,6 +368,7 @@ static char *dwarf_abbrev_buffer;
static char *dwarf_line_buffer;
static char *dwarf_str_buffer;
static char *dwarf_macinfo_buffer;
+static char *dwarf_loc_buffer;

/* A zeroed version of a partial die for initialization purposes. */
static struct partial_die_info zeroed_partial_die;
@@ -454,6 +471,13 @@ struct dwarf2_pinfo

unsigned int dwarf_macinfo_size;

+ /* Pointer to start of dwarf location list buffer for the objfile. */
+
+ char *dwarf_loc_buffer;
+
+ /* Size of dwarf location list section for the objfile. */
+
+ unsigned int dwarf_loc_size;
};

#define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
@@ -467,6 +491,8 @@ struct dwarf2_pinfo
#define DWARF_STR_SIZE(p) (PST_PRIVATE(p)->dwarf_str_size)
#define DWARF_MACINFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_macinfo_buffer)
#define DWARF_MACINFO_SIZE(p) (PST_PRIVATE(p)->dwarf_macinfo_size)
+#define DWARF_LOC_BUFFER(p) (PST_PRIVATE(p)->dwarf_loc_buffer)
+#define DWARF_LOC_SIZE(p) (PST_PRIVATE(p)->dwarf_loc_size)

/* Maintain an array of referenced fundamental types for the current
compilation unit being read. For DWARF version 1, we have to construct
@@ -688,6 +714,8 @@ char *dwarf2_read_section (struct objfil

static void dwarf2_read_abbrevs (bfd *, unsigned int);

+static void dwarf2_read_loclist (bfd *abfd, struct comp_unit_head *cu_header);
+
static void dwarf2_empty_abbrev_table (PTR);

static struct abbrev_info *dwarf2_lookup_abbrev (unsigned int);
@@ -874,12 +902,6 @@ static char *dwarf_bool_name (unsigned i

static char *dwarf_type_encoding_name (unsigned int);

-#if 0
-static char *dwarf_cfi_name (unsigned int);
-
-struct die_info *copy_die (struct die_info *);
-#endif
-
static struct die_info *sibling_die (struct die_info *);

static void dump_die (struct die_info *);
@@ -906,6 +928,9 @@ static struct abbrev_info *dwarf_alloc_a

static struct die_info *dwarf_alloc_die (void);

+static struct loclist_block *dwarf_alloc_loclist_block (void);
+static struct loclist_master *dwarf_alloc_loclist_master (void);
+
static void initialize_cu_func_list (void);

static void add_to_cu_func_list (const char *, CORE_ADDR, CORE_ADDR);
@@ -927,6 +952,7 @@ dwarf2_has_info (bfd *abfd)
dwarf_line_offset = 0;
dwarf_str_offset = 0;
dwarf_macinfo_offset = 0;
+ dwarf_loc_offset = 0;
dwarf_frame_offset = 0;
dwarf_eh_frame_offset = 0;
bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
@@ -1035,6 +1061,13 @@ dwarf2_build_psymtabs (struct objfile *o
else
dwarf_macinfo_buffer = NULL;

+ if (dwarf_loc_offset)
+ dwarf_loc_buffer = dwarf2_read_section (objfile,
+ dwarf_loc_offset,
+ dwarf_loc_size);
+ else
+ dwarf_loc_buffer = NULL;
+
if (mainline
|| (objfile->global_psymbols.size == 0
&& objfile->static_psymbols.size == 0))
@@ -1245,6 +1280,8 @@ dwarf2_build_psymtabs_hard (struct objfi
DWARF_STR_SIZE (pst) = dwarf_str_size;
DWARF_MACINFO_BUFFER (pst) = dwarf_macinfo_buffer;
DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
+ DWARF_LOC_BUFFER (pst) = dwarf_loc_buffer;
+ DWARF_LOC_SIZE (pst) = dwarf_loc_size;
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));

/* Store the function that reads in the rest of the symbol table */
@@ -1581,6 +1618,8 @@ psymtab_to_symtab_1 (struct partial_symt
dwarf_str_size = DWARF_STR_SIZE (pst);
dwarf_macinfo_buffer = DWARF_MACINFO_BUFFER (pst);
dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
+ dwarf_loc_buffer = DWARF_LOC_BUFFER (pst);
+ dwarf_loc_size = DWARF_LOC_SIZE (pst);
baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
cu_header_offset = offset;
info_ptr = dwarf_info_buffer + offset;
@@ -1598,6 +1637,7 @@ psymtab_to_symtab_1 (struct partial_symt
dwarf2_read_abbrevs (abfd, cu_header.abbrev_offset);
make_cleanup (dwarf2_empty_abbrev_table, NULL);

+ dwarf2_read_loclist (abfd, &cu_header);
dies = read_comp_unit (info_ptr, abfd, &cu_header);

make_cleanup_free_die_list (dies);
@@ -3408,6 +3448,115 @@ dwarf2_read_section (struct objfile *obj
return buf;
}

+static struct loclist_block *
+dwarf2_loclist_lookup_block (unsigned int offset)
+{
+ /* .debug_loc goes here ... mludvig */
+ struct dwarf_block *blkp;
+ struct loclist_master *ll_ptr;
+
+ ll_ptr = loclist_base;
+
+ while (ll_ptr && ll_ptr->offset != offset)
+ ll_ptr = ll_ptr->next;
+
+ if(!ll_ptr)
+ {
+ warning ("Couldn't find appropriate location list for offset %u\n",
+ offset);
+ return NULL;
+ }
+
+ if (ll_ptr && !ll_ptr->blocks)
+ {
+ warning ("Loclist for off=%u doesn't have any blocks?\n", offset);
+ return NULL;
+ }
+
+ return ll_ptr->blocks;
+}
+
+static struct loclist_block *
+dwarf2_read_loclist_blocks (bfd *abfd, char **base, char *end,
+ unsigned int addr_size)
+{
+ char *ptr;
+ CORE_ADDR lopc, hipc;
+ unsigned int data_size;
+ char *data_ptr;
+ struct loclist_block *llb_first = NULL, *llb_last = NULL;
+
+ ptr = *base;
+
+ while (ptr < end) {
+ if (addr_size == 4) {
+ lopc = read_4_bytes (abfd, ptr);
+ ptr += 4;
+ hipc = read_4_bytes (abfd, ptr);
+ ptr += 4;
+ }
+ else if (addr_size == 8) {
+ lopc = read_8_bytes (abfd, ptr);
+ ptr += 8;
+ hipc = read_8_bytes (abfd, ptr);
+ ptr += 8;
+ }
+ else
+ error ("Address size == %d ... unsupported!", addr_size);
+
+ if (lopc == 0 && hipc == 0)
+ break;
+
+ if (lopc == 0 && llb_last != NULL)
+ {
+ ptr -= 8;
+ break;
+ }
+
+ if (llb_last == NULL) {
+ llb_last = dwarf_alloc_loclist_block ();
+ llb_first = llb_last;
+ }
+ else {
+ llb_last->next = dwarf_alloc_loclist_block ();
+ llb_last = llb_last->next;
+ }
+
+ llb_last->lowpc = lopc;
+ llb_last->highpc = hipc;
+
+ llb_last->blk.size = read_2_bytes (abfd, ptr);
+ ptr += 2;
+ llb_last->blk.data = ptr;
+ ptr += llb_last->blk.size;
+ }
+
+ *base = ptr;
+ return llb_first;
+}
+
+static void
+dwarf2_read_loclist (bfd *abfd, struct comp_unit_head *cu_header)
+{
+ char *loclist_ptr, *loclist_end;
+ struct loclist_master *ll_master;
+
+ loclist_ptr = dwarf_loc_buffer;
+ loclist_end = dwarf_loc_buffer + dwarf_loc_size;
+
+ while (loclist_ptr < loclist_end)
+ {
+ ll_master = dwarf_alloc_loclist_master();
+ ll_master->next = loclist_base;
+ loclist_base = ll_master;
+
+ ll_master->offset = loclist_ptr - dwarf_loc_buffer;
+ ll_master->blocks = dwarf2_read_loclist_blocks
+ (abfd, &loclist_ptr, loclist_end,
+ cu_header->addr_size);
+ }
+}
+
/* In DWARF version 2, the description of the debugging information is
stored in a separate .debug_abbrev section. Before we read any
dies from a section we read in all abbreviations and install them
@@ -4785,7 +4942,16 @@ new_symbol (struct die_info *die, struct
else if (attr->form == DW_FORM_data4
|| attr->form == DW_FORM_data8)
{
- complain (&dwarf2_complex_location_expr);
+ struct dwarf_block *blkp = NULL;
+ struct loclist_block *llbp;
+
+ llbp = dwarf2_loclist_lookup_block (
+ (unsigned int)DW_ADDR (attr));
+ if (llbp)
+ blkp = &llbp->blk;
+ if (blkp)
+ SYMBOL_VALUE_ADDRESS (sym) =
+ decode_locdesc (blkp, objfile, cu_header);
}
else
{
@@ -4823,7 +4989,16 @@ new_symbol (struct die_info *die, struct
else if (attr->form == DW_FORM_data4
|| attr->form == DW_FORM_data8)
{
- complain (&dwarf2_complex_location_expr);
+ struct dwarf_block *blkp = NULL;
+ struct loclist_block *llbp;
+
+ llbp = dwarf2_loclist_lookup_block (
+ (unsigned int)DW_ADDR (attr));
+ if (llbp)
+ blkp = &llbp->blk;
+ if (blkp)
+ SYMBOL_VALUE_ADDRESS (sym) = addr =
+ decode_locdesc (blkp, objfile, cu_header);
}
else
{
@@ -4882,8 +5057,31 @@ new_symbol (struct die_info *die, struct
attr = dwarf_attr (die, DW_AT_location);
if (attr)
{
- SYMBOL_VALUE (sym) =
- decode_locdesc (DW_BLOCK (attr), objfile, cu_header);
+ if (attr_form_is_block (attr))
+ {
+ SYMBOL_VALUE (sym) =
+ decode_locdesc (DW_BLOCK (attr), objfile, cu_header);
+ }
+ else if (attr->form == DW_FORM_data4
+ || attr->form == DW_FORM_data8)
+ {
+ struct dwarf_block *blkp = NULL;
+ struct loclist_block *llbp;
+
+ llbp = dwarf2_loclist_lookup_block (
+ (unsigned int)DW_ADDR (attr));
+ if (llbp)
+ blkp = &llbp->blk;
+ if (blkp)
+ SYMBOL_VALUE_ADDRESS (sym) =
+ decode_locdesc (blkp, objfile, cu_header);
+ }
+ else
+ {
+ complain (&dwarf2_invalid_attrib_class, "DW_AT_location",
+ "external variable");
+ addr = 0;
+ }
if (isreg)
{
SYMBOL_CLASS (sym) = LOC_REGPARM;
@@ -6660,6 +6863,26 @@ dwarf_alloc_die (void)
die = (struct die_info *) xmalloc (sizeof (struct die_info));
memset (die, 0, sizeof (struct die_info));
return (die);
+}
+
+static struct loclist_block *
+dwarf_alloc_loclist_block (void)
+{
+ struct loclist_block *llb;
+
+ llb = (struct loclist_block *) xmalloc (sizeof (struct loclist_block));
+ memset (llb, 0, sizeof (struct loclist_block));
+ return (llb);
+}
+
+static struct loclist_master *
+dwarf_alloc_loclist_master (void)
+{
+ struct loclist_master *llm;
+
+ llm = (struct loclist_master *) xmalloc (sizeof (struct loclist_master));
+ memset (llm, 0, sizeof (struct loclist_master));
+ return (llm);
}

\f