X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fs390-nat.c;h=3af42ff80df1a51f1ace18d759ee163999c5a8aa;hb=139f2ac873b8899228e9f99dc3b50d3416336bc7;hp=b8da548f05a344f80f97d789f9855cac69f81138;hpb=9cbd5950d6314c1447900d98b6f1d157c1e33942;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c index b8da548f05..3af42ff80d 100644 --- a/gdb/s390-nat.c +++ b/gdb/s390-nat.c @@ -1,5 +1,6 @@ /* S390 native-dependent code for GDB, the GNU debugger. - Copyright 2001, 2003 Free Software Foundation, Inc + Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2009 + Free Software Foundation, Inc Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) for IBM Deutschland Entwicklung GmbH, IBM Corporation. @@ -8,7 +9,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -17,14 +18,14 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + along with this program. If not, see . */ #include "defs.h" -#include "tm.h" #include "regcache.h" #include "inferior.h" +#include "target.h" +#include "linux-nat.h" +#include "auxv.h" #include "s390-tdep.h" @@ -32,8 +33,12 @@ #include #include #include -#include #include +#include + +#ifndef HWCAP_S390_HIGH_GPRS +#define HWCAP_S390_HIGH_GPRS 512 +#endif /* Map registers to gregset/ptrace offsets. @@ -51,65 +56,69 @@ we have to fix up the 64-bit registers we get from the kernel to make them look like 32-bit registers. */ #ifdef __s390x__ -#define SUBOFF(i) \ - ((TARGET_PTR_BIT == 32 \ +#define SUBOFF(gdbarch, i) \ + ((gdbarch_ptr_bit (gdbarch) == 32 \ && ((i) == S390_PSWA_REGNUM \ || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0) #else -#define SUBOFF(i) 0 +#define SUBOFF(gdbarch, i) 0 #endif /* Fill GDB's register array with the general-purpose register values in *REGP. */ void -supply_gregset (gregset_t *regp) +supply_gregset (struct regcache *regcache, const gregset_t *regp) { + struct gdbarch *gdbarch = get_regcache_arch (regcache); int i; for (i = 0; i < S390_NUM_REGS; i++) if (regmap_gregset[i] != -1) - regcache_raw_supply (current_regcache, i, - (char *)regp + regmap_gregset[i] + SUBOFF (i)); + regcache_raw_supply (regcache, i, + (const char *)regp + regmap_gregset[i] + + SUBOFF (gdbarch, i)); } /* Fill register REGNO (if it is a general-purpose register) in *REGP with the value in GDB's register array. If REGNO is -1, do this for all registers. */ void -fill_gregset (gregset_t *regp, int regno) +fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno) { + struct gdbarch *gdbarch = get_regcache_arch (regcache); int i; for (i = 0; i < S390_NUM_REGS; i++) if (regmap_gregset[i] != -1) if (regno == -1 || regno == i) - regcache_raw_collect (current_regcache, i, - (char *)regp + regmap_gregset[i] + SUBOFF (i)); + regcache_raw_collect (regcache, i, + (char *)regp + regmap_gregset[i] + + SUBOFF (gdbarch, i)); } /* Fill GDB's register array with the floating-point register values in *REGP. */ void -supply_fpregset (fpregset_t *regp) +supply_fpregset (struct regcache *regcache, const fpregset_t *regp) { int i; for (i = 0; i < S390_NUM_REGS; i++) if (regmap_fpregset[i] != -1) - regcache_raw_supply (current_regcache, i, - ((char *)regp) + regmap_fpregset[i]); + regcache_raw_supply (regcache, i, + (const char *)regp + regmap_fpregset[i]); } /* Fill register REGNO (if it is a general-purpose register) in *REGP with the value in GDB's register array. If REGNO is -1, do this for all registers. */ void -fill_fpregset (fpregset_t *regp, int regno) +fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno) { int i; for (i = 0; i < S390_NUM_REGS; i++) if (regmap_fpregset[i] != -1) if (regno == -1 || regno == i) - regcache_raw_collect (current_regcache, i, - ((char *)regp) + regmap_fpregset[i]); + regcache_raw_collect (regcache, i, + (char *)regp + regmap_fpregset[i]); } /* Find the TID for the current inferior thread to use with ptrace. */ @@ -127,7 +136,7 @@ s390_inferior_tid (void) /* Fetch all general-purpose registers from process/thread TID and store their values in GDB's register cache. */ static void -fetch_regs (int tid) +fetch_regs (struct regcache *regcache, int tid) { gregset_t regs; ptrace_area parea; @@ -136,15 +145,15 @@ fetch_regs (int tid) parea.process_addr = (addr_t) ®s; parea.kernel_addr = offsetof (struct user_regs_struct, psw); if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) - perror_with_name ("Couldn't get registers"); + perror_with_name (_("Couldn't get registers")); - supply_gregset (®s); + supply_gregset (regcache, (const gregset_t *) ®s); } /* Store all valid general-purpose registers in GDB's register cache into the process/thread specified by TID. */ static void -store_regs (int tid, int regnum) +store_regs (const struct regcache *regcache, int tid, int regnum) { gregset_t regs; ptrace_area parea; @@ -153,18 +162,18 @@ store_regs (int tid, int regnum) parea.process_addr = (addr_t) ®s; parea.kernel_addr = offsetof (struct user_regs_struct, psw); if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) - perror_with_name ("Couldn't get registers"); + perror_with_name (_("Couldn't get registers")); - fill_gregset (®s, regnum); + fill_gregset (regcache, ®s, regnum); if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0) - perror_with_name ("Couldn't write registers"); + perror_with_name (_("Couldn't write registers")); } /* Fetch all floating-point registers from process/thread TID and store their values in GDB's register cache. */ static void -fetch_fpregs (int tid) +fetch_fpregs (struct regcache *regcache, int tid) { fpregset_t fpregs; ptrace_area parea; @@ -173,15 +182,15 @@ fetch_fpregs (int tid) parea.process_addr = (addr_t) &fpregs; parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs); if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) - perror_with_name ("Couldn't get floating point status"); + perror_with_name (_("Couldn't get floating point status")); - supply_fpregset (&fpregs); + supply_fpregset (regcache, (const fpregset_t *) &fpregs); } /* Store all valid floating-point registers in GDB's register cache into the process/thread specified by TID. */ static void -store_fpregs (int tid, int regnum) +store_fpregs (const struct regcache *regcache, int tid, int regnum) { fpregset_t fpregs; ptrace_area parea; @@ -190,44 +199,46 @@ store_fpregs (int tid, int regnum) parea.process_addr = (addr_t) &fpregs; parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs); if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) - perror_with_name ("Couldn't get floating point status"); + perror_with_name (_("Couldn't get floating point status")); - fill_fpregset (&fpregs, regnum); + fill_fpregset (regcache, &fpregs, regnum); if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0) - perror_with_name ("Couldn't write floating point status"); + perror_with_name (_("Couldn't write floating point status")); } /* Fetch register REGNUM from the child process. If REGNUM is -1, do this for all registers. */ -void -fetch_inferior_registers (int regnum) +static void +s390_linux_fetch_inferior_registers (struct target_ops *ops, + struct regcache *regcache, int regnum) { int tid = s390_inferior_tid (); if (regnum == -1 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) - fetch_regs (tid); + fetch_regs (regcache, tid); if (regnum == -1 || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1)) - fetch_fpregs (tid); + fetch_fpregs (regcache, tid); } /* Store register REGNUM back into the child process. If REGNUM is -1, do this for all registers. */ -void -store_inferior_registers (int regnum) +static void +s390_linux_store_inferior_registers (struct target_ops *ops, + struct regcache *regcache, int regnum) { int tid = s390_inferior_tid (); if (regnum == -1 || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) - store_regs (tid, regnum); + store_regs (regcache, tid, regnum); if (regnum == -1 || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1)) - store_fpregs (tid, regnum); + store_fpregs (regcache, tid, regnum); } @@ -248,11 +259,12 @@ struct watch_area static struct watch_area *watch_base = NULL; -int +static int s390_stopped_by_watchpoint (void) { per_lowcore_bits per_lowcore; ptrace_area parea; + int result; /* Speed up common case. */ if (!watch_base) @@ -262,16 +274,26 @@ s390_stopped_by_watchpoint (void) parea.process_addr = (addr_t) & per_lowcore; parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore); if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0) - perror_with_name ("Couldn't retrieve watchpoint status"); + perror_with_name (_("Couldn't retrieve watchpoint status")); + + result = (per_lowcore.perc_storage_alteration == 1 + && per_lowcore.perc_store_real_address == 0); - return per_lowcore.perc_storage_alteration == 1 - && per_lowcore.perc_store_real_address == 0; + if (result) + { + /* Do not report this watchpoint again. */ + memset (&per_lowcore, 0, sizeof (per_lowcore)); + if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0) + perror_with_name (_("Couldn't clear watchpoint status")); + } + + return result; } static void -s390_fix_watch_points (void) +s390_fix_watch_points (ptid_t ptid) { - int tid = s390_inferior_tid (); + int tid; per_struct per_info; ptrace_area parea; @@ -279,6 +301,10 @@ s390_fix_watch_points (void) CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0; struct watch_area *area; + tid = TIDGET (ptid); + if (tid == 0) + tid = PIDGET (ptid); + for (area = watch_base; area; area = area->next) { watch_lo_addr = min (watch_lo_addr, area->lo_addr); @@ -289,7 +315,7 @@ s390_fix_watch_points (void) parea.process_addr = (addr_t) & per_info; parea.kernel_addr = offsetof (struct user_regs_struct, per_info); if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0) - perror_with_name ("Couldn't retrieve watchpoint status"); + perror_with_name (_("Couldn't retrieve watchpoint status")); if (watch_base) { @@ -305,13 +331,16 @@ s390_fix_watch_points (void) per_info.ending_addr = watch_hi_addr; if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0) - perror_with_name ("Couldn't modify watchpoint status"); + perror_with_name (_("Couldn't modify watchpoint status")); } -int -s390_insert_watchpoint (CORE_ADDR addr, int len) +static int +s390_insert_watchpoint (CORE_ADDR addr, int len, int type) { + struct lwp_info *lp; + ptid_t ptid; struct watch_area *area = xmalloc (sizeof (struct watch_area)); + if (!area) return -1; @@ -321,13 +350,16 @@ s390_insert_watchpoint (CORE_ADDR addr, int len) area->next = watch_base; watch_base = area; - s390_fix_watch_points (); + ALL_LWPS (lp, ptid) + s390_fix_watch_points (ptid); return 0; } -int -s390_remove_watchpoint (CORE_ADDR addr, int len) +static int +s390_remove_watchpoint (CORE_ADDR addr, int len, int type) { + struct lwp_info *lp; + ptid_t ptid; struct watch_area *area, **parea; for (parea = &watch_base; *parea; parea = &(*parea)->next) @@ -346,14 +378,128 @@ s390_remove_watchpoint (CORE_ADDR addr, int len) *parea = area->next; xfree (area); - s390_fix_watch_points (); + ALL_LWPS (lp, ptid) + s390_fix_watch_points (ptid); return 0; } +static int +s390_can_use_hw_breakpoint (int type, int cnt, int othertype) +{ + return type == bp_hardware_watchpoint; +} -int -kernel_u_size (void) +static int +s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt) { - return sizeof (struct user); + return 1; +} + +static int +s390_target_wordsize (void) +{ + int wordsize = 4; + + /* Check for 64-bit inferior process. This is the case when the host is + 64-bit, and in addition bit 32 of the PSW mask is set. */ +#ifdef __s390x__ + long pswm; + + errno = 0; + pswm = (long) ptrace (PTRACE_PEEKUSER, s390_inferior_tid (), PT_PSWMASK, 0); + if (errno == 0 && (pswm & 0x100000000ul) != 0) + wordsize = 8; +#endif + + return wordsize; } +static int +s390_auxv_parse (struct target_ops *ops, gdb_byte **readptr, + gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) +{ + int sizeof_auxv_field = s390_target_wordsize (); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + gdb_byte *ptr = *readptr; + + if (endptr == ptr) + return 0; + + if (endptr - ptr < sizeof_auxv_field * 2) + return -1; + + *typep = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order); + ptr += sizeof_auxv_field; + *valp = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order); + ptr += sizeof_auxv_field; + + *readptr = ptr; + return 1; +} + +#ifdef __s390x__ +static unsigned long +s390_get_hwcap (void) +{ + CORE_ADDR field; + + if (target_auxv_search (¤t_target, AT_HWCAP, &field)) + return (unsigned long) field; + + return 0; +} +#endif + +static const struct target_desc * +s390_read_description (struct target_ops *ops) +{ +#ifdef __s390x__ + /* If GDB itself is compiled as 64-bit, we are running on a machine in + z/Architecture mode. If the target is running in 64-bit addressing + mode, report s390x architecture. If the target is running in 31-bit + addressing mode, but the kernel supports using 64-bit registers in + that mode, report s390 architecture with 64-bit GPRs. */ + + if (s390_target_wordsize () == 8) + return tdesc_s390x_linux64; + + if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS) + return tdesc_s390_linux64; +#endif + + /* If GDB itself is compiled as 31-bit, or if we're running a 31-bit inferior + on a 64-bit kernel that does not support using 64-bit registers in 31-bit + mode, report s390 architecture with 32-bit GPRs. */ + return tdesc_s390_linux32; +} + +void _initialize_s390_nat (void); + +void +_initialize_s390_nat (void) +{ + struct target_ops *t; + + /* Fill in the generic GNU/Linux methods. */ + t = linux_target (); + + /* Add our register access methods. */ + t->to_fetch_registers = s390_linux_fetch_inferior_registers; + t->to_store_registers = s390_linux_store_inferior_registers; + + /* Add our watchpoint methods. */ + t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint; + t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint; + t->to_have_continuable_watchpoint = 1; + t->to_stopped_by_watchpoint = s390_stopped_by_watchpoint; + t->to_insert_watchpoint = s390_insert_watchpoint; + t->to_remove_watchpoint = s390_remove_watchpoint; + + /* Detect target architecture. */ + t->to_read_description = s390_read_description; + t->to_auxv_parse = s390_auxv_parse; + + /* Register the target. */ + linux_nat_add_target (t); + linux_nat_set_new_thread (t, s390_fix_watch_points); +}