summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdwarf/common/dwarf_ranges.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libdwarf/common/dwarf_ranges.c')
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_ranges.c419
1 files changed, 340 insertions, 79 deletions
diff --git a/usr/src/lib/libdwarf/common/dwarf_ranges.c b/usr/src/lib/libdwarf/common/dwarf_ranges.c
index ae6d5cf9b5..5f6ac72987 100644
--- a/usr/src/lib/libdwarf/common/dwarf_ranges.c
+++ b/usr/src/lib/libdwarf/common/dwarf_ranges.c
@@ -1,48 +1,40 @@
/*
+ Copyright (C) 2008-2020 David Anderson. All Rights Reserved.
+ Portions Copyright 2012 SN Systems Ltd. All rights reserved.
- Copyright (C) 2008-2010 David Anderson. All Rights Reserved.
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of version 2.1 of the
+ GNU Lesser General Public License as published by the Free
+ Software Foundation.
- This program is free software; you can redistribute it and/or modify it
- under the terms of version 2.1 of the GNU Lesser General Public License
- as published by the Free Software Foundation.
+ This program is distributed in the hope that it would be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.
- This program is distributed in the hope that it would be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ Further, this software is distributed without any warranty
+ that it is free of the rightful claim of any third person
+ regarding infringement or the like. Any license provided
+ herein, whether implied or otherwise, applies only to this
+ software file. Patent licenses, if any, provided herein
+ do not apply to combinations of this program with other
+ software, or any other product whatsoever.
- Further, this software is distributed without any warranty that it is
- free of the rightful claim of any third person regarding infringement
- or the like. Any license provided herein, whether implied or
- otherwise, applies only to this software file. Patent licenses, if
- any, provided herein do not apply to combinations of this program with
- other software, or any other product whatsoever.
+ You should have received a copy of the GNU Lesser General
+ Public License along with this program; if not, write the
+ Free Software Foundation, Inc., 51 Franklin Street - Fifth
+ Floor, Boston MA 02110-1301, USA.
- You should have received a copy of the GNU Lesser General Public
- License along with this program; if not, write the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
- USA.
-
- Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
- Mountain View, CA 94043, or:
-
- http://www.sgi.com
-
- For further information regarding this notice, see:
-
- http://oss.sgi.com/projects/GenInfo/NoticeExplan
-
-*/
-/* The address of the Free Software Foundation is
- Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- Boston, MA 02110-1301, USA.
- SGI has moved from the Crittenden Lane address.
*/
-
-
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include "dwarf_incl.h"
+#include "dwarf_alloc.h"
+#include "dwarf_error.h"
+#include "dwarf_util.h"
+#include "dwarfstring.h"
struct ranges_entry {
struct ranges_entry *next;
@@ -50,6 +42,55 @@ struct ranges_entry {
};
+static void
+free_allocated_ranges( struct ranges_entry *base)
+{
+ struct ranges_entry *cur = 0;
+ struct ranges_entry *next = 0;
+ for ( cur = base ; cur ; cur = next ) {
+ next = cur->next;
+ free(cur);
+ }
+}
+
+/* We encapsulate the macro use so we can
+ free local malloc resources that would otherwise
+ leak. See the call points below. */
+static int
+read_unaligned_addr_check(Dwarf_Debug dbg,
+ Dwarf_Addr *addr_out,
+ Dwarf_Small *rangeptr,
+ unsigned address_size,
+ Dwarf_Error *error,
+ Dwarf_Small *section_end)
+{
+ Dwarf_Addr a = 0;
+
+ READ_UNALIGNED_CK(dbg,a,
+ Dwarf_Addr, rangeptr,
+ address_size,
+ error,section_end);
+ *addr_out = a;
+ return DW_DLV_OK;
+}
+/* As of DWARF5 the ranges section each range list set has
+ a range-list-table header. See "7.28 Range List Table"
+ in the DWARF5 standard.
+ For DWARF5 the offset should be the offset of
+ the range-list-table-header for that range list.
+ For DWARF3 and DWARF4 the offset has to be that
+ of a range list.
+*/
+/* Ranges and pc values can be in a split dwarf object.
+ In that case the appropriate values need to be
+ incremented by data from the executable in
+ the compilation unit with the same dwo_id.
+
+ We return an error which is on the incoming dbg, not
+ the possibly-tied-dbg localdbg.
+ If incoming die is NULL there is no context, so do not look
+ for a tied file, and address_size is the size
+ of the overall object, not the address_size of the context. */
#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff)
int dwarf_get_ranges_a(Dwarf_Debug dbg,
Dwarf_Off rangesoffset,
@@ -70,84 +111,306 @@ int dwarf_get_ranges_a(Dwarf_Debug dbg,
unsigned copyindex = 0;
Dwarf_Half address_size = 0;
int res = DW_DLV_ERROR;
+ Dwarf_Unsigned ranges_base = 0;
+ Dwarf_Unsigned addr_base = 0;
+ Dwarf_Debug localdbg = dbg;
+ Dwarf_Error localerror = 0;
+ Dwarf_Half die_version = 3; /* default for dwarf_get_ranges() */
+ UNUSEDARG Dwarf_Half offset_size = 4;
+ Dwarf_CU_Context cucontext = 0;
+
+ if (!dbg) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return DW_DLV_ERROR;
+ }
+ address_size = localdbg->de_pointer_size; /* default */
+ if (die) {
+ /* If we wind up using the tied file the die_version
+ had better match! It cannot be other than a match. */
+ /* Can return DW_DLV_ERROR, not DW_DLV_NO_ENTRY.
+ Add err code if error. Version comes from the
+ cu context, not the DIE itself. */
+ res = dwarf_get_version_of_die(die,&die_version,
+ &offset_size);
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT);
+ return DW_DLV_ERROR;
+ }
+ if (!die->di_cu_context) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT);
+ return DW_DLV_ERROR;
+ }
+ cucontext = die->di_cu_context;
+ /* The DW4 ranges base was never used in GNU
+ but did get emitted.
+ http://llvm.1065342.n5.nabble.com/DebugInfo-DW-AT-GNU-ranges-base-in-non-fission-td64194.html
+ */
+#if 0
+ if (cucontext->cc_unit_type != DW_UT_skeleton &&
+ cucontext->cc_version_stamp != DW_CU_VERSION4 &&
+ cucontext->cc_ranges_base_present) {
+ /* Never needed. See DW_AT_GNU_ranges_base
+ in find_cu_die_base_fields() in dwarf_die_deliv.c */
+ ranges_base = cucontext->cc_ranges_base;
+ }
+#endif
+ address_size = cucontext->cc_address_size;
+ }
+
+ /* If tied object exists,
+ base object is DWP and tied object is the
+ skeleton/executabl CU containing a skeleton CU
+ with DW_AT_addr_base/DW_AT_GNU_addr_base and
+ DW_AT_rnglists_base/DW_AT_GNU_ranges base. */
+ if (die &&dbg->de_tied_data.td_tied_object) {
+
+ int restied = 0;
+
+ /* dwo/dwp CU may have (DW5 pg 63)
+ DW_AT_name
+ DW_AT_language
+ DW_AT_macros
+ DW_AT_producer
+ DW_AT_identifier_case
+ DW_AT_main_subprogram
+ DW_AT_entry_pc
+ DW_AT_ranges if DW5 offset of header (see
+ ranges_base/rnglists_base below),
+ else of ranges
+ DW_AT_GNU_pubnames
+ DW_AT_stmt_list, a trivial stmt list with
+ the list of directories and file names
+ where needed for Type Units (DW5 pg 64)
+ and must have
+ DW_AT_[GNU_]dwo_id
+ and inherited from skeleton:
+ DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges,
+ DW_AT_stmt_list, DW_AT_comp_dir,
+ DW_AT_use_UTF8, DW_AT_str_offsets_base,
+ DW_AT_addr_base and DW_AT_rnglists_base.
- res = _dwarf_load_section(dbg, &dbg->de_debug_ranges,error);
- if (res != DW_DLV_OK) {
+ skeleton CU may have (DW5 pg 62)
+ DW_AT_[GNU_]addr_base possibly needed by dwp
+ DW_AT_str_offsets_base possibly needed by dwp
+ DW_AT_GNU_ranges_base (GNU)possibly needed by dwp
+ DW_AT_rnglists_base (DWARF5)possibly needed by dwp
+ DW_AT_low_pc
+ DW_AT_high_pc
+ DW_AT_ranges
+ DW_AT_str_offsets_base
+ DW_AT_[GNU_]dwo_name
+ DW_AT_stmt_list
+ DW_AT_comp_dir
+ DW_AT_use_UTF8
+ and must have
+ DW_AT_[GNU_]dwo_id
+ .debug_ranges does not
+ exist in the DWP, it is only in the executable.
+ */
+ restied = _dwarf_get_ranges_base_attr_from_tied(dbg,
+ cucontext,
+ &ranges_base,
+ &addr_base,
+ error);
+ if (restied == DW_DLV_ERROR ) {
+ if(!error) {
+ return restied;
+ }
+ dwarf_dealloc(localdbg,*error,DW_DLA_ERROR);
+ *error = 0;
+ /* Nothing else to do. Look in original dbg. */
+ } else if (restied == DW_DLV_NO_ENTRY ) {
+ /* Nothing else to do. Look in original dbg. */
+ } else {
+ /* Ranges are never in a split dwarf object.
+ In the base object
+ instead. Use the tied_object */
+ localdbg = dbg->de_tied_data.td_tied_object;
+ }
+ }
+#if 0
+FIXME Implement debug_rnglists!
+ /* de_debug_ranges is DW 3,4.
+ de_debug_rnglists is DW5. */
+ if (die_version >= DW_CU_VERSION5) {
+ res = _dwarf_load_section(localdbg,
+ &localdbg->de_debug_rngslists,&localerror);
+ } else {
+ res = _dwarf_load_section(localdbg,
+ &localdbg->de_debug_ranges,&localerror);
+ }
+#endif
+ res = _dwarf_load_section(localdbg, &localdbg->de_debug_ranges,&localerror);
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error_mv_s_to_t(localdbg,&localerror,dbg,error);
+ return res;
+ } else if (res == DW_DLV_NO_ENTRY) {
return res;
}
- if(rangesoffset >= dbg->de_debug_ranges.dss_size) {
- _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
- return (DW_DLV_ERROR);
+ /* Be safe in case adding rangesoffset and rangebase
+ overflows. */
+ if (rangesoffset == localdbg->de_debug_ranges.dss_size) {
+ return DW_DLV_NO_ENTRY;
}
- address_size = _dwarf_get_address_size(dbg, die);
- section_end = dbg->de_debug_ranges.dss_data +
- dbg->de_debug_ranges.dss_size;
- rangeptr = dbg->de_debug_ranges.dss_data + rangesoffset;
+ if (rangesoffset > localdbg->de_debug_ranges.dss_size) {
+ dwarfstring m;
+
+ dwarfstring_constructor(&m);
+ dwarfstring_append_printf_u(&m,
+ "DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
+ " rangesoffset is 0x%lx ",rangesoffset);
+ dwarfstring_append_printf_u(&m,
+ " and section size is 0x%lx.",
+ localdbg->de_debug_ranges.dss_size);
+ _dwarf_error_string(dbg, error,
+ DW_DLE_DEBUG_RANGES_OFFSET_BAD,
+ dwarfstring_string(&m));
+ dwarfstring_destructor(&m);
+ return DW_DLV_ERROR;
+ }
+ if (ranges_base >= localdbg->de_debug_ranges.dss_size) {
+ dwarfstring m;
+
+ dwarfstring_constructor(&m);
+ dwarfstring_append_printf_u(&m,
+ "DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
+ " ranges base is 0x%lx ",ranges_base);
+ dwarfstring_append_printf_u(&m,
+ " and section size is 0x%lx.",
+ localdbg->de_debug_ranges.dss_size);
+ _dwarf_error_string(dbg, error,
+ DW_DLE_DEBUG_RANGES_OFFSET_BAD,
+ dwarfstring_string(&m));
+ dwarfstring_destructor(&m);
+ return DW_DLV_ERROR;
+ }
+ if ((rangesoffset +ranges_base) >=
+ localdbg->de_debug_ranges.dss_size) {
+ dwarfstring m;
+
+ dwarfstring_constructor(&m);
+ dwarfstring_append_printf_u(&m,
+ "DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
+ " ranges base+offset is 0x%lx ",
+ ranges_base+rangesoffset);
+ dwarfstring_append_printf_u(&m,
+ " and section size is 0x%lx.",
+ localdbg->de_debug_ranges.dss_size);
+ _dwarf_error_string(dbg, error,
+ DW_DLE_DEBUG_RANGES_OFFSET_BAD,
+ dwarfstring_string(&m));
+ dwarfstring_destructor(&m);
+ return DW_DLV_ERROR;
+ }
+
+ /* tied address_size must match the dwo address_size */
+ section_end = localdbg->de_debug_ranges.dss_data +
+ localdbg->de_debug_ranges.dss_size;
+ rangeptr = localdbg->de_debug_ranges.dss_data +
+ rangesoffset + ranges_base;
beginrangeptr = rangeptr;
- for(;;) {
- struct ranges_entry * re = calloc(sizeof(struct ranges_entry),1);
- if(!re) {
- _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
- return (DW_DLV_ERROR);
+ for (;;) {
+ struct ranges_entry * re = 0;
+
+ if (rangeptr == section_end) {
+ break;
}
- if(rangeptr >= section_end) {
- return (DW_DLV_NO_ENTRY);
+ if (rangeptr > section_end) {
+ dwarfstring m;
+
+ free_allocated_ranges(base);
+ dwarfstring_constructor(&m);
+ dwarfstring_append(&m,
+ "DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
+ " ranges pointer ran off the end "
+ "of the section");
+ _dwarf_error_string(dbg, error,
+ DW_DLE_DEBUG_RANGES_OFFSET_BAD,
+ dwarfstring_string(&m));
+ dwarfstring_destructor(&m);
+ return DW_DLV_ERROR;
+ }
+ re = calloc(sizeof(struct ranges_entry),1);
+ if (!re) {
+ free_allocated_ranges(base);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
+ return DW_DLV_ERROR;
}
- if((rangeptr + (2*address_size)) > section_end) {
- _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
- return (DW_DLV_ERROR);
+ if ((rangeptr + (2*address_size)) > section_end) {
+ free(re);
+ free_allocated_ranges(base);
+ _dwarf_error_string(dbg, error,
+ DW_DLE_DEBUG_RANGES_OFFSET_BAD,
+ "DW_DLE_DEBUG_RANGES_OFFSET_BAD: "
+ " Not at the end of the ranges section "
+ " but there is not enough room in the section "
+ " for the next ranges entry");
+ return DW_DLV_ERROR;
}
entry_count++;
- READ_UNALIGNED(dbg,re->cur.dwr_addr1,
- Dwarf_Addr, rangeptr,
- address_size);
+ res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr1,
+ rangeptr, address_size,error,section_end);
+ if (res != DW_DLV_OK) {
+ free(re);
+ free_allocated_ranges(base);
+ return res;
+ }
rangeptr += address_size;
- READ_UNALIGNED(dbg,re->cur.dwr_addr2 ,
- Dwarf_Addr, rangeptr,
- address_size);
+ res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr2,
+ rangeptr, address_size,error,section_end);
+ if (res != DW_DLV_OK) {
+ free(re);
+ free_allocated_ranges(base);
+ return res;
+ }
rangeptr += address_size;
- if(!base) {
- base = re;
- last = re;
+ if (!base) {
+ base = re;
+ last = re;
} else {
- last->next = re;
- last = re;
+ last->next = re;
+ last = re;
}
- if(re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) {
+ if (re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) {
re->cur.dwr_type = DW_RANGES_END;
break;
- } else if ( re->cur.dwr_addr1 == MAX_ADDR) {
+ } else if (re->cur.dwr_addr1 == MAX_ADDR) {
re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION;
} else {
re->cur.dwr_type = DW_RANGES_ENTRY;
}
}
+ /* We return ranges on dbg, so use that to allocate. */
ranges_data_out = (Dwarf_Ranges *)
- _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count);
- if(!ranges_data_out) {
- _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
- return (DW_DLV_ERROR);
+ _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count);
+ if (!ranges_data_out) {
+ /* Error, apply to original, not local dbg. */
+ free_allocated_ranges(base);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
+ return (DW_DLV_ERROR);
}
curre = base;
*rangesbuf = ranges_data_out;
*listlen = entry_count;
- for( copyindex = 0; curre && (copyindex < entry_count);
+ for (copyindex = 0; curre && (copyindex < entry_count);
++copyindex,++ranges_data_out) {
- struct ranges_entry *r = curre;
*ranges_data_out = curre->cur;
curre = curre->next;
- free(r);
}
+ /* ASSERT: curre == NULL */
+ free_allocated_ranges(base);
+ base = 0;
/* Callers will often not care about the bytes used. */
- if(bytecount) {
+ if (bytecount) {
*bytecount = rangeptr - beginrangeptr;
}
- return DW_DLV_OK;
+ return DW_DLV_OK;
}
+
int dwarf_get_ranges(Dwarf_Debug dbg,
Dwarf_Off rangesoffset,
Dwarf_Ranges ** rangesbuf,
@@ -161,11 +424,9 @@ int dwarf_get_ranges(Dwarf_Debug dbg,
return res;
}
-void
+void
dwarf_ranges_dealloc(Dwarf_Debug dbg, Dwarf_Ranges * rangesbuf,
- Dwarf_Signed rangecount)
+ UNUSEDARG Dwarf_Signed rangecount)
{
dwarf_dealloc(dbg,rangesbuf, DW_DLA_RANGES);
-
}
-