1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-12-27 21:43:42 +01:00
}(Logical change 1.162)
This commit is contained in:
hp.com!davidm 2004-01-30 00:01:24 +00:00
parent a758c420e1
commit 410f962b8d
12 changed files with 0 additions and 1275 deletions

View file

@ -1,326 +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.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdlib.h>
#include "internal.h"
#include "tdep.h"
static void
free_regions (unw_dyn_region_info_t *region)
{
if (region->next)
free_regions (region->next);
free (region);
}
static int
intern_op (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_dyn_op_t *op, void *arg)
{
int ret;
if ((ret = fetch8 (as, a, addr, &op->tag, arg)) < 0
|| (ret = fetch8 (as, a, addr, &op->qp, arg)) < 0
|| (ret = fetch16 (as, a, addr, &op->reg, arg)) < 0
|| (ret = fetch32 (as, a, addr, &op->when, arg)) < 0
|| (ret = fetchw (as, a, addr, &op->val, arg)) < 0)
return ret;
return 0;
}
static int
intern_regions (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unw_dyn_region_info_t **regionp, void *arg)
{
uint32_t insn_count, op_count, i;
unw_dyn_region_info_t *region;
unw_word_t next_addr;
int ret;
*regionp = NULL;
if (!*addr)
return 0; /* NULL region-list */
if ((ret = fetchw (as, a, addr, &next_addr, arg)) < 0
|| (ret = fetch32 (as, a, addr, (int32_t *) &insn_count, arg)) < 0
|| (ret = fetch32 (as, a, addr, (int32_t *) &op_count, arg)) < 0)
return ret;
region = calloc (1, _U_dyn_region_info_size (op_count));
if (!region)
{
ret = -UNW_ENOMEM;
goto out;
}
region->insn_count = insn_count;
region->op_count = op_count;
for (i = 0; i < op_count; ++i)
if ((ret = intern_op (as, a, addr, region->op + i, arg)) < 0)
goto out;
if (next_addr)
if ((ret = intern_regions (as, a, &next_addr, &region->next, arg)) < 0)
goto out;
*regionp = region;
return 0;
out:
if (region)
free_regions (region);
return ret;
}
static int
intern_array (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unw_word_t table_len, unw_word_t **table_data,
void *arg)
{
unw_word_t i, *data = calloc (table_len, WSIZE);
int ret = 0;
if (!data)
{
ret = -UNW_ENOMEM;
goto out;
}
for (i = 0; i < table_len; ++i)
if (fetchw (as, a, addr, data + i, arg) < 0)
goto out;
*table_data = data;
return 0;
out:
if (data)
free (data);
return ret;
}
static void
free_dyn_info (unw_dyn_info_t *di)
{
switch (di->format)
{
case UNW_INFO_FORMAT_DYNAMIC:
if (di->u.pi.regions)
{
free_regions (di->u.pi.regions);
di->u.pi.regions = NULL;
}
break;
case UNW_INFO_FORMAT_TABLE:
if (di->u.ti.table_data)
{
free (di->u.ti.table_data);
di->u.ti.table_data = NULL;
}
break;
case UNW_INFO_FORMAT_REMOTE_TABLE:
default:
break;
}
}
static int
intern_dyn_info (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unw_dyn_info_t *di, void *arg)
{
unw_word_t first_region;
int ret;
switch (di->format)
{
case UNW_INFO_FORMAT_DYNAMIC:
if ((ret = fetchw (as, a, addr, &di->u.pi.name_ptr, arg)) < 0
|| (ret = fetchw (as, a, addr, &di->u.pi.handler, arg)) < 0
|| (ret = fetch32 (as, a, addr,
(int32_t *) &di->u.pi.flags, arg)) < 0)
goto out;
*addr += 4; /* skip over pad0 */
if ((ret = fetchw (as, a, addr, &first_region, arg)) < 0
|| (ret = intern_regions (as, a, &first_region, &di->u.pi.regions,
arg)) < 0)
goto out;
break;
case UNW_INFO_FORMAT_TABLE:
if ((ret = fetchw (as, a, addr, &di->u.ti.name_ptr, arg)) < 0
|| (ret = fetchw (as, a, addr, &di->u.ti.segbase, arg)) < 0
|| (ret = fetchw (as, a, addr, &di->u.ti.table_len, arg)) < 0
|| (ret = intern_array (as, a, addr, di->u.ti.table_len,
&di->u.ti.table_data, arg)) < 0)
goto out;
break;
case UNW_INFO_FORMAT_REMOTE_TABLE:
if ((ret = fetchw (as, a, addr, &di->u.rti.name_ptr, arg)) < 0
|| (ret = fetchw (as, a, addr, &di->u.rti.segbase, arg)) < 0
|| (ret = fetchw (as, a, addr, &di->u.rti.table_len, arg)) < 0
|| (ret = fetchw (as, a, addr, &di->u.rti.table_data, arg)) < 0)
goto out;
break;
default:
ret = -UNW_ENOINFO;
goto out;
}
return 0;
out:
free_dyn_info (di);
return ret;
}
HIDDEN int
unwi_dyn_remote_find_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi,
int need_unwind_info, void *arg)
{
unw_accessors_t *a = unw_get_accessors (as);
unw_word_t dyn_list_addr, addr, next_addr, gen1, gen2, start_ip, end_ip;
unw_dyn_info_t *di = NULL;
int ret;
if (as->dyn_info_list_addr)
dyn_list_addr = as->dyn_info_list_addr;
else
{
if ((*a->get_dyn_info_list_addr) (as, &dyn_list_addr, arg) < 0)
return -UNW_ENOINFO;
if (as->caching_policy != UNW_CACHE_NONE)
as->dyn_info_list_addr = dyn_list_addr;
}
do
{
addr = dyn_list_addr;
ret = -UNW_ENOINFO;
if (fetchw (as, a, &addr, &gen1, arg) < 0
|| fetchw (as, a, &addr, &next_addr, arg) < 0)
return ret;
for (addr = next_addr; addr != 0; addr = next_addr)
{
if (fetchw (as, a, &addr, &next_addr, arg) < 0)
goto recheck; /* only fail if generation # didn't change */
addr += WSIZE; /* skip over prev_addr */
if (fetchw (as, a, &addr, &start_ip, arg) < 0
|| fetchw (as, a, &addr, &end_ip, arg) < 0)
goto recheck; /* only fail if generation # didn't change */
if (ip >= start_ip && ip < end_ip)
{
if (!di)
di = calloc (1, sizeof (*di));
di->start_ip = start_ip;
di->end_ip = end_ip;
if (fetchw (as, a, &addr, &di->gp, arg) < 0
|| fetch32 (as, a, &addr, &di->format, arg) < 0)
goto recheck; /* only fail if generation # didn't change */
addr += 4; /* skip over padding */
if (need_unwind_info
&& intern_dyn_info (as, a, &addr, di, arg) < 0)
goto recheck; /* only fail if generation # didn't change */
if (unwi_extract_dynamic_proc_info (as, ip, pi, di,
need_unwind_info, arg) < 0)
{
free_dyn_info (di);
goto recheck; /* only fail if generation # didn't change */
}
ret = 0; /* OK, found it */
break;
}
}
/* Re-check generation number to ensure the data we have is
consistent. */
recheck:
addr = dyn_list_addr;
if (fetchw (as, a, &addr, &gen2, arg) < 0)
return ret;
}
while (gen1 != gen2);
if (ret < 0 && di)
free (di);
return ret;
}
HIDDEN void
unwi_dyn_remote_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi,
void *arg)
{
if (!pi->unwind_info)
return;
free_dyn_info (pi->unwind_info);
free (pi->unwind_info);
pi->unwind_info = NULL;
}
/* Returns 1 if the cache is up-to-date or -1 if the cache contained
stale data and had to be flushed. */
HIDDEN int
unwi_dyn_validate_cache (unw_addr_space_t as, void *arg)
{
unw_word_t addr, gen;
unw_accessors_t *a;
if (!as->dyn_info_list_addr)
/* If we don't have the dyn_info_list_addr, we don't have anything
in the cache. */
return 0;
a = unw_get_accessors (as);
addr = as->dyn_info_list_addr;
if (fetchw (as, a, &addr, &gen, arg) < 0)
return 1;
if (gen == as->dyn_generation)
return 1;
unw_flush_cache (as, 0, 0);
as->dyn_generation = gen;
return -1;
}

