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 )