dwarf_init_finish.c [plain text]
#include "config.h"
#include "dwarf_incl.h"
#ifdef HAVE_ELF_H
#include <elf.h>
#endif
#ifdef __SGI_FAST_LIBELF
#include <libelf_sgi.h>
#else
#ifdef HAVE_LIBELF_H
#include <libelf.h>
#else
#ifdef HAVE_LIBELF_LIBELF_H
#include <libelf/libelf.h>
#endif
#endif
#endif
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include "dwarf_incl.h"
#include "malloc_check.h"
#define DWARF_DBG_ERROR(dbg,errval,retval) \
_dwarf_error(dbg, error, errval); return(retval);
#define FALSE 0
#define TRUE 1
#ifdef __SGI_FAST_LIBELF
#else
#ifdef HAVE_ELF64_GETEHDR
extern Elf64_Ehdr *elf64_getehdr(Elf *);
#endif
#ifdef HAVE_ELF64_GETSHDR
extern Elf64_Shdr *elf64_getshdr(Elf_Scn *);
#endif
#endif
static Dwarf_Small _dwarf_assume_string_bad;
int
dwarf_set_stringcheck(int newval)
{
int oldval = _dwarf_assume_string_bad;
_dwarf_assume_string_bad = newval;
return oldval;
}
#ifdef __SGI_FAST_LIBELF
static int
_dwarf_error_code_from_elf_sgi_error_code(enum elf_sgi_error_type val)
{
switch (val) {
case ELF_SGI_ERROR_OK:
return DW_DLE_NE;
case ELF_SGI_ERROR_BAD_ALLOC:
return DW_DLE_MAF;
case ELF_SGI_ERROR_FORMAT:
return DW_DLE_MDE;
case ELF_SGI_ERROR_ERRNO:
return DW_DLE_IOF;
case ELF_SGI_ERROR_TOO_BIG:
return DW_DLE_MOF;
default:
return DW_DLE_LEE;
}
}
#endif
static int
_dwarf_setup(Dwarf_Debug dbg, dwarf_elf_handle elf, Dwarf_Error * error)
{
#ifdef __SGI_FAST_LIBELF
Elf64_Ehdr ehdr;
Elf64_Shdr shdr;
enum elf_sgi_error_type sres;
unsigned char const *ehdr_ident;
#else
Elf32_Ehdr *ehdr32;
#ifdef HAVE_ELF64_GETEHDR
Elf64_Ehdr *ehdr64;
#endif
Elf32_Shdr *shdr32;
#ifdef HAVE_ELF64_GETSHDR
Elf64_Shdr *shdr64;
#endif
Elf_Scn *scn;
char *ehdr_ident;
#endif
Dwarf_Half machine;
char *scn_name;
int is_64bit;
int foundDwarf;
Dwarf_Unsigned section_size;
Dwarf_Unsigned section_count;
Dwarf_Half section_index;
foundDwarf = FALSE;
dbg->de_elf = elf;
dbg->de_assume_string_in_bounds = _dwarf_assume_string_bad;
#ifdef __SGI_FAST_LIBELF
sres = elf_sgi_ehdr(elf, &ehdr);
if (sres != ELF_SGI_ERROR_OK) {
DWARF_DBG_ERROR(dbg,
_dwarf_error_code_from_elf_sgi_error_code(sres),
DW_DLV_ERROR);
}
ehdr_ident = ehdr.e_ident;
section_count = ehdr.e_shnum;
machine = ehdr.e_machine;
#else
if ((ehdr_ident = elf_getident(elf, NULL)) == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_ELF_GETIDENT_ERROR, DW_DLV_ERROR);
}
#endif
is_64bit = (ehdr_ident[EI_CLASS] == ELFCLASS64);
dbg->de_same_endian = 1;
dbg->de_copy_word = memcpy;
#ifdef WORDS_BIGENDIAN
dbg->de_big_endian_object = 1;
if (ehdr_ident[EI_DATA] == ELFDATA2LSB) {
dbg->de_same_endian = 0;
dbg->de_big_endian_object = 0;
dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
}
#else
dbg->de_big_endian_object = 0;
if (ehdr_ident[EI_DATA] == ELFDATA2MSB) {
dbg->de_same_endian = 0;
dbg->de_big_endian_object = 1;
dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
}
#endif
dbg->de_length_size = is_64bit ? 8 : 4;
dbg->de_pointer_size = is_64bit ? 8 : 4;
#ifdef __SGI_FAST_LIBELF
#else
#ifdef HAVE_ELF64_GETEHDR
if (is_64bit) {
ehdr64 = elf64_getehdr(elf);
if (ehdr64 == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_ELF_GETEHDR_ERROR,
DW_DLV_ERROR);
}
section_count = ehdr64->e_shnum;
machine = ehdr64->e_machine;
} else
#endif
{
ehdr32 = elf32_getehdr(elf);
if (ehdr32 == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_ELF_GETEHDR_ERROR,
DW_DLV_ERROR);
}
section_count = ehdr32->e_shnum;
machine = ehdr32->e_machine;
}
#endif
if (is_64bit && machine != EM_MIPS) {
dbg->de_length_size = 4;
}
for (section_index = 1; section_index < section_count;
++section_index) {
#ifdef __SGI_FAST_LIBELF
sres = elf_sgi_shdr(elf, section_index, &shdr);
if (sres != ELF_SGI_ERROR_OK) {
DWARF_DBG_ERROR(dbg,
_dwarf_error_code_from_elf_sgi_error_code
(sres), DW_DLV_ERROR);
}
section_size = shdr.sh_size;
sres =
elf_sgi_string(elf, ehdr.e_shstrndx, shdr.sh_name,
(char const **) &scn_name);
if (sres != ELF_SGI_ERROR_OK) {
DWARF_DBG_ERROR(dbg,
_dwarf_error_code_from_elf_sgi_error_code
(sres), DW_DLV_ERROR);
}
#else
scn = elf_getscn(elf, section_index);
if (scn == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_MDE, DW_DLV_ERROR);
}
#ifdef HAVE_ELF64_GETSHDR
if (is_64bit) {
shdr64 = elf64_getshdr(scn);
if (shdr64 == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_ELF_GETSHDR_ERROR,
DW_DLV_ERROR);
}
section_size = shdr64->sh_size;
if ((scn_name = elf_strptr(elf, ehdr64->e_shstrndx,
shdr64->sh_name))
== NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_ELF_STRPTR_ERROR,
DW_DLV_ERROR);
}
} else
#endif
{
if ((shdr32 = elf32_getshdr(scn)) == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_ELF_GETSHDR_ERROR, 0);
}
section_size = shdr32->sh_size;
if ((scn_name = elf_strptr(elf, ehdr32->e_shstrndx,
shdr32->sh_name)) == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_ELF_STRPTR_ERROR,
DW_DLV_ERROR);
}
}
#endif
if (strncmp(scn_name, ".debug_", 7)
&& strcmp(scn_name, ".eh_frame")
)
continue;
else if (strcmp(scn_name, ".debug_info") == 0) {
if (dbg->de_debug_info != NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_DEBUG_INFO_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
DWARF_DBG_ERROR(dbg, DW_DLE_DEBUG_INFO_NULL,
DW_DLV_ERROR);
}
foundDwarf = TRUE;
dbg->de_debug_info_index = section_index;
dbg->de_debug_info_size = section_size;
}
else if (strcmp(scn_name, ".debug_abbrev") == 0) {
if (dbg->de_debug_abbrev != NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_DEBUG_ABBREV_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
DWARF_DBG_ERROR(dbg, DW_DLE_DEBUG_ABBREV_NULL,
DW_DLV_ERROR);
}
dbg->de_debug_abbrev_index = section_index;
dbg->de_debug_abbrev_size = section_size;
}
else if (strcmp(scn_name, ".debug_aranges") == 0) {
if (dbg->de_debug_aranges_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_ARANGES_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_aranges_index = section_index;
dbg->de_debug_aranges_size = section_size;
}
else if (strcmp(scn_name, ".debug_line") == 0) {
if (dbg->de_debug_line_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_LINE_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_line_index = section_index;
dbg->de_debug_line_size = section_size;
}
else if (strcmp(scn_name, ".debug_frame") == 0) {
if (dbg->de_debug_frame_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_FRAME_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_frame_index = section_index;
dbg->de_debug_frame_size = section_size;
foundDwarf = TRUE;
} else if (strcmp(scn_name, ".eh_frame") == 0) {
if (dbg->de_debug_frame_eh_gnu_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_FRAME_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_frame_eh_gnu_index = section_index;
dbg->de_debug_frame_size_eh_gnu = section_size;
foundDwarf = TRUE;
}
else if (strcmp(scn_name, ".debug_loc") == 0) {
if (dbg->de_debug_loc_index != 0) {
DWARF_DBG_ERROR(dbg, DW_DLE_DEBUG_LOC_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_loc_index = section_index;
dbg->de_debug_loc_size = section_size;
}
else if (strcmp(scn_name, ".debug_pubnames") == 0) {
if (dbg->de_debug_pubnames_index != 0) {
DWARF_DBG_ERROR(dbg, DW_DLE_DEBUG_PUBNAMES_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_pubnames_index = section_index;
dbg->de_debug_pubnames_size = section_size;
}
else if (strcmp(scn_name, ".debug_str") == 0) {
if (dbg->de_debug_str_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_STR_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_str_index = section_index;
dbg->de_debug_str_size = section_size;
}
else if (strcmp(scn_name, ".debug_funcnames") == 0) {
if (dbg->de_debug_funcnames_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_FUNCNAMES_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_funcnames_index = section_index;
dbg->de_debug_funcnames_size = section_size;
}
else if (strcmp(scn_name, ".debug_typenames") == 0) {
if (dbg->de_debug_typenames_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_TYPENAMES_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_typenames_index = section_index;
dbg->de_debug_typenames_size = section_size;
} else if (strcmp(scn_name, ".debug_pubtypes") == 0) {
if (dbg->de_debug_pubtypes_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_PUBTYPES_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_pubtypes_index = section_index;
dbg->de_debug_pubtypes_size = section_size;
}
else if (strcmp(scn_name, ".debug_varnames") == 0) {
if (dbg->de_debug_varnames_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_VARNAMES_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_varnames_index = section_index;
dbg->de_debug_varnames_size = section_size;
}
else if (strcmp(scn_name, ".debug_weaknames") == 0) {
if (dbg->de_debug_weaknames_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_WEAKNAMES_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_weaknames_index = section_index;
dbg->de_debug_weaknames_size = section_size;
} else if (strcmp(scn_name, ".debug_macinfo") == 0) {
if (dbg->de_debug_macinfo_index != 0) {
DWARF_DBG_ERROR(dbg,
DW_DLE_DEBUG_MACINFO_DUPLICATE,
DW_DLV_ERROR);
}
if (section_size == 0) {
continue;
}
dbg->de_debug_macinfo_index = section_index;
dbg->de_debug_macinfo_size = section_size;
}
}
if (foundDwarf) {
return DW_DLV_OK;
}
return (DW_DLV_NO_ENTRY);
}
int
dwarf_init(int fd,
Dwarf_Unsigned access,
Dwarf_Handler errhand,
Dwarf_Ptr errarg, Dwarf_Debug * ret_dbg, Dwarf_Error * error)
{
Dwarf_Debug dbg;
struct stat fstat_buf;
dwarf_elf_handle elf;
int res;
#ifdef __SGI_FAST_LIBELF
enum elf_sgi_error_type sres;
#else
Elf_Cmd what_kind_of_elf_read;
#endif
dbg = _dwarf_get_debug();
if (dbg == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR);
}
dbg->de_errhand = errhand;
dbg->de_errarg = errarg;
dbg->de_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE;
dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM;
if (fstat(fd, &fstat_buf) != 0) {
DWARF_DBG_ERROR(dbg, DW_DLE_FSTAT_ERROR, DW_DLV_ERROR);
}
if (!S_ISREG(fstat_buf.st_mode)) {
DWARF_DBG_ERROR(dbg, DW_DLE_FSTAT_MODE_ERROR, DW_DLV_ERROR);
}
if (access != DW_DLC_READ) {
DWARF_DBG_ERROR(dbg, DW_DLE_INIT_ACCESS_WRONG, DW_DLV_ERROR);
}
dbg->de_access = access;
#ifdef __SGI_FAST_LIBELF
elf = elf_sgi_new();
if (elf == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_MAF, DW_DLV_ERROR);
}
sres = elf_sgi_begin_fd(elf, fd, 0);
if (sres != ELF_SGI_ERROR_OK) {
elf_sgi_free(elf);
DWARF_DBG_ERROR(dbg,
_dwarf_error_code_from_elf_sgi_error_code(sres),
DW_DLV_ERROR);
}
#else
elf_version(EV_CURRENT);
#ifdef HAVE_ELF_C_READ_MMAP
what_kind_of_elf_read = ELF_C_READ_MMAP;
#else
what_kind_of_elf_read = ELF_C_READ;
#endif
if ((elf = elf_begin(fd, what_kind_of_elf_read, 0)) == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_ELF_BEGIN_ERROR, DW_DLV_ERROR);
}
#endif
dbg->de_elf_must_close = 1;
if ((res = _dwarf_setup(dbg, elf, error)) != DW_DLV_OK) {
#ifdef __SGI_FAST_LIBELF
elf_sgi_free(elf);
#else
elf_end(elf);
#endif
free(dbg);
return (res);
}
_dwarf_setup_debug(dbg);
*ret_dbg = dbg;
return (DW_DLV_OK);
}
int
dwarf_elf_init(dwarf_elf_handle elf_file_pointer,
Dwarf_Unsigned access,
Dwarf_Handler errhand,
Dwarf_Ptr errarg,
Dwarf_Debug * ret_dbg, Dwarf_Error * error)
{
Dwarf_Debug dbg;
int res;
dbg = _dwarf_get_debug();
if (dbg == NULL) {
DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR);
}
dbg->de_errhand = errhand;
dbg->de_errarg = errarg;
dbg->de_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE;
dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM;
if (access != DW_DLC_READ) {
DWARF_DBG_ERROR(dbg, DW_DLE_INIT_ACCESS_WRONG, DW_DLV_ERROR);
}
dbg->de_access = access;
dbg->de_elf_must_close = 0;
if ((res = _dwarf_setup(dbg, elf_file_pointer, error)) != DW_DLV_OK) {
free(dbg);
return (res);
}
_dwarf_setup_debug(dbg);
*ret_dbg = dbg;
return (DW_DLV_OK);
}
int
dwarf_finish(Dwarf_Debug dbg, Dwarf_Error * error)
{
int res = DW_DLV_OK;
if (dbg->de_elf_must_close) {
#ifdef __SGI_FAST_LIBELF
elf_sgi_free(dbg->de_elf);
#else
elf_end(dbg->de_elf);
#endif
}
res = _dwarf_free_all_of_one_debug(dbg);
if (res == DW_DLV_ERROR) {
DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR);
}
dwarf_malloc_check_complete("After Final free");
return res;
}
int
dwarf_get_elf(Dwarf_Debug dbg, dwarf_elf_handle * elf,
Dwarf_Error * error)
{
if (dbg == NULL) {
_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
return (DW_DLV_ERROR);
}
*elf = dbg->de_elf;
return (DW_DLV_OK);
}
int
_dwarf_load_section(Dwarf_Debug dbg,
Dwarf_Half section_index,
Dwarf_Small ** section_data, Dwarf_Error * error)
{
if (section_index == 0) {
return DW_DLV_NO_ENTRY;
}
if (*section_data != NULL) {
return DW_DLV_OK;
}
{
#ifdef __SGI_FAST_LIBELF
enum elf_sgi_error_type sres;
sres = elf_sgi_section(dbg->de_elf,
section_index, (void **) section_data);
if (sres != ELF_SGI_ERROR_OK) {
DWARF_DBG_ERROR(dbg,
_dwarf_error_code_from_elf_sgi_error_code
(sres), DW_DLV_ERROR);
}
#else
Elf_Scn *scn;
Elf_Data *data;
scn = elf_getscn(dbg->de_elf, section_index);
if (scn == NULL) {
_dwarf_error(dbg, error, DW_DLE_MDE);
return DW_DLV_ERROR;
}
data = elf_getdata(scn, NULL);
if (data == NULL) {
_dwarf_error(dbg, error, DW_DLE_MDE);
return DW_DLV_ERROR;
}
*section_data = data->d_buf;
#endif
}
return DW_DLV_OK;
}
int
dwarf_get_section_max_offsets(Dwarf_Debug dbg,
Dwarf_Unsigned * debug_info_size,
Dwarf_Unsigned * debug_abbrev_size,
Dwarf_Unsigned * debug_line_size,
Dwarf_Unsigned * debug_loc_size,
Dwarf_Unsigned * debug_aranges_size,
Dwarf_Unsigned * debug_macinfo_size,
Dwarf_Unsigned * debug_pubnames_size,
Dwarf_Unsigned * debug_str_size,
Dwarf_Unsigned * debug_frame_size,
Dwarf_Unsigned * debug_ranges_size,
Dwarf_Unsigned * debug_typenames_size)
{
*debug_info_size = dbg->de_debug_info_size;
*debug_abbrev_size = dbg->de_debug_abbrev_size;
*debug_line_size = dbg->de_debug_line_size;
*debug_loc_size = dbg->de_debug_loc_size;
*debug_aranges_size = dbg->de_debug_aranges_size;
*debug_macinfo_size = dbg->de_debug_macinfo_size;
*debug_pubnames_size = dbg->de_debug_pubnames_size;
*debug_str_size = dbg->de_debug_str_size;
*debug_frame_size = dbg->de_debug_frame_size;
*debug_ranges_size = 0;
*debug_typenames_size = dbg->de_debug_typenames_size;
return DW_DLV_OK;
}