summaryrefslogtreecommitdiffstats
path: root/libdw/dwarf_formstring.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdw/dwarf_formstring.c')
-rw-r--r--libdw/dwarf_formstring.c131
1 files changed, 118 insertions, 13 deletions
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index 83abd53d..c3e892a8 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -1,7 +1,6 @@
/* Return string associated with given attribute.
- Copyright (C) 2003-2010, 2013 Red Hat, Inc.
+ Copyright (C) 2003-2010, 2013, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2003.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -47,8 +46,11 @@ dwarf_formstring (Dwarf_Attribute *attrp)
/* A simple inlined string. */
return (const char *) attrp->valp;
- Dwarf *dbg = attrp->cu->dbg;
- Dwarf *dbg_ret = attrp->form == DW_FORM_GNU_strp_alt ? dbg->alt_dwarf : dbg;
+ Dwarf_CU *cu = attrp->cu;
+ Dwarf *dbg = cu->dbg;
+ Dwarf *dbg_ret = ((attrp->form == DW_FORM_GNU_strp_alt
+ || attrp->form == DW_FORM_strp_sup)
+ ? INTUSE(dwarf_getalt) (dbg) : dbg);
if (unlikely (dbg_ret == NULL))
{
@@ -56,20 +58,123 @@ dwarf_formstring (Dwarf_Attribute *attrp)
return NULL;
}
-
- if (unlikely (attrp->form != DW_FORM_strp
- && attrp->form != DW_FORM_GNU_strp_alt)
- || dbg_ret->sectiondata[IDX_debug_str] == NULL)
+ Elf_Data *data = ((attrp->form == DW_FORM_line_strp)
+ ? dbg_ret->sectiondata[IDX_debug_line_str]
+ : dbg_ret->sectiondata[IDX_debug_str]);
+ if (data == NULL)
{
- __libdw_seterrno (DWARF_E_NO_STRING);
+ __libdw_seterrno ((attrp->form == DW_FORM_line_strp)
+ ? DWARF_E_NO_DEBUG_LINE_STR
+ : DWARF_E_NO_DEBUG_STR);
return NULL;
}
uint64_t off;
- if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (attrp->cu), attrp->valp,
- attrp->cu->offset_size, &off, IDX_debug_str, 1))
- return NULL;
+ if (attrp->form == DW_FORM_strp
+ || attrp->form == DW_FORM_GNU_strp_alt
+ || attrp->form == DW_FORM_strp_sup)
+ {
+ if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (cu),
+ attrp->valp, cu->offset_size, &off,
+ IDX_debug_str, 1))
+ return NULL;
+ }
+ else if (attrp->form == DW_FORM_line_strp)
+ {
+ if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (cu),
+ attrp->valp, cu->offset_size, &off,
+ IDX_debug_line_str, 1))
+ return NULL;
+ }
+ else
+ {
+ Dwarf_Word idx;
+ const unsigned char *datap = attrp->valp;
+ const unsigned char *endp = cu->endp;
+ switch (attrp->form)
+ {
+ case DW_FORM_strx:
+ case DW_FORM_GNU_str_index:
+ if (datap >= endp)
+ {
+ invalid:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
+ }
+ get_uleb128 (idx, datap, endp);
+ break;
+
+ case DW_FORM_strx1:
+ if (datap >= endp - 1)
+ goto invalid;
+ idx = *datap;
+ break;
+
+ case DW_FORM_strx2:
+ if (datap >= endp - 2)
+ goto invalid;
+ idx = read_2ubyte_unaligned (dbg, datap);
+ break;
+
+ case DW_FORM_strx3:
+ if (datap >= endp - 3)
+ goto invalid;
+ idx = read_3ubyte_unaligned (dbg, datap);
+ break;
+
+ case DW_FORM_strx4:
+ if (datap >= endp - 4)
+ goto invalid;
+ idx = read_4ubyte_unaligned (dbg, datap);
+ break;
+
+ default:
+ __libdw_seterrno (DWARF_E_NO_STRING);
+ return NULL;
+ }
+
+ /* So we got an index in the .debug_str_offsets. Lets see if it
+ is valid and we can get the actual .debug_str offset. */
+ Dwarf_Off str_off = __libdw_cu_str_off_base (cu);
+ if (str_off == (Dwarf_Off) -1)
+ return NULL;
+
+ if (dbg->sectiondata[IDX_debug_str_offsets] == NULL)
+ {
+ __libdw_seterrno (DWARF_E_NO_STR_OFFSETS);
+ return NULL;
+ }
+
+ /* The section should at least contain room for one offset. */
+ int offset_size = cu->offset_size;
+ if (cu->offset_size > dbg->sectiondata[IDX_debug_str_offsets]->d_size)
+ {
+ invalid_offset:
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return NULL;
+ }
+
+ /* And the base offset should be at least inside the section. */
+ if (str_off > (dbg->sectiondata[IDX_debug_str_offsets]->d_size
+ - offset_size))
+ goto invalid_offset;
+
+ size_t max_idx = (dbg->sectiondata[IDX_debug_str_offsets]->d_size
+ - offset_size - str_off) / offset_size;
+ if (idx > max_idx)
+ goto invalid_offset;
+
+ datap = (dbg->sectiondata[IDX_debug_str_offsets]->d_buf
+ + str_off + (idx * offset_size));
+ if (offset_size == 4)
+ off = read_4ubyte_unaligned (dbg, datap);
+ else
+ off = read_8ubyte_unaligned (dbg, datap);
+
+ if (off > dbg->sectiondata[IDX_debug_str]->d_size)
+ goto invalid_offset;
+ }
- return (const char *) dbg_ret->sectiondata[IDX_debug_str]->d_buf + off;
+ return (const char *) data->d_buf + off;
}
INTDEF(dwarf_formstring)