View file

@ -1,95 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "internal.h"
static inline int
intern_string (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t addr, char *buf, size_t buf_len, void *arg)
{
size_t i;
int ret;
for (i = 0; i < buf_len; ++i)
{
if ((ret = fetch8 (as, a, &addr, buf + i, arg)) < 0)
return ret;
if (buf[i] == '\0')
return 0; /* copied full string; return success */
}
buf[buf_len - 1] = '\0'; /* ensure string is NUL terminated */
return -UNW_ENOMEM;
}
HIDDEN int
unwi_get_proc_name (unw_addr_space_t as, unw_word_t ip,
char *buf, size_t buf_len, unw_word_t *offp, void *arg)
{
unw_accessors_t *a = unw_get_accessors (as);
unw_proc_info_t pi;
int ret;
buf[0] = '\0'; /* always return a valid string, even if it's empty */
ret = unwi_find_dynamic_proc_info (as, ip, &pi, 1, arg);
if (ret == 0)
{
unw_dyn_info_t *di = pi.unwind_info;
if (offp)
*offp = ip - pi.start_ip;
switch (di->format)
{
case UNW_INFO_FORMAT_DYNAMIC:
ret = intern_string (as, a, di->u.pi.name_ptr, buf, buf_len, arg);
break;
case UNW_INFO_FORMAT_TABLE:
case UNW_INFO_FORMAT_REMOTE_TABLE:
/* XXX should we create a fake name, e.g.: "tablenameN",
where N is the index of the function in the table??? */
ret = -UNW_ENOINFO;
break;
default:
ret = -UNW_EINVAL;
break;
}
unwi_put_dynamic_unwind_info (as, &pi, arg);
return ret;
}
if (ret != -UNW_ENOINFO)
return ret;
/* not a dynamic procedure, try to lookup static procedure name: */
if (a->get_proc_name)
return (*a->get_proc_name) (as, ip, buf, buf_len, offp, arg);
return -UNW_ENOINFO;
}

