* RFA: ia64 portion of libunwind patch
@ 2003-10-24 0:11 J. Johnston
2003-10-24 17:57 ` Kevin Buettner
2003-10-29 15:18 ` Andrew Cagney
0 siblings, 2 replies; 32+ messages in thread
From: J. Johnston @ 2003-10-24 0:11 UTC (permalink / raw)
To: gdb-patches; +Cc: ac131313
[-- Attachment #1: Type: text/plain, Size: 1137 bytes --]
As requested, here is the other part of the libunwind patch to the ia64-tdep.c file.
2003-10-23 Jeff Johnston <jjohnstn@redhat.com>
David Mosberger <davidm@hpl.hp.com>
* ia64-tdep.c: Include <fcntl.h>, elf.h, and <sys/mman.h>.
[HAVE_LIBUNWIND_IA64_H]: Include libunwind-frame.h and libunwind-ia64.h.
(ia64_getunwind): New function for libunwind support.
(ia64_rse_slot_num, ia64_rse_skip_regs): Ditto.
(ia64_gdb2uw_regnum, ia64_uw2gdb_regnum): Ditto.
(ia64_is_fpreg, ia64_access_reg): Ditto.
(ia64_access_fpreg, ia64_access_mem): Ditto.
(get_kernel_table, map_segment): Ditto.
(map_info_free, ia64_find_unwind_table): Ditto.
(ia64_find_proc_info_x, ia64_put_unwind_info): Ditto.
(ia64_get_dyn_info_list, ia64_libunwind_frame_this_id): Ditto.
(ia64_libunwind_frame_prev_register): Ditto.
(ia64_libunwind_frame_sniffer,
(ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Add libunwind frame
sniffer. Register libunwind functions needed by generic libunwind
frame code using libunwind_frame_set_descr().
Ok to commit? Questions regarding this in conjunction with the generic
libunwind frame code?
-- Jeff J.
[-- Attachment #2: ia64-tdep.c.libunwind.patch --]
[-- Type: text/plain, Size: 20252 bytes --]
Index: ia64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
retrieving revision 1.101
diff -u -p -r1.101 ia64-tdep.c
--- ia64-tdep.c 23 Oct 2003 22:06:37 -0000 1.101
+++ ia64-tdep.c 24 Oct 2003 00:00:41 -0000
@@ -36,8 +36,16 @@
#include "objfiles.h"
#include "elf/common.h" /* for DT_PLTGOT value */
#include "elf-bfd.h"
+#include "elf.h" /* for PT_IA64_UNWIND value */
+#include <fcntl.h>
+#include <sys/mman.h>
#include "dis-asm.h"
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "libunwind-frame.h"
+#include "libunwind-ia64.h"
+#endif
+
/* Hook for determining the global pointer when calling functions in
the inferior under AIX. The initialization code in ia64-aix-nat.c
sets this hook to the address of a function which will find the
@@ -2104,6 +2112,659 @@ static const struct frame_base ia64_fram
ia64_frame_base_address
};
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+# ifndef __NR_getunwind
+# define __NR_getunwind 1215
+# endif
+
+static unsigned long
+ia64_getunwind (void *buf, size_t len)
+{
+ return syscall (__NR_getunwind, buf, len);
+}
+
+struct ia64_unwind_table_entry
+ {
+ unw_word_t start_offset;
+ unw_word_t end_offset;
+ unw_word_t info_offset;
+ };
+
+static __inline__ uint64_t
+ia64_rse_slot_num (uint64_t addr)
+{
+ return (addr >> 3) & 0x3f;
+}
+
+static __inline__ uint64_t
+ia64_rse_skip_regs (uint64_t addr, long num_regs)
+{
+ long delta = ia64_rse_slot_num(addr) + num_regs;
+
+ if (num_regs < 0)
+ delta -= 0x3e;
+ return addr + ((num_regs + delta/0x3f) << 3);
+}
+
+static int
+ia64_gdb2uw_regnum (int regnum)
+{
+ if (regnum == sp_regnum)
+ return UNW_IA64_SP;
+ else if (regnum == IA64_BSP_REGNUM)
+ return UNW_IA64_BSP;
+ else if ((unsigned) (regnum - IA64_GR0_REGNUM) < 128)
+ return UNW_IA64_GR + (regnum - IA64_GR0_REGNUM);
+ else if ((unsigned) (regnum - V32_REGNUM) < 95)
+ return UNW_IA64_GR + 32 + (regnum - V32_REGNUM);
+ else if ((unsigned) (regnum - IA64_FR0_REGNUM) < 128)
+ return UNW_IA64_FR + (regnum - IA64_FR0_REGNUM);
+ else if ((unsigned) (regnum - IA64_PR0_REGNUM) < 64)
+ return -1;
+ else if ((unsigned) (regnum - IA64_BR0_REGNUM) < 8)
+ return UNW_IA64_BR + (regnum - IA64_BR0_REGNUM);
+ else if (regnum == IA64_PR_REGNUM)
+ return UNW_IA64_PR;
+ else if (regnum == IA64_IP_REGNUM)
+ return UNW_REG_IP;
+ else if (regnum == IA64_CFM_REGNUM)
+ return UNW_IA64_CFM;
+ else if ((unsigned) (regnum - IA64_AR0_REGNUM) < 128)
+ return UNW_IA64_AR + (regnum - IA64_AR0_REGNUM);
+ else if ((unsigned) (regnum - IA64_NAT0_REGNUM) < 128)
+ return UNW_IA64_NAT + (regnum - IA64_NAT0_REGNUM);
+ else
+ return -1;
+}
+
+static int
+ia64_uw2gdb_regnum (int uw_regnum)
+{
+ if (uw_regnum == UNW_IA64_SP)
+ return sp_regnum;
+ else if (uw_regnum == UNW_IA64_BSP)
+ return IA64_BSP_REGNUM;
+ else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 32)
+ return IA64_GR0_REGNUM + (uw_regnum - UNW_IA64_GR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 128)
+ return V32_REGNUM + (uw_regnum - (IA64_GR0_REGNUM + 32));
+ else if ((unsigned) (uw_regnum - UNW_IA64_FR) < 128)
+ return IA64_FR0_REGNUM + (uw_regnum - UNW_IA64_FR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_BR) < 8)
+ return IA64_BR0_REGNUM + (uw_regnum - UNW_IA64_BR);
+ else if (uw_regnum == UNW_IA64_PR)
+ return IA64_PR_REGNUM;
+ else if (uw_regnum == UNW_REG_IP)
+ return IA64_IP_REGNUM;
+ else if (uw_regnum == UNW_IA64_CFM)
+ return IA64_CFM_REGNUM;
+ else if ((unsigned) (uw_regnum - UNW_IA64_AR) < 128)
+ return IA64_AR0_REGNUM + (uw_regnum - UNW_IA64_AR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_NAT) < 128)
+ return IA64_NAT0_REGNUM + (uw_regnum - UNW_IA64_NAT);
+ else
+ return -1;
+}
+
+static int
+ia64_is_fpreg (int uw_regnum)
+{
+ return unw_is_fpreg (uw_regnum);
+}
+
+static int
+ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+ unw_word_t bsp, sof, sol, cfm, psr, ip;
+ struct frame_info *next_frame = arg;
+ long new_sof, old_sof;
+ char buf[MAX_REGISTER_SIZE];
+
+ if (write)
+ {
+ if (regnum < 0)
+ /* ignore writes to pseudo-registers such as UNW_IA64_PROC_STARTI. */
+ return 0;
+
+ switch (uw_regnum)
+ {
+ case UNW_REG_IP:
+ ia64_write_pc (*val, inferior_ptid);
+ break;
+
+ case UNW_IA64_AR_BSPSTORE:
+ write_register (IA64_BSP_REGNUM, *val);
+ break;
+
+ case UNW_IA64_AR_BSP:
+ case UNW_IA64_BSP:
+ /* Account for the fact that ptrace() expects bsp to point
+ after the current register frame. */
+ cfm = read_register (IA64_CFM_REGNUM);
+ sof = (cfm & 0x7f);
+ bsp = ia64_rse_skip_regs (*val, sof);
+ write_register (IA64_BSP_REGNUM, bsp);
+ break;
+
+ 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. */
+ bsp = read_register (IA64_BSP_REGNUM);
+ cfm = read_register (IA64_CFM_REGNUM);
+ old_sof = (cfm & 0x7f);
+ new_sof = (*val & 0x7f);
+ if (old_sof != new_sof)
+ {
+ bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
+ write_register (IA64_BSP_REGNUM, bsp);
+ }
+ write_register (IA64_CFM_REGNUM, *val);
+ break;
+
+ default:
+ write_register (regnum, *val);
+ break;
+ }
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_reg: to cache: %4s=%016lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), *val);
+ }
+ else
+ {
+ switch (uw_regnum)
+ {
+ case UNW_REG_IP:
+ frame_unwind_register (next_frame, IA64_IP_REGNUM, buf);
+ ip = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 8);
+ *val = ip | ((psr >> 41) & 0x3);
+ break;
+
+ case UNW_IA64_AR_BSP:
+ /* Account for the fact that ptrace() returns a value for
+ bsp that points *after* the current register frame. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ sof = (cfm & 0x7f);
+ *val = ia64_rse_skip_regs (bsp, -sof);
+ break;
+
+ case UNW_IA64_AR_BSPSTORE:
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+
+ default:
+ frame_unwind_register (next_frame, regnum, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_reg: from cache: %4s=%016lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), *val);
+ }
+ return 0;
+}
+
+static int
+ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+
+ if (write)
+ regcache_cooked_write (current_regcache, regnum, (char *) val);
+ else
+ regcache_cooked_read (current_regcache, regnum, (char *) val);
+ return 0;
+}
+
+static int
+ia64_access_mem(unw_addr_space_t as,
+ unw_word_t addr, unw_word_t *val,
+ int write, void *arg)
+{
+ /* XXX do we need to normalize byte-order here? */
+ if (write)
+ return target_write_memory (addr, (char *) val, sizeof (unw_word_t));
+ else
+ return target_read_memory (addr, (char *) val, sizeof (unw_word_t));
+}
+
+static int
+get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
+{
+ size_t size;
+ struct ia64_table_entry
+ {
+ uint64_t start_offset;
+ uint64_t end_offset;
+ uint64_t info_offset;
+ };
+ static struct ia64_table_entry *ktab = NULL, *etab;
+
+ if (!ktab)
+ {
+ size = ia64_getunwind (NULL, 0);
+ ktab = xmalloc (size);
+ ia64_getunwind (ktab, size);
+
+ /* Determine length of kernel's unwind table and relocate
+ it's entries. */
+ for (etab = ktab; etab->start_offset; ++etab)
+ etab->info_offset += (uint64_t) ktab;
+ }
+
+ if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset)
+ return -UNW_ENOINFO;
+
+ di->format = UNW_INFO_FORMAT_TABLE;
+ di->gp = 0;
+ di->start_ip = ktab[0].start_offset;
+ di->end_ip = etab[-1].end_offset;
+ di->u.ti.name_ptr = (unw_word_t) "<kernel>";
+ di->u.ti.segbase = 0;
+ di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
+ di->u.ti.table_data = (unw_word_t *) ktab;
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "get_kernel_table: found table `%s': "
+ "segbase=%lx, length=%lu, gp=%lx\n",
+ (char *) di->u.ti.name_ptr, di->u.ti.segbase,
+ di->u.ti.table_len, di->gp);
+ return 0;
+}
+
+struct map_info
+{
+ void *buf;
+ size_t length;
+ int mapped;
+};
+
+static void *
+map_segment (bfd *bfd, Elf_Internal_Phdr *p_text, struct map_info *mi)
+ {
+ size_t page_mask = getpagesize () - 1, nbytes;
+ char *buf, *cp;
+ ssize_t nread;
+ int fd;
+
+ if (bfd->iostream)
+ fd = fileno (bfd->iostream);
+ else
+ fd = open (bfd_get_filename (bfd), O_RDONLY);
+
+ if (fd < 0)
+ return NULL;
+
+ buf = mmap (0, p_text->p_filesz, PROT_READ, MAP_PRIVATE, fd,
+ p_text->p_offset & ~page_mask);
+ if (buf != (char *) -1)
+ {
+ mi->buf = buf;
+ mi->length = p_text->p_filesz;
+ mi->mapped = 1;
+ buf += p_text->p_offset & page_mask;
+ }
+ else
+ {
+ /* mmap () failed, try reading the file: */
+ mi->mapped = 0;
+
+ if (lseek (fd, p_text->p_offset, SEEK_SET) < 0)
+ {
+ if (!bfd->iostream)
+ close (fd);
+ return NULL;
+ }
+
+ nbytes = p_text->p_filesz;
+ cp = buf = xmalloc (nbytes);
+ while ((nbytes > 0) && (nread = read (fd, cp, nbytes)) > 0)
+ {
+ cp += nread;
+ nbytes -= nread;
+ }
+ if (nbytes > 0)
+ {
+ /* premature end-of-file or some error */
+ xfree (buf);
+ buf = 0;
+ }
+ mi->buf = buf;
+ }
+ if (!bfd->iostream)
+ close (fd);
+
+ return buf;
+}
+
+static void
+map_info_free (struct map_info *mi)
+{
+ if (mi->mapped)
+ munmap (mi->buf, mi->length);
+ else if (mi->buf)
+ xfree (mi->buf);
+}
+
+static int
+ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip,
+ unw_dyn_info_t *dip, struct map_info *mip)
+{
+ Elf_Internal_Phdr *phdr, *p_text = NULL, *p_unwind = NULL;
+ Elf_Internal_Ehdr *ehdr;
+ void *unwind_info_base;
+ unw_word_t segbase = 0;
+ CORE_ADDR load_base;
+ bfd *bfd;
+ int i;
+
+ bfd = objfile->obfd;
+ ehdr = elf_tdata (bfd)->elf_header;
+ phdr = elf_tdata (bfd)->phdr;
+
+ load_base = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ {
+ switch (phdr[i].p_type)
+ {
+ case PT_LOAD:
+ if ((unw_word_t) (ip - load_base - phdr[i].p_vaddr)
+ < phdr[i].p_memsz)
+ p_text = phdr + i;
+ break;
+
+ case PT_IA_64_UNWIND:
+ p_unwind = phdr + i;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!p_text || !p_unwind
+ /* Verify that the segment that contains the IP also contains
+ the static unwind table. If not, we are dealing with
+ runtime-generated code, for which we have no info here. */
+ || (p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
+ return -UNW_ENOINFO;
+
+ segbase = p_text->p_vaddr + load_base;
+
+ dip->start_ip = segbase;
+ dip->end_ip = dip->start_ip + p_text->p_memsz;
+ dip->gp = FIND_GLOBAL_POINTER (ip);
+ dip->format = UNW_INFO_FORMAT_TABLE;
+ dip->u.ti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
+ dip->u.ti.segbase = segbase;
+ dip->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
+ unwind_info_base = map_segment (bfd, p_text, mip);
+ if (!unwind_info_base)
+ return -UNW_ENOINFO;
+ dip->u.ti.table_data = (unw_word_t *)
+ ((char *) unwind_info_base + (p_unwind->p_vaddr - p_text->p_vaddr));
+
+ /* The following 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. */
+ if (ip < dip->start_ip || ip >= dip->end_ip)
+ return -UNW_ENOINFO;
+
+ return 0;
+}
+
+static int
+ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
+{
+ struct obj_section *sec = find_pc_section (ip);
+ unw_dyn_info_t di;
+ int ret;
+ struct map_info mi;
+
+ if (!sec)
+ {
+ /* XXX This only works if the host and the target architecture are
+ both ia64 and if the have (more or less) the same kernel
+ version. */
+ if (get_kernel_table (ip, &di) < 0)
+ return -UNW_ENOINFO;
+ }
+ else
+ {
+ ret = ia64_find_unwind_table (sec->objfile, ip, &di, &mi);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "acquire_unwind_info: %lx -> "
+ "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
+ "length=%lu,data=%p)\n", ip, (char *)di.u.ti.name_ptr,
+ di.u.ti.segbase, di.start_ip, di.end_ip,
+ di.gp, di.u.ti.table_len, di.u.ti.table_data);
+
+ ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info, arg);
+
+ /* We no longer need the dyn info storage so free it. */
+ map_info_free (&mi);
+
+ return ret;
+}
+
+static void
+ia64_put_unwind_info (unw_addr_space_t as,
+ unw_proc_info_t *pip, void *arg)
+{
+ /* Nothing required for now. */
+}
+
+static int
+ia64_get_dyn_info_list (unw_addr_space_t as,
+ unw_word_t *dilap, void *arg)
+{
+ extern unw_word_t (*unw_ia64_find_dyn_list_p) (unw_addr_space_t, void *,
+ size_t, unw_word_t,
+ unw_word_t, void *);
+ struct obj_section *text_sec;
+ struct objfile *objfile;
+ unw_word_t ip, addr;
+ unw_dyn_info_t di;
+ int ret;
+
+ if (!libunwind_is_initialized ())
+ return -UNW_ENOINFO;
+
+ for (objfile = object_files; objfile; objfile = objfile->next)
+ {
+ struct map_info mi;
+
+ text_sec = objfile->sections + SECT_OFF_TEXT (objfile);
+ ip = text_sec->addr;
+ ret = ia64_find_unwind_table (objfile, ip, &di, &mi);
+ if (ret >= 0)
+ {
+ addr = libunwind_find_dyn_list (as, di.u.ti.table_data,
+ (di.u.ti.table_len
+ * sizeof (di.u.ti.table_data[0])),
+ di.u.ti.segbase, di.gp, arg);
+ /* We no longer need the dyn info storage so free it. */
+ map_info_free (&mi);
+
+ if (addr)
+ {
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "dynamic unwind table in objfile %s "
+ "at %lx (gp=%lx)\n",
+ bfd_get_filename (objfile->obfd),
+ addr, di.gp);
+ *dilap = addr;
+ return 0;
+ }
+ }
+ }
+ return -UNW_ENOINFO;
+}
+
+static void
+ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ char buf[8];
+ CORE_ADDR bsp;
+ struct frame_id id;
+
+ libunwind_frame_this_id (next_frame, this_cache, &id);
+
+ /* We must add the bsp as the special address for frame comparison purposes. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+
+ (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "libunwind frame id: code %lx, stack %lx, special %lx, next_frame %p\n",
+ id.code_addr, id.stack_addr, bsp, next_frame);
+}
+
+static void
+ia64_libunwind_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ int reg = regnum;
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ reg = IA64_PR_REGNUM;
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ reg = IA64_UNAT_REGNUM;
+
+ /* Let libunwind do most of the work. */
+ libunwind_frame_prev_register (next_frame, this_cache, reg,
+ optimizedp, lvalp, addrp, realnump, valuep);
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ ULONGEST prN_val;
+
+ if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ int rrb_pr = 0;
+ ULONGEST cfm;
+ unsigned char buf[MAX_REGISTER_SIZE];
+
+ /* Fetch predicate register rename base from current frame
+ marker for this frame. */
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ rrb_pr = (cfm >> 32) & 0x3f;
+
+ /* Adjust the register number to account for register rotation. */
+ regnum = VP16_REGNUM
+ + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
+ }
+ prN_val = extract_bit_field ((unsigned char *) valuep,
+ regnum - VP0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
+ }
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ {
+ ULONGEST unatN_val;
+
+ unatN_val = extract_bit_field ((unsigned char *) valuep,
+ regnum - IA64_NAT0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ unatN_val);
+ }
+ else if (regnum == IA64_BSP_REGNUM)
+ {
+ char cfm_valuep[MAX_REGISTER_SIZE];
+ int cfm_optim;
+ int cfm_realnum;
+ enum lval_type cfm_lval;
+ CORE_ADDR cfm_addr;
+ CORE_ADDR bsp, prev_cfm, prev_bsp;
+
+ /* We want to calculate the previous bsp as the end of the previous register stack frame.
+ This corresponds to what the hardware bsp register will be if we pop the frame
+ back which is why we might have been called. We know that libunwind will pass us back
+ the beginning of the current frame so we should just add sof to it. */
+ prev_bsp = extract_unsigned_integer (valuep, 8);
+ libunwind_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM,
+ &cfm_optim, &cfm_lval, &cfm_addr, &cfm_realnum, cfm_valuep);
+ prev_cfm = extract_unsigned_integer (cfm_valuep, 8);
+ prev_bsp = rse_address_add (prev_bsp, (prev_cfm & 0x7f));
+
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ prev_bsp);
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "libunwind prev register <%s> is %lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8));
+}
+
+static const struct frame_unwind ia64_libunwind_frame_unwind =
+{
+ NORMAL_FRAME,
+ ia64_libunwind_frame_this_id,
+ ia64_libunwind_frame_prev_register
+};
+
+static const struct frame_unwind *
+ia64_libunwind_frame_sniffer (struct frame_info *next_frame)
+{
+ if (libunwind_is_initialized () && libunwind_frame_sniffer (next_frame))
+ return &ia64_libunwind_frame_unwind;
+
+ return NULL;
+}
+
+static unw_accessors_t ia64_unw_accessors =
+{
+ ia64_find_proc_info_x,
+ ia64_put_unwind_info,
+ ia64_get_dyn_info_list,
+ ia64_access_mem,
+ ia64_access_reg,
+ ia64_access_fpreg,
+ /* resume */
+ /* get_proc_name */
+};
+
+static struct libunwind_descr ia64_libunwind_descr =
+{
+ ia64_gdb2uw_regnum,
+ ia64_uw2gdb_regnum,
+ ia64_is_fpreg,
+ &ia64_unw_accessors,
+};
+
+#endif /* HAVE_LIBUNWIND_IA64_H */
+
/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc
and TYPE is the type (which is known to be struct, union or array). */
@@ -2826,6 +3487,10 @@ ia64_gdbarch_init (struct gdbarch_info i
set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc);
frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
+#ifdef HAVE_LIBUNWIND_IA64_H
+ frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer);
+ libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr);
+#endif
frame_unwind_append_sniffer (gdbarch, ia64_frame_sniffer);
frame_base_set_default (gdbarch, &ia64_frame_base);
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-24 0:11 RFA: ia64 portion of libunwind patch J. Johnston
@ 2003-10-24 17:57 ` Kevin Buettner
2003-10-24 18:20 ` J. Johnston
2003-10-29 15:18 ` Andrew Cagney
1 sibling, 1 reply; 32+ messages in thread
From: Kevin Buettner @ 2003-10-24 17:57 UTC (permalink / raw)
To: J. Johnston, gdb-patches; +Cc: ac131313
On Oct 23, 8:11pm, J. Johnston wrote:
> Ok to commit? Questions regarding this in conjunction with the generic
> libunwind frame code?
> +#ifdef HAVE_LIBUNWIND_IA64_H
> +
> +# ifndef __NR_getunwind
> +# define __NR_getunwind 1215
> +# endif
Is this part still needed?
...........
> +static void *
> +map_segment (bfd *bfd, Elf_Internal_Phdr *p_text, struct map_info *mi)
> + {
> + size_t page_mask = getpagesize () - 1, nbytes;
> + char *buf, *cp;
> + ssize_t nread;
> + int fd;
> +
> + if (bfd->iostream)
> + fd = fileno (bfd->iostream);
> + else
> + fd = open (bfd_get_filename (bfd), O_RDONLY);
> +
> + if (fd < 0)
> + return NULL;
> +
> + buf = mmap (0, p_text->p_filesz, PROT_READ, MAP_PRIVATE, fd,
> + p_text->p_offset & ~page_mask);
> + if (buf != (char *) -1)
> + {
> + mi->buf = buf;
> + mi->length = p_text->p_filesz;
> + mi->mapped = 1;
> + buf += p_text->p_offset & page_mask;
> + }
> + else
> + {
> + /* mmap () failed, try reading the file: */
> + mi->mapped = 0;
> +
> + if (lseek (fd, p_text->p_offset, SEEK_SET) < 0)
> + {
> + if (!bfd->iostream)
> + close (fd);
> + return NULL;
> + }
> +
> + nbytes = p_text->p_filesz;
> + cp = buf = xmalloc (nbytes);
> + while ((nbytes > 0) && (nread = read (fd, cp, nbytes)) > 0)
> + {
> + cp += nread;
> + nbytes -= nread;
> + }
> + if (nbytes > 0)
> + {
> + /* premature end-of-file or some error */
> + xfree (buf);
> + buf = 0;
> + }
> + mi->buf = buf;
> + }
> + if (!bfd->iostream)
> + close (fd);
> +
> + return buf;
> +}
For the above, why isn't bfd being employed to read the segment?
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-24 17:57 ` Kevin Buettner
@ 2003-10-24 18:20 ` J. Johnston
2003-10-24 18:56 ` Kevin Buettner
0 siblings, 1 reply; 32+ messages in thread
From: J. Johnston @ 2003-10-24 18:20 UTC (permalink / raw)
To: Kevin Buettner; +Cc: gdb-patches, ac131313
Kevin Buettner wrote:
> On Oct 23, 8:11pm, J. Johnston wrote:
>
>
>>Ok to commit? Questions regarding this in conjunction with the generic
>>libunwind frame code?
>
>
>>+#ifdef HAVE_LIBUNWIND_IA64_H
>>+
>>+# ifndef __NR_getunwind
>>+# define __NR_getunwind 1215
>>+# endif
>
>
> Is this part still needed?
>
Not if we include <sys/syscall.h>
> ...........
>
>
>>+static void *
>>+map_segment (bfd *bfd, Elf_Internal_Phdr *p_text, struct map_info *mi)
>>+ {
>>+ size_t page_mask = getpagesize () - 1, nbytes;
>>+ char *buf, *cp;
>>+ ssize_t nread;
>>+ int fd;
>>+
>>+ if (bfd->iostream)
>>+ fd = fileno (bfd->iostream);
>>+ else
>>+ fd = open (bfd_get_filename (bfd), O_RDONLY);
>>+
>>+ if (fd < 0)
>>+ return NULL;
>>+
>>+ buf = mmap (0, p_text->p_filesz, PROT_READ, MAP_PRIVATE, fd,
>>+ p_text->p_offset & ~page_mask);
>>+ if (buf != (char *) -1)
>>+ {
>>+ mi->buf = buf;
>>+ mi->length = p_text->p_filesz;
>>+ mi->mapped = 1;
>>+ buf += p_text->p_offset & page_mask;
>>+ }
>>+ else
>>+ {
>>+ /* mmap () failed, try reading the file: */
>>+ mi->mapped = 0;
>>+
>>+ if (lseek (fd, p_text->p_offset, SEEK_SET) < 0)
>>+ {
>>+ if (!bfd->iostream)
>>+ close (fd);
>>+ return NULL;
>>+ }
>>+
>>+ nbytes = p_text->p_filesz;
>>+ cp = buf = xmalloc (nbytes);
>>+ while ((nbytes > 0) && (nread = read (fd, cp, nbytes)) > 0)
>>+ {
>>+ cp += nread;
>>+ nbytes -= nread;
>>+ }
>>+ if (nbytes > 0)
>>+ {
>>+ /* premature end-of-file or some error */
>>+ xfree (buf);
>>+ buf = 0;
>>+ }
>>+ mi->buf = buf;
>>+ }
>>+ if (!bfd->iostream)
>>+ close (fd);
>>+
>>+ return buf;
>>+}
>
>
> For the above, why isn't bfd being employed to read the segment?
>
Are you referring to using bfd_bread() if the mmap fails or do you mean
something higher level?
-- Jeff J.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-24 18:20 ` J. Johnston
@ 2003-10-24 18:56 ` Kevin Buettner
2003-10-24 21:53 ` Marcel Moolenaar
2003-10-28 23:53 ` J. Johnston
0 siblings, 2 replies; 32+ messages in thread
From: Kevin Buettner @ 2003-10-24 18:56 UTC (permalink / raw)
To: J. Johnston, Kevin Buettner; +Cc: Marcel Moolenaar, ac131313, gdb-patches
On Oct 24, 2:20pm, J. Johnston wrote:
> Kevin Buettner wrote:
>
> >>+#ifdef HAVE_LIBUNWIND_IA64_H
> >>+
> >>+# ifndef __NR_getunwind
> >>+# define __NR_getunwind 1215
> >>+# endif
> >
> > Is this part still needed?
>
> Not if we include <sys/syscall.h>
I would prefer to see <sys/syscall.h> included -- but not in
ia64-tdep.c. This include and the code for ia64_getunwind() will have
to go in ia64-linux-nat.c. Presumably, if a remote target wanted to
use the unwind library, there'd need to be some remote protocol
modifications.
Also, apparently, there'll be some FreeBSD patches for IA-64 coming
down the pike. FreeBSD, if it chooses to use the libunwind library,
will need to implement its own version of ia64_getunwind().
Hmm... thinking about this some more, I'd like to know why a syscall
is required. Is there anyway this functionality could be implemented
in an OS independent fashion?
> >>+static void *
> >>+map_segment (bfd *bfd, Elf_Internal_Phdr *p_text, struct map_info *mi)
[...]
> > For the above, why isn't bfd being employed to read the segment?
>
> Are you referring to using bfd_bread() if the mmap fails or do you mean
> something higher level?
I hadn't given it much thought. It looked odd to see file reading
code in this patch. It might be okay to use bfd_bread if the mmap
fails, but I'd prefer to push as much of this problem (reading of
files) as possible over to the bfd side.
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-24 18:56 ` Kevin Buettner
@ 2003-10-24 21:53 ` Marcel Moolenaar
2003-10-24 23:58 ` Kevin Buettner
2003-10-28 23:53 ` J. Johnston
1 sibling, 1 reply; 32+ messages in thread
From: Marcel Moolenaar @ 2003-10-24 21:53 UTC (permalink / raw)
To: Kevin Buettner; +Cc: J. Johnston, ac131313, gdb-patches
On Fri, Oct 24, 2003 at 11:56:25AM -0700, Kevin Buettner wrote:
> >
> > >>+#ifdef HAVE_LIBUNWIND_IA64_H
> > >>+
> > >>+# ifndef __NR_getunwind
> > >>+# define __NR_getunwind 1215
> > >>+# endif
> > >
> > > Is this part still needed?
> >
> > Not if we include <sys/syscall.h>
>
> I would prefer to see <sys/syscall.h> included -- but not in
> ia64-tdep.c. This include and the code for ia64_getunwind() will have
> to go in ia64-linux-nat.c. Presumably, if a remote target wanted to
> use the unwind library, there'd need to be some remote protocol
> modifications.
Isn't the unwind library linked into gdb and using callbacks for
memory reads and obtaining register values so that we can use the
existing protocol commands to extract information from the inferior?
Hmmm... this raises the question how the unwind library knows about
dynamic unwind descriptors in remote targets...
> Also, apparently, there'll be some FreeBSD patches for IA-64 coming
> down the pike. FreeBSD, if it chooses to use the libunwind library,
> will need to implement its own version of ia64_getunwind().
Yes, I intend to have an unwind library on FreeBSD. I'm happy to see
that support is being added. Standardizing on David's unwind library
is possible now that it has the MIT license. Unfortunately it depends
on many GNU build tools (autoconf, automake, libtool etc). This may
be a reason for me to use an API compatible alternative as I expect it
to be a PITA to import libunwind into FreeBSD and have it play nice
with the BSD make infrastructure. Also, my first attempts to port it
to FreeBSD weren't as successful as I hoped it would be. There's a
certain amount of Linuxism in it that didn't (near) trivially map to
FreeBSDisms. Anyway: I'll be talking to David when the time comes :-)
--
Marcel Moolenaar USPA: A-39004 marcel@xcllnt.net
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-24 21:53 ` Marcel Moolenaar
@ 2003-10-24 23:58 ` Kevin Buettner
0 siblings, 0 replies; 32+ messages in thread
From: Kevin Buettner @ 2003-10-24 23:58 UTC (permalink / raw)
To: Marcel Moolenaar, Kevin Buettner; +Cc: J. Johnston, ac131313, gdb-patches
On Oct 24, 2:52pm, Marcel Moolenaar wrote:
> On Fri, Oct 24, 2003 at 11:56:25AM -0700, Kevin Buettner wrote:
> > I would prefer to see <sys/syscall.h> included -- but not in
> > ia64-tdep.c. This include and the code for ia64_getunwind() will have
> > to go in ia64-linux-nat.c. Presumably, if a remote target wanted to
> > use the unwind library, there'd need to be some remote protocol
> > modifications.
>
> Isn't the unwind library linked into gdb and using callbacks for
> memory reads and obtaining register values so that we can use the
> existing protocol commands to extract information from the inferior?
I haven't looked recently (and don't remember from when I did look at
it), but I would hope it would do something along those lines.
Unfortunately, the patch which Jeff submitted contains the following:
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+# ifndef __NR_getunwind
+# define __NR_getunwind 1215
+# endif
+
+static unsigned long
+ia64_getunwind (void *buf, size_t len)
+{
+ return syscall (__NR_getunwind, buf, len);
+}
where ia64_getunwind() is called from within get_kernel_table() (which
is also new).
Anyway, this sort of thing needs to go in a *-nat.c file. Corresponding
methods need to be created so that we'll be able to fetch this information
from a remote target.
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-24 18:56 ` Kevin Buettner
2003-10-24 21:53 ` Marcel Moolenaar
@ 2003-10-28 23:53 ` J. Johnston
2003-10-29 1:28 ` Daniel Jacobowitz
` (2 more replies)
1 sibling, 3 replies; 32+ messages in thread
From: J. Johnston @ 2003-10-28 23:53 UTC (permalink / raw)
To: Kevin Buettner; +Cc: Marcel Moolenaar, ac131313, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2790 bytes --]
I have addressed your comments below. The bfd stuff (map_segment, map_info) has
been replaced by a simple call to bfd_bread(). I have moved the getunwind
syscall stuff into ia64-linux-tdep.c and I access it via the gdbarch_tdep structure.
The new ChangeLog is:
2003-10-28 Jeff Johnston <jjohnstn@redhat.com>
David Mosberger <davidm@hpl.hp.com>
* ia64-tdep.c: Include <fcntl.h>, elf.h, and <sys/mman.h>.
[HAVE_LIBUNWIND_IA64_H]: Include libunwind-frame.h and libunwind-ia64.h.
(gdbarch_tdep): Add getunwind_table function pointer to struct.
(ia64_rse_slot_num, ia64_rse_skip_regs): Ditto.
(ia64_gdb2uw_regnum, ia64_uw2gdb_regnum): Ditto.
(ia64_is_fpreg, ia64_access_reg): Ditto.
(ia64_access_fpreg, ia64_access_mem): Ditto.
(get_kernel_table): Ditto.
(ia64_find_unwind_table): Ditto.
(ia64_find_proc_info_x, ia64_put_unwind_info): Ditto.
(ia64_get_dyn_info_list, ia64_libunwind_frame_this_id): Ditto.
(ia64_libunwind_frame_prev_register): Ditto.
(ia64_libunwind_frame_sniffer,
(ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Add libunwind frame
sniffer. Set up getunwind_table function. Register libunwind functions
needed by generic libunwind frame code using
libunwind_frame_set_descr().
Ok? More comments?
-- Jeff J.
Kevin Buettner wrote:
> On Oct 24, 2:20pm, J. Johnston wrote:
>
>
>>Kevin Buettner wrote:
>>
>>
>>>>+#ifdef HAVE_LIBUNWIND_IA64_H
>>>>+
>>>>+# ifndef __NR_getunwind
>>>>+# define __NR_getunwind 1215
>>>>+# endif
>>>
>>>Is this part still needed?
>>
>>Not if we include <sys/syscall.h>
>
>
> I would prefer to see <sys/syscall.h> included -- but not in
> ia64-tdep.c. This include and the code for ia64_getunwind() will have
> to go in ia64-linux-nat.c. Presumably, if a remote target wanted to
> use the unwind library, there'd need to be some remote protocol
> modifications.
>
> Also, apparently, there'll be some FreeBSD patches for IA-64 coming
> down the pike. FreeBSD, if it chooses to use the libunwind library,
> will need to implement its own version of ia64_getunwind().
>
> Hmm... thinking about this some more, I'd like to know why a syscall
> is required. Is there anyway this functionality could be implemented
> in an OS independent fashion?
>
>
>>>>+static void *
>>>>+map_segment (bfd *bfd, Elf_Internal_Phdr *p_text, struct map_info *mi)
>
> [...]
>
>
>>>For the above, why isn't bfd being employed to read the segment?
>>
>>Are you referring to using bfd_bread() if the mmap fails or do you mean
>>something higher level?
>
>
> I hadn't given it much thought. It looked odd to see file reading
> code in this patch. It might be okay to use bfd_bread if the mmap
> fails, but I'd prefer to push as much of this problem (reading of
> files) as possible over to the bfd side.
>
> Kevin
>
[-- Attachment #2: ia64-libunwind.patch --]
[-- Type: text/plain, Size: 20923 bytes --]
Index: ia64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
retrieving revision 1.101
diff -u -p -r1.101 ia64-tdep.c
--- ia64-tdep.c 23 Oct 2003 22:06:37 -0000 1.101
+++ ia64-tdep.c 28 Oct 2003 23:45:54 -0000
@@ -36,8 +36,16 @@
#include "objfiles.h"
#include "elf/common.h" /* for DT_PLTGOT value */
#include "elf-bfd.h"
+#include "elf.h" /* for PT_IA64_UNWIND value */
+#include <fcntl.h>
+#include <sys/mman.h>
#include "dis-asm.h"
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "libunwind-frame.h"
+#include "libunwind-ia64.h"
+#endif
+
/* Hook for determining the global pointer when calling functions in
the inferior under AIX. The initialization code in ia64-aix-nat.c
sets this hook to the address of a function which will find the
@@ -87,6 +95,7 @@ typedef enum instruction_type
/* FIXME: These extern declarations should go in ia64-tdep.h. */
extern CORE_ADDR ia64_linux_sigcontext_register_address (CORE_ADDR, int);
extern CORE_ADDR ia64_aix_sigcontext_register_address (CORE_ADDR, int);
+extern unsigned long ia64_linux_getunwind_table (void *, size_t);
static gdbarch_init_ftype ia64_gdbarch_init;
@@ -264,12 +273,16 @@ struct gdbarch_tdep
and register number, returns the offset to the
given register from the start of the frame. */
CORE_ADDR (*find_global_pointer) (CORE_ADDR);
+
+ unsigned long (*getunwind_table) (void *buf, size_t len);
};
#define SIGCONTEXT_REGISTER_ADDRESS \
(gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
#define FIND_GLOBAL_POINTER \
(gdbarch_tdep (current_gdbarch)->find_global_pointer)
+#define GETUNWIND_TABLE \
+ (gdbarch_tdep (current_gdbarch)->getunwind_table)
int
ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
@@ -2104,6 +2117,580 @@ static const struct frame_base ia64_fram
ia64_frame_base_address
};
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+struct ia64_unwind_table_entry
+ {
+ unw_word_t start_offset;
+ unw_word_t end_offset;
+ unw_word_t info_offset;
+ };
+
+static __inline__ uint64_t
+ia64_rse_slot_num (uint64_t addr)
+{
+ return (addr >> 3) & 0x3f;
+}
+
+static __inline__ uint64_t
+ia64_rse_skip_regs (uint64_t addr, long num_regs)
+{
+ long delta = ia64_rse_slot_num(addr) + num_regs;
+
+ if (num_regs < 0)
+ delta -= 0x3e;
+ return addr + ((num_regs + delta/0x3f) << 3);
+}
+
+static int
+ia64_gdb2uw_regnum (int regnum)
+{
+ if (regnum == sp_regnum)
+ return UNW_IA64_SP;
+ else if (regnum == IA64_BSP_REGNUM)
+ return UNW_IA64_BSP;
+ else if ((unsigned) (regnum - IA64_GR0_REGNUM) < 128)
+ return UNW_IA64_GR + (regnum - IA64_GR0_REGNUM);
+ else if ((unsigned) (regnum - V32_REGNUM) < 95)
+ return UNW_IA64_GR + 32 + (regnum - V32_REGNUM);
+ else if ((unsigned) (regnum - IA64_FR0_REGNUM) < 128)
+ return UNW_IA64_FR + (regnum - IA64_FR0_REGNUM);
+ else if ((unsigned) (regnum - IA64_PR0_REGNUM) < 64)
+ return -1;
+ else if ((unsigned) (regnum - IA64_BR0_REGNUM) < 8)
+ return UNW_IA64_BR + (regnum - IA64_BR0_REGNUM);
+ else if (regnum == IA64_PR_REGNUM)
+ return UNW_IA64_PR;
+ else if (regnum == IA64_IP_REGNUM)
+ return UNW_REG_IP;
+ else if (regnum == IA64_CFM_REGNUM)
+ return UNW_IA64_CFM;
+ else if ((unsigned) (regnum - IA64_AR0_REGNUM) < 128)
+ return UNW_IA64_AR + (regnum - IA64_AR0_REGNUM);
+ else if ((unsigned) (regnum - IA64_NAT0_REGNUM) < 128)
+ return UNW_IA64_NAT + (regnum - IA64_NAT0_REGNUM);
+ else
+ return -1;
+}
+
+static int
+ia64_uw2gdb_regnum (int uw_regnum)
+{
+ if (uw_regnum == UNW_IA64_SP)
+ return sp_regnum;
+ else if (uw_regnum == UNW_IA64_BSP)
+ return IA64_BSP_REGNUM;
+ else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 32)
+ return IA64_GR0_REGNUM + (uw_regnum - UNW_IA64_GR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 128)
+ return V32_REGNUM + (uw_regnum - (IA64_GR0_REGNUM + 32));
+ else if ((unsigned) (uw_regnum - UNW_IA64_FR) < 128)
+ return IA64_FR0_REGNUM + (uw_regnum - UNW_IA64_FR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_BR) < 8)
+ return IA64_BR0_REGNUM + (uw_regnum - UNW_IA64_BR);
+ else if (uw_regnum == UNW_IA64_PR)
+ return IA64_PR_REGNUM;
+ else if (uw_regnum == UNW_REG_IP)
+ return IA64_IP_REGNUM;
+ else if (uw_regnum == UNW_IA64_CFM)
+ return IA64_CFM_REGNUM;
+ else if ((unsigned) (uw_regnum - UNW_IA64_AR) < 128)
+ return IA64_AR0_REGNUM + (uw_regnum - UNW_IA64_AR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_NAT) < 128)
+ return IA64_NAT0_REGNUM + (uw_regnum - UNW_IA64_NAT);
+ else
+ return -1;
+}
+
+static int
+ia64_is_fpreg (int uw_regnum)
+{
+ return unw_is_fpreg (uw_regnum);
+}
+
+static int
+ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+ unw_word_t bsp, sof, sol, cfm, psr, ip;
+ struct frame_info *next_frame = arg;
+ long new_sof, old_sof;
+ char buf[MAX_REGISTER_SIZE];
+
+ if (write)
+ {
+ if (regnum < 0)
+ /* ignore writes to pseudo-registers such as UNW_IA64_PROC_STARTI. */
+ return 0;
+
+ switch (uw_regnum)
+ {
+ case UNW_REG_IP:
+ ia64_write_pc (*val, inferior_ptid);
+ break;
+
+ case UNW_IA64_AR_BSPSTORE:
+ write_register (IA64_BSP_REGNUM, *val);
+ break;
+
+ case UNW_IA64_AR_BSP:
+ case UNW_IA64_BSP:
+ /* Account for the fact that ptrace() expects bsp to point
+ after the current register frame. */
+ cfm = read_register (IA64_CFM_REGNUM);
+ sof = (cfm & 0x7f);
+ bsp = ia64_rse_skip_regs (*val, sof);
+ write_register (IA64_BSP_REGNUM, bsp);
+ break;
+
+ 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. */
+ bsp = read_register (IA64_BSP_REGNUM);
+ cfm = read_register (IA64_CFM_REGNUM);
+ old_sof = (cfm & 0x7f);
+ new_sof = (*val & 0x7f);
+ if (old_sof != new_sof)
+ {
+ bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
+ write_register (IA64_BSP_REGNUM, bsp);
+ }
+ write_register (IA64_CFM_REGNUM, *val);
+ break;
+
+ default:
+ write_register (regnum, *val);
+ break;
+ }
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_reg: to cache: %4s=%016lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), *val);
+ }
+ else
+ {
+ switch (uw_regnum)
+ {
+ case UNW_REG_IP:
+ frame_unwind_register (next_frame, IA64_IP_REGNUM, buf);
+ ip = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 8);
+ *val = ip | ((psr >> 41) & 0x3);
+ break;
+
+ case UNW_IA64_AR_BSP:
+ /* Account for the fact that ptrace() returns a value for
+ bsp that points *after* the current register frame. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ sof = (cfm & 0x7f);
+ *val = ia64_rse_skip_regs (bsp, -sof);
+ break;
+
+ case UNW_IA64_AR_BSPSTORE:
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+
+ default:
+ frame_unwind_register (next_frame, regnum, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_reg: from cache: %4s=%016lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), *val);
+ }
+ return 0;
+}
+
+static int
+ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+
+ if (write)
+ regcache_cooked_write (current_regcache, regnum, (char *) val);
+ else
+ regcache_cooked_read (current_regcache, regnum, (char *) val);
+ return 0;
+}
+
+static int
+ia64_access_mem(unw_addr_space_t as,
+ unw_word_t addr, unw_word_t *val,
+ int write, void *arg)
+{
+ /* XXX do we need to normalize byte-order here? */
+ if (write)
+ return target_write_memory (addr, (char *) val, sizeof (unw_word_t));
+ else
+ return target_read_memory (addr, (char *) val, sizeof (unw_word_t));
+}
+
+static int
+get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
+{
+ size_t size;
+ struct ia64_table_entry
+ {
+ uint64_t start_offset;
+ uint64_t end_offset;
+ uint64_t info_offset;
+ };
+ static struct ia64_table_entry *ktab = NULL, *etab;
+
+ if (GETUNWIND_TABLE == 0)
+ internal_error (__FILE__, __LINE__,
+ "get_kernel_table: GETUNWIND_TABLE is 0");
+
+ if (!ktab)
+ {
+ size = GETUNWIND_TABLE (NULL, 0);
+ ktab = xmalloc (size);
+ GETUNWIND_TABLE (ktab, size);
+
+ /* Determine length of kernel's unwind table and relocate
+ it's entries. */
+ for (etab = ktab; etab->start_offset; ++etab)
+ etab->info_offset += (uint64_t) ktab;
+ }
+
+ if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset)
+ return -UNW_ENOINFO;
+
+ di->format = UNW_INFO_FORMAT_TABLE;
+ di->gp = 0;
+ di->start_ip = ktab[0].start_offset;
+ di->end_ip = etab[-1].end_offset;
+ di->u.ti.name_ptr = (unw_word_t) "<kernel>";
+ di->u.ti.segbase = 0;
+ di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
+ di->u.ti.table_data = (unw_word_t *) ktab;
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "get_kernel_table: found table `%s': "
+ "segbase=%lx, length=%lu, gp=%lx\n",
+ (char *) di->u.ti.name_ptr, di->u.ti.segbase,
+ di->u.ti.table_len, di->gp);
+ return 0;
+}
+
+static int
+ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip,
+ unw_dyn_info_t *dip, void **buf)
+{
+ Elf_Internal_Phdr *phdr, *p_text = NULL, *p_unwind = NULL;
+ Elf_Internal_Ehdr *ehdr;
+ unw_word_t segbase = 0;
+ CORE_ADDR load_base;
+ bfd *bfd;
+ int i;
+
+ bfd = objfile->obfd;
+ ehdr = elf_tdata (bfd)->elf_header;
+ phdr = elf_tdata (bfd)->phdr;
+
+ load_base = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ {
+ switch (phdr[i].p_type)
+ {
+ case PT_LOAD:
+ if ((unw_word_t) (ip - load_base - phdr[i].p_vaddr)
+ < phdr[i].p_memsz)
+ p_text = phdr + i;
+ break;
+
+ case PT_IA_64_UNWIND:
+ p_unwind = phdr + i;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!p_text || !p_unwind
+ /* Verify that the segment that contains the IP also contains
+ the static unwind table. If not, we are dealing with
+ runtime-generated code, for which we have no info here. */
+ || (p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
+ return -UNW_ENOINFO;
+
+ segbase = p_text->p_vaddr + load_base;
+
+ dip->start_ip = segbase;
+ dip->end_ip = dip->start_ip + p_text->p_memsz;
+ dip->gp = FIND_GLOBAL_POINTER (ip);
+ dip->format = UNW_INFO_FORMAT_TABLE;
+ dip->u.ti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
+ dip->u.ti.segbase = segbase;
+ dip->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
+
+ *buf = xmalloc (p_text->p_filesz);
+ bfd_seek (bfd, p_text->p_offset, SEEK_SET);
+ bfd_bread (*buf, p_text->p_filesz, bfd);
+
+ dip->u.ti.table_data = (unw_word_t *)
+ ((char *)(*buf) + (p_unwind->p_vaddr - p_text->p_vaddr));
+
+ /* The following 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. */
+ if (ip < dip->start_ip || ip >= dip->end_ip)
+ return -UNW_ENOINFO;
+
+ return 0;
+}
+
+static int
+ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
+{
+ struct obj_section *sec = find_pc_section (ip);
+ unw_dyn_info_t di;
+ int ret;
+ void *buf = NULL;
+
+ if (!sec)
+ {
+ /* XXX This only works if the host and the target architecture are
+ both ia64 and if the have (more or less) the same kernel
+ version. */
+ if (get_kernel_table (ip, &di) < 0)
+ return -UNW_ENOINFO;
+ }
+ else
+ {
+ ret = ia64_find_unwind_table (sec->objfile, ip, &di, &buf);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "acquire_unwind_info: %lx -> "
+ "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
+ "length=%lu,data=%p)\n", ip, (char *)di.u.ti.name_ptr,
+ di.u.ti.segbase, di.start_ip, di.end_ip,
+ di.gp, di.u.ti.table_len, di.u.ti.table_data);
+
+ ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info, arg);
+
+ /* We no longer need the dyn info storage so free it. */
+ xfree (buf);
+
+ return ret;
+}
+
+static void
+ia64_put_unwind_info (unw_addr_space_t as,
+ unw_proc_info_t *pip, void *arg)
+{
+ /* Nothing required for now. */
+}
+
+static int
+ia64_get_dyn_info_list (unw_addr_space_t as,
+ unw_word_t *dilap, void *arg)
+{
+ extern unw_word_t (*unw_ia64_find_dyn_list_p) (unw_addr_space_t, void *,
+ size_t, unw_word_t,
+ unw_word_t, void *);
+ struct obj_section *text_sec;
+ struct objfile *objfile;
+ unw_word_t ip, addr;
+ unw_dyn_info_t di;
+ int ret;
+
+ if (!libunwind_is_initialized ())
+ return -UNW_ENOINFO;
+
+ for (objfile = object_files; objfile; objfile = objfile->next)
+ {
+ void *buf = NULL;
+
+ text_sec = objfile->sections + SECT_OFF_TEXT (objfile);
+ ip = text_sec->addr;
+ ret = ia64_find_unwind_table (objfile, ip, &di, &buf);
+ if (ret >= 0)
+ {
+ addr = libunwind_find_dyn_list (as, di.u.ti.table_data,
+ (di.u.ti.table_len
+ * sizeof (di.u.ti.table_data[0])),
+ di.u.ti.segbase, di.gp, arg);
+ /* We no longer need the dyn info storage so free it. */
+ xfree (buf);
+
+ if (addr)
+ {
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "dynamic unwind table in objfile %s "
+ "at %lx (gp=%lx)\n",
+ bfd_get_filename (objfile->obfd),
+ addr, di.gp);
+ *dilap = addr;
+ return 0;
+ }
+ }
+ }
+ return -UNW_ENOINFO;
+}
+
+static void
+ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ char buf[8];
+ CORE_ADDR bsp;
+ struct frame_id id;
+
+ libunwind_frame_this_id (next_frame, this_cache, &id);
+
+ /* We must add the bsp as the special address for frame comparison purposes. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+
+ (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "libunwind frame id: code %lx, stack %lx, special %lx, next_frame %p\n",
+ id.code_addr, id.stack_addr, bsp, next_frame);
+}
+
+static void
+ia64_libunwind_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ int reg = regnum;
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ reg = IA64_PR_REGNUM;
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ reg = IA64_UNAT_REGNUM;
+
+ /* Let libunwind do most of the work. */
+ libunwind_frame_prev_register (next_frame, this_cache, reg,
+ optimizedp, lvalp, addrp, realnump, valuep);
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ ULONGEST prN_val;
+
+ if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ int rrb_pr = 0;
+ ULONGEST cfm;
+ unsigned char buf[MAX_REGISTER_SIZE];
+
+ /* Fetch predicate register rename base from current frame
+ marker for this frame. */
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ rrb_pr = (cfm >> 32) & 0x3f;
+
+ /* Adjust the register number to account for register rotation. */
+ regnum = VP16_REGNUM
+ + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
+ }
+ prN_val = extract_bit_field ((unsigned char *) valuep,
+ regnum - VP0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
+ }
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ {
+ ULONGEST unatN_val;
+
+ unatN_val = extract_bit_field ((unsigned char *) valuep,
+ regnum - IA64_NAT0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ unatN_val);
+ }
+ else if (regnum == IA64_BSP_REGNUM)
+ {
+ char cfm_valuep[MAX_REGISTER_SIZE];
+ int cfm_optim;
+ int cfm_realnum;
+ enum lval_type cfm_lval;
+ CORE_ADDR cfm_addr;
+ CORE_ADDR bsp, prev_cfm, prev_bsp;
+
+ /* We want to calculate the previous bsp as the end of the previous register stack frame.
+ This corresponds to what the hardware bsp register will be if we pop the frame
+ back which is why we might have been called. We know that libunwind will pass us back
+ the beginning of the current frame so we should just add sof to it. */
+ prev_bsp = extract_unsigned_integer (valuep, 8);
+ libunwind_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM,
+ &cfm_optim, &cfm_lval, &cfm_addr, &cfm_realnum, cfm_valuep);
+ prev_cfm = extract_unsigned_integer (cfm_valuep, 8);
+ prev_bsp = rse_address_add (prev_bsp, (prev_cfm & 0x7f));
+
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ prev_bsp);
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "libunwind prev register <%s> is %lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8));
+}
+
+static const struct frame_unwind ia64_libunwind_frame_unwind =
+{
+ NORMAL_FRAME,
+ ia64_libunwind_frame_this_id,
+ ia64_libunwind_frame_prev_register
+};
+
+static const struct frame_unwind *
+ia64_libunwind_frame_sniffer (struct frame_info *next_frame)
+{
+ if (libunwind_is_initialized () && libunwind_frame_sniffer (next_frame))
+ return &ia64_libunwind_frame_unwind;
+
+ return NULL;
+}
+
+static unw_accessors_t ia64_unw_accessors =
+{
+ ia64_find_proc_info_x,
+ ia64_put_unwind_info,
+ ia64_get_dyn_info_list,
+ ia64_access_mem,
+ ia64_access_reg,
+ ia64_access_fpreg,
+ /* resume */
+ /* get_proc_name */
+};
+
+static struct libunwind_descr ia64_libunwind_descr =
+{
+ ia64_gdb2uw_regnum,
+ ia64_uw2gdb_regnum,
+ ia64_is_fpreg,
+ &ia64_unw_accessors,
+};
+
+#endif /* HAVE_LIBUNWIND_IA64_H */
+
/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc
and TYPE is the type (which is known to be struct, union or array). */
@@ -2771,6 +3358,12 @@ ia64_gdbarch_init (struct gdbarch_info i
else
tdep->find_global_pointer = generic_elf_find_global_pointer;
+ /* Set the method for obtaining the unwind table information. */
+ if (os_ident == ELFOSABI_LINUX)
+ tdep->getunwind_table = ia64_linux_getunwind_table;
+ else
+ tdep->getunwind_table = 0;
+
/* Define the ia64 floating-point format to gdb. */
builtin_type_ia64_ext =
init_type (TYPE_CODE_FLT, 128 / 8,
@@ -2826,6 +3419,10 @@ ia64_gdbarch_init (struct gdbarch_info i
set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc);
frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
+#ifdef HAVE_LIBUNWIND_IA64_H
+ frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer);
+ libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr);
+#endif
frame_unwind_append_sniffer (gdbarch, ia64_frame_sniffer);
frame_base_set_default (gdbarch, &ia64_frame_base);
Index: ia64-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-linux-tdep.c,v
retrieving revision 1.4
diff -u -p -r1.4 ia64-linux-tdep.c
--- ia64-linux-tdep.c 15 Oct 2003 22:55:32 -0000 1.4
+++ ia64-linux-tdep.c 28 Oct 2003 23:45:54 -0000
@@ -22,6 +22,7 @@
#include "defs.h"
#include "arch-utils.h"
#include "gdbcore.h"
+#include <sys/syscall.h>
/* The sigtramp code is in a non-readable (executable-only) region
of memory called the ``gate page''. The addresses in question
@@ -92,4 +93,10 @@ ia64_linux_sigcontext_register_address (
default :
return 0;
}
+}
+
+unsigned long
+ia64_linux_getunwind_table (void *buf, size_t len)
+{
+ return syscall (__NR_getunwind, buf, len);
}
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-28 23:53 ` J. Johnston
@ 2003-10-29 1:28 ` Daniel Jacobowitz
2003-10-29 4:48 ` Kevin Buettner
2003-10-29 22:48 ` Andrew Cagney
2003-10-29 23:28 ` Andrew Cagney
2003-11-02 20:39 ` Elena Zannoni
2 siblings, 2 replies; 32+ messages in thread
From: Daniel Jacobowitz @ 2003-10-29 1:28 UTC (permalink / raw)
To: J. Johnston; +Cc: Kevin Buettner, Marcel Moolenaar, ac131313, gdb-patches
On Tue, Oct 28, 2003 at 06:53:36PM -0500, J. Johnston wrote:
> I have addressed your comments below. The bfd stuff (map_segment,
> map_info) has been replaced by a simple call to bfd_bread(). I have moved
> the getunwind syscall stuff into ia64-linux-tdep.c and I access it via the
> gdbarch_tdep structure.
Nothing which involves a syscall is acceptable in a tdep file. That's
what the t means - target support.
Move it to the -nat file. I don't know how you should integrate it
with the gdbarch tdep.
--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-29 1:28 ` Daniel Jacobowitz
@ 2003-10-29 4:48 ` Kevin Buettner
2003-10-29 18:43 ` J. Johnston
2003-10-29 22:48 ` Andrew Cagney
1 sibling, 1 reply; 32+ messages in thread
From: Kevin Buettner @ 2003-10-29 4:48 UTC (permalink / raw)
To: Daniel Jacobowitz, J. Johnston
Cc: Kevin Buettner, Marcel Moolenaar, ac131313, gdb-patches
On Oct 28, 8:28pm, Daniel Jacobowitz wrote:
> On Tue, Oct 28, 2003 at 06:53:36PM -0500, J. Johnston wrote:
> > I have addressed your comments below. The bfd stuff (map_segment,
> > map_info) has been replaced by a simple call to bfd_bread(). I have moved
> > the getunwind syscall stuff into ia64-linux-tdep.c and I access it via the
> > gdbarch_tdep structure.
>
> Nothing which involves a syscall is acceptable in a tdep file. That's
> what the t means - target support.
>
> Move it to the -nat file.
Yes, I agree with Daniel. Earlier, I had said:
... and the code for ia64_getunwind() will have to go in
ia64-linux-nat.c. Presumably, if a remote target wanted to use
the unwind library, there'd need to be some remote protocol
modifications.
I also asked the following questions:
Hmm... thinking about this some more, I'd like to know why a
syscall is required. Is there any way this functionality could be
implemented in an OS independent fashion?
I'm guessing that there's kernel state that the unwinder needs to be
made aware of and that it won't be possible to implement ia64_getunwind()
in an OS independent manner. (I'd like someone to verify this though...)
> I don't know how you should integrate it with the gdbarch tdep.
If my speculation above is correct, I don't think the gdbarch tdep
ought to be used for accessing ia64_getunwind(). This sort of smells
like something that belongs in the target vector. (Since we need
different mechanisms for the remote and native cases.) But, since
this functionality is highly ia64-centric, I'd really hate to pollute
the target vector with such a method. The only approach that comes
to mind (at the moment) is something similar to the
native_find_global_pointer hook in ia64-tdep.c. (AIX/rs6000 has
something similar.) Note though that this kind of hook doesn't
help with the native / remote problem.
Again, it'd be really, *really*, REALLY nice if we could come up with
an OS independent way of determining the necessary information. E.g.
Is there any way to do memory reads to obtain the necessary information?
(I'm guessing not, but it doesn't hurt to ask...)
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-24 0:11 RFA: ia64 portion of libunwind patch J. Johnston
2003-10-24 17:57 ` Kevin Buettner
@ 2003-10-29 15:18 ` Andrew Cagney
1 sibling, 0 replies; 32+ messages in thread
From: Andrew Cagney @ 2003-10-29 15:18 UTC (permalink / raw)
To: J. Johnston; +Cc: gdb-patches, ac131313
Jeff,
before you find your self doing another iteration of this patch, can I
suggest waiting until I've taken a look. A superficial scan of the
e-mails suggets that some strange target related things are going on.
Andrew
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-29 4:48 ` Kevin Buettner
@ 2003-10-29 18:43 ` J. Johnston
0 siblings, 0 replies; 32+ messages in thread
From: J. Johnston @ 2003-10-29 18:43 UTC (permalink / raw)
To: Kevin Buettner; +Cc: Daniel Jacobowitz, Marcel Moolenaar, ac131313, gdb-patches
Kevin Buettner wrote:
> On Oct 28, 8:28pm, Daniel Jacobowitz wrote:
>
>
>>On Tue, Oct 28, 2003 at 06:53:36PM -0500, J. Johnston wrote:
>>
>>>I have addressed your comments below. The bfd stuff (map_segment,
>>>map_info) has been replaced by a simple call to bfd_bread(). I have moved
>>>the getunwind syscall stuff into ia64-linux-tdep.c and I access it via the
>>>gdbarch_tdep structure.
>>
>>Nothing which involves a syscall is acceptable in a tdep file. That's
>>what the t means - target support.
>>
>>Move it to the -nat file.
>
>
> Yes, I agree with Daniel. Earlier, I had said:
>
> ... and the code for ia64_getunwind() will have to go in
> ia64-linux-nat.c. Presumably, if a remote target wanted to use
> the unwind library, there'd need to be some remote protocol
> modifications.
>
Sorry, I understand now.
> I also asked the following questions:
>
> Hmm... thinking about this some more, I'd like to know why a
> syscall is required. Is there any way this functionality could be
> implemented in an OS independent fashion?
>
> I'm guessing that there's kernel state that the unwinder needs to be
> made aware of and that it won't be possible to implement ia64_getunwind()
> in an OS independent manner. (I'd like someone to verify this though...)
>
The kernel unwind table is kmalloc'd. The syscall makes a copy of it.
>
>>I don't know how you should integrate it with the gdbarch tdep.
>
>
> If my speculation above is correct, I don't think the gdbarch tdep
> ought to be used for accessing ia64_getunwind(). This sort of smells
> like something that belongs in the target vector. (Since we need
> different mechanisms for the remote and native cases.) But, since
> this functionality is highly ia64-centric, I'd really hate to pollute
> the target vector with such a method. The only approach that comes
> to mind (at the moment) is something similar to the
> native_find_global_pointer hook in ia64-tdep.c. (AIX/rs6000 has
> something similar.) Note though that this kind of hook doesn't
> help with the native / remote problem.
>
> Again, it'd be really, *really*, REALLY nice if we could come up with
> an OS independent way of determining the necessary information. E.g.
> Is there any way to do memory reads to obtain the necessary information?
> (I'm guessing not, but it doesn't hurt to ask...)
>
Andrew has suggested I look at to_read_partial.
-- Jeff J.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-29 1:28 ` Daniel Jacobowitz
2003-10-29 4:48 ` Kevin Buettner
@ 2003-10-29 22:48 ` Andrew Cagney
2003-11-04 19:09 ` J. Johnston
1 sibling, 1 reply; 32+ messages in thread
From: Andrew Cagney @ 2003-10-29 22:48 UTC (permalink / raw)
To: Daniel Jacobowitz, J. Johnston
Cc: Kevin Buettner, Marcel Moolenaar, ac131313, gdb-patches
> Nothing which involves a syscall is acceptable in a tdep file. That's
> what the t means - target support.
("tdep" mysteriously means "architecture vector support". That "t"
really no longer makes sense :-()
Yes, architecture vector shouldn't be directly making syscalls. Instead
the architecture specific code should use the target vector to obtain
this system information. Here I think the best option is to add another
TARGET_OBJECT_xxxx variant and then use the target_read() method to pull
in the data.
As for the native target side, ia64-linux-nat should export something
like ia64_linux_child_read_partial that performs the syscall. The
tricky [er messy] part is wiring it into child_ops, I see there are lots
of choices :-(
- define a nm-*.c macro and have that enable the assignment (ex #define
NATIVE_TO_READ_PARTIAL ia64_linux_child?) (ref KILL_INFERIOR)
- have a callback set the to_read_partial method in child_ops
(exec_set_find_memory_regions)
- modify all the targets so that each implements the new method
- others?
Is this information available via /proc? In a core file?
Andrew
PS: Note this pending patch. Dependant on the timing you or I may need
to tweak the name.
http://sources.redhat.com/ml/gdb-patches/2003-10/msg00795.html
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-28 23:53 ` J. Johnston
2003-10-29 1:28 ` Daniel Jacobowitz
@ 2003-10-29 23:28 ` Andrew Cagney
2003-11-02 20:39 ` Elena Zannoni
2 siblings, 0 replies; 32+ messages in thread
From: Andrew Cagney @ 2003-10-29 23:28 UTC (permalink / raw)
To: J. Johnston; +Cc: Kevin Buettner, ac131313, gdb-patches
Jeff,
Can you expand a little here on how this function interacts with
libunwind? I can see that its reading in data, but is that data found
in the target's space? If it is then the info should be pulled direct
from the target and the BFD/objfile should not be used. The relevant
target stratum can then re-direct the request to a local file.
I'm also wondering if the unwind code (probably impossible I know) could
use a callback to request the memory rather than require an entire buffer.
Hence the question.
Andrew
> +static int
> +ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
> + int need_unwind_info, void *arg)
> +{
> + struct obj_section *sec = find_pc_section (ip);
> + unw_dyn_info_t di;
> + int ret;
> + void *buf = NULL;
> +
> + if (!sec)
> + {
> + /* XXX This only works if the host and the target architecture are
> + both ia64 and if the have (more or less) the same kernel
> + version. */
> + if (get_kernel_table (ip, &di) < 0)
> + return -UNW_ENOINFO;
> + }
> + else
> + {
> + ret = ia64_find_unwind_table (sec->objfile, ip, &di, &buf);
> + if (ret < 0)
> + return ret;
> + }
> +
> + if (gdbarch_debug >= 1)
> + fprintf_unfiltered (gdb_stdlog, "acquire_unwind_info: %lx -> "
> + "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
> + "length=%lu,data=%p)\n", ip, (char *)di.u.ti.name_ptr,
> + di.u.ti.segbase, di.start_ip, di.end_ip,
> + di.gp, di.u.ti.table_len, di.u.ti.table_data);
> +
> + ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info, arg);
> +
> + /* We no longer need the dyn info storage so free it. */
> + xfree (buf);
> +
> + return ret;
> +}
> +
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-28 23:53 ` J. Johnston
2003-10-29 1:28 ` Daniel Jacobowitz
2003-10-29 23:28 ` Andrew Cagney
@ 2003-11-02 20:39 ` Elena Zannoni
2 siblings, 0 replies; 32+ messages in thread
From: Elena Zannoni @ 2003-11-02 20:39 UTC (permalink / raw)
To: J. Johnston; +Cc: Kevin Buettner, Marcel Moolenaar, ac131313, gdb-patches
J. Johnston writes:
> I have addressed your comments below. The bfd stuff (map_segment, map_info) has
> been replaced by a simple call to bfd_bread(). I have moved the getunwind
> syscall stuff into ia64-linux-tdep.c and I access it via the gdbarch_tdep structure.
>
> The new ChangeLog is:
>
> 2003-10-28 Jeff Johnston <jjohnstn@redhat.com>
> David Mosberger <davidm@hpl.hp.com>
>
> * ia64-tdep.c: Include <fcntl.h>, elf.h, and <sys/mman.h>.
> [HAVE_LIBUNWIND_IA64_H]: Include libunwind-frame.h and libunwind-ia64.h.
> (gdbarch_tdep): Add getunwind_table function pointer to struct.
> (ia64_rse_slot_num, ia64_rse_skip_regs): Ditto.
> (ia64_gdb2uw_regnum, ia64_uw2gdb_regnum): Ditto.
> (ia64_is_fpreg, ia64_access_reg): Ditto.
> (ia64_access_fpreg, ia64_access_mem): Ditto.
> (get_kernel_table): Ditto.
> (ia64_find_unwind_table): Ditto.
> (ia64_find_proc_info_x, ia64_put_unwind_info): Ditto.
> (ia64_get_dyn_info_list, ia64_libunwind_frame_this_id): Ditto.
> (ia64_libunwind_frame_prev_register): Ditto.
> (ia64_libunwind_frame_sniffer,
> (ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Add libunwind frame
> sniffer. Set up getunwind_table function. Register libunwind functions
> needed by generic libunwind frame code using
> libunwind_frame_set_descr().
>
> Ok? More comments?
yes, more comments :-) I mean, can you add comments in the code. There
are basically none, and this stuff is quite complex. If anybody else
needs to uderstand the details, it definitely would be easier if each
function had a comment explaining what it does.
elena
>
> -- Jeff J.
>
>
> Kevin Buettner wrote:
> > On Oct 24, 2:20pm, J. Johnston wrote:
> >
> >
> >>Kevin Buettner wrote:
> >>
> >>
> >>>>+#ifdef HAVE_LIBUNWIND_IA64_H
> >>>>+
> >>>>+# ifndef __NR_getunwind
> >>>>+# define __NR_getunwind 1215
> >>>>+# endif
> >>>
> >>>Is this part still needed?
> >>
> >>Not if we include <sys/syscall.h>
> >
> >
> > I would prefer to see <sys/syscall.h> included -- but not in
> > ia64-tdep.c. This include and the code for ia64_getunwind() will have
> > to go in ia64-linux-nat.c. Presumably, if a remote target wanted to
> > use the unwind library, there'd need to be some remote protocol
> > modifications.
> >
> > Also, apparently, there'll be some FreeBSD patches for IA-64 coming
> > down the pike. FreeBSD, if it chooses to use the libunwind library,
> > will need to implement its own version of ia64_getunwind().
> >
> > Hmm... thinking about this some more, I'd like to know why a syscall
> > is required. Is there anyway this functionality could be implemented
> > in an OS independent fashion?
> >
> >
> >>>>+static void *
> >>>>+map_segment (bfd *bfd, Elf_Internal_Phdr *p_text, struct map_info *mi)
> >
> > [...]
> >
> >
> >>>For the above, why isn't bfd being employed to read the segment?
> >>
> >>Are you referring to using bfd_bread() if the mmap fails or do you mean
> >>something higher level?
> >
> >
> > I hadn't given it much thought. It looked odd to see file reading
> > code in this patch. It might be okay to use bfd_bread if the mmap
> > fails, but I'd prefer to push as much of this problem (reading of
> > files) as possible over to the bfd side.
> >
> > Kevin
> >
> Index: ia64-tdep.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
> retrieving revision 1.101
> diff -u -p -r1.101 ia64-tdep.c
> --- ia64-tdep.c 23 Oct 2003 22:06:37 -0000 1.101
> +++ ia64-tdep.c 28 Oct 2003 23:45:54 -0000
> @@ -36,8 +36,16 @@
> #include "objfiles.h"
> #include "elf/common.h" /* for DT_PLTGOT value */
> #include "elf-bfd.h"
> +#include "elf.h" /* for PT_IA64_UNWIND value */
> +#include <fcntl.h>
> +#include <sys/mman.h>
> #include "dis-asm.h"
>
> +#ifdef HAVE_LIBUNWIND_IA64_H
> +#include "libunwind-frame.h"
> +#include "libunwind-ia64.h"
> +#endif
> +
> /* Hook for determining the global pointer when calling functions in
> the inferior under AIX. The initialization code in ia64-aix-nat.c
> sets this hook to the address of a function which will find the
> @@ -87,6 +95,7 @@ typedef enum instruction_type
> /* FIXME: These extern declarations should go in ia64-tdep.h. */
> extern CORE_ADDR ia64_linux_sigcontext_register_address (CORE_ADDR, int);
> extern CORE_ADDR ia64_aix_sigcontext_register_address (CORE_ADDR, int);
> +extern unsigned long ia64_linux_getunwind_table (void *, size_t);
>
> static gdbarch_init_ftype ia64_gdbarch_init;
>
> @@ -264,12 +273,16 @@ struct gdbarch_tdep
> and register number, returns the offset to the
> given register from the start of the frame. */
> CORE_ADDR (*find_global_pointer) (CORE_ADDR);
> +
> + unsigned long (*getunwind_table) (void *buf, size_t len);
> };
>
> #define SIGCONTEXT_REGISTER_ADDRESS \
> (gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
> #define FIND_GLOBAL_POINTER \
> (gdbarch_tdep (current_gdbarch)->find_global_pointer)
> +#define GETUNWIND_TABLE \
> + (gdbarch_tdep (current_gdbarch)->getunwind_table)
>
> int
> ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
> @@ -2104,6 +2117,580 @@ static const struct frame_base ia64_fram
> ia64_frame_base_address
> };
>
> +#ifdef HAVE_LIBUNWIND_IA64_H
> +
> +struct ia64_unwind_table_entry
> + {
> + unw_word_t start_offset;
> + unw_word_t end_offset;
> + unw_word_t info_offset;
> + };
> +
> +static __inline__ uint64_t
> +ia64_rse_slot_num (uint64_t addr)
> +{
> + return (addr >> 3) & 0x3f;
> +}
> +
> +static __inline__ uint64_t
> +ia64_rse_skip_regs (uint64_t addr, long num_regs)
> +{
> + long delta = ia64_rse_slot_num(addr) + num_regs;
> +
> + if (num_regs < 0)
> + delta -= 0x3e;
> + return addr + ((num_regs + delta/0x3f) << 3);
> +}
> +
> +static int
> +ia64_gdb2uw_regnum (int regnum)
> +{
> + if (regnum == sp_regnum)
> + return UNW_IA64_SP;
> + else if (regnum == IA64_BSP_REGNUM)
> + return UNW_IA64_BSP;
> + else if ((unsigned) (regnum - IA64_GR0_REGNUM) < 128)
> + return UNW_IA64_GR + (regnum - IA64_GR0_REGNUM);
> + else if ((unsigned) (regnum - V32_REGNUM) < 95)
> + return UNW_IA64_GR + 32 + (regnum - V32_REGNUM);
> + else if ((unsigned) (regnum - IA64_FR0_REGNUM) < 128)
> + return UNW_IA64_FR + (regnum - IA64_FR0_REGNUM);
> + else if ((unsigned) (regnum - IA64_PR0_REGNUM) < 64)
> + return -1;
> + else if ((unsigned) (regnum - IA64_BR0_REGNUM) < 8)
> + return UNW_IA64_BR + (regnum - IA64_BR0_REGNUM);
> + else if (regnum == IA64_PR_REGNUM)
> + return UNW_IA64_PR;
> + else if (regnum == IA64_IP_REGNUM)
> + return UNW_REG_IP;
> + else if (regnum == IA64_CFM_REGNUM)
> + return UNW_IA64_CFM;
> + else if ((unsigned) (regnum - IA64_AR0_REGNUM) < 128)
> + return UNW_IA64_AR + (regnum - IA64_AR0_REGNUM);
> + else if ((unsigned) (regnum - IA64_NAT0_REGNUM) < 128)
> + return UNW_IA64_NAT + (regnum - IA64_NAT0_REGNUM);
> + else
> + return -1;
> +}
> +
> +static int
> +ia64_uw2gdb_regnum (int uw_regnum)
> +{
> + if (uw_regnum == UNW_IA64_SP)
> + return sp_regnum;
> + else if (uw_regnum == UNW_IA64_BSP)
> + return IA64_BSP_REGNUM;
> + else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 32)
> + return IA64_GR0_REGNUM + (uw_regnum - UNW_IA64_GR);
> + else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 128)
> + return V32_REGNUM + (uw_regnum - (IA64_GR0_REGNUM + 32));
> + else if ((unsigned) (uw_regnum - UNW_IA64_FR) < 128)
> + return IA64_FR0_REGNUM + (uw_regnum - UNW_IA64_FR);
> + else if ((unsigned) (uw_regnum - UNW_IA64_BR) < 8)
> + return IA64_BR0_REGNUM + (uw_regnum - UNW_IA64_BR);
> + else if (uw_regnum == UNW_IA64_PR)
> + return IA64_PR_REGNUM;
> + else if (uw_regnum == UNW_REG_IP)
> + return IA64_IP_REGNUM;
> + else if (uw_regnum == UNW_IA64_CFM)
> + return IA64_CFM_REGNUM;
> + else if ((unsigned) (uw_regnum - UNW_IA64_AR) < 128)
> + return IA64_AR0_REGNUM + (uw_regnum - UNW_IA64_AR);
> + else if ((unsigned) (uw_regnum - UNW_IA64_NAT) < 128)
> + return IA64_NAT0_REGNUM + (uw_regnum - UNW_IA64_NAT);
> + else
> + return -1;
> +}
> +
> +static int
> +ia64_is_fpreg (int uw_regnum)
> +{
> + return unw_is_fpreg (uw_regnum);
> +}
> +
> +static int
> +ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
> + int write, void *arg)
> +{
> + int regnum = ia64_uw2gdb_regnum (uw_regnum);
> + unw_word_t bsp, sof, sol, cfm, psr, ip;
> + struct frame_info *next_frame = arg;
> + long new_sof, old_sof;
> + char buf[MAX_REGISTER_SIZE];
> +
> + if (write)
> + {
> + if (regnum < 0)
> + /* ignore writes to pseudo-registers such as UNW_IA64_PROC_STARTI. */
> + return 0;
> +
> + switch (uw_regnum)
> + {
> + case UNW_REG_IP:
> + ia64_write_pc (*val, inferior_ptid);
> + break;
> +
> + case UNW_IA64_AR_BSPSTORE:
> + write_register (IA64_BSP_REGNUM, *val);
> + break;
> +
> + case UNW_IA64_AR_BSP:
> + case UNW_IA64_BSP:
> + /* Account for the fact that ptrace() expects bsp to point
> + after the current register frame. */
> + cfm = read_register (IA64_CFM_REGNUM);
> + sof = (cfm & 0x7f);
> + bsp = ia64_rse_skip_regs (*val, sof);
> + write_register (IA64_BSP_REGNUM, bsp);
> + break;
> +
> + 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. */
> + bsp = read_register (IA64_BSP_REGNUM);
> + cfm = read_register (IA64_CFM_REGNUM);
> + old_sof = (cfm & 0x7f);
> + new_sof = (*val & 0x7f);
> + if (old_sof != new_sof)
> + {
> + bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
> + write_register (IA64_BSP_REGNUM, bsp);
> + }
> + write_register (IA64_CFM_REGNUM, *val);
> + break;
> +
> + default:
> + write_register (regnum, *val);
> + break;
> + }
> + if (gdbarch_debug >= 1)
> + fprintf_unfiltered (gdb_stdlog,
> + " access_reg: to cache: %4s=%016lx\n",
> + (((unsigned) regnum <= IA64_NAT127_REGNUM)
> + ? ia64_register_names[regnum] : "r??"), *val);
> + }
> + else
> + {
> + switch (uw_regnum)
> + {
> + case UNW_REG_IP:
> + frame_unwind_register (next_frame, IA64_IP_REGNUM, buf);
> + ip = extract_unsigned_integer (buf, 8);
> + frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
> + psr = extract_unsigned_integer (buf, 8);
> + *val = ip | ((psr >> 41) & 0x3);
> + break;
> +
> + case UNW_IA64_AR_BSP:
> + /* Account for the fact that ptrace() returns a value for
> + bsp that points *after* the current register frame. */
> + frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
> + bsp = extract_unsigned_integer (buf, 8);
> + frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
> + cfm = extract_unsigned_integer (buf, 8);
> + sof = (cfm & 0x7f);
> + *val = ia64_rse_skip_regs (bsp, -sof);
> + break;
> +
> + case UNW_IA64_AR_BSPSTORE:
> + frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
> + *val = extract_unsigned_integer (buf, 8);
> + break;
> +
> + default:
> + frame_unwind_register (next_frame, regnum, buf);
> + *val = extract_unsigned_integer (buf, 8);
> + break;
> + }
> +
> + if (gdbarch_debug >= 1)
> + fprintf_unfiltered (gdb_stdlog,
> + " access_reg: from cache: %4s=%016lx\n",
> + (((unsigned) regnum <= IA64_NAT127_REGNUM)
> + ? ia64_register_names[regnum] : "r??"), *val);
> + }
> + return 0;
> +}
> +
> +static int
> +ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val,
> + int write, void *arg)
> +{
> + int regnum = ia64_uw2gdb_regnum (uw_regnum);
> +
> + if (write)
> + regcache_cooked_write (current_regcache, regnum, (char *) val);
> + else
> + regcache_cooked_read (current_regcache, regnum, (char *) val);
> + return 0;
> +}
> +
> +static int
> +ia64_access_mem(unw_addr_space_t as,
> + unw_word_t addr, unw_word_t *val,
> + int write, void *arg)
> +{
> + /* XXX do we need to normalize byte-order here? */
> + if (write)
> + return target_write_memory (addr, (char *) val, sizeof (unw_word_t));
> + else
> + return target_read_memory (addr, (char *) val, sizeof (unw_word_t));
> +}
> +
> +static int
> +get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
> +{
> + size_t size;
> + struct ia64_table_entry
> + {
> + uint64_t start_offset;
> + uint64_t end_offset;
> + uint64_t info_offset;
> + };
> + static struct ia64_table_entry *ktab = NULL, *etab;
> +
> + if (GETUNWIND_TABLE == 0)
> + internal_error (__FILE__, __LINE__,
> + "get_kernel_table: GETUNWIND_TABLE is 0");
> +
> + if (!ktab)
> + {
> + size = GETUNWIND_TABLE (NULL, 0);
> + ktab = xmalloc (size);
> + GETUNWIND_TABLE (ktab, size);
> +
> + /* Determine length of kernel's unwind table and relocate
> + it's entries. */
> + for (etab = ktab; etab->start_offset; ++etab)
> + etab->info_offset += (uint64_t) ktab;
> + }
> +
> + if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset)
> + return -UNW_ENOINFO;
> +
> + di->format = UNW_INFO_FORMAT_TABLE;
> + di->gp = 0;
> + di->start_ip = ktab[0].start_offset;
> + di->end_ip = etab[-1].end_offset;
> + di->u.ti.name_ptr = (unw_word_t) "<kernel>";
> + di->u.ti.segbase = 0;
> + di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
> + di->u.ti.table_data = (unw_word_t *) ktab;
> +
> + if (gdbarch_debug >= 1)
> + fprintf_unfiltered (gdb_stdlog, "get_kernel_table: found table `%s': "
> + "segbase=%lx, length=%lu, gp=%lx\n",
> + (char *) di->u.ti.name_ptr, di->u.ti.segbase,
> + di->u.ti.table_len, di->gp);
> + return 0;
> +}
> +
> +static int
> +ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip,
> + unw_dyn_info_t *dip, void **buf)
> +{
> + Elf_Internal_Phdr *phdr, *p_text = NULL, *p_unwind = NULL;
> + Elf_Internal_Ehdr *ehdr;
> + unw_word_t segbase = 0;
> + CORE_ADDR load_base;
> + bfd *bfd;
> + int i;
> +
> + bfd = objfile->obfd;
> + ehdr = elf_tdata (bfd)->elf_header;
> + phdr = elf_tdata (bfd)->phdr;
> +
> + load_base = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
> +
> + for (i = 0; i < ehdr->e_phnum; ++i)
> + {
> + switch (phdr[i].p_type)
> + {
> + case PT_LOAD:
> + if ((unw_word_t) (ip - load_base - phdr[i].p_vaddr)
> + < phdr[i].p_memsz)
> + p_text = phdr + i;
> + break;
> +
> + case PT_IA_64_UNWIND:
> + p_unwind = phdr + i;
> + break;
> +
> + default:
> + break;
> + }
> + }
> +
> + if (!p_text || !p_unwind
> + /* Verify that the segment that contains the IP also contains
> + the static unwind table. If not, we are dealing with
> + runtime-generated code, for which we have no info here. */
> + || (p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
> + return -UNW_ENOINFO;
> +
> + segbase = p_text->p_vaddr + load_base;
> +
> + dip->start_ip = segbase;
> + dip->end_ip = dip->start_ip + p_text->p_memsz;
> + dip->gp = FIND_GLOBAL_POINTER (ip);
> + dip->format = UNW_INFO_FORMAT_TABLE;
> + dip->u.ti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
> + dip->u.ti.segbase = segbase;
> + dip->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
> +
> + *buf = xmalloc (p_text->p_filesz);
> + bfd_seek (bfd, p_text->p_offset, SEEK_SET);
> + bfd_bread (*buf, p_text->p_filesz, bfd);
> +
> + dip->u.ti.table_data = (unw_word_t *)
> + ((char *)(*buf) + (p_unwind->p_vaddr - p_text->p_vaddr));
> +
> + /* The following 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. */
> + if (ip < dip->start_ip || ip >= dip->end_ip)
> + return -UNW_ENOINFO;
> +
> + return 0;
> +}
> +
> +static int
> +ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
> + int need_unwind_info, void *arg)
> +{
> + struct obj_section *sec = find_pc_section (ip);
> + unw_dyn_info_t di;
> + int ret;
> + void *buf = NULL;
> +
> + if (!sec)
> + {
> + /* XXX This only works if the host and the target architecture are
> + both ia64 and if the have (more or less) the same kernel
> + version. */
> + if (get_kernel_table (ip, &di) < 0)
> + return -UNW_ENOINFO;
> + }
> + else
> + {
> + ret = ia64_find_unwind_table (sec->objfile, ip, &di, &buf);
> + if (ret < 0)
> + return ret;
> + }
> +
> + if (gdbarch_debug >= 1)
> + fprintf_unfiltered (gdb_stdlog, "acquire_unwind_info: %lx -> "
> + "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
> + "length=%lu,data=%p)\n", ip, (char *)di.u.ti.name_ptr,
> + di.u.ti.segbase, di.start_ip, di.end_ip,
> + di.gp, di.u.ti.table_len, di.u.ti.table_data);
> +
> + ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info, arg);
> +
> + /* We no longer need the dyn info storage so free it. */
> + xfree (buf);
> +
> + return ret;
> +}
> +
> +static void
> +ia64_put_unwind_info (unw_addr_space_t as,
> + unw_proc_info_t *pip, void *arg)
> +{
> + /* Nothing required for now. */
> +}
> +
> +static int
> +ia64_get_dyn_info_list (unw_addr_space_t as,
> + unw_word_t *dilap, void *arg)
> +{
> + extern unw_word_t (*unw_ia64_find_dyn_list_p) (unw_addr_space_t, void *,
> + size_t, unw_word_t,
> + unw_word_t, void *);
> + struct obj_section *text_sec;
> + struct objfile *objfile;
> + unw_word_t ip, addr;
> + unw_dyn_info_t di;
> + int ret;
> +
> + if (!libunwind_is_initialized ())
> + return -UNW_ENOINFO;
> +
> + for (objfile = object_files; objfile; objfile = objfile->next)
> + {
> + void *buf = NULL;
> +
> + text_sec = objfile->sections + SECT_OFF_TEXT (objfile);
> + ip = text_sec->addr;
> + ret = ia64_find_unwind_table (objfile, ip, &di, &buf);
> + if (ret >= 0)
> + {
> + addr = libunwind_find_dyn_list (as, di.u.ti.table_data,
> + (di.u.ti.table_len
> + * sizeof (di.u.ti.table_data[0])),
> + di.u.ti.segbase, di.gp, arg);
> + /* We no longer need the dyn info storage so free it. */
> + xfree (buf);
> +
> + if (addr)
> + {
> + if (gdbarch_debug >= 1)
> + fprintf_unfiltered (gdb_stdlog,
> + "dynamic unwind table in objfile %s "
> + "at %lx (gp=%lx)\n",
> + bfd_get_filename (objfile->obfd),
> + addr, di.gp);
> + *dilap = addr;
> + return 0;
> + }
> + }
> + }
> + return -UNW_ENOINFO;
> +}
> +
> +static void
> +ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
> + struct frame_id *this_id)
> +{
> + char buf[8];
> + CORE_ADDR bsp;
> + struct frame_id id;
> +
> + libunwind_frame_this_id (next_frame, this_cache, &id);
> +
> + /* We must add the bsp as the special address for frame comparison purposes. */
> + frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
> + bsp = extract_unsigned_integer (buf, 8);
> +
> + (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
> +
> + if (gdbarch_debug >= 1)
> + fprintf_unfiltered (gdb_stdlog,
> + "libunwind frame id: code %lx, stack %lx, special %lx, next_frame %p\n",
> + id.code_addr, id.stack_addr, bsp, next_frame);
> +}
> +
> +static void
> +ia64_libunwind_frame_prev_register (struct frame_info *next_frame,
> + void **this_cache,
> + int regnum, int *optimizedp,
> + enum lval_type *lvalp, CORE_ADDR *addrp,
> + int *realnump, void *valuep)
> +{
> + int reg = regnum;
> +
> + if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
> + reg = IA64_PR_REGNUM;
> + else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
> + reg = IA64_UNAT_REGNUM;
> +
> + /* Let libunwind do most of the work. */
> + libunwind_frame_prev_register (next_frame, this_cache, reg,
> + optimizedp, lvalp, addrp, realnump, valuep);
> +
> + if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
> + {
> + ULONGEST prN_val;
> +
> + if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
> + {
> + int rrb_pr = 0;
> + ULONGEST cfm;
> + unsigned char buf[MAX_REGISTER_SIZE];
> +
> + /* Fetch predicate register rename base from current frame
> + marker for this frame. */
> + frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
> + cfm = extract_unsigned_integer (buf, 8);
> + rrb_pr = (cfm >> 32) & 0x3f;
> +
> + /* Adjust the register number to account for register rotation. */
> + regnum = VP16_REGNUM
> + + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
> + }
> + prN_val = extract_bit_field ((unsigned char *) valuep,
> + regnum - VP0_REGNUM, 1);
> + store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
> + }
> + else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
> + {
> + ULONGEST unatN_val;
> +
> + unatN_val = extract_bit_field ((unsigned char *) valuep,
> + regnum - IA64_NAT0_REGNUM, 1);
> + store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
> + unatN_val);
> + }
> + else if (regnum == IA64_BSP_REGNUM)
> + {
> + char cfm_valuep[MAX_REGISTER_SIZE];
> + int cfm_optim;
> + int cfm_realnum;
> + enum lval_type cfm_lval;
> + CORE_ADDR cfm_addr;
> + CORE_ADDR bsp, prev_cfm, prev_bsp;
> +
> + /* We want to calculate the previous bsp as the end of the previous register stack frame.
> + This corresponds to what the hardware bsp register will be if we pop the frame
> + back which is why we might have been called. We know that libunwind will pass us back
> + the beginning of the current frame so we should just add sof to it. */
> + prev_bsp = extract_unsigned_integer (valuep, 8);
> + libunwind_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM,
> + &cfm_optim, &cfm_lval, &cfm_addr, &cfm_realnum, cfm_valuep);
> + prev_cfm = extract_unsigned_integer (cfm_valuep, 8);
> + prev_bsp = rse_address_add (prev_bsp, (prev_cfm & 0x7f));
> +
> + store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
> + prev_bsp);
> + }
> +
> + if (gdbarch_debug >= 1)
> + fprintf_unfiltered (gdb_stdlog,
> + "libunwind prev register <%s> is %lx\n",
> + (((unsigned) regnum <= IA64_NAT127_REGNUM)
> + ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8));
> +}
> +
> +static const struct frame_unwind ia64_libunwind_frame_unwind =
> +{
> + NORMAL_FRAME,
> + ia64_libunwind_frame_this_id,
> + ia64_libunwind_frame_prev_register
> +};
> +
> +static const struct frame_unwind *
> +ia64_libunwind_frame_sniffer (struct frame_info *next_frame)
> +{
> + if (libunwind_is_initialized () && libunwind_frame_sniffer (next_frame))
> + return &ia64_libunwind_frame_unwind;
> +
> + return NULL;
> +}
> +
> +static unw_accessors_t ia64_unw_accessors =
> +{
> + ia64_find_proc_info_x,
> + ia64_put_unwind_info,
> + ia64_get_dyn_info_list,
> + ia64_access_mem,
> + ia64_access_reg,
> + ia64_access_fpreg,
> + /* resume */
> + /* get_proc_name */
> +};
> +
> +static struct libunwind_descr ia64_libunwind_descr =
> +{
> + ia64_gdb2uw_regnum,
> + ia64_uw2gdb_regnum,
> + ia64_is_fpreg,
> + &ia64_unw_accessors,
> +};
> +
> +#endif /* HAVE_LIBUNWIND_IA64_H */
> +
> /* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
> EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc
> and TYPE is the type (which is known to be struct, union or array). */
> @@ -2771,6 +3358,12 @@ ia64_gdbarch_init (struct gdbarch_info i
> else
> tdep->find_global_pointer = generic_elf_find_global_pointer;
>
> + /* Set the method for obtaining the unwind table information. */
> + if (os_ident == ELFOSABI_LINUX)
> + tdep->getunwind_table = ia64_linux_getunwind_table;
> + else
> + tdep->getunwind_table = 0;
> +
> /* Define the ia64 floating-point format to gdb. */
> builtin_type_ia64_ext =
> init_type (TYPE_CODE_FLT, 128 / 8,
> @@ -2826,6 +3419,10 @@ ia64_gdbarch_init (struct gdbarch_info i
>
> set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc);
> frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
> +#ifdef HAVE_LIBUNWIND_IA64_H
> + frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer);
> + libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr);
> +#endif
> frame_unwind_append_sniffer (gdbarch, ia64_frame_sniffer);
> frame_base_set_default (gdbarch, &ia64_frame_base);
>
> Index: ia64-linux-tdep.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/ia64-linux-tdep.c,v
> retrieving revision 1.4
> diff -u -p -r1.4 ia64-linux-tdep.c
> --- ia64-linux-tdep.c 15 Oct 2003 22:55:32 -0000 1.4
> +++ ia64-linux-tdep.c 28 Oct 2003 23:45:54 -0000
> @@ -22,6 +22,7 @@
> #include "defs.h"
> #include "arch-utils.h"
> #include "gdbcore.h"
> +#include <sys/syscall.h>
>
> /* The sigtramp code is in a non-readable (executable-only) region
> of memory called the ``gate page''. The addresses in question
> @@ -92,4 +93,10 @@ ia64_linux_sigcontext_register_address (
> default :
> return 0;
> }
> +}
> +
> +unsigned long
> +ia64_linux_getunwind_table (void *buf, size_t len)
> +{
> + return syscall (__NR_getunwind, buf, len);
> }
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-10-29 22:48 ` Andrew Cagney
@ 2003-11-04 19:09 ` J. Johnston
2003-11-04 20:48 ` Kevin Buettner
` (4 more replies)
0 siblings, 5 replies; 32+ messages in thread
From: J. Johnston @ 2003-11-04 19:09 UTC (permalink / raw)
To: Andrew Cagney
Cc: Daniel Jacobowitz, Kevin Buettner, Marcel Moolenaar, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2057 bytes --]
I have chosen the first option to implement the syscall. I have included a
patch here regarding this mechanism.
Ok to commit?
-- Jeff J.
2003-11-04 Jeff Johnston <jjohnstn@redhat.com>
* config/ia64/nm-linux.h (CHILD_TO_XFER_PARTIAL): New macro to set up the
ia64 linux native target to_xfer_partial method.
(ia64_linux_xfer_partial): New prototype.
* ia64-linux-nat.c (ia64_linux_xfer_partial): New function.
* inftarg.c (init_child_ops)[CHILD_TO_XFER_PARTIAL]: Set up xfer partial
method if one provided via macro.
* target.c (init_dummy_target): Initialize to_xfer_partial to default.
* target.h (target_object): Add new TARGET_OBJECT_UNWIND_TABLE enum.
Andrew Cagney wrote:
>> Nothing which involves a syscall is acceptable in a tdep file. That's
>> what the t means - target support.
>
>
> ("tdep" mysteriously means "architecture vector support". That "t"
> really no longer makes sense :-()
>
> Yes, architecture vector shouldn't be directly making syscalls. Instead
> the architecture specific code should use the target vector to obtain
> this system information. Here I think the best option is to add another
> TARGET_OBJECT_xxxx variant and then use the target_read() method to pull
> in the data.
>
> As for the native target side, ia64-linux-nat should export something
> like ia64_linux_child_read_partial that performs the syscall. The
> tricky [er messy] part is wiring it into child_ops, I see there are lots
> of choices :-(
>
> - define a nm-*.c macro and have that enable the assignment (ex #define
> NATIVE_TO_READ_PARTIAL ia64_linux_child?) (ref KILL_INFERIOR)
>
> - have a callback set the to_read_partial method in child_ops
> (exec_set_find_memory_regions)
>
> - modify all the targets so that each implements the new method
>
> - others?
>
> Is this information available via /proc? In a core file?
>
> Andrew
>
> PS: Note this pending patch. Dependant on the timing you or I may need
> to tweak the name.
> http://sources.redhat.com/ml/gdb-patches/2003-10/msg00795.html
>
>
>
[-- Attachment #2: xfer_partial.patch --]
[-- Type: text/plain, Size: 4491 bytes --]
Index: config/ia64/nm-linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/ia64/nm-linux.h,v
retrieving revision 1.10
diff -u -r1.10 nm-linux.h
--- config/ia64/nm-linux.h 20 Jun 2003 13:57:29 -0000 1.10
+++ config/ia64/nm-linux.h 4 Nov 2003 16:53:37 -0000
@@ -69,4 +69,13 @@
extern int ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr,
int len);
+#include "target.h"
+
+#define CHILD_TO_XFER_PARTIAL ia64_linux_xfer_partial
+extern LONGEST ia64_linux_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, const void *writebuf,
+ void *readbuf,
+ ULONGEST offset, LONGEST len);
+
#endif /* #ifndef NM_LINUX_H */
Index: ia64-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-linux-nat.c,v
retrieving revision 1.20
diff -u -r1.20 ia64-linux-nat.c
--- ia64-linux-nat.c 2 Oct 2003 20:28:29 -0000 1.20
+++ ia64-linux-nat.c 4 Nov 2003 16:53:37 -0000
@@ -34,6 +34,7 @@
#ifdef HAVE_SYS_REG_H
#include <sys/reg.h>
#endif
+#include <sys/syscall.h>
#include <sys/user.h>
#include <asm/ptrace_offsets.h>
@@ -644,4 +645,48 @@
write_register_pid (IA64_PSR_REGNUM, psr, ptid);
return (CORE_ADDR) siginfo.si_addr;
+}
+
+LONGEST
+ia64_linux_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, const void *writebuf,
+ void *readbuf,
+ ULONGEST offset, LONGEST len)
+{
+ switch (object)
+ {
+ case TARGET_OBJECT_UNWIND_TABLE:
+ return syscall (__NR_getunwind, readbuf, len);
+ case TARGET_OBJECT_MEMORY:
+ if (ops->to_xfer_memory != NULL)
+ /* Fall back to the target's "to_xfer_memory" method. */
+ {
+ int xfered = -1;
+ errno = 0;
+ if (writebuf != NULL)
+ {
+ void *buffer = xmalloc (len);
+ struct cleanup *cleanup = make_cleanup (xfree, buffer);
+ memcpy (buffer, writebuf, len);
+ xfered = ops->to_xfer_memory (offset, buffer, len, 1/*write*/, NULL,
+ ops);
+ do_cleanups (cleanup);
+ }
+ if (readbuf != NULL)
+ xfered = ops->to_xfer_memory (offset, readbuf, len, 0/*read*/, NULL,
+ ops);
+
+ if (xfered > 0)
+ return xfered;
+ else if (xfered == 0 && errno == 0)
+ /* "to_xfer_memory" uses 0, cross checked against ERRNO as one
+ indication of an error. */
+ return 0;
+ else
+ return -1;
+ }
+ default:
+ return -1;
+ }
}
Index: inftarg.c
===================================================================
RCS file: /cvs/src/src/gdb/inftarg.c,v
retrieving revision 1.18
diff -u -r1.18 inftarg.c
--- inftarg.c 21 Sep 2003 01:26:45 -0000 1.18
+++ inftarg.c 4 Nov 2003 16:53:37 -0000
@@ -609,6 +609,9 @@
child_ops.to_get_current_exception_event = child_get_current_exception_event;
child_ops.to_pid_to_exec_file = child_pid_to_exec_file;
child_ops.to_stratum = process_stratum;
+#ifdef CHILD_TO_XFER_PARTIAL
+ child_ops.to_xfer_partial = CHILD_TO_XFER_PARTIAL;
+#endif
child_ops.to_has_all_memory = 1;
child_ops.to_has_memory = 1;
child_ops.to_has_stack = 1;
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.64
diff -u -r1.64 target.c
--- target.c 31 Oct 2003 15:25:34 -0000 1.64
+++ target.c 4 Nov 2003 16:53:38 -0000
@@ -1644,6 +1644,7 @@
dummy_target.to_stratum = dummy_stratum;
dummy_target.to_find_memory_regions = dummy_find_memory_regions;
dummy_target.to_make_corefile_notes = dummy_make_corefile_notes;
+ dummy_target.to_xfer_partial = default_xfer_partial;
dummy_target.to_magic = OPS_MAGIC;
}
\f
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.51
diff -u -r1.51 target.h
--- target.h 31 Oct 2003 19:19:51 -0000 1.51
+++ target.h 4 Nov 2003 16:53:38 -0000
@@ -223,8 +223,10 @@
/* AVR target specific transfer. See "avr-tdep.c" and "remote.c". */
TARGET_OBJECT_AVR,
/* Transfer up-to LEN bytes of memory starting at OFFSET. */
- TARGET_OBJECT_MEMORY
- /* Possible future ojbects: TARGET_OJBECT_FILE, TARGET_OBJECT_PROC,
+ TARGET_OBJECT_MEMORY,
+ /* Kernel Unwind Table. See "ia64-tdep.c". */
+ TARGET_OBJECT_UNWIND_TABLE,
+ /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC,
TARGET_OBJECT_AUXV, ... */
};
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-11-04 19:09 ` J. Johnston
@ 2003-11-04 20:48 ` Kevin Buettner
2003-11-06 17:21 ` RFA: ia64 portion of libunwind patch updated J. Johnston
` (3 subsequent siblings)
4 siblings, 0 replies; 32+ messages in thread
From: Kevin Buettner @ 2003-11-04 20:48 UTC (permalink / raw)
To: J. Johnston, Andrew Cagney
Cc: Daniel Jacobowitz, Kevin Buettner, Marcel Moolenaar, gdb-patches
On Nov 4, 2:09pm, J. Johnston wrote:
> I have chosen the first option to implement the syscall. I have included a
> patch here regarding this mechanism.
>
> Ok to commit?
>
> 2003-11-04 Jeff Johnston <jjohnstn@redhat.com>
>
> * config/ia64/nm-linux.h (CHILD_TO_XFER_PARTIAL): New macro to set up the
> ia64 linux native target to_xfer_partial method.
> (ia64_linux_xfer_partial): New prototype.
> * ia64-linux-nat.c (ia64_linux_xfer_partial): New function.
> * inftarg.c (init_child_ops)[CHILD_TO_XFER_PARTIAL]: Set up xfer partial
> method if one provided via macro.
> * target.c (init_dummy_target): Initialize to_xfer_partial to default.
> * target.h (target_object): Add new TARGET_OBJECT_UNWIND_TABLE enum.
The IA-64 specific portions of this patch are approved so long as the
approach taken is acceptable to the target vector maintainer (Andrew).
Note that we'll still (at some point) need to add machinery to remote.c
in order to work with remote IA-64 targets.
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* RFA: ia64 portion of libunwind patch updated
2003-11-04 19:09 ` J. Johnston
2003-11-04 20:48 ` Kevin Buettner
@ 2003-11-06 17:21 ` J. Johnston
2003-11-14 21:24 ` J. Johnston
2003-11-17 17:05 ` Kevin Buettner
2003-11-06 20:03 ` [commit] Fix two xfer partial bugs; Was; RFA: ia64 portion of libunwind patch Andrew Cagney
` (2 subsequent siblings)
4 siblings, 2 replies; 32+ messages in thread
From: J. Johnston @ 2003-11-06 17:21 UTC (permalink / raw)
To: gdb-patches
Cc: Andrew Cagney, Daniel Jacobowitz, Kevin Buettner, Marcel Moolenaar
[-- Attachment #1: Type: text/plain, Size: 1277 bytes --]
The attached patch is the updated ia64 libunwind patch addressing a number of
comments. The bfd stuff has been replaced with a simple target memory read.
The syscall stuff has been replaced with a call to target_read_partial() which
has been implemented in another patch. I have added a few comments per Elena's
suggestion.
Ok to commit?
-- Jeff J.
2003-11-06 Jeff Johnston <jjohnstn@redhat.com>
David Mosberger <davidm@hpl.hp.com>
* ia64-tdep.c: Include elf.h.
[HAVE_LIBUNWIND_IA64_H]: Include libunwind-frame.h and libunwind-ia64.h.
(ia64_rse_slot_num, ia64_rse_skip_regs): New for libunwind support.
(ia64_gdb2uw_regnum, ia64_uw2gdb_regnum): Ditto.
(ia64_is_fpreg, ia64_access_reg): Ditto.
(ia64_access_fpreg, ia64_access_mem): Ditto.
(get_kernel_table): Ditto.
(ia64_find_unwind_table): Ditto.
(ia64_find_proc_info_x, ia64_put_unwind_info): Ditto.
(ia64_get_dyn_info_list, ia64_libunwind_frame_this_id): Ditto.
(ia64_libunwind_frame_prev_register): Ditto.
(ia64_libunwind_frame_sniffer): Ditto.
(ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Add libunwind frame
sniffer. Register libunwind functions needed by generic libunwind frame
code using libunwind_frame_set_descr().
[-- Attachment #2: ia64-tdep.libunwind.patch2 --]
[-- Type: text/plain, Size: 20757 bytes --]
Index: ia64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
retrieving revision 1.103
diff -u -p -r1.103 ia64-tdep.c
--- ia64-tdep.c 6 Nov 2003 02:52:27 -0000 1.103
+++ ia64-tdep.c 6 Nov 2003 17:13:36 -0000
@@ -36,8 +36,14 @@
#include "objfiles.h"
#include "elf/common.h" /* for DT_PLTGOT value */
#include "elf-bfd.h"
+#include "elf.h" /* for PT_IA64_UNWIND value */
#include "dis-asm.h"
+#ifdef HAVE_LIBUNWIND_IA64_H
+#include "libunwind-frame.h"
+#include "libunwind-ia64.h"
+#endif
+
/* Hook for determining the global pointer when calling functions in
the inferior under AIX. The initialization code in ia64-aix-nat.c
sets this hook to the address of a function which will find the
@@ -87,6 +93,7 @@ typedef enum instruction_type
/* FIXME: These extern declarations should go in ia64-tdep.h. */
extern CORE_ADDR ia64_linux_sigcontext_register_address (CORE_ADDR, int);
extern CORE_ADDR ia64_aix_sigcontext_register_address (CORE_ADDR, int);
+extern unsigned long ia64_linux_getunwind_table (void *, size_t);
static gdbarch_init_ftype ia64_gdbarch_init;
@@ -2099,6 +2106,614 @@ static const struct frame_base ia64_fram
ia64_frame_base_address
};
+#ifdef HAVE_LIBUNWIND_IA64_H
+
+struct ia64_unwind_table_entry
+ {
+ unw_word_t start_offset;
+ unw_word_t end_offset;
+ unw_word_t info_offset;
+ };
+
+static __inline__ uint64_t
+ia64_rse_slot_num (uint64_t addr)
+{
+ return (addr >> 3) & 0x3f;
+}
+
+/* Skip over a designated number of registers in the backing
+ store, remembering every 64th position is for NAT. */
+static __inline__ uint64_t
+ia64_rse_skip_regs (uint64_t addr, long num_regs)
+{
+ long delta = ia64_rse_slot_num(addr) + num_regs;
+
+ if (num_regs < 0)
+ delta -= 0x3e;
+ return addr + ((num_regs + delta/0x3f) << 3);
+}
+
+/* Gdb libunwind-frame callback function to convert from an ia64 gdb register
+ number to a libunwind register number. */
+static int
+ia64_gdb2uw_regnum (int regnum)
+{
+ if (regnum == sp_regnum)
+ return UNW_IA64_SP;
+ else if (regnum == IA64_BSP_REGNUM)
+ return UNW_IA64_BSP;
+ else if ((unsigned) (regnum - IA64_GR0_REGNUM) < 128)
+ return UNW_IA64_GR + (regnum - IA64_GR0_REGNUM);
+ else if ((unsigned) (regnum - V32_REGNUM) < 95)
+ return UNW_IA64_GR + 32 + (regnum - V32_REGNUM);
+ else if ((unsigned) (regnum - IA64_FR0_REGNUM) < 128)
+ return UNW_IA64_FR + (regnum - IA64_FR0_REGNUM);
+ else if ((unsigned) (regnum - IA64_PR0_REGNUM) < 64)
+ return -1;
+ else if ((unsigned) (regnum - IA64_BR0_REGNUM) < 8)
+ return UNW_IA64_BR + (regnum - IA64_BR0_REGNUM);
+ else if (regnum == IA64_PR_REGNUM)
+ return UNW_IA64_PR;
+ else if (regnum == IA64_IP_REGNUM)
+ return UNW_REG_IP;
+ else if (regnum == IA64_CFM_REGNUM)
+ return UNW_IA64_CFM;
+ else if ((unsigned) (regnum - IA64_AR0_REGNUM) < 128)
+ return UNW_IA64_AR + (regnum - IA64_AR0_REGNUM);
+ else if ((unsigned) (regnum - IA64_NAT0_REGNUM) < 128)
+ return UNW_IA64_NAT + (regnum - IA64_NAT0_REGNUM);
+ else
+ return -1;
+}
+
+/* Gdb libunwind-frame callback function to convert from a libunwind register
+ number to a ia64 gdb register number. */
+static int
+ia64_uw2gdb_regnum (int uw_regnum)
+{
+ if (uw_regnum == UNW_IA64_SP)
+ return sp_regnum;
+ else if (uw_regnum == UNW_IA64_BSP)
+ return IA64_BSP_REGNUM;
+ else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 32)
+ return IA64_GR0_REGNUM + (uw_regnum - UNW_IA64_GR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 128)
+ return V32_REGNUM + (uw_regnum - (IA64_GR0_REGNUM + 32));
+ else if ((unsigned) (uw_regnum - UNW_IA64_FR) < 128)
+ return IA64_FR0_REGNUM + (uw_regnum - UNW_IA64_FR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_BR) < 8)
+ return IA64_BR0_REGNUM + (uw_regnum - UNW_IA64_BR);
+ else if (uw_regnum == UNW_IA64_PR)
+ return IA64_PR_REGNUM;
+ else if (uw_regnum == UNW_REG_IP)
+ return IA64_IP_REGNUM;
+ else if (uw_regnum == UNW_IA64_CFM)
+ return IA64_CFM_REGNUM;
+ else if ((unsigned) (uw_regnum - UNW_IA64_AR) < 128)
+ return IA64_AR0_REGNUM + (uw_regnum - UNW_IA64_AR);
+ else if ((unsigned) (uw_regnum - UNW_IA64_NAT) < 128)
+ return IA64_NAT0_REGNUM + (uw_regnum - UNW_IA64_NAT);
+ else
+ return -1;
+}
+
+/* Gdb libunwind-frame callback function to reveal if register is a float
+ register or not. */
+static int
+ia64_is_fpreg (int uw_regnum)
+{
+ return unw_is_fpreg (uw_regnum);
+}
+
+/* Libunwind callback accessor function for general registers. */
+static int
+ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+ unw_word_t bsp, sof, sol, cfm, psr, ip;
+ struct frame_info *next_frame = arg;
+ long new_sof, old_sof;
+ char buf[MAX_REGISTER_SIZE];
+
+ if (write)
+ {
+ if (regnum < 0)
+ /* ignore writes to pseudo-registers such as UNW_IA64_PROC_STARTI. */
+ return 0;
+
+ switch (uw_regnum)
+ {
+ case UNW_REG_IP:
+ ia64_write_pc (*val, inferior_ptid);
+ break;
+
+ case UNW_IA64_AR_BSPSTORE:
+ write_register (IA64_BSP_REGNUM, *val);
+ break;
+
+ case UNW_IA64_AR_BSP:
+ case UNW_IA64_BSP:
+ /* Account for the fact that ptrace() expects bsp to point
+ after the current register frame. */
+ cfm = read_register (IA64_CFM_REGNUM);
+ sof = (cfm & 0x7f);
+ bsp = ia64_rse_skip_regs (*val, sof);
+ write_register (IA64_BSP_REGNUM, bsp);
+ break;
+
+ 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. */
+ bsp = read_register (IA64_BSP_REGNUM);
+ cfm = read_register (IA64_CFM_REGNUM);
+ old_sof = (cfm & 0x7f);
+ new_sof = (*val & 0x7f);
+ if (old_sof != new_sof)
+ {
+ bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
+ write_register (IA64_BSP_REGNUM, bsp);
+ }
+ write_register (IA64_CFM_REGNUM, *val);
+ break;
+
+ default:
+ write_register (regnum, *val);
+ break;
+ }
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_reg: to cache: %4s=%016lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), *val);
+ }
+ else
+ {
+ switch (uw_regnum)
+ {
+ case UNW_REG_IP:
+ /* Libunwind expects to see the pc value which means the slot number
+ from the psr must be merged with the ip word address. */
+ frame_unwind_register (next_frame, IA64_IP_REGNUM, buf);
+ ip = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 8);
+ *val = ip | ((psr >> 41) & 0x3);
+ break;
+
+ case UNW_IA64_AR_BSP:
+ /* Libunwind expects to see the beginning of the current register
+ frame so we must account for the fact that ptrace() will return a value
+ for bsp that points *after* the current register frame. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ sof = (cfm & 0x7f);
+ *val = ia64_rse_skip_regs (bsp, -sof);
+ break;
+
+ case UNW_IA64_AR_BSPSTORE:
+ /* Libunwind wants bspstore to be after the current register frame.
+ This is what ptrace() and gdb treats as the regular bsp value. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+
+ default:
+ /* For all other registers, just unwind the value directly. */
+ frame_unwind_register (next_frame, regnum, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_reg: from cache: %4s=%016lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), *val);
+ }
+ return 0;
+}
+
+/* Libunwind callback accessor function for floating-point registers. */
+static int
+ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+
+ if (write)
+ regcache_cooked_write (current_regcache, regnum, (char *) val);
+ else
+ regcache_cooked_read (current_regcache, regnum, (char *) val);
+ return 0;
+}
+
+/* Libunwind callback accessor function for accessing memory. */
+static int
+ia64_access_mem (unw_addr_space_t as,
+ unw_word_t addr, unw_word_t *val,
+ int write, void *arg)
+{
+ /* XXX do we need to normalize byte-order here? */
+ if (write)
+ return target_write_memory (addr, (char *) val, sizeof (unw_word_t));
+ else
+ return target_read_memory (addr, (char *) val, sizeof (unw_word_t));
+}
+
+/* Call low-level function to access the kernel unwind table. */
+static int
+getunwind_table (void *buf, size_t len)
+{
+ LONGEST x;
+ x = target_read_partial (¤t_target, TARGET_OBJECT_UNWIND_TABLE, NULL,
+ buf, 0, len);
+
+ return (int)x;
+}
+
+/* Get the kernel unwind table. */
+static int
+get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
+{
+ size_t size;
+ struct ia64_table_entry
+ {
+ uint64_t start_offset;
+ uint64_t end_offset;
+ uint64_t info_offset;
+ };
+ static struct ia64_table_entry *ktab = NULL, *etab;
+
+ if (!ktab)
+ {
+ size = getunwind_table (NULL, 0);
+ if ((int)size < 0)
+ return -UNW_ENOINFO;
+ ktab = xmalloc (size);
+ getunwind_table (ktab, size);
+
+ /* Determine length of kernel's unwind table and relocate
+ it's entries. */
+ for (etab = ktab; etab->start_offset; ++etab)
+ etab->info_offset += (uint64_t) ktab;
+ }
+
+ if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset)
+ return -UNW_ENOINFO;
+
+ di->format = UNW_INFO_FORMAT_TABLE;
+ di->gp = 0;
+ di->start_ip = ktab[0].start_offset;
+ di->end_ip = etab[-1].end_offset;
+ di->u.ti.name_ptr = (unw_word_t) "<kernel>";
+ di->u.ti.segbase = 0;
+ di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
+ di->u.ti.table_data = (unw_word_t *) ktab;
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "get_kernel_table: found table `%s': "
+ "segbase=%lx, length=%lu, gp=%lx\n",
+ (char *) di->u.ti.name_ptr, di->u.ti.segbase,
+ di->u.ti.table_len, di->gp);
+ return 0;
+}
+
+/* Find the unwind table entry for a specified address. */
+static int
+ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip,
+ unw_dyn_info_t *dip, void **buf)
+{
+ Elf_Internal_Phdr *phdr, *p_text = NULL, *p_unwind = NULL;
+ Elf_Internal_Ehdr *ehdr;
+ unw_word_t segbase = 0;
+ CORE_ADDR load_base;
+ bfd *bfd;
+ int i;
+
+ bfd = objfile->obfd;
+
+ ehdr = elf_tdata (bfd)->elf_header;
+ phdr = elf_tdata (bfd)->phdr;
+
+ load_base = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ {
+ switch (phdr[i].p_type)
+ {
+ case PT_LOAD:
+ if ((unw_word_t) (ip - load_base - phdr[i].p_vaddr)
+ < phdr[i].p_memsz)
+ p_text = phdr + i;
+ break;
+
+ case PT_IA_64_UNWIND:
+ p_unwind = phdr + i;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!p_text || !p_unwind
+ /* Verify that the segment that contains the IP also contains
+ the static unwind table. If not, we are dealing with
+ runtime-generated code, for which we have no info here. */
+ || (p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
+ return -UNW_ENOINFO;
+
+ segbase = p_text->p_vaddr + load_base;
+
+ dip->start_ip = segbase;
+ dip->end_ip = dip->start_ip + p_text->p_memsz;
+ dip->gp = FIND_GLOBAL_POINTER (ip);
+ dip->format = UNW_INFO_FORMAT_TABLE;
+ dip->u.ti.name_ptr = (unw_word_t) bfd_get_filename (bfd);
+ dip->u.ti.segbase = segbase;
+ dip->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
+
+ /* The following 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. */
+ if (ip < dip->start_ip || ip >= dip->end_ip)
+ return -UNW_ENOINFO;
+
+ /* Read in the libunwind table. */
+ *buf = xmalloc (p_unwind->p_memsz);
+ target_read_memory (p_unwind->p_vaddr + load_base, (char *)(*buf), p_unwind->p_memsz);
+
+ dip->u.ti.table_data = (unw_word_t *)(*buf);
+
+ return 0;
+}
+
+/* Libunwind callback accessor function to acquire procedure unwind-info. */
+static int
+ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
+{
+ struct obj_section *sec = find_pc_section (ip);
+ unw_dyn_info_t di;
+ int ret;
+ void *buf = NULL;
+
+ if (!sec)
+ {
+ /* XXX This only works if the host and the target architecture are
+ both ia64 and if the have (more or less) the same kernel
+ version. */
+ if (get_kernel_table (ip, &di) < 0)
+ return -UNW_ENOINFO;
+ }
+ else
+ {
+ ret = ia64_find_unwind_table (sec->objfile, ip, &di, &buf);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog, "acquire_unwind_info: %lx -> "
+ "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
+ "length=%lu,data=%p)\n", ip, (char *)di.u.ti.name_ptr,
+ di.u.ti.segbase, di.start_ip, di.end_ip,
+ di.gp, di.u.ti.table_len, di.u.ti.table_data);
+
+ ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info, arg);
+
+ /* We no longer need the dyn info storage so free it. */
+ xfree (buf);
+
+ return ret;
+}
+
+/* Libunwind callback accessor function for cleanup. */
+static void
+ia64_put_unwind_info (unw_addr_space_t as,
+ unw_proc_info_t *pip, void *arg)
+{
+ /* Nothing required for now. */
+}
+
+/* Libunwind callback accessor function to get head of the dynamic
+ unwind-info registration list. */
+static int
+ia64_get_dyn_info_list (unw_addr_space_t as,
+ unw_word_t *dilap, void *arg)
+{
+ struct obj_section *text_sec;
+ struct objfile *objfile;
+ unw_word_t ip, addr;
+ unw_dyn_info_t di;
+ int ret;
+
+ if (!libunwind_is_initialized ())
+ return -UNW_ENOINFO;
+
+ for (objfile = object_files; objfile; objfile = objfile->next)
+ {
+ void *buf = NULL;
+
+ text_sec = objfile->sections + SECT_OFF_TEXT (objfile);
+ ip = text_sec->addr;
+ ret = ia64_find_unwind_table (objfile, ip, &di, &buf);
+ if (ret >= 0)
+ {
+ addr = libunwind_find_dyn_list (as, di.u.ti.table_data,
+ (di.u.ti.table_len
+ * sizeof (di.u.ti.table_data[0])),
+ di.u.ti.segbase, di.gp, arg);
+ /* We no longer need the dyn info storage so free it. */
+ xfree (buf);
+
+ if (addr)
+ {
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "dynamic unwind table in objfile %s "
+ "at %lx (gp=%lx)\n",
+ bfd_get_filename (objfile->obfd),
+ addr, di.gp);
+ *dilap = addr;
+ return 0;
+ }
+ }
+ }
+ return -UNW_ENOINFO;
+}
+
+
+/* Frame interface functions for libunwind. */
+
+static void
+ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ char buf[8];
+ CORE_ADDR bsp;
+ struct frame_id id;
+
+ libunwind_frame_this_id (next_frame, this_cache, &id);
+
+ /* We must add the bsp as the special address for frame comparison purposes. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+
+ (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "libunwind frame id: code %lx, stack %lx, special %lx, next_frame %p\n",
+ id.code_addr, id.stack_addr, bsp, next_frame);
+}
+
+static void
+ia64_libunwind_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ int reg = regnum;
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ reg = IA64_PR_REGNUM;
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ reg = IA64_UNAT_REGNUM;
+
+ /* Let libunwind do most of the work. */
+ libunwind_frame_prev_register (next_frame, this_cache, reg,
+ optimizedp, lvalp, addrp, realnump, valuep);
+
+ if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ ULONGEST prN_val;
+
+ if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
+ {
+ int rrb_pr = 0;
+ ULONGEST cfm;
+ unsigned char buf[MAX_REGISTER_SIZE];
+
+ /* Fetch predicate register rename base from current frame
+ marker for this frame. */
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ rrb_pr = (cfm >> 32) & 0x3f;
+
+ /* Adjust the register number to account for register rotation. */
+ regnum = VP16_REGNUM
+ + ((regnum - VP16_REGNUM) + rrb_pr) % 48;
+ }
+ prN_val = extract_bit_field ((unsigned char *) valuep,
+ regnum - VP0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
+ }
+ else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
+ {
+ ULONGEST unatN_val;
+
+ unatN_val = extract_bit_field ((unsigned char *) valuep,
+ regnum - IA64_NAT0_REGNUM, 1);
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ unatN_val);
+ }
+ else if (regnum == IA64_BSP_REGNUM)
+ {
+ char cfm_valuep[MAX_REGISTER_SIZE];
+ int cfm_optim;
+ int cfm_realnum;
+ enum lval_type cfm_lval;
+ CORE_ADDR cfm_addr;
+ CORE_ADDR bsp, prev_cfm, prev_bsp;
+
+ /* We want to calculate the previous bsp as the end of the previous register stack frame.
+ This corresponds to what the hardware bsp register will be if we pop the frame
+ back which is why we might have been called. We know that libunwind will pass us back
+ the beginning of the current frame so we should just add sof to it. */
+ prev_bsp = extract_unsigned_integer (valuep, 8);
+ libunwind_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM,
+ &cfm_optim, &cfm_lval, &cfm_addr, &cfm_realnum, cfm_valuep);
+ prev_cfm = extract_unsigned_integer (cfm_valuep, 8);
+ prev_bsp = rse_address_add (prev_bsp, (prev_cfm & 0x7f));
+
+ store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ prev_bsp);
+ }
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "libunwind prev register <%s> is %lx\n",
+ (((unsigned) regnum <= IA64_NAT127_REGNUM)
+ ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8));
+}
+
+static const struct frame_unwind ia64_libunwind_frame_unwind =
+{
+ NORMAL_FRAME,
+ ia64_libunwind_frame_this_id,
+ ia64_libunwind_frame_prev_register
+};
+
+static const struct frame_unwind *
+ia64_libunwind_frame_sniffer (struct frame_info *next_frame)
+{
+ if (libunwind_is_initialized () && libunwind_frame_sniffer (next_frame))
+ return &ia64_libunwind_frame_unwind;
+
+ return NULL;
+}
+
+/* Set of libunwind callback acccessor functions. */
+static unw_accessors_t ia64_unw_accessors =
+{
+ ia64_find_proc_info_x,
+ ia64_put_unwind_info,
+ ia64_get_dyn_info_list,
+ ia64_access_mem,
+ ia64_access_reg,
+ ia64_access_fpreg,
+ /* resume */
+ /* get_proc_name */
+};
+
+/* Set of ia64 gdb libunwind-frame callbacks and data for generic libunwind-frame code to use. */
+static struct libunwind_descr ia64_libunwind_descr =
+{
+ ia64_gdb2uw_regnum,
+ ia64_uw2gdb_regnum,
+ ia64_is_fpreg,
+ &ia64_unw_accessors,
+};
+
+#endif /* HAVE_LIBUNWIND_IA64_H */
+
/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc
and TYPE is the type (which is known to be struct, union or array). */
@@ -2795,6 +3410,10 @@ ia64_gdbarch_init (struct gdbarch_info i
set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc);
frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
+#ifdef HAVE_LIBUNWIND_IA64_H
+ frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer);
+ libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr);
+#endif
frame_unwind_append_sniffer (gdbarch, ia64_frame_sniffer);
frame_base_set_default (gdbarch, &ia64_frame_base);
^ permalink raw reply [flat|nested] 32+ messages in thread
* [commit] Fix two xfer partial bugs; Was; RFA: ia64 portion of libunwind patch
2003-11-04 19:09 ` J. Johnston
2003-11-04 20:48 ` Kevin Buettner
2003-11-06 17:21 ` RFA: ia64 portion of libunwind patch updated J. Johnston
@ 2003-11-06 20:03 ` Andrew Cagney
2003-11-06 20:12 ` J. Johnston
2003-11-06 22:32 ` [patch/rfc] Add child_to_xfer_partial; Was: " Andrew Cagney
2003-11-14 0:26 ` RFA: " J. Johnston
4 siblings, 1 reply; 32+ messages in thread
From: Andrew Cagney @ 2003-11-06 20:03 UTC (permalink / raw)
To: J. Johnston
Cc: Andrew Cagney, Daniel Jacobowitz, Kevin Buettner,
Marcel Moolenaar, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 589 bytes --]
Jeff,
I've just committed the attached. It fixes two bugs when using xfer
partial in an existing target.
- the "add_target" method was always overriding the child's
to_xfer_partial method. The consequence is that the code your patch
adds is never called!
- the code would all off the end of a stack which this part of the
change fixed: * target.c (init_dummy_target): Initialize to_xfer_partial
to default.
I've one more tweak to the target code. Once thats in can you please
confirm that this new child method is called and is needed - seems
things work without it?
Andrew
[-- Attachment #2: diffs --]
[-- Type: text/plain, Size: 1039 bytes --]
2003-11-06 Andrew Cagney <cagney@redhat.com>
Jeff Johnston <jjohnstn@redhat.com>
* target.c (add_target): Only set "to_xfer_partial" when NULL.
(init_dummy_target): Set "to_xfer_partial".
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.64
diff -u -r1.64 target.c
--- target.c 31 Oct 2003 15:25:34 -0000 1.64
+++ target.c 6 Nov 2003 19:55:45 -0000
@@ -220,7 +220,8 @@
add_target (struct target_ops *t)
{
/* Provide default values for all "must have" methods. */
- t->to_xfer_partial = default_xfer_partial;
+ if (t->to_xfer_partial == NULL)
+ t->to_xfer_partial = default_xfer_partial;
if (!target_structs)
{
@@ -1644,6 +1645,7 @@
dummy_target.to_stratum = dummy_stratum;
dummy_target.to_find_memory_regions = dummy_find_memory_regions;
dummy_target.to_make_corefile_notes = dummy_make_corefile_notes;
+ dummy_target.to_xfer_partial = default_xfer_partial;
dummy_target.to_magic = OPS_MAGIC;
}
\f
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [commit] Fix two xfer partial bugs; Was; RFA: ia64 portion of libunwind patch
2003-11-06 20:03 ` [commit] Fix two xfer partial bugs; Was; RFA: ia64 portion of libunwind patch Andrew Cagney
@ 2003-11-06 20:12 ` J. Johnston
0 siblings, 0 replies; 32+ messages in thread
From: J. Johnston @ 2003-11-06 20:12 UTC (permalink / raw)
To: Andrew Cagney
Cc: Daniel Jacobowitz, Kevin Buettner, Marcel Moolenaar, gdb-patches
Andrew Cagney wrote:
> Jeff,
>
> I've just committed the attached. It fixes two bugs when using xfer
> partial in an existing target.
>
> - the "add_target" method was always overriding the child's
> to_xfer_partial method. The consequence is that the code your patch
> adds is never called!
>
> - the code would all off the end of a stack which this part of the
> change fixed: * target.c (init_dummy_target): Initialize to_xfer_partial
> to default.
>
> I've one more tweak to the target code. Once thats in can you please
> confirm that this new child method is called and is needed - seems
> things work without it?
>
Yes. It is only called if the find_pc_in_section() call fails which it doesn't
for the gdb testsuite.
I can try hardwiring a failure to verify that code works once you have your
changes in.
-- Jeff J.
^ permalink raw reply [flat|nested] 32+ messages in thread
* [patch/rfc] Add child_to_xfer_partial; Was: ia64 portion of libunwind patch
2003-11-04 19:09 ` J. Johnston
` (2 preceding siblings ...)
2003-11-06 20:03 ` [commit] Fix two xfer partial bugs; Was; RFA: ia64 portion of libunwind patch Andrew Cagney
@ 2003-11-06 22:32 ` Andrew Cagney
2003-11-06 22:47 ` J. Johnston
2003-11-07 1:04 ` Kevin Buettner
2003-11-14 0:26 ` RFA: " J. Johnston
4 siblings, 2 replies; 32+ messages in thread
From: Andrew Cagney @ 2003-11-06 22:32 UTC (permalink / raw)
To: J. Johnston
Cc: Andrew Cagney, Daniel Jacobowitz, Kevin Buettner,
Marcel Moolenaar, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 752 bytes --]
Jeff,
This adds a child_xfer_partial method to "inftarg.c". I've included a
hook vis:
> +#if 0
> + case TARGET_OBJECT_UNWIND_TABLE:
> +#ifndef NATIVE_XFER_UNWIND_TABLE
> +#define NATIVE_XFER_UNWIND_TABLE(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN)
> (-1)
> +#endif
> + return NATIVE_XFER_UNWIND_TABLE (ops, object, annex, writebuf,
> + readbuf, offset, len);
> +#endif
so that, in theory, all you need do is define that in the linux specific
nm-*.h file.
I think this will make plugging in additional xfer methods easier. How
does it look?
Anyone else?
Andrew
PS: You'll notice that it also contains lurking code to add support for
an auxv transfer.
PPS: Note that I need to better test it.
[-- Attachment #2: diffs --]
[-- Type: text/plain, Size: 1925 bytes --]
2003-11-06 Andrew Cagney <cagney@redhat.com>
* inftarg.c (child_xfer_partial): New function
(init_child_ops): Set "to_xfer_partial".
Index: inftarg.c
===================================================================
RCS file: /cvs/src/src/gdb/inftarg.c,v
retrieving revision 1.18
diff -u -r1.18 inftarg.c
--- inftarg.c 21 Sep 2003 01:26:45 -0000 1.18
+++ inftarg.c 6 Nov 2003 22:20:17 -0000
@@ -551,7 +551,45 @@
*/
return NULL;
}
-\f
+
+/* Perform a partial transfer to/from the specified object. */
+
+static LONGEST
+child_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, const void *writebuf,
+ void *readbuf, ULONGEST offset, LONGEST len)
+{
+ switch (object)
+ {
+ case TARGET_OBJECT_MEMORY:
+ if (readbuf)
+ return child_xfer_memory (offset, readbuf, len, 0/*write*/,
+ NULL, ops);
+ if (writebuf)
+ return child_xfer_memory (offset, readbuf, len, 1/*write*/,
+ NULL, ops);
+ return -1;
+
+#if 0
+ case TARGET_OBJECT_UNWIND_TABLE:
+#ifndef NATIVE_XFER_UNWIND_TABLE
+#define NATIVE_XFER_UNWIND_TABLE(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN) (-1)
+#endif
+ return NATIVE_XFER_UNWIND_TABLE (ops, object, annex, writebuf,
+ readbuf, offset, len);
+#endif
+
+#if 0
+ case TARGET_OBJECT_AUXV:
+ return native_xfer_auxv (PIDGET (inferior_ptid), writebuf, readbuf,
+ offset, len);
+#endif
+
+ default:
+ return -1;
+ }
+}
#if !defined(CHILD_PID_TO_STR)
char *
@@ -578,6 +616,7 @@
child_ops.to_store_registers = store_inferior_registers;
child_ops.to_prepare_to_store = child_prepare_to_store;
child_ops.to_xfer_memory = child_xfer_memory;
+ child_ops.to_xfer_partial = child_xfer_partial;
child_ops.to_files_info = child_files_info;
child_ops.to_insert_breakpoint = memory_insert_breakpoint;
child_ops.to_remove_breakpoint = memory_remove_breakpoint;
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [patch/rfc] Add child_to_xfer_partial; Was: ia64 portion of libunwind patch
2003-11-06 22:32 ` [patch/rfc] Add child_to_xfer_partial; Was: " Andrew Cagney
@ 2003-11-06 22:47 ` J. Johnston
2003-11-07 21:40 ` Andrew Cagney
2003-11-07 1:04 ` Kevin Buettner
1 sibling, 1 reply; 32+ messages in thread
From: J. Johnston @ 2003-11-06 22:47 UTC (permalink / raw)
To: Andrew Cagney
Cc: Daniel Jacobowitz, Kevin Buettner, Marcel Moolenaar, gdb-patches
Andrew Cagney wrote:
> Jeff,
>
> This adds a child_xfer_partial method to "inftarg.c". I've included a
> hook vis:
>
>> +#if 0
>> + case TARGET_OBJECT_UNWIND_TABLE:
>> +#ifndef NATIVE_XFER_UNWIND_TABLE
>> +#define
>> NATIVE_XFER_UNWIND_TABLE(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN)
>> (-1)
>> +#endif
>> + return NATIVE_XFER_UNWIND_TABLE (ops, object, annex, writebuf,
>> + readbuf, offset, len);
>> +#endif
>
>
> so that, in theory, all you need do is define that in the linux specific
> nm-*.h file.
>
> I think this will make plugging in additional xfer methods easier. How
> does it look?
>
I like it because it means I only have to provide the particular functionality
instead of overriding the whole function which could be dangerous if other
changes were made to the default_xfer_partial routine.
> Anyone else?
> Andrew
>
> PS: You'll notice that it also contains lurking code to add support for
> an auxv transfer.
>
> PPS: Note that I need to better test it.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [patch/rfc] Add child_to_xfer_partial; Was: ia64 portion of libunwind patch
2003-11-06 22:32 ` [patch/rfc] Add child_to_xfer_partial; Was: " Andrew Cagney
2003-11-06 22:47 ` J. Johnston
@ 2003-11-07 1:04 ` Kevin Buettner
1 sibling, 0 replies; 32+ messages in thread
From: Kevin Buettner @ 2003-11-07 1:04 UTC (permalink / raw)
To: Andrew Cagney, J. Johnston
Cc: Daniel Jacobowitz, Kevin Buettner, Marcel Moolenaar, gdb-patches
On Nov 6, 5:32pm, Andrew Cagney wrote:
> This adds a child_xfer_partial method to "inftarg.c". I've included a
> hook vis:
>
> > +#if 0
> > + case TARGET_OBJECT_UNWIND_TABLE:
> > +#ifndef NATIVE_XFER_UNWIND_TABLE
> > +#define NATIVE_XFER_UNWIND_TABLE(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN)
> > (-1)
> > +#endif
> > + return NATIVE_XFER_UNWIND_TABLE (ops, object, annex, writebuf,
> > + readbuf, offset, len);
> > +#endif
>
> so that, in theory, all you need do is define that in the linux specific
> nm-*.h file.
>
> I think this will make plugging in additional xfer methods easier. How
> does it look?
>
> Anyone else?
Looks good to me. I assume it's #if 0'd because TARGET_OBJECT_UNWIND_TABLE
isn't defined yet?
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [patch/rfc] Add child_to_xfer_partial; Was: ia64 portion of libunwind patch
2003-11-06 22:47 ` J. Johnston
@ 2003-11-07 21:40 ` Andrew Cagney
0 siblings, 0 replies; 32+ messages in thread
From: Andrew Cagney @ 2003-11-07 21:40 UTC (permalink / raw)
To: J. Johnston
Cc: Andrew Cagney, Daniel Jacobowitz, Kevin Buettner,
Marcel Moolenaar, gdb-patches
> I like it because it means I only have to provide the particular functionality instead of overriding the whole function which could be dangerous if other changes were made to the default_xfer_partial routine.
I'ts in. Any luck with a testcase for the unwind table? Something to
add to gdb.arch. If none of us can figure out a way to tickle this code
then it may not even be needed.
Kevin wrote ..
> I assume it's #if 0'd because TARGET_OBJECT_UNWIND_TABLE
> isn't defined yet?
Yep. The intent is to sketch out the mechanism's basic structure. Jeff
will enable the code if/when it is needed.
Andrew
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-11-04 19:09 ` J. Johnston
` (3 preceding siblings ...)
2003-11-06 22:32 ` [patch/rfc] Add child_to_xfer_partial; Was: " Andrew Cagney
@ 2003-11-14 0:26 ` J. Johnston
2003-11-14 1:17 ` Kevin Buettner
4 siblings, 1 reply; 32+ messages in thread
From: J. Johnston @ 2003-11-14 0:26 UTC (permalink / raw)
To: J. Johnston
Cc: Andrew Cagney, Daniel Jacobowitz, Kevin Buettner,
Marcel Moolenaar, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2721 bytes --]
I have just added a new patch which accounts for Andrew's latest xfer_partial
changes.
Ok to commit?
-- Jeff J.
2003-11-13 Jeff Johnston <jjohnstn@redhat.com>
* config/ia64/nm-linux.h (NATIVE_XFER_UNWIND_TABLE): New macro to
set up the ia64 linux native target method for getting the kernel
unwind table.
* ia64-linux-nat.c (ia64_linux_xfer_unwind_table): New function.
* inftarg.c (child_xfer_partial): Enable section of code to
handle TARGET_OBJECT_UNWIND_TABLE.
* target.h (target_object): Add new TARGET_OBJECT_UNWIND_TABLE macro.
J. Johnston wrote:
> I have chosen the first option to implement the syscall. I have
> included a patch here regarding this mechanism.
>
> Ok to commit?
>
> -- Jeff J.
>
> 2003-11-04 Jeff Johnston <jjohnstn@redhat.com>
>
> * config/ia64/nm-linux.h (CHILD_TO_XFER_PARTIAL): New macro to set
> up the ia64 linux native target to_xfer_partial method.
> (ia64_linux_xfer_partial): New prototype.
> * ia64-linux-nat.c (ia64_linux_xfer_partial): New function.
> * inftarg.c (init_child_ops)[CHILD_TO_XFER_PARTIAL]: Set up xfer
> partial method if one provided via macro.
> * target.c (init_dummy_target): Initialize to_xfer_partial to default.
> * target.h (target_object): Add new TARGET_OBJECT_UNWIND_TABLE enum.
>
>
> Andrew Cagney wrote:
>
>>> Nothing which involves a syscall is acceptable in a tdep file. That's
>>> what the t means - target support.
>>
>>
>>
>> ("tdep" mysteriously means "architecture vector support". That "t"
>> really no longer makes sense :-()
>>
>> Yes, architecture vector shouldn't be directly making syscalls.
>> Instead the architecture specific code should use the target vector to
>> obtain this system information. Here I think the best option is to
>> add another TARGET_OBJECT_xxxx variant and then use the target_read()
>> method to pull in the data.
>>
>> As for the native target side, ia64-linux-nat should export something
>> like ia64_linux_child_read_partial that performs the syscall. The
>> tricky [er messy] part is wiring it into child_ops, I see there are
>> lots of choices :-(
>>
>> - define a nm-*.c macro and have that enable the assignment (ex
>> #define NATIVE_TO_READ_PARTIAL ia64_linux_child?) (ref KILL_INFERIOR)
>>
>> - have a callback set the to_read_partial method in child_ops
>> (exec_set_find_memory_regions)
>>
>> - modify all the targets so that each implements the new method
>>
>> - others?
>>
>> Is this information available via /proc? In a core file?
>>
>> Andrew
>>
>> PS: Note this pending patch. Dependant on the timing you or I may
>> need to tweak the name.
>> http://sources.redhat.com/ml/gdb-patches/2003-10/msg00795.html
>>
>>
>>
[-- Attachment #2: xfer_partial.patch2 --]
[-- Type: text/plain, Size: 3072 bytes --]
Index: config/ia64/nm-linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/ia64/nm-linux.h,v
retrieving revision 1.10
diff -u -r1.10 nm-linux.h
--- config/ia64/nm-linux.h 20 Jun 2003 13:57:29 -0000 1.10
+++ config/ia64/nm-linux.h 14 Nov 2003 00:06:02 -0000
@@ -69,4 +69,15 @@
extern int ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr,
int len);
+#include "target.h"
+
+#define NATIVE_XFER_UNWIND_TABLE ia64_linux_xfer_unwind_table
+extern LONGEST ia64_linux_xfer_unwind_table (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ void *readbuf,
+ const void *writebuf,
+ ULONGEST offset,
+ LONGEST len);
+
#endif /* #ifndef NM_LINUX_H */
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.53
diff -u -r1.53 target.h
--- target.h 10 Nov 2003 21:20:44 -0000 1.53
+++ target.h 14 Nov 2003 00:06:03 -0000
@@ -223,8 +223,10 @@
/* AVR target specific transfer. See "avr-tdep.c" and "remote.c". */
TARGET_OBJECT_AVR,
/* Transfer up-to LEN bytes of memory starting at OFFSET. */
- TARGET_OBJECT_MEMORY
- /* Possible future ojbects: TARGET_OJBECT_FILE, TARGET_OBJECT_PROC,
+ TARGET_OBJECT_MEMORY,
+ /* Kernel Unwind Table. See "ia64-tdep.c". */
+ TARGET_OBJECT_UNWIND_TABLE,
+ /* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC,
TARGET_OBJECT_AUXV, ... */
};
Index: inftarg.c
===================================================================
RCS file: /cvs/src/src/gdb/inftarg.c,v
retrieving revision 1.20
diff -u -r1.20 inftarg.c
--- inftarg.c 10 Nov 2003 21:20:44 -0000 1.20
+++ inftarg.c 14 Nov 2003 00:06:03 -0000
@@ -571,14 +571,12 @@
NULL, ops);
return -1;
-#if 0
case TARGET_OBJECT_UNWIND_TABLE:
#ifndef NATIVE_XFER_UNWIND_TABLE
#define NATIVE_XFER_UNWIND_TABLE(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN) (-1)
#endif
return NATIVE_XFER_UNWIND_TABLE (ops, object, annex, readbuf, writebuf,
offset, len);
-#endif
#if 0
case TARGET_OBJECT_AUXV:
Index: ia64-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-linux-nat.c,v
retrieving revision 1.20
diff -u -r1.20 ia64-linux-nat.c
--- ia64-linux-nat.c 2 Oct 2003 20:28:29 -0000 1.20
+++ ia64-linux-nat.c 14 Nov 2003 00:06:03 -0000
@@ -34,6 +34,7 @@
#ifdef HAVE_SYS_REG_H
#include <sys/reg.h>
#endif
+#include <sys/syscall.h>
#include <sys/user.h>
#include <asm/ptrace_offsets.h>
@@ -644,4 +645,14 @@
write_register_pid (IA64_PSR_REGNUM, psr, ptid);
return (CORE_ADDR) siginfo.si_addr;
+}
+
+LONGEST
+ia64_linux_xfer_unwind_table (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len)
+{
+ return syscall (__NR_getunwind, readbuf, len);
}
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-11-14 0:26 ` RFA: " J. Johnston
@ 2003-11-14 1:17 ` Kevin Buettner
2003-11-14 20:49 ` J. Johnston
0 siblings, 1 reply; 32+ messages in thread
From: Kevin Buettner @ 2003-11-14 1:17 UTC (permalink / raw)
To: J. Johnston
Cc: Andrew Cagney, Daniel Jacobowitz, Kevin Buettner,
Marcel Moolenaar, gdb-patches
On Nov 13, 7:26pm, J. Johnston wrote:
> I have just added a new patch which accounts for Andrew's latest xfer_partial
> changes.
>
> 2003-11-13 Jeff Johnston <jjohnstn@redhat.com>
>
> * config/ia64/nm-linux.h (NATIVE_XFER_UNWIND_TABLE): New macro to
> set up the ia64 linux native target method for getting the kernel
> unwind table.
> * ia64-linux-nat.c (ia64_linux_xfer_unwind_table): New function.
> * inftarg.c (child_xfer_partial): Enable section of code to
> handle TARGET_OBJECT_UNWIND_TABLE.
> * target.h (target_object): Add new TARGET_OBJECT_UNWIND_TABLE macro.
Okay.
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch
2003-11-14 1:17 ` Kevin Buettner
@ 2003-11-14 20:49 ` J. Johnston
0 siblings, 0 replies; 32+ messages in thread
From: J. Johnston @ 2003-11-14 20:49 UTC (permalink / raw)
To: Kevin Buettner
Cc: Andrew Cagney, Daniel Jacobowitz, Marcel Moolenaar, gdb-patches
Patch checked in. Thanks.
-- Jeff J.
Kevin Buettner wrote:
> On Nov 13, 7:26pm, J. Johnston wrote:
>
>
>>I have just added a new patch which accounts for Andrew's latest xfer_partial
>>changes.
>>
>>2003-11-13 Jeff Johnston <jjohnstn@redhat.com>
>>
>> * config/ia64/nm-linux.h (NATIVE_XFER_UNWIND_TABLE): New macro to
>> set up the ia64 linux native target method for getting the kernel
>> unwind table.
>> * ia64-linux-nat.c (ia64_linux_xfer_unwind_table): New function.
>> * inftarg.c (child_xfer_partial): Enable section of code to
>> handle TARGET_OBJECT_UNWIND_TABLE.
>> * target.h (target_object): Add new TARGET_OBJECT_UNWIND_TABLE macro.
>
>
> Okay.
>
> Kevin
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch updated
2003-11-06 17:21 ` RFA: ia64 portion of libunwind patch updated J. Johnston
@ 2003-11-14 21:24 ` J. Johnston
2003-11-17 17:01 ` Kevin Buettner
2003-11-17 17:05 ` Kevin Buettner
1 sibling, 1 reply; 32+ messages in thread
From: J. Johnston @ 2003-11-14 21:24 UTC (permalink / raw)
To: Andrew Cagney, Kevin Buettner
Cc: J. Johnston, gdb-patches, Daniel Jacobowitz, Marcel Moolenaar
In light of the recent checked-in patches concerning libunwind and the resolved
issues, is the ia64-tdep.c patch ok now? The issue regarding whether libunwind
could more efficiently reference the table entries will require an ABI change to
libunwind and needs some thought from David.
-- Jeff J.
J. Johnston wrote:
> The attached patch is the updated ia64 libunwind patch addressing a
> number of comments. The bfd stuff has been replaced with a simple
> target memory read. The syscall stuff has been replaced with a call to
> target_read_partial() which has been implemented in another patch. I
> have added a few comments per Elena's suggestion.
>
> Ok to commit?
>
> -- Jeff J.
>
> 2003-11-06 Jeff Johnston <jjohnstn@redhat.com>
> David Mosberger <davidm@hpl.hp.com>
>
> * ia64-tdep.c: Include elf.h.
> [HAVE_LIBUNWIND_IA64_H]: Include libunwind-frame.h and
> libunwind-ia64.h.
> (ia64_rse_slot_num, ia64_rse_skip_regs): New for libunwind support.
> (ia64_gdb2uw_regnum, ia64_uw2gdb_regnum): Ditto.
> (ia64_is_fpreg, ia64_access_reg): Ditto.
> (ia64_access_fpreg, ia64_access_mem): Ditto.
> (get_kernel_table): Ditto.
> (ia64_find_unwind_table): Ditto.
> (ia64_find_proc_info_x, ia64_put_unwind_info): Ditto.
> (ia64_get_dyn_info_list, ia64_libunwind_frame_this_id): Ditto.
> (ia64_libunwind_frame_prev_register): Ditto.
> (ia64_libunwind_frame_sniffer): Ditto.
> (ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Add libunwind frame
> sniffer. Register libunwind functions needed by generic libunwind
> frame
> code using libunwind_frame_set_descr().
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch updated
2003-11-14 21:24 ` J. Johnston
@ 2003-11-17 17:01 ` Kevin Buettner
2003-11-17 17:03 ` Kevin Buettner
0 siblings, 1 reply; 32+ messages in thread
From: Kevin Buettner @ 2003-11-17 17:01 UTC (permalink / raw)
To: J. Johnston, Andrew Cagney, Kevin Buettner
Cc: gdb-patches, Daniel Jacobowitz, Marcel Moolenaar
On Nov 14, 4:24pm, J. Johnston wrote:
> In light of the recent checked-in patches concerning libunwind and
> the resolved issues, is the ia64-tdep.c patch ok now? The issue
> regarding whether libunwind could more efficiently reference the
> table entries will require an ABI change to libunwind and needs some
> thought from David.
Would you mind posting an updated patch?
Thanks,
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch updated
2003-11-17 17:01 ` Kevin Buettner
@ 2003-11-17 17:03 ` Kevin Buettner
0 siblings, 0 replies; 32+ messages in thread
From: Kevin Buettner @ 2003-11-17 17:03 UTC (permalink / raw)
To: Kevin Buettner, J. Johnston, Andrew Cagney
Cc: gdb-patches, Daniel Jacobowitz, Marcel Moolenaar
On Nov 17, 10:01am, Kevin Buettner wrote:
> On Nov 14, 4:24pm, J. Johnston wrote:
>
> > In light of the recent checked-in patches concerning libunwind and
> > the resolved issues, is the ia64-tdep.c patch ok now? The issue
> > regarding whether libunwind could more efficiently reference the
> > table entries will require an ABI change to libunwind and needs some
> > thought from David.
>
> Would you mind posting an updated patch?
Umm, never mind. I just found Jeff's patch from Nov 6. Looking at it
now.
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch updated
2003-11-06 17:21 ` RFA: ia64 portion of libunwind patch updated J. Johnston
2003-11-14 21:24 ` J. Johnston
@ 2003-11-17 17:05 ` Kevin Buettner
2003-11-17 21:40 ` J. Johnston
1 sibling, 1 reply; 32+ messages in thread
From: Kevin Buettner @ 2003-11-17 17:05 UTC (permalink / raw)
To: J. Johnston, gdb-patches
Cc: Andrew Cagney, Daniel Jacobowitz, Kevin Buettner, Marcel Moolenaar
On Nov 6, 12:21pm, J. Johnston wrote:
> The attached patch is the updated ia64 libunwind patch addressing a number of
> comments. The bfd stuff has been replaced with a simple target memory read.
> The syscall stuff has been replaced with a call to target_read_partial() which
> has been implemented in another patch. I have added a few comments per Elena's
> suggestion.
>
> Ok to commit?
>
> 2003-11-06 Jeff Johnston <jjohnstn@redhat.com>
> David Mosberger <davidm@hpl.hp.com>
>
> * ia64-tdep.c: Include elf.h.
> [HAVE_LIBUNWIND_IA64_H]: Include libunwind-frame.h and libunwind-ia64.h.
> (ia64_rse_slot_num, ia64_rse_skip_regs): New for libunwind support.
> (ia64_gdb2uw_regnum, ia64_uw2gdb_regnum): Ditto.
> (ia64_is_fpreg, ia64_access_reg): Ditto.
> (ia64_access_fpreg, ia64_access_mem): Ditto.
> (get_kernel_table): Ditto.
> (ia64_find_unwind_table): Ditto.
> (ia64_find_proc_info_x, ia64_put_unwind_info): Ditto.
> (ia64_get_dyn_info_list, ia64_libunwind_frame_this_id): Ditto.
> (ia64_libunwind_frame_prev_register): Ditto.
> (ia64_libunwind_frame_sniffer): Ditto.
> (ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Add libunwind frame
> sniffer. Register libunwind functions needed by generic libunwind frame
> code using libunwind_frame_set_descr().
Okay.
Kevin
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch updated
2003-11-17 17:05 ` Kevin Buettner
@ 2003-11-17 21:40 ` J. Johnston
2003-11-17 22:32 ` Marcel Moolenaar
0 siblings, 1 reply; 32+ messages in thread
From: J. Johnston @ 2003-11-17 21:40 UTC (permalink / raw)
To: Kevin Buettner
Cc: gdb-patches, Andrew Cagney, Daniel Jacobowitz, Marcel Moolenaar
Patch checked in. Thanks.
-- Jeff J.
Kevin Buettner wrote:
> On Nov 6, 12:21pm, J. Johnston wrote:
>
>
>>The attached patch is the updated ia64 libunwind patch addressing a number of
>>comments. The bfd stuff has been replaced with a simple target memory read.
>>The syscall stuff has been replaced with a call to target_read_partial() which
>>has been implemented in another patch. I have added a few comments per Elena's
>>suggestion.
>>
>>Ok to commit?
>>
>>2003-11-06 Jeff Johnston <jjohnstn@redhat.com>
>> David Mosberger <davidm@hpl.hp.com>
>>
>> * ia64-tdep.c: Include elf.h.
>> [HAVE_LIBUNWIND_IA64_H]: Include libunwind-frame.h and libunwind-ia64.h.
>> (ia64_rse_slot_num, ia64_rse_skip_regs): New for libunwind support.
>> (ia64_gdb2uw_regnum, ia64_uw2gdb_regnum): Ditto.
>> (ia64_is_fpreg, ia64_access_reg): Ditto.
>> (ia64_access_fpreg, ia64_access_mem): Ditto.
>> (get_kernel_table): Ditto.
>> (ia64_find_unwind_table): Ditto.
>> (ia64_find_proc_info_x, ia64_put_unwind_info): Ditto.
>> (ia64_get_dyn_info_list, ia64_libunwind_frame_this_id): Ditto.
>> (ia64_libunwind_frame_prev_register): Ditto.
>> (ia64_libunwind_frame_sniffer): Ditto.
>> (ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Add libunwind frame
>> sniffer. Register libunwind functions needed by generic libunwind frame
>> code using libunwind_frame_set_descr().
>
>
> Okay.
>
> Kevin
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: RFA: ia64 portion of libunwind patch updated
2003-11-17 21:40 ` J. Johnston
@ 2003-11-17 22:32 ` Marcel Moolenaar
0 siblings, 0 replies; 32+ messages in thread
From: Marcel Moolenaar @ 2003-11-17 22:32 UTC (permalink / raw)
To: J. Johnston; +Cc: Kevin Buettner, gdb-patches, Andrew Cagney, Daniel Jacobowitz
On Mon, Nov 17, 2003 at 04:40:27PM -0500, J. Johnston wrote:
> Patch checked in. Thanks.
Cool! Thanks for the effort. Now I can play with it on FreeBSD
as well.
BTW: libunwind-0.93 doesn't compile on Red Hat AS 2.1 due to
sigcontext changes. Does it make sense to spend some time
trying to fix that or is AS 2.1 really too old for that?
Or can we use an older version of libunwind there (IOW is
the API compatible)?
Some background information:
\begin{libunwind-build-log}
gcc -DHAVE_CONFIG_H -I. -I../../../src/libunwind-0.93/src -I../include -I../../../src/libunwind-0.93/include -I. -D_GNU_SOURCE -DDEBUG -g -Wall -Wsign-compare -c ../../../src/libunwind-0.93/src/ia64/Ginit-ia64.c -MT Ginit-ia64.lo -MD -MP -MF .deps/Ginit-ia64.TPlo -fPIC -o .libs/Ginit-ia64.o
../../../src/libunwind-0.93/src/ia64/Ginit-ia64.c: In function `uc_addr':
../../../src/libunwind-0.93/src/ia64/Ginit-ia64.c:110: structure has no member named `sc_rbs_base'
gmake[2]: *** [Ginit-ia64.lo] Error 1
gmake[2]: Leaving directory `/proj/eclipse/extra/marcel/unwind/obj/libunwind-0.93/src'
gmake[1]: *** [all] Error 2
\end{libunwind-build-log}
The sigcontext between AS3.0 and AS2.1 changed in the following way:
\begin{diff}
--- sigcontext.h.as2.1 2003-11-17 14:26:11.000000000 -0800
+++ sigcontext.h.as3.0 2003-11-17 14:26:36.000000000 -0800
@@ -2,13 +2,14 @@
#define _ASM_IA64_SIGCONTEXT_H
/*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
*/
#include <asm/fpu.h>
+#include <asm/signal.h>
-#define IA64_SC_FLAG_ONSTACK_BIT 1 /* is handler running on signal stack? */
+#define IA64_SC_FLAG_ONSTACK_BIT 0 /* is handler running on signal stack? */
#define IA64_SC_FLAG_IN_SYSCALL_BIT 1 /* did signal interrupt a syscall? */
#define IA64_SC_FLAG_FPH_VALID_BIT 2 /* is state in f[32]-f[127] valid? */
@@ -18,6 +19,19 @@
# ifndef __ASSEMBLY__
+/*
+ * Note on handling of register backing store: sc_ar_bsp contains the address that would
+ * be found in ar.bsp after executing a "cover" instruction the context in which the
+ * signal was raised. If signal delivery required switching to an alternate signal stack
+ * (sc_rbs_base is not NULL), the "dirty" partition (as it would exist after executing the
+ * imaginary "cover" instruction) is backed by the *alternate* signal stack, not the
+ * original one. In this case, sc_rbs_base contains the base address of the new register
+ * backing store. The number of registers in the dirty partition can be calculated as:
+ *
+ * ndirty = ia64_rse_num_regs(sc_rbs_base, sc_rbs_base + (sc_loadrs >> 16))
+ *
+ */
+
struct sigcontext {
unsigned long sc_flags; /* see manifest constants above */
unsigned long sc_nat; /* bit i == 1 iff scratch reg gr[i] is a NaT */
@@ -40,8 +54,12 @@
unsigned long sc_gr[32]; /* general registers (static partition) */
struct ia64_fpreg sc_fr[128]; /* floating-point registers */
- unsigned long sc_rsvd[16]; /* reserved for future use */
+ unsigned long sc_rbs_base; /* NULL or new base of sighandler's rbs */
+ unsigned long sc_loadrs; /* see description above */
+ unsigned long sc_ar25; /* cmp8xchg16 uses this */
+ unsigned long sc_ar26; /* rsvd for scratch use */
+ unsigned long sc_rsvd[12]; /* reserved for future use */
/*
* The mask must come last so we can increase _NSIG_WORDS
* without breaking binary compatibility.
\end{diff}
--
Marcel Moolenaar USPA: A-39004 marcel@xcllnt.net
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2003-11-17 22:32 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-10-24 0:11 RFA: ia64 portion of libunwind patch J. Johnston
2003-10-24 17:57 ` Kevin Buettner
2003-10-24 18:20 ` J. Johnston
2003-10-24 18:56 ` Kevin Buettner
2003-10-24 21:53 ` Marcel Moolenaar
2003-10-24 23:58 ` Kevin Buettner
2003-10-28 23:53 ` J. Johnston
2003-10-29 1:28 ` Daniel Jacobowitz
2003-10-29 4:48 ` Kevin Buettner
2003-10-29 18:43 ` J. Johnston
2003-10-29 22:48 ` Andrew Cagney
2003-11-04 19:09 ` J. Johnston
2003-11-04 20:48 ` Kevin Buettner
2003-11-06 17:21 ` RFA: ia64 portion of libunwind patch updated J. Johnston
2003-11-14 21:24 ` J. Johnston
2003-11-17 17:01 ` Kevin Buettner
2003-11-17 17:03 ` Kevin Buettner
2003-11-17 17:05 ` Kevin Buettner
2003-11-17 21:40 ` J. Johnston
2003-11-17 22:32 ` Marcel Moolenaar
2003-11-06 20:03 ` [commit] Fix two xfer partial bugs; Was; RFA: ia64 portion of libunwind patch Andrew Cagney
2003-11-06 20:12 ` J. Johnston
2003-11-06 22:32 ` [patch/rfc] Add child_to_xfer_partial; Was: " Andrew Cagney
2003-11-06 22:47 ` J. Johnston
2003-11-07 21:40 ` Andrew Cagney
2003-11-07 1:04 ` Kevin Buettner
2003-11-14 0:26 ` RFA: " J. Johnston
2003-11-14 1:17 ` Kevin Buettner
2003-11-14 20:49 ` J. Johnston
2003-10-29 23:28 ` Andrew Cagney
2003-11-02 20:39 ` Elena Zannoni
2003-10-29 15:18 ` Andrew Cagney
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox