bfd: Add Support for DW_FORM_strx* and DW_FORM_addrx*

This commit is contained in:
Potharla, Rupesh
2022-05-24 00:01:49 +00:00
committed by Alan Modra
parent 9e2bb0cb5e
commit f67741e172

View File

@ -189,6 +189,18 @@ struct dwarf2_debug_file
/* Length of the loaded .debug_str section. */
bfd_size_type dwarf_str_size;
/* Pointer to the .debug_str_offsets section loaded into memory. */
bfd_byte *dwarf_str_offsets_buffer;
/* Length of the loaded .debug_str_offsets section. */
bfd_size_type dwarf_str_offsets_size;
/* Pointer to the .debug_addr section loaded into memory. */
bfd_byte *dwarf_addr_buffer;
/* Length of the loaded .debug_addr section. */
bfd_size_type dwarf_addr_size;
/* Pointer to the .debug_line_str section loaded into memory. */
bfd_byte *dwarf_line_str_buffer;
@ -382,6 +394,12 @@ struct comp_unit
/* Used when iterating over trie leaves to know which units we have
already seen in this iteration. */
bool mark;
/* Base address of debug_addr section. */
size_t dwarf_addr_offset;
/* Base address of string offset table. */
size_t dwarf_str_offset;
};
/* This data structure holds the information of an abbrev. */
@ -424,6 +442,8 @@ const struct dwarf_debug_section dwarf_debug_sections[] =
{ ".debug_static_vars", ".zdebug_static_vars" },
{ ".debug_str", ".zdebug_str", },
{ ".debug_str", ".zdebug_str", },
{ ".debug_str_offsets", ".zdebug_str_offsets", },
{ ".debug_addr", ".zdebug_addr", },
{ ".debug_line_str", ".zdebug_line_str", },
{ ".debug_types", ".zdebug_types" },
/* GNU DWARF 1 extensions */
@ -458,6 +478,8 @@ enum dwarf_debug_section_enum
debug_static_vars,
debug_str,
debug_str_alt,
debug_str_offsets,
debug_addr,
debug_line_str,
debug_types,
debug_sfnames,
@ -1307,12 +1329,92 @@ is_int_form (const struct attribute *attr)
}
}
static const char *
read_indexed_string (bfd_uint64_t idx ATTRIBUTE_UNUSED,
struct comp_unit * unit ATTRIBUTE_UNUSED)
/* Returns true if the form is strx[1-4]. */
static inline bool
is_strx_form (enum dwarf_form form)
{
/* FIXME: Add support for indexed strings. */
return "<indexed strings not yet supported>";
return (form == DW_FORM_strx
|| form == DW_FORM_strx1
|| form == DW_FORM_strx2
|| form == DW_FORM_strx3
|| form == DW_FORM_strx4);
}
/* Return true if the form is addrx[1-4]. */
static inline bool
is_addrx_form (enum dwarf_form form)
{
return (form == DW_FORM_addrx
|| form == DW_FORM_addrx1
|| form == DW_FORM_addrx2
|| form == DW_FORM_addrx3
|| form == DW_FORM_addrx4);
}
/* Returns the address in .debug_addr section using DW_AT_addr_base.
Used to implement DW_FORM_addrx*. */
static bfd_vma
read_indexed_address (bfd_uint64_t idx,
struct comp_unit *unit)
{
struct dwarf2_debug *stash = unit->stash;
struct dwarf2_debug_file *file = unit->file;
size_t addr_base = unit->dwarf_addr_offset;
bfd_byte *info_ptr;
if (stash == NULL)
return 0;
if (!read_section (unit->abfd, &stash->debug_sections[debug_addr],
file->syms, 0,
&file->dwarf_addr_buffer, &file->dwarf_addr_size))
return 0;
info_ptr = file->dwarf_addr_buffer + addr_base + idx * unit->offset_size;
if (unit->offset_size == 4)
return bfd_get_32 (unit->abfd, info_ptr);
else
return bfd_get_64 (unit->abfd, info_ptr);
}
/* Returns the string using DW_AT_str_offsets_base.
Used to implement DW_FORM_strx*. */
static const char *
read_indexed_string (bfd_uint64_t idx,
struct comp_unit *unit)
{
struct dwarf2_debug *stash = unit->stash;
struct dwarf2_debug_file *file = unit->file;
bfd_byte *info_ptr;
unsigned long str_offset;
if (stash == NULL)
return NULL;
if (!read_section (unit->abfd, &stash->debug_sections[debug_str],
file->syms, 0,
&file->dwarf_str_buffer, &file->dwarf_str_size))
return NULL;
if (!read_section (unit->abfd, &stash->debug_sections[debug_str_offsets],
file->syms, 0,
&file->dwarf_str_offsets_buffer,
&file->dwarf_str_offsets_size))
return NULL;
info_ptr = (file->dwarf_str_offsets_buffer
+ unit->dwarf_str_offset
+ idx * unit->offset_size);
if (unit->offset_size == 4)
str_offset = bfd_get_32 (unit->abfd, info_ptr);
else
str_offset = bfd_get_64 (unit->abfd, info_ptr);
return (const char *) file->dwarf_str_buffer + str_offset;
}
/* Read and fill in the value of attribute ATTR as described by FORM.
@ -1381,21 +1483,37 @@ read_attribute_value (struct attribute * attr,
case DW_FORM_ref1:
case DW_FORM_flag:
case DW_FORM_data1:
case DW_FORM_addrx1:
attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end);
break;
case DW_FORM_addrx1:
attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end);
/* dwarf_addr_offset value 0 indicates the attribute DW_AT_addr_base
is not yet read. */
if (unit->dwarf_addr_offset != 0)
attr->u.val = read_indexed_address (attr->u.val, unit);
break;
case DW_FORM_data2:
case DW_FORM_addrx2:
case DW_FORM_ref2:
attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
break;
case DW_FORM_addrx2:
attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
if (unit->dwarf_addr_offset != 0)
attr->u.val = read_indexed_address (attr->u.val, unit);
break;
case DW_FORM_addrx3:
attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end);
if (unit->dwarf_addr_offset != 0)
attr->u.val = read_indexed_address(attr->u.val, unit);
break;
case DW_FORM_ref4:
case DW_FORM_data4:
attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
break;
case DW_FORM_addrx4:
attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
if (unit->dwarf_addr_offset != 0)
attr->u.val = read_indexed_address (attr->u.val, unit);
break;
case DW_FORM_data8:
case DW_FORM_ref8:
@ -1416,24 +1534,31 @@ read_attribute_value (struct attribute * attr,
break;
case DW_FORM_strx1:
attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end);
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
/* dwarf_str_offset value 0 indicates the attribute DW_AT_str_offsets_base
is not yet read. */
if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
break;
case DW_FORM_strx2:
attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
break;
case DW_FORM_strx3:
attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end);
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
break;
case DW_FORM_strx4:
attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
break;
case DW_FORM_strx:
attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
false, info_ptr_end);
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
if (unit->dwarf_str_offset != 0)
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
break;
case DW_FORM_exprloc:
case DW_FORM_block:
@ -1455,9 +1580,14 @@ read_attribute_value (struct attribute * attr,
break;
case DW_FORM_ref_udata:
case DW_FORM_udata:
attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
false, info_ptr_end);
break;
case DW_FORM_addrx:
attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
false, info_ptr_end);
if (unit->dwarf_addr_offset != 0)
attr->u.val = read_indexed_address (attr->u.val, unit);
break;
case DW_FORM_indirect:
form = _bfd_safe_read_leb128 (abfd, &info_ptr,
@ -2396,6 +2526,11 @@ read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp,
{
case DW_FORM_string:
case DW_FORM_line_strp:
case DW_FORM_strx:
case DW_FORM_strx1:
case DW_FORM_strx2:
case DW_FORM_strx3:
case DW_FORM_strx4:
*stringp = attr.u.str;
break;
@ -4031,6 +4166,80 @@ scan_unit_for_symbols (struct comp_unit *unit)
return false;
}
/* Read the attributes of the form strx and addrx. */
static void
reread_attribute (struct comp_unit *unit,
struct attribute *attr,
bfd_vma *low_pc,
bfd_vma *high_pc,
bool *high_pc_relative,
bool compunit)
{
if (is_strx_form (attr->form))
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
if (is_addrx_form (attr->form))
attr->u.val = read_indexed_address (attr->u.val, unit);
switch (attr->name)
{
case DW_AT_stmt_list:
unit->stmtlist = 1;
unit->line_offset = attr->u.val;
break;
case DW_AT_name:
if (is_str_form (attr))
unit->name = attr->u.str;
break;
case DW_AT_low_pc:
*low_pc = attr->u.val;
if (compunit)
unit->base_address = *low_pc;
break;
case DW_AT_high_pc:
*high_pc = attr->u.val;
*high_pc_relative = attr->form != DW_FORM_addr;
break;
case DW_AT_ranges:
if (!read_rangelist (unit, &unit->arange,
&unit->file->trie_root, attr->u.val))
return;
break;
case DW_AT_comp_dir:
{
char *comp_dir = attr->u.str;
if (!is_str_form (attr))
{
_bfd_error_handler
(_("DWARF error: DW_AT_comp_dir attribute encountered "
"with a non-string form"));
comp_dir = NULL;
}
if (comp_dir)
{
char *cp = strchr (comp_dir, ':');
if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/')
comp_dir = cp + 1;
}
unit->comp_dir = comp_dir;
break;
}
case DW_AT_language:
unit->lang = attr->u.val;
default:
break;
}
}
/* Parse a DWARF2 compilation unit starting at INFO_PTR. UNIT_LENGTH
includes the compilation unit header that proceeds the DIE's, but
does not include the length field that precedes each compilation
@ -4064,6 +4273,10 @@ parse_comp_unit (struct dwarf2_debug *stash,
bfd *abfd = file->bfd_ptr;
bool high_pc_relative = false;
enum dwarf_unit_type unit_type;
struct attribute *str_addrp = NULL;
size_t str_count = 0;
size_t str_alloc = 0;
bool compunit_flag = false;
version = read_2_bytes (abfd, &info_ptr, end_ptr);
if (version < 2 || version > 5)
@ -4168,11 +4381,33 @@ parse_comp_unit (struct dwarf2_debug *stash,
unit->file = file;
unit->info_ptr_unit = info_ptr_unit;
if (abbrev->tag == DW_TAG_compile_unit)
compunit_flag = true;
for (i = 0; i < abbrev->num_attrs; ++i)
{
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, end_ptr);
if (info_ptr == NULL)
return NULL;
goto err_exit;
/* Identify attributes of the form strx* and addrx* which come before
DW_AT_str_offsets_base and DW_AT_addr_base respectively in the CU.
Store the attributes in an array and process them later. */
if ((unit->dwarf_str_offset == 0 && is_strx_form (attr.form))
|| (unit->dwarf_addr_offset == 0 && is_addrx_form (attr.form)))
{
if (str_count <= str_alloc)
{
str_alloc = 2 * str_alloc + 200;
str_addrp = bfd_realloc (str_addrp,
str_alloc * sizeof (*str_addrp));
if (str_addrp == NULL)
goto err_exit;
}
str_addrp[str_count] = attr;
str_count++;
continue;
}
/* Store the data if it is of an attribute we want to keep in a
partial symbol table. */
@ -4198,7 +4433,7 @@ parse_comp_unit (struct dwarf2_debug *stash,
/* If the compilation unit DIE has a DW_AT_low_pc attribute,
this is the base address to use when reading location
lists or range lists. */
if (abbrev->tag == DW_TAG_compile_unit)
if (compunit_flag)
unit->base_address = low_pc;
}
break;
@ -4215,7 +4450,7 @@ parse_comp_unit (struct dwarf2_debug *stash,
if (is_int_form (&attr)
&& !read_rangelist (unit, &unit->arange,
&unit->file->trie_root, attr.u.val))
return NULL;
goto err_exit;
break;
case DW_AT_comp_dir:
@ -4248,21 +4483,40 @@ parse_comp_unit (struct dwarf2_debug *stash,
unit->lang = attr.u.val;
break;
case DW_AT_addr_base:
unit->dwarf_addr_offset = attr.u.val;
break;
case DW_AT_str_offsets_base:
unit->dwarf_str_offset = attr.u.val;
break;
default:
break;
}
}
for (i = 0; i < str_count; ++i)
reread_attribute (unit, &str_addrp[i], &low_pc, &high_pc,
&high_pc_relative, compunit_flag);
if (high_pc_relative)
high_pc += low_pc;
if (high_pc != 0)
{
if (!arange_add (unit, &unit->arange, &unit->file->trie_root,
low_pc, high_pc))
return NULL;
goto err_exit;
}
unit->first_child_die_ptr = info_ptr;
free (str_addrp);
return unit;
err_exit:
free (str_addrp);
return NULL;
}
/* Return TRUE if UNIT may contain the address given by ADDR. When