View file

@ -1,61 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "_UPT_internal.h"
int
_UPT_access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
int write, void *arg)
{
struct UPT_info *ui = arg;
pid_t pid = ui->pid;
errno = 0;
if (write)
{
debug (100, "%s: mem[%lx] <- %lx\n", __FUNCTION__,
(long) addr, (long) *val);
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
ptrace (PTRACE_POKEDATA, pid, addr, *val);
if (errno)
return -UNW_EINVAL;
#endif
}
else
{
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
*val = ptrace (PTRACE_PEEKDATA, pid, addr, 0);
if (errno)
return -UNW_EINVAL;
#endif
debug (100, "%s: mem[%lx] -> %lx\n", __FUNCTION__,
(long) addr, (long) *val);
}
return 0;
}

View file

@ -1,253 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "_UPT_internal.h"
#if UNW_TARGET_IA64
# include <elf.h>
# ifdef HAVE_ASM_PTRACE_OFFSETS_H
# include <asm/ptrace_offsets.h>
# endif
# include "ia64/rse.h"
#endif
int
_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
int write, void *arg)
{
struct UPT_info *ui = arg;
pid_t pid = ui->pid;
#if UNW_DEBUG
if (write)
debug (100, "%s: %s <- %lx\n",
__FUNCTION__, unw_regname (reg), (long) *val);
#endif
#if UNW_TARGET_IA64
if ((unsigned) reg - UNW_IA64_NAT < 32)
{
unsigned long nat_bits, mask;
/* The Linux ptrace represents the statc NaT bits as a single word. */
mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT);
errno = 0;
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
nat_bits = ptrace (PTRACE_PEEKUSER, pid, PT_NAT_BITS, 0);
if (errno)
goto badreg;
#endif
if (write)
{
if (*val)
nat_bits |= mask;
else
nat_bits &= ~mask;
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
ptrace (PTRACE_POKEUSER, pid, PT_NAT_BITS, nat_bits);
if (errno)
goto badreg;
#endif
}
goto out;
}
else
switch (reg)
{
case UNW_IA64_GR + 0:
if (write)
goto badreg;
*val = 0;
return 0;
case UNW_REG_IP:
{
unsigned long ip, psr;
/* distribute bundle-addr. & slot-number across PT_IIP & PT_IPSR. */
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
psr = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IPSR, 0);
if (errno)
goto badreg;
#endif
if (write)
{
ip = *val & ~0xfUL;
psr = (psr & ~0x3UL << 41) | (*val & 0x3);
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
ptrace (PTRACE_POKEUSER, pid, PT_CR_IIP, ip);
ptrace (PTRACE_POKEUSER, pid, PT_CR_IPSR, psr);
if (errno)
goto badreg;
#endif
}
else
{
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
ip = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IIP, 0);
if (errno)
goto badreg;
#endif
*val = ip + ((psr >> 41) & 0x3);
}
goto out;
}
case UNW_IA64_AR_BSPSTORE:
reg = UNW_IA64_AR_BSP;
break;
case UNW_IA64_AR_BSP:
case UNW_IA64_BSP:
{
unsigned long sof, cfm, bsp;
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
/* Account for the fact that ptrace() expects bsp to point
_after_ the current register frame. */
errno = 0;
cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0);
if (errno)
goto badreg;
#endif
sof = (cfm & 0x7f);
if (write)
{
bsp = ia64_rse_skip_regs (*val, sof);
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, bsp);
if (errno)
goto badreg;
#endif
}
else
{
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0);
if (errno)
goto badreg;
#endif
*val = ia64_rse_skip_regs (bsp, -sof);
}
goto out;
}
case UNW_IA64_CFM:
/* If we change CFM, we need to adjust ptrace's notion of bsp
accordingly, so that the real bsp remains unchanged. */
if (write)
{
unsigned long new_sof, old_sof, cfm, bsp;
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0);
cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0);
#endif
if (errno)
goto badreg;
old_sof = (cfm & 0x7f);
new_sof = (*val & 0x7f);
if (old_sof != new_sof)
{
bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, 0);
if (errno)
goto badreg;
#endif
}
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
ptrace (PTRACE_POKEUSER, pid, PT_CFM, *val);
if (errno)
goto badreg;
#endif
goto out;
}
break;
}
#endif
if ((unsigned) reg >= sizeof (_UPT_reg_offset) / sizeof (_UPT_reg_offset[0]))
goto badreg;
#ifdef HAVE_TTRACE
# warning No support for ttrace() yet.
#else
errno = 0;
if (write)
ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg], *val);
else
*val = ptrace (PTRACE_PEEKUSER, pid, _UPT_reg_offset[reg], 0);
if (errno)
goto badreg;
#endif
#ifdef UNW_TARGET_IA64
out:
#endif
#if UNW_DEBUG
if (!write)
debug (100, "%s: %s -> %lx\n",
__FUNCTION__, unw_regname (reg), (long) *val);
#endif
return 0;
badreg:
debug (1, "%s: bad register number %u\n", __FUNCTION__, reg);
return -UNW_EBADREG;
}

