GDB (API)
/home/stan/gdb/src/gdb/amd64obsd-tdep.c
Go to the documentation of this file.
00001 /* Target-dependent code for OpenBSD/amd64.
00002 
00003    Copyright (C) 2003-2013 Free Software Foundation, Inc.
00004 
00005    This file is part of GDB.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 3 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00019 
00020 #include "defs.h"
00021 #include "frame.h"
00022 #include "frame-unwind.h"
00023 #include "gdbcore.h"
00024 #include "symtab.h"
00025 #include "objfiles.h"
00026 #include "osabi.h"
00027 #include "regcache.h"
00028 #include "regset.h"
00029 #include "target.h"
00030 #include "trad-frame.h"
00031 
00032 #include "gdb_assert.h"
00033 #include "gdb_string.h"
00034 
00035 #include "amd64-tdep.h"
00036 #include "i387-tdep.h"
00037 #include "solib-svr4.h"
00038 #include "bsd-uthread.h"
00039 
00040 /* Support for core dumps.  */
00041 
00042 static void
00043 amd64obsd_supply_regset (const struct regset *regset,
00044                          struct regcache *regcache, int regnum,
00045                          const void *regs, size_t len)
00046 {
00047   const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
00048 
00049   gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE);
00050 
00051   i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
00052   amd64_supply_fxsave (regcache, regnum,
00053                        ((const gdb_byte *)regs) + tdep->sizeof_gregset);
00054 }
00055 
00056 static const struct regset *
00057 amd64obsd_regset_from_core_section (struct gdbarch *gdbarch,
00058                                     const char *sect_name, size_t sect_size)
00059 {
00060   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
00061 
00062   /* OpenBSD core dumps don't use seperate register sets for the
00063      general-purpose and floating-point registers.  */
00064 
00065   if (strcmp (sect_name, ".reg") == 0
00066       && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE)
00067     {
00068       if (tdep->gregset == NULL)
00069         tdep->gregset = regset_alloc (gdbarch, amd64obsd_supply_regset, NULL);
00070       return tdep->gregset;
00071     }
00072 
00073   return NULL;
00074 }
00075 
00076 
00077 /* Support for signal handlers.  */
00078 
00079 /* Default page size.  */
00080 static const int amd64obsd_page_size = 4096;
00081 
00082 /* Return whether THIS_FRAME corresponds to an OpenBSD sigtramp
00083    routine.  */
00084 
00085 static int
00086 amd64obsd_sigtramp_p (struct frame_info *this_frame)
00087 {
00088   CORE_ADDR pc = get_frame_pc (this_frame);
00089   CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1));
00090   const gdb_byte osigreturn[] =
00091   {
00092     0x48, 0xc7, 0xc0,
00093     0x67, 0x00, 0x00, 0x00,     /* movq $SYS_sigreturn, %rax */
00094     0xcd, 0x80                  /* int $0x80 */
00095   };
00096   const gdb_byte sigreturn[] =
00097   {
00098     0x48, 0xc7, 0xc0,
00099     0x67, 0x00, 0x00, 0x00,     /* movq $SYS_sigreturn, %rax */
00100     0x0f, 0x05                  /* syscall */
00101   };
00102   size_t buflen = (sizeof sigreturn) + 1;
00103   gdb_byte *buf;
00104   const char *name;
00105 
00106   /* If the function has a valid symbol name, it isn't a
00107      trampoline.  */
00108   find_pc_partial_function (pc, &name, NULL, NULL);
00109   if (name != NULL)
00110     return 0;
00111 
00112   /* If the function lives in a valid section (even without a starting
00113      point) it isn't a trampoline.  */
00114   if (find_pc_section (pc) != NULL)
00115     return 0;
00116 
00117   /* If we can't read the instructions at START_PC, return zero.  */
00118   buf = alloca ((sizeof sigreturn) + 1);
00119   if (!safe_frame_unwind_memory (this_frame, start_pc + 6, buf, buflen))
00120     return 0;
00121 
00122   /* Check for sigreturn(2).  Depending on how the assembler encoded
00123      the `movq %rsp, %rdi' instruction, the code starts at offset 6 or
00124      7.  OpenBSD 5.0 and later use the `syscall' instruction.  Older
00125      versions use `int $0x80'.  Check for both.  */
00126   if (memcmp (buf, sigreturn, sizeof sigreturn)
00127       && memcmp (buf + 1, sigreturn, sizeof sigreturn)
00128       && memcmp (buf, osigreturn, sizeof osigreturn)
00129       && memcmp (buf + 1, osigreturn, sizeof osigreturn))
00130     return 0;
00131 
00132   return 1;
00133 }
00134 
00135 /* Assuming THIS_FRAME is for a BSD sigtramp routine, return the
00136    address of the associated sigcontext structure.  */
00137 
00138 static CORE_ADDR
00139 amd64obsd_sigcontext_addr (struct frame_info *this_frame)
00140 {
00141   CORE_ADDR pc = get_frame_pc (this_frame);
00142   ULONGEST offset = (pc & (amd64obsd_page_size - 1));
00143 
00144   /* The %rsp register points at `struct sigcontext' upon entry of a
00145      signal trampoline.  The relevant part of the trampoline is
00146 
00147         call    *%rax
00148         movq    %rsp, %rdi
00149         pushq   %rdi
00150         movq    $SYS_sigreturn,%rax
00151         int     $0x80
00152 
00153      (see /usr/src/sys/arch/amd64/amd64/locore.S).  The `pushq'
00154      instruction clobbers %rsp, but its value is saved in `%rdi'.  */
00155 
00156   if (offset > 5)
00157     return get_frame_register_unsigned (this_frame, AMD64_RDI_REGNUM);
00158   else
00159     return get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
00160 }
00161 
00162 /* OpenBSD 3.5 or later.  */
00163 
00164 /* Mapping between the general-purpose registers in `struct reg'
00165    format and GDB's register cache layout.  */
00166 
00167 /* From <machine/reg.h>.  */
00168 int amd64obsd_r_reg_offset[] =
00169 {
00170   14 * 8,                       /* %rax */
00171   13 * 8,                       /* %rbx */
00172   3 * 8,                        /* %rcx */
00173   2 * 8,                        /* %rdx */
00174   1 * 8,                        /* %rsi */
00175   0 * 8,                        /* %rdi */
00176   12 * 8,                       /* %rbp */
00177   15 * 8,                       /* %rsp */
00178   4 * 8,                        /* %r8 ..  */
00179   5 * 8,
00180   6 * 8,
00181   7 * 8,
00182   8 * 8,
00183   9 * 8,
00184   10 * 8,
00185   11 * 8,                       /* ... %r15 */
00186   16 * 8,                       /* %rip */
00187   17 * 8,                       /* %eflags */
00188   18 * 8,                       /* %cs */
00189   19 * 8,                       /* %ss */
00190   20 * 8,                       /* %ds */
00191   21 * 8,                       /* %es */
00192   22 * 8,                       /* %fs */
00193   23 * 8                        /* %gs */
00194 };
00195 
00196 /* From <machine/signal.h>.  */
00197 static int amd64obsd_sc_reg_offset[] =
00198 {
00199   14 * 8,                       /* %rax */
00200   13 * 8,                       /* %rbx */
00201   3 * 8,                        /* %rcx */
00202   2 * 8,                        /* %rdx */
00203   1 * 8,                        /* %rsi */
00204   0 * 8,                        /* %rdi */
00205   12 * 8,                       /* %rbp */
00206   24 * 8,                       /* %rsp */
00207   4 * 8,                        /* %r8 ...  */
00208   5 * 8,
00209   6 * 8,
00210   7 * 8,
00211   8 * 8,
00212   9 * 8,
00213   10 * 8,
00214   11 * 8,                       /* ... %r15 */
00215   21 * 8,                       /* %rip */
00216   23 * 8,                       /* %eflags */
00217   22 * 8,                       /* %cs */
00218   25 * 8,                       /* %ss */
00219   18 * 8,                       /* %ds */
00220   17 * 8,                       /* %es */
00221   16 * 8,                       /* %fs */
00222   15 * 8                        /* %gs */
00223 };
00224 
00225 /* From /usr/src/lib/libpthread/arch/amd64/uthread_machdep.c.  */
00226 static int amd64obsd_uthread_reg_offset[] =
00227 {
00228   19 * 8,                       /* %rax */
00229   16 * 8,                       /* %rbx */
00230   18 * 8,                       /* %rcx */
00231   17 * 8,                       /* %rdx */
00232   14 * 8,                       /* %rsi */
00233   13 * 8,                       /* %rdi */
00234   15 * 8,                       /* %rbp */
00235   -1,                           /* %rsp */
00236   12 * 8,                       /* %r8 ...  */
00237   11 * 8,
00238   10 * 8,
00239   9 * 8,
00240   8 * 8,
00241   7 * 8,
00242   6 * 8,
00243   5 * 8,                        /* ... %r15 */
00244   20 * 8,                       /* %rip */
00245   4 * 8,                        /* %eflags */
00246   21 * 8,                       /* %cs */
00247   -1,                           /* %ss */
00248   3 * 8,                        /* %ds */
00249   2 * 8,                        /* %es */
00250   1 * 8,                        /* %fs */
00251   0 * 8                         /* %gs */
00252 };
00253 
00254 /* Offset within the thread structure where we can find the saved
00255    stack pointer (%esp).  */
00256 #define AMD64OBSD_UTHREAD_RSP_OFFSET    400
00257 
00258 static void
00259 amd64obsd_supply_uthread (struct regcache *regcache,
00260                           int regnum, CORE_ADDR addr)
00261 {
00262   struct gdbarch *gdbarch = get_regcache_arch (regcache);
00263   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
00264   CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
00265   CORE_ADDR sp = 0;
00266   gdb_byte buf[8];
00267   int i;
00268 
00269   gdb_assert (regnum >= -1);
00270 
00271   if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
00272     {
00273       int offset;
00274 
00275       /* Fetch stack pointer from thread structure.  */
00276       sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
00277 
00278       /* Adjust the stack pointer such that it looks as if we just
00279          returned from _thread_machdep_switch.  */
00280       offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
00281       store_unsigned_integer (buf, 8, byte_order, sp + offset);
00282       regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf);
00283     }
00284 
00285   for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
00286     {
00287       if (amd64obsd_uthread_reg_offset[i] != -1
00288           && (regnum == -1 || regnum == i))
00289         {
00290           /* Fetch stack pointer from thread structure (if we didn't
00291              do so already).  */
00292           if (sp == 0)
00293             sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
00294 
00295           /* Read the saved register from the stack frame.  */
00296           read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
00297           regcache_raw_supply (regcache, i, buf);
00298         }
00299     }
00300 }
00301 
00302 static void
00303 amd64obsd_collect_uthread (const struct regcache *regcache,
00304                            int regnum, CORE_ADDR addr)
00305 {
00306   struct gdbarch *gdbarch = get_regcache_arch (regcache);
00307   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
00308   CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
00309   CORE_ADDR sp = 0;
00310   gdb_byte buf[8];
00311   int i;
00312 
00313   gdb_assert (regnum >= -1);
00314 
00315   if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
00316     {
00317       int offset;
00318 
00319       /* Calculate the stack pointer (frame pointer) that will be
00320          stored into the thread structure.  */
00321       offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
00322       regcache_raw_collect (regcache, AMD64_RSP_REGNUM, buf);
00323       sp = extract_unsigned_integer (buf, 8, byte_order) - offset;
00324 
00325       /* Store the stack pointer.  */
00326       write_memory_unsigned_integer (sp_addr, 8, byte_order, sp);
00327 
00328       /* The stack pointer was (potentially) modified.  Make sure we
00329          build a proper stack frame.  */
00330       regnum = -1;
00331     }
00332 
00333   for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
00334     {
00335       if (amd64obsd_uthread_reg_offset[i] != -1
00336           && (regnum == -1 || regnum == i))
00337         {
00338           /* Fetch stack pointer from thread structure (if we didn't
00339              calculate it already).  */
00340           if (sp == 0)
00341             sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
00342 
00343           /* Write the register into the stack frame.  */
00344           regcache_raw_collect (regcache, i, buf);
00345           write_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
00346         }
00347     }
00348 }
00349 /* Kernel debugging support.  */
00350 
00351 /* From <machine/frame.h>.  Easy since `struct trapframe' matches
00352    `struct sigcontext'.  */
00353 #define amd64obsd_tf_reg_offset amd64obsd_sc_reg_offset
00354 
00355 static struct trad_frame_cache *
00356 amd64obsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
00357 {
00358   struct gdbarch *gdbarch = get_frame_arch (this_frame);
00359   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
00360   struct trad_frame_cache *cache;
00361   CORE_ADDR func, sp, addr;
00362   ULONGEST cs;
00363   const char *name;
00364   int i;
00365 
00366   if (*this_cache)
00367     return *this_cache;
00368 
00369   cache = trad_frame_cache_zalloc (this_frame);
00370   *this_cache = cache;
00371 
00372   func = get_frame_func (this_frame);
00373   sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
00374 
00375   find_pc_partial_function (func, &name, NULL, NULL);
00376   if (name && strncmp (name, "Xintr", 5) == 0)
00377     addr = sp + 8;              /* It's an interrupt frame.  */
00378   else
00379     addr = sp;
00380 
00381   for (i = 0; i < ARRAY_SIZE (amd64obsd_tf_reg_offset); i++)
00382     if (amd64obsd_tf_reg_offset[i] != -1)
00383       trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]);
00384 
00385   /* Read %cs from trap frame.  */
00386   addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM];
00387   cs = read_memory_unsigned_integer (addr, 8, byte_order);
00388   if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
00389     {
00390       /* Trap from user space; terminate backtrace.  */
00391       trad_frame_set_id (cache, outer_frame_id);
00392     }
00393   else
00394     {
00395       /* Construct the frame ID using the function start.  */
00396       trad_frame_set_id (cache, frame_id_build (sp + 16, func));
00397     }
00398 
00399   return cache;
00400 }
00401 
00402 static void
00403 amd64obsd_trapframe_this_id (struct frame_info *this_frame,
00404                              void **this_cache, struct frame_id *this_id)
00405 {
00406   struct trad_frame_cache *cache =
00407     amd64obsd_trapframe_cache (this_frame, this_cache);
00408   
00409   trad_frame_get_id (cache, this_id);
00410 }
00411 
00412 static struct value *
00413 amd64obsd_trapframe_prev_register (struct frame_info *this_frame,
00414                                    void **this_cache, int regnum)
00415 {
00416   struct trad_frame_cache *cache =
00417     amd64obsd_trapframe_cache (this_frame, this_cache);
00418 
00419   return trad_frame_get_register (cache, this_frame, regnum);
00420 }
00421 
00422 static int
00423 amd64obsd_trapframe_sniffer (const struct frame_unwind *self,
00424                              struct frame_info *this_frame,
00425                              void **this_prologue_cache)
00426 {
00427   ULONGEST cs;
00428   const char *name;
00429 
00430   /* Check Current Privilege Level and bail out if we're not executing
00431      in kernel space.  */
00432   cs = get_frame_register_unsigned (this_frame, AMD64_CS_REGNUM);
00433   if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
00434     return 0;
00435 
00436   find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL);
00437   return (name && ((strcmp (name, "calltrap") == 0)
00438                    || (strcmp (name, "osyscall1") == 0)
00439                    || (strcmp (name, "Xsyscall") == 0)
00440                    || (strncmp (name, "Xintr", 5) == 0)));
00441 }
00442 
00443 static const struct frame_unwind amd64obsd_trapframe_unwind = {
00444   /* FIXME: kettenis/20051219: This really is more like an interrupt
00445      frame, but SIGTRAMP_FRAME would print <signal handler called>,
00446      which really is not what we want here.  */
00447   NORMAL_FRAME,
00448   default_frame_unwind_stop_reason,
00449   amd64obsd_trapframe_this_id,
00450   amd64obsd_trapframe_prev_register,
00451   NULL,
00452   amd64obsd_trapframe_sniffer
00453 };
00454 
00455 
00456 static void
00457 amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
00458 {
00459   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
00460 
00461   amd64_init_abi (info, gdbarch);
00462 
00463   /* Initialize general-purpose register set details.  */
00464   tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
00465   tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
00466   tdep->sizeof_gregset = 24 * 8;
00467 
00468   tdep->jb_pc_offset = 7 * 8;
00469 
00470   tdep->sigtramp_p = amd64obsd_sigtramp_p;
00471   tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
00472   tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
00473   tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
00474 
00475   /* OpenBSD provides a user-level threads implementation.  */
00476   bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread);
00477   bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread);
00478 
00479   /* OpenBSD uses SVR4-style shared libraries.  */
00480   set_solib_svr4_fetch_link_map_offsets
00481     (gdbarch, svr4_lp64_fetch_link_map_offsets);
00482 
00483   /* Unwind kernel trap frames correctly.  */
00484   frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind);
00485 }
00486 
00487 /* Traditional (a.out) NetBSD-style core dumps.  */
00488 
00489 static void
00490 amd64obsd_core_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
00491 {
00492   amd64obsd_init_abi (info, gdbarch);
00493 
00494   set_gdbarch_regset_from_core_section
00495     (gdbarch, amd64obsd_regset_from_core_section);
00496 }
00497 
00498 
00499 /* Provide a prototype to silence -Wmissing-prototypes.  */
00500 void _initialize_amd64obsd_tdep (void);
00501 
00502 void
00503 _initialize_amd64obsd_tdep (void)
00504 {
00505   /* The OpenBSD/amd64 native dependent code makes this assumption.  */
00506   gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
00507 
00508   gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
00509                           GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi);
00510 
00511   /* OpenBSD uses traditional (a.out) NetBSD-style core dumps.  */
00512   gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
00513                           GDB_OSABI_NETBSD_AOUT, amd64obsd_core_init_abi);
00514 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines