mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-30 19:53:46 +00:00
d21be3b4e1
(from https://sourceware.org/elfutils/, GPL/LGPL licensed)
169 lines
4.5 KiB
C
169 lines
4.5 KiB
C
/* Find CU for given offset.
|
|
Copyright (C) 2003-2010, 2014 Red Hat, Inc.
|
|
This file is part of elfutils.
|
|
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
|
|
|
|
This file is free software; you can redistribute it and/or modify
|
|
it under the terms of either
|
|
|
|
* the GNU Lesser General Public License as published by the Free
|
|
Software Foundation; either version 3 of the License, or (at
|
|
your option) any later version
|
|
|
|
or
|
|
|
|
* the GNU General Public License as published by the Free
|
|
Software Foundation; either version 2 of the License, or (at
|
|
your option) any later version
|
|
|
|
or both in parallel, as here.
|
|
|
|
elfutils is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received copies of the GNU General Public License and
|
|
the GNU Lesser General Public License along with this program. If
|
|
not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <search.h>
|
|
#include "libdwP.h"
|
|
|
|
static int
|
|
findcu_cb (const void *arg1, const void *arg2)
|
|
{
|
|
struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
|
|
struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2;
|
|
|
|
/* Find out which of the two arguments is the search value. It has
|
|
end offset 0. */
|
|
if (cu1->end == 0)
|
|
{
|
|
if (cu1->start < cu2->start)
|
|
return -1;
|
|
if (cu1->start >= cu2->end)
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if (cu2->start < cu1->start)
|
|
return 1;
|
|
if (cu2->start >= cu1->end)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct Dwarf_CU *
|
|
internal_function
|
|
__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
|
|
{
|
|
Dwarf_Off *const offsetp
|
|
= debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
|
|
void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
|
|
|
|
Dwarf_Off oldoff = *offsetp;
|
|
uint16_t version;
|
|
uint8_t address_size;
|
|
uint8_t offset_size;
|
|
Dwarf_Off abbrev_offset;
|
|
uint64_t type_sig8 = 0;
|
|
Dwarf_Off type_offset = 0;
|
|
|
|
if (INTUSE(dwarf_next_unit) (dbg, oldoff, offsetp, NULL,
|
|
&version, &abbrev_offset,
|
|
&address_size, &offset_size,
|
|
debug_types ? &type_sig8 : NULL,
|
|
debug_types ? &type_offset : NULL) != 0)
|
|
/* No more entries. */
|
|
return NULL;
|
|
|
|
/* We only know how to handle the DWARF version 2 through 4 formats. */
|
|
if (unlikely (version < 2) || unlikely (version > 4))
|
|
{
|
|
__libdw_seterrno (DWARF_E_INVALID_DWARF);
|
|
return NULL;
|
|
}
|
|
|
|
/* Invalid or truncated debug section data? */
|
|
Elf_Data *data = dbg->sectiondata[debug_types
|
|
? IDX_debug_types : IDX_debug_info];
|
|
if (unlikely (*offsetp > data->d_size))
|
|
*offsetp = data->d_size;
|
|
|
|
/* Create an entry for this CU. */
|
|
struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
|
|
|
|
newp->dbg = dbg;
|
|
newp->start = oldoff;
|
|
newp->end = *offsetp;
|
|
newp->address_size = address_size;
|
|
newp->offset_size = offset_size;
|
|
newp->version = version;
|
|
newp->type_sig8 = type_sig8;
|
|
newp->type_offset = type_offset;
|
|
Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
|
|
newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
|
|
newp->lines = NULL;
|
|
newp->locs = NULL;
|
|
|
|
if (debug_types)
|
|
Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, type_sig8, newp);
|
|
|
|
newp->startp = data->d_buf + newp->start;
|
|
newp->endp = data->d_buf + newp->end;
|
|
|
|
/* Add the new entry to the search tree. */
|
|
if (tsearch (newp, tree, findcu_cb) == NULL)
|
|
{
|
|
/* Something went wrong. Undo the operation. */
|
|
*offsetp = oldoff;
|
|
__libdw_seterrno (DWARF_E_NOMEM);
|
|
return NULL;
|
|
}
|
|
|
|
return newp;
|
|
}
|
|
|
|
struct Dwarf_CU *
|
|
internal_function
|
|
__libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool debug_types)
|
|
{
|
|
void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
|
|
Dwarf_Off *next_offset
|
|
= debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
|
|
|
|
/* Maybe we already know that CU. */
|
|
struct Dwarf_CU fake = { .start = start, .end = 0 };
|
|
struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
|
|
if (found != NULL)
|
|
return *found;
|
|
|
|
if (start < *next_offset)
|
|
{
|
|
__libdw_seterrno (DWARF_E_INVALID_DWARF);
|
|
return NULL;
|
|
}
|
|
|
|
/* No. Then read more CUs. */
|
|
while (1)
|
|
{
|
|
struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, debug_types);
|
|
if (newp == NULL)
|
|
return NULL;
|
|
|
|
/* Is this the one we are looking for? */
|
|
if (start < *next_offset)
|
|
// XXX Match exact offset.
|
|
return newp;
|
|
}
|
|
/* NOTREACHED */
|
|
}
|