View file

@ -1,238 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <elf.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include "_UPT_internal.h"
#if UNW_TARGET_IA64
#include "elf64.h"
static unw_word_t
find_gp (struct UPT_info *ui, Elf64_Phdr *pdyn, Elf64_Addr load_base)
{
Elf64_Off soff, str_soff;
Elf64_Ehdr *ehdr = ui->ei.image;
Elf64_Shdr *shdr;
Elf64_Shdr *str_shdr;
Elf64_Addr gp = 0;
char *strtab;
int i;
if (pdyn)
{
/* If we have a PT_DYNAMIC program header, fetch the gp-value
from the DT_PLTGOT entry. */
Elf64_Dyn *dyn = (Elf64_Dyn *) (pdyn->p_offset + (char *) ui->ei.image);
for (; dyn->d_tag != DT_NULL; ++dyn)
if (dyn->d_tag == DT_PLTGOT)
{
gp = (Elf64_Addr) dyn->d_un.d_ptr + load_base;
goto done;
}
}
/* Without a PT_DYAMIC header, lets try to look for a non-empty .opd
section. If there is such a section, we know it's full of
function descriptors, and we can simply pick up the gp from the
second word of the first entry in this table. */
soff = ehdr->e_shoff;
str_soff = soff + (ehdr->e_shstrndx * ehdr->e_shentsize);
if (soff + ehdr->e_shnum * ehdr->e_shentsize > ui->ei.size)
{
debug (1, "%s: section table outside of image? (%lu > %lu)",
__FUNCTION__, soff + ehdr->e_shnum * ehdr->e_shentsize,
ui->ei.size);
goto done;
}
shdr = (Elf64_Shdr *) ((char *) ui->ei.image + soff);
str_shdr = (Elf64_Shdr *) ((char *) ui->ei.image + str_soff);
strtab = (char *) ui->ei.image + str_shdr->sh_offset;
for (i = 0; i < ehdr->e_shnum; ++i)
{
if (strcmp (strtab + shdr->sh_name, ".opd") == 0
&& shdr->sh_size >= 16)
{
gp = ((Elf64_Addr *) ((char *) ui->ei.image + shdr->sh_offset))[1];
goto done;
}
shdr = (Elf64_Shdr *) (((char *) shdr) + ehdr->e_shentsize);
}
done:
debug (100, "%s: image at %p, gp = %lx\n", __FUNCTION__, ui->ei.image, gp);
return gp;
}
HIDDEN unw_dyn_info_t *
_UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
char *path, unw_word_t segbase, unw_word_t mapoff)
{
Elf64_Phdr *phdr, *ptxt = NULL, *punw = NULL, *pdyn = NULL;
Elf64_Ehdr *ehdr;
int i;
if (!_Uelf64_valid_object (&ui->ei))
return NULL;
ehdr = ui->ei.image;
phdr = (Elf64_Phdr *) ((char *) ui->ei.image + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; ++i)
{
switch (phdr[i].p_type)
{
case PT_LOAD:
if (phdr[i].p_offset == mapoff)
ptxt = phdr + i;
break;
case PT_IA_64_UNWIND:
punw = phdr + i;
break;
case PT_DYNAMIC:
pdyn = phdr + i;
break;
default:
break;
}
}
if (!ptxt || !punw)
return NULL;
ui->di_cache.start_ip = segbase;
ui->di_cache.end_ip = ui->di_cache.start_ip + ptxt->p_memsz;
ui->di_cache.gp = find_gp (ui, pdyn, segbase - ptxt->p_vaddr);
ui->di_cache.format = UNW_INFO_FORMAT_TABLE;
ui->di_cache.u.ti.name_ptr = 0;
ui->di_cache.u.ti.segbase = segbase;
ui->di_cache.u.ti.table_len = punw->p_memsz / sizeof (unw_word_t);
ui->di_cache.u.ti.table_data = (unw_word_t *)
((char *) ui->ei.image + (punw->p_vaddr - ptxt->p_vaddr));
return &ui->di_cache;
}
#elif UNW_TARGET_X86
HIDDEN unw_dyn_info_t *
_UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
char *path, unw_word_t segbase, unw_word_t mapoff)
{
return NULL;
}
#endif /* UNW_TARGET_X86 */
static unw_dyn_info_t *
get_unwind_info (struct UPT_info *ui, unw_addr_space_t as, unw_word_t ip)
{
unsigned long segbase, mapoff;
char path[PATH_MAX];
unw_dyn_info_t *di;
#if UNW_TARGET_IA64 && defined(__linux)
if (!ui->ktab.start_ip && _Uia64_get_kernel_table (&ui->ktab) < 0)
return NULL;
if (ip >= ui->ktab.start_ip && ip < ui->ktab.end_ip)
return &ui->ktab;
#endif
if (ip >= ui->di_cache.start_ip && ip < ui->di_cache.end_ip)
return &ui->di_cache;
if (ui->ei.image)
{
munmap (ui->ei.image, ui->ei.size);
ui->ei.image = NULL;
ui->ei.size = 0;
/* invalidate the cache: */
ui->di_cache.start_ip = ui->di_cache.end_ip = 0;
}
if (tdep_get_elf_image (&ui->ei, ui->pid, ip, &segbase, &mapoff) < 0)
return NULL;
di = _UPTi_find_unwind_table (ui, as, path, segbase, mapoff);
if (!di
/* This can happen in corner cases where dynamically generated
code falls into the same page that contains the data-segment
and the page-offset of the code is within the first page of
the executable. */
|| ip < di->start_ip || ip >= di->end_ip)
return NULL;
return di;
}
int
_UPT_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
int need_unwind_info, void *arg)
{
struct UPT_info *ui = arg;
unw_dyn_info_t *di;
di = get_unwind_info (ui, as, ip);
if (!di)
return -UNW_ENOINFO;
#if UNW_TARGET_IA64
if (di == &ui->ktab)
{
/* The kernel unwind table resides in local memory, so we have
to use the local address space to search it. Since
_UPT_put_unwind_info() has no easy way of detecting this
case, we simply make a copy of the unwind-info, so
_UPT_put_unwind_info() can always free() the unwind-info
without ill effects. */
int ret = tdep_search_unwind_table (unw_local_addr_space, ip, di, pi,
need_unwind_info, arg);
if (ret >= 0 && need_unwind_info)
{
void *mem = malloc (pi->unwind_info_size);
if (!mem)
return -UNW_ENOMEM;
memcpy (mem, pi->unwind_info, pi->unwind_info_size);
pi->unwind_info = mem;
}
return ret;
}
else
#endif
return tdep_search_unwind_table (as, ip, di, pi, need_unwind_info, arg);
}

