1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-09-27 17:09:29 +02:00

(struct ia64_table_entry): New type (moved from unwind_i.h).

(lookup): New function (moved from parser.c).
(_Uia64_search_unwind_table): New function (based on code in parser.c).
(kernel_table): New variable.
(get_kernel_table): Relocate the kernel table's "info_offset" values as we
	count it.  Adjust for new callback-interface.
(callback): Adjust for new interface.
(_Uia64_find_proc_info): Rename from _Uia64_glibc_acquire_unwind_info).

}(Logical change 1.29)
This commit is contained in:
mostang.com!davidm 2002-12-03 08:19:58 +00:00
parent 42fdeb430b
commit 22c1128cf7

View file

@ -1,186 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
This file is based on gcc/config/ia64/fde-glibc.c, which is copyright
by:
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@cygnus.com>. */
#ifndef UNW_REMOTE_ONLY
#include <link.h>
#include <stddef.h>
#include <stdlib.h>
#include "unwind_i.h"
#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \
|| (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG))
# error You need GLIBC 2.2.4 or later on IA-64 Linux
#endif
#ifdef HAVE_GETUNWIND
extern unsigned long getunwind (void *buf, size_t len);
#else /* HAVE_GETUNWIND */
/* XXX fix me */
#include <unistd.h>
#include <sys/syscall.h>
# ifndef __NR_getunwind
# define __NR_getunwind 1215
# endif
static unsigned long
getunwind (void *buf, size_t len)
{
return syscall (SYS_getunwind, buf, len);
}
#endif /* HAVE_GETUNWIND */
static int
get_kernel_table (void *ptr)
{
struct ia64_unwind_table_entry *ktab, *etab;
unw_ia64_table_t *info = ptr;
size_t size;
debug (100, "unwind: checking kernel unwind table");
size = getunwind (NULL, 0);
ktab = sos_alloc (size);
if (!ktab)
{
dprintf (__FILE__".%s: failed to allocate %Zu bytes",
__FUNCTION__, size);
return -UNW_ENOMEM;
}
getunwind (ktab, size);
/* Determine length of kernel's unwind table. */
for (etab = ktab; etab->start_offset; ++etab);
if (info->segbase < ktab[0].start_offset
|| info->segbase >= etab[-1].end_offset)
{
sos_free (ktab);
return -1;
}
info->name = "<kernel>";
info->gp = 0;
info->segbase = 0;
info->start = ktab[0].start_offset;
info->end = etab[-1].end_offset;
info->length = etab - ktab;
info->array = ktab;
info->unwind_info_base = (const u_int8_t *) ktab;
debug (100, "unwind: found table `%s': segbase=%lx, length=%lu, gp=%lx\n",
info->name, info->segbase, info->length, info->gp);
return 0;
}
static int
callback (struct dl_phdr_info *info, size_t size, void *ptr)
{
unw_ia64_table_t *data = ptr;
const Elf64_Phdr *phdr, *p_unwind, *p_dynamic, *p_text;
long n;
Elf64_Addr load_base;
/* Make sure struct dl_phdr_info is at least as big as we need. */
if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
+ sizeof (info->dlpi_phnum))
return -1;
debug (100, "unwind: checking `%s'\n", info->dlpi_name);
phdr = info->dlpi_phdr;
load_base = info->dlpi_addr;
p_text = NULL;
p_unwind = NULL;
p_dynamic = NULL;
/* See if PC falls into one of the loaded segments. Find the unwind
segment at the same time. */
for (n = info->dlpi_phnum; --n >= 0; phdr++)
{
if (phdr->p_type == PT_LOAD)
{
Elf64_Addr vaddr = phdr->p_vaddr + load_base;
if (data->segbase >= vaddr && data->segbase < vaddr + phdr->p_memsz)
p_text = phdr;
}
else if (phdr->p_type == PT_IA_64_UNWIND)
p_unwind = phdr;
else if (phdr->p_type == PT_DYNAMIC)
p_dynamic = phdr;
}
if (!p_text || !p_unwind)
return 0;
if (p_dynamic)
{
/* For dynamicly linked executables and shared libraries,
DT_PLTGOT is the gp value for that object. */
Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base);
for (; dyn->d_tag != DT_NULL ; dyn++)
if (dyn->d_tag == DT_PLTGOT)
{
/* On IA-64, _DYNAMIC is writable and GLIBC has relocated it. */
data->gp = dyn->d_un.d_ptr;
break;
}
}
else
{
/* Otherwise this is a static executable with no _DYNAMIC.
The gp is constant program-wide. */
register unsigned long gp __asm__("gp");
data->gp = gp;
}
data->name = info->dlpi_name;
data->array
= (struct ia64_unwind_table_entry *) (p_unwind->p_vaddr + load_base);
data->length = p_unwind->p_memsz / sizeof (struct ia64_unwind_table_entry);
data->segbase = p_text->p_vaddr + load_base;
data->start = p_text->p_vaddr + load_base;
data->end = p_text->p_vaddr + load_base + p_text->p_memsz;
data->unwind_info_base = (const u_int8_t *) data->segbase;
debug (100, "unwind: found table `%s': segbase=%lx, length=%lu, gp=%lx, "
"array=%p\n", data->name, data->segbase, data->length, data->gp,
data->array);
return 1;
}
int
_Uia64_glibc_acquire_unwind_info (unw_word_t ip, void *info, void *arg)
{
((unw_ia64_table_t *) info)->segbase = ip; /* this is cheap... */
if (dl_iterate_phdr (callback, info) > 0)
return 0;
return get_kernel_table (info);
}
int
_Uia64_glibc_release_unwind_info (void *info, void *arg)
{
/* nothing to do */
return 0;
}
#endif /* !UNW_REMOTE_ONLY */