XS-libdwarf
view release on metacpan or search on metacpan
libdwarf-code-0.11.1/src/lib/libdwarf/dwarf_init_finish.c view on Meta::CPAN
#define ELFCOMPRESS_ZSTD 2
#endif
/* If your mingw elf.h is missing SHT_RELA and you do not
need SHT_RELA support
this define should work for you.
It is the elf value, hopefully it will
not cause trouble. If does not work, try -1
or something else
and let us know what works. */
#ifndef SHT_RELA
#define SHT_RELA 4
#endif
#ifndef SHT_REL
#define SHT_REL 9
# endif
/* For COMDAT GROUPS. Guarantees we can compile. We hope. */
#ifndef SHT_GROUP
#define SHT_GROUP 17
#endif
#ifndef SHF_COMPRESSED
/* This from ubuntu xenial. Is in top of trunk binutils
as of February 2016. Elf Section Flag */
#define SHF_COMPRESSED (1 << 11)
#endif
/* This static is copied to the dbg on dbg init
so that the static need not be referenced at
run time, preserving better locality of
reference.
Value is 0 means do the string check.
Value non-zero means do not do the check.
*/
static Dwarf_Small _dwarf_assume_string_in_bounds;
static Dwarf_Small _dwarf_apply_relocs = 1;
/* Call this after calling dwarf_init but before doing anything else.
It applies to all objects, not just the current object. */
int
dwarf_set_reloc_application(int apply)
{
int oldval = _dwarf_apply_relocs;
_dwarf_apply_relocs = (Dwarf_Small)apply;
return oldval;
}
int
dwarf_set_stringcheck(int newval)
{
int oldval = _dwarf_assume_string_in_bounds;
_dwarf_assume_string_in_bounds = (Dwarf_Small)newval;
return oldval;
}
/* Unifies the basic duplicate/empty testing and section
data setting to one place. */
static int
get_basic_section_data(Dwarf_Debug dbg,
struct Dwarf_Section_s *secdata,
struct Dwarf_Obj_Access_Section_a_s *doas,
Dwarf_Unsigned section_index,
unsigned group_number,
Dwarf_Error* error,
int duperr, int emptyerr )
{
/* There is an elf convention that section index 0 is reserved,
and that section is always empty.
Non-elf object formats must honor that by ensuring that
(when they assign numbers to 'sections' or
'section-like-things')
they never assign a real section section-number
0 to dss_index. */
if (secdata->dss_index != 0) {
DWARF_DBG_ERROR(dbg, duperr, DW_DLV_ERROR);
}
if (doas->as_size == 0) {
/* As of 2018 it seems impossible to detect
(via dwarfdump) whether emptyerr has any
practical effect, whether TRUE or FALSE. */
if (emptyerr == 0 ) {
/* Allow empty section. */
return DW_DLV_OK;
}
/* Know no reason to allow section */
DWARF_DBG_ERROR(dbg, emptyerr, DW_DLV_ERROR);
}
secdata->dss_index = section_index;
secdata->dss_size = doas->as_size;
secdata->dss_group_number = group_number;
secdata->dss_addr = doas->as_addr;
secdata->dss_link = doas->as_link;
secdata->dss_flags = doas->as_flags;
if (secdata->dss_flags & SHF_COMPRESSED) {
secdata->dss_shf_compressed = TRUE;
}
secdata->dss_entrysize = doas->as_entrysize;
secdata->dss_addralign = doas->as_addralign;
return DW_DLV_OK;
}
static void
add_relx_data_to_secdata( struct Dwarf_Section_s *secdata,
struct Dwarf_Obj_Access_Section_a_s *doas,
Dwarf_Unsigned section_index,
int is_rela)
{
secdata->dss_reloc_index = section_index;
secdata->dss_reloc_size = doas->as_size;
secdata->dss_reloc_entrysize = doas->as_entrysize;
secdata->dss_reloc_addr = doas->as_addr;
secdata->dss_reloc_symtab = doas->as_link;
secdata->dss_reloc_link = doas->as_link;
secdata->dss_is_rela = (char)is_rela;
}
#if 0 /* dump_bytes */
static void
dump_bytes(const char *msg,Dwarf_Small * start, long len)
{
Dwarf_Small *end = start + len;
Dwarf_Small *cur = start;
printf("dump_bytes: %s ",msg);
for (; cur < end; cur++) {
printf("%02x",*cur);
}
printf("\n");
}
static int
all_sig8_bits_zero(Dwarf_Sig8 *val)
{
unsigned u = 0;
for ( ; u < sizeof(*val); ++u) {
if (val->signature[u] != 0) {
return FALSE;
}
}
return TRUE;
}
#endif /*0*/
static int
is_section_name_known_already(Dwarf_Debug dbg, const char *scn_name)
{
unsigned i = 0;
for ( ; i < dbg->de_debug_sections_total_entries; ++i) {
struct Dwarf_dbg_sect_s *section = &dbg->de_debug_sections[i];
if (!strcmp(scn_name, section->ds_name)) {
/* The caller will declare this a duplicate, an error. */
return DW_DLV_OK;
}
}
/* This is normal, we expect we've not accepted
scn_name already. */
return DW_DLV_NO_ENTRY;
}
/* Given an Elf ptr, set up dbg with pointers
to all the Dwarf data sections.
Return NULL on error.
This function is also responsible for determining
whether the given object contains Dwarf information
or not. The test currently used is that it contains
either a .debug_info or a .debug_frame section. If
not, it returns DW_DLV_NO_ENTRY causing dwarf_init() also to
return DW_DLV_NO_ENTRY. Earlier, we had thought of using only
the presence/absence of .debug_info to test, but we
added .debug_frame since there could be stripped objects
that have only a .debug_frame section for exception
processing.
DW_DLV_NO_ENTRY or DW_DLV_OK or DW_DLV_ERROR
libdwarf-code-0.11.1/src/lib/libdwarf/dwarf_init_finish.c view on Meta::CPAN
static int
this_section_dwarf_relevant(const char *scn_name,
int type,
int *is_rela)
{
/* A small helper function for _dwarf_setup(). */
if (_dwarf_startswith(scn_name, ".zdebug_") ||
_dwarf_startswith(scn_name, ".debug_")) {
/* standard debug */
return TRUE;
}
if (_dwarf_ignorethissection(scn_name)) {
return FALSE;
}
/* Now check if a special section could be
in a section_group, but though seems unlikely. */
if (!strcmp(scn_name, ".eh_frame")) {
/* This is not really a group related file, but
it is harmless to consider it such. */
return TRUE;
}
if (!strcmp(scn_name, ".gnu_debuglink")) {
/* This is not a group or DWARF related file, but
it is useful for split dwarf. */
return TRUE;
}
if (!strcmp(scn_name, ".note.gnu.build-id")) {
/* This is not a group or DWARF related file, but
it is useful for split dwarf. */
return TRUE;
}
if (!strcmp(scn_name, ".gdb_index")) {
return TRUE;
}
if (is_a_special_section_semi_dwarf(scn_name)) {
return TRUE;
}
if (is_a_relx_section(scn_name,type,is_rela)) {
return TRUE;
}
/* All sorts of sections are of no interest: .text
.rel. and many others. */
return FALSE;
}
/* This assumes any non-Elf object files have no SHT_GROUP
sections. So this code will not be invoked on non-Elf objects.
One supposes this is unlikely to match any non-Elf
version of COMDAT. */
static int
insert_sht_list_in_group_map(Dwarf_Debug dbg,
struct Dwarf_Obj_Access_Section_a_s *doas,
unsigned comdat_group_number,
unsigned section_number,
Dwarf_Unsigned section_count,
struct Dwarf_Obj_Access_Interface_a_s * obj,
unsigned *did_add_map,
Dwarf_Error *error)
{
struct Dwarf_Section_s secdata;
Dwarf_Small * data = 0;
int res = 0;
Dwarf_Small* secend = 0;
memset(&secdata,0,sizeof(secdata));
secdata.dss_size = doas->as_size;
secdata.dss_entrysize = doas->as_entrysize;
secdata.dss_group_number = 1; /* arbitrary. */
secdata.dss_index = section_number;
secdata.dss_name = ".group";
secdata.dss_standard_name = ".group";
secdata.dss_number = section_number;
secdata.dss_ignore_reloc_group_sec = TRUE;
res = _dwarf_load_section(dbg,&secdata,error);
if (res != DW_DLV_OK) {
if (secdata.dss_data_was_malloc) {
free(secdata.dss_data);
secdata.dss_data = 0;
}
return res;
}
if (!secdata.dss_data) {
_dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR);
return DW_DLV_ERROR;
}
if (doas->as_entrysize != 4) {
if (secdata.dss_data_was_malloc) {
free(secdata.dss_data);
secdata.dss_data = 0;
}
_dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR);
return DW_DLV_ERROR;
}
/* So now pick up the data in dss_data.
It is an array of 32 bit fields.
Entry zero is just a constant 1.
Each additional is a section number. */
data = secdata.dss_data;
secend = data + secdata.dss_size;
{
Dwarf_Unsigned i = 1;
Dwarf_Unsigned count = doas->as_size/doas->as_entrysize;
Dwarf_Unsigned fval = 0;
/* The fields treatments with regard
to endianness is unclear. In any case a single
bit should be on, as 0x01000000
without any endiannes swapping.
Or so it seems given limited evidence.
We read with length checking and allow the
reader to byte swap and then fix things.
At least one test case has big-endian
data but little-endian SHT_GROUP data. */
if ((data+DWARF_32BIT_SIZE) > secend) {
/* Duplicates the check in READ_UNALIGNED_CK
so we can free allocated memory bere. */
if (secdata.dss_data_was_malloc) {
free(secdata.dss_data);
secdata.dss_data = 0;
}
_dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR);
return DW_DLV_ERROR;
}
READ_UNALIGNED_CK(dbg,fval,Dwarf_Unsigned,
data,
DWARF_32BIT_SIZE,
error,
secend);
if (fval != 1 && fval != 0x1000000) {
/* Could be corrupted elf object. */
if (secdata.dss_data_was_malloc) {
free(secdata.dss_data);
secdata.dss_data = 0;
}
_dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR);
return DW_DLV_ERROR;
}
data = data + doas->as_entrysize;
for (i = 1 ; i < count ; ++i) {
Dwarf_Unsigned val = 0;
if ((data+DWARF_32BIT_SIZE) > secend) {
/* Duplicates the check in READ_UNALIGNED_CK
so we can free allocated memory bere. */
if (secdata.dss_data_was_malloc) {
free(secdata.dss_data);
secdata.dss_data = 0;
}
_dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR);
return DW_DLV_ERROR;
}
READ_UNALIGNED_CK(dbg,val,Dwarf_Unsigned,
data,
DWARF_32BIT_SIZE,
error,
secend);
if (val > section_count) {
/* Might be confused endianness by
the compiler generating the SHT_GROUP.
This is pretty horrible. */
Dwarf_Unsigned valr = 0;
_dwarf_memcpy_swap_bytes(&valr,&val,
DWARF_32BIT_SIZE);
if (valr > section_count) {
if (secdata.dss_data_was_malloc) {
free(secdata.dss_data);
secdata.dss_data = 0;
}
_dwarf_error(dbg,error,
DW_DLE_GROUP_INTERNAL_ERROR);
return DW_DLV_ERROR;
}
/* Ok. Yes, ugly. */
val = valr;
}
{
/* Ensure this group entry DWARF relevant before
adding to group map */
struct Dwarf_Obj_Access_Section_a_s doasx;
int resx = DW_DLV_ERROR;
int err = 0;
int is_rela = FALSE;
memset(&doasx,0,sizeof(doasx));
resx = obj->ai_methods->
om_get_section_info(obj->ai_object,
val,
&doasx, &err);
if (resx == DW_DLV_NO_ENTRY){
/* Should we really ignore this? */
continue;
}
if (resx == DW_DLV_ERROR){
if (secdata.dss_data_was_malloc) {
free(secdata.dss_data);
secdata.dss_data = 0;
}
_dwarf_error(dbg,error,err);
return resx;
}
if (!this_section_dwarf_relevant(doasx.as_name,
(int)doasx.as_type,&is_rela) ) {
continue;
}
data += DWARF_32BIT_SIZE;
*did_add_map = TRUE;
res = _dwarf_insert_in_group_map(dbg,
(unsigned)comdat_group_number,
(unsigned)val,
doasx.as_name,
error);
if (res != DW_DLV_OK) {
if (secdata.dss_data_was_malloc) {
free(secdata.dss_data);
secdata.dss_data = 0;
}
return res;
}
}
}
}
if (secdata.dss_data_was_malloc) {
free(secdata.dss_data);
secdata.dss_data = 0;
}
return DW_DLV_OK;
}
/* Split dwarf CUs can be in an object with non-split
or split may be in a separate object.
If all in one object the default is to deal with group_number
and ignore DW_GROUPNUMBER_DWO.
If only .dwo the default is DW_GROUPNUMBER_DWO(2).
Otherwise use DW_GROUP_NUMBER_BASE(1).
If there are COMDAT SHT_GROUP sections, these
are assigned group numbers 3-N as needed.
At present this makes the assumption that COMDAT group
(ie, SHT_GROUP) sections
have lower section numbers than the sections COMDAT refers to.
It is not clear whether this is guaranteed, COMDAT is not
an official Elf thing and documentation is scarce.
In the 1990's SGI folks and others formed a committee
and attempted to get COMDAT and a feature allowing section
numbers greater than 16 bits into Elf, but there was no
group that was able to approve such things.
This is called once at dbg init time.
*/
static int
determine_target_group(Dwarf_Unsigned section_count,
struct Dwarf_Obj_Access_Interface_a_s * obj,
unsigned *group_number_out,
Dwarf_Debug dbg,
Dwarf_Error *error)
{
unsigned obj_section_index = 0;
int found_group_one = 0;
int found_group_two = 0;
struct Dwarf_Group_Data_s *grp = 0;
unsigned comdat_group_next = 3;
unsigned lowest_comdat_groupnum = 0;
grp = &dbg->de_groupnumbers;
grp->gd_number_of_groups = 0;
grp->gd_number_of_sections = (unsigned int)section_count;
if (grp->gd_map) {
_dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR);
return DW_DLV_OK;
}
for (obj_section_index = 0; obj_section_index < section_count;
++obj_section_index) {
struct Dwarf_Obj_Access_Section_a_s doas;
int res = DW_DLV_ERROR;
int err = 0;
const char *scn_name = 0;
unsigned groupnumber = 0;
unsigned mapgroupnumber = 0;
int is_rela = FALSE;
memset(&doas,0,sizeof(doas));
libdwarf-code-0.11.1/src/lib/libdwarf/dwarf_init_finish.c view on Meta::CPAN
groupnumber = DW_GROUPNUMBER_BASE;
}
}
if (!this_section_dwarf_relevant(scn_name,
(int)doas.as_type,
&is_rela) ) {
continue;
}
if (!is_a_relx_section(scn_name,(int)doas.as_type,
&is_rela)
&& !is_a_special_section_semi_dwarf(scn_name)) {
/* We do these actions only for group-related
sections. Do for .debug_info etc,
never for .strtab or .rela.*
We already tested for relevance, so that part
is not news. */
if (mapgroupnumber == dbg->de_groupnumber) {
/* OK. Mapped. Part of the group.. This will
catch the cases where there are versions of
a section in multiple COMDATs and in BASE
an DWO to get the right one */
} else {
/* This section not mapped into this group. */
if (groupnumber == 1 && dbg->de_groupnumber > 2 &&
!_dwarf_section_in_group_by_name(dbg,scn_name,
dbg->de_groupnumber)) {
/* Load the section (but as group 1) */
} else {
continue;
}
}
}
/* BUILDING_SECTIONS. See also BUILDING_MAP, SETUP_SECTION */
{
/* Build up the sections table and the
de_debug* etc pointers in Dwarf_Debug. */
struct Dwarf_dbg_sect_s *section = 0;
int found_match = FALSE;
res = is_section_name_known_already(dbg,scn_name);
if (res == DW_DLV_OK) {
#if 0 /* Removed check for section duplication */
/* DUPLICATE */
DWARF_DBG_ERROR(dbg, DW_DLE_SECTION_DUPLICATION,
DW_DLV_ERROR);
/* Metrowerks does this nonsense */
#endif
continue;
}
if (res == DW_DLV_ERROR) {
free(sections);
DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
}
/* No entry: new-to-us section, the normal case. */
res = _dwarf_enter_section_in_de_debug_sections_array(dbg,
scn_name, obj_section_index, groupnumber,&err);
if (res == DW_DLV_OK) {
section = &dbg->de_debug_sections[
dbg->de_debug_sections_total_entries-1];
res = get_basic_section_data(dbg,
section->ds_secdata, &doas,
obj_section_index,
groupnumber,
error,
section->ds_duperr,
section->ds_emptyerr);
if (res != DW_DLV_OK) {
free(sections);
return res;
}
sections[obj_section_index] = section->ds_secdata;
foundDwarf += section->ds_have_dwarf;
found_match = TRUE;
/* Normal section set up.
Fall through. */
} else if (res == DW_DLV_NO_ENTRY) {
/* We get here for relocation sections.
Fall through. */
} else {
free(sections);
DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
}
if (!found_match) {
/* For an object file with incorrect rel[a]
section name, the 'readelf' tool,
prints correct debug information,
as the tool takes the section type instead
of the section name. If the current section
is a RELA one and the 'sh_info'
refers to a debug section, add the
relocation data. */
if (is_a_relx_section(scn_name,
(int)doas.as_type, &is_rela)) {
if ( doas.as_info < section_count) {
if (sections[doas.as_info]) {
add_relx_data_to_secdata(
sections[doas.as_info],
&doas,
obj_section_index,is_rela);
}
} else {
/* Something is wrong with the ELF file. */
free(sections);
DWARF_DBG_ERROR(dbg, DW_DLE_ELF_SECT_ERR,
DW_DLV_ERROR);
}
}
}
/* Fetch next section */
}
}
/* Free table with section information. */
free(sections);
if (foundDwarf) {
return DW_DLV_OK;
}
return DW_DLV_NO_ENTRY;
}
/* There is one table per CU and one per TU, and each
table refers to the associated other DWARF data
for that CU or TU.
See DW_SECT_*
In DWARF4 the type units are in .debug_types
In DWARF5 the type units are in .debug_info.
*/
static int
load_debugfission_tables(Dwarf_Debug dbg,Dwarf_Error *error)
{
int i = 0;
if (dbg->de_debug_cu_index.dss_size ==0 &&
dbg->de_debug_tu_index.dss_size ==0) {
/* This is the normal case.
No debug fission. Not a .dwp object. */
return DW_DLV_NO_ENTRY;
}
for (i = 0; i < 2; ++i) {
Dwarf_Xu_Index_Header xuptr = 0;
struct Dwarf_Section_s* dwsect = 0;
Dwarf_Unsigned version = 0;
Dwarf_Unsigned number_of_cols /* L */ = 0;
Dwarf_Unsigned number_of_CUs /* N */ = 0;
Dwarf_Unsigned number_of_slots /* M */ = 0;
const char *secname = 0;
int res = 0;
const char *type = 0;
if (i == 0) {
dwsect = &dbg->de_debug_cu_index;
type = "cu";
} else {
dwsect = &dbg->de_debug_tu_index;
( run in 1.109 second using v1.01-cache-2.11-cpan-39bf76dae61 )