View file

@ -1,94 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "_UPT_internal.h"
#ifdef UNW_TARGET_IA64
# include "elf64.h"
# include "os-linux.h"
#endif
int
_UPT_get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dil_addr,
void *arg)
{
#if UNW_TARGET_IA64
unsigned long lo, hi, off;
struct UPT_info *ui = arg;
struct map_iterator mi;
char path[PATH_MAX];
unw_dyn_info_t *di;
unw_word_t res;
#endif
int count = 0;
debug (100, "%s: looking for dyn_info list\n", __FUNCTION__);
#if UNW_TARGET_IA64
maps_init (&mi, ui->pid);
while (maps_next (&mi, &lo, &hi, &off, path))
{
if (off)
continue;
if (ui->ei.image)
{
munmap (ui->ei.image, ui->ei.size);
/* invalidate the cache: */
ui->di_cache.start_ip = ui->di_cache.end_ip = 0;
}
if (elf_map_image (&ui->ei, path) < 0)
return -UNW_ENOINFO;
debug (100, "%s: checking object %s\n", __FUNCTION__, path);
di = _UPTi_find_unwind_table (ui, as, path, lo, off);
if (di)
{
res = _Uia64_find_dyn_list (as, di, arg);
if (res && count++ == 0)
{
debug (100, "%s: dyn_info_list_addr = 0x%lx\n",
__FUNCTION__, (long) res);
*dil_addr = res;
}
}
}
maps_close (&mi);
#else
# warning Implement me, please.
#endif
/* If multiple dynamic-info list addresses are found, we would have
to determine which was is the one actually in use (since the
dynamic name resolution algorithm will pick one "winner").
Perhaps we'd have to track them all until we find one that's
non-empty. Hopefully, this case simply will never arise, since
only libunwind defines the dynamic info list head. */
assert (count <= 1);
return (count > 0) ? 0 : -UNW_ENOINFO;
}

View file

@ -1,101 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind-internal.h"
PROTECTED _Unwind_Reason_Code
_Unwind_RaiseException (struct _Unwind_Exception *exception_object)
{
unsigned long exception_class = exception_object->exception_class;
_Unwind_Personality_Fn personality;
struct _Unwind_Context context;
_Unwind_Reason_Code reason;
unw_proc_info_t pi;
unw_context_t uc;
unw_word_t ip;
int ret;
debug (1, "%s(exception_object=%p)\n", __FUNCTION__, exception_object);
if (_Unwind_InitContext (&context, &uc) < 0)
return _URC_FATAL_PHASE1_ERROR;
/* Phase 1 (search phase) */
while (1)
{
if ((ret = unw_step (&context.cursor)) <= 0)
{
if (ret == 0)
{
debug (1, "%s: no handler found\n", __FUNCTION__);
return _URC_END_OF_STACK;
}
else
return _URC_FATAL_PHASE1_ERROR;
}
if (unw_get_proc_info (&context.cursor, &pi) < 0)
return _URC_FATAL_PHASE1_ERROR;
personality = (_Unwind_Personality_Fn) pi.handler;
if (personality)
{
reason = (*personality) (_U_VERSION, _UA_SEARCH_PHASE,
exception_class, exception_object,
&context);
if (reason != _URC_CONTINUE_UNWIND)
{
if (reason == _URC_HANDLER_FOUND)
break;
else
{
debug (1, "%s: personality returned %d\n",
__FUNCTION__, reason);
return _URC_FATAL_PHASE1_ERROR;
}
}
}
}
/* Exceptions are associated with IP-ranges. If a given exception
is handled at a particular IP, it will _always_ be handled at
that IP. If this weren't true, we'd have to track the tuple
(IP,SP,BSP) to uniquely identify the stack frame that's handling
the exception. */
if (unw_get_reg (&context.cursor, UNW_REG_IP, &ip) < 0)
return _URC_FATAL_PHASE1_ERROR;
exception_object->private_1 = 0; /* clear "stop" pointer */
exception_object->private_2 = ip; /* save frame marker */
debug (1, "%s: found handler for IP=%lx; entering cleanup phase\n",
__FUNCTION__, ip);
/* Reset the cursor to the first frame: */
if (unw_init_local (&context.cursor, &uc) < 0)
return _URC_FATAL_PHASE1_ERROR;
return _Unwind_Phase2 (exception_object, &context);
}

View file

@ -1,39 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdlib.h>
#include "unwind_i.h"
PROTECTED void
unw_destroy_addr_space (unw_addr_space_t as)
{
#ifndef UNW_LOCAL_ONLY
# if UNW_DEBUG
memset (as, 0, sizeof (*as));
# endif
free (as);
#endif
}

View file

@ -1,34 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
PROTECTED int
unw_get_reg (unw_cursor_t *cursor, int regnum, unw_word_t *valp)
{
struct cursor *c = (struct cursor *) cursor;
return x86_access_reg (c, regnum, valp, 0);
}

View file

@ -1,34 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
PROTECTED int
unw_set_reg (unw_cursor_t *cursor, int regnum, unw_word_t valp)
{
struct cursor *c = (struct cursor *) cursor;
return x86_access_reg (c, regnum, &valp, 1);
}