OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [gdb/] [s390-nat.c] - Blame information for rev 280

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 24 jeremybenn
/* S390 native-dependent code for GDB, the GNU debugger.
2
   Copyright (C) 2001, 2003, 2004, 2005, 2006
3
   Free Software Foundation, Inc
4
 
5
   Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
6
   for IBM Deutschland Entwicklung GmbH, IBM Corporation.
7
 
8
   This file is part of GDB.
9
 
10
   This program is free software; you can redistribute it and/or modify
11
   it under the terms of the GNU General Public License as published by
12
   the Free Software Foundation; either version 3 of the License, or
13
   (at your option) any later version.
14
 
15
   This program is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
   GNU General Public License for more details.
19
 
20
   You should have received a copy of the GNU General Public License
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
22
 
23
#include "defs.h"
24
#include "regcache.h"
25
#include "inferior.h"
26
#include "target.h"
27
#include "linux-nat.h"
28
 
29
#include "s390-tdep.h"
30
 
31
#include <asm/ptrace.h>
32
#include <sys/ptrace.h>
33
#include <asm/types.h>
34
#include <sys/procfs.h>
35
#include <sys/ucontext.h>
36
 
37
 
38
/* Map registers to gregset/ptrace offsets.
39
   These arrays are defined in s390-tdep.c.  */
40
 
41
#ifdef __s390x__
42
#define regmap_gregset s390x_regmap_gregset
43
#else
44
#define regmap_gregset s390_regmap_gregset
45
#endif
46
 
47
#define regmap_fpregset s390_regmap_fpregset
48
 
49
/* When debugging a 32-bit executable running under a 64-bit kernel,
50
   we have to fix up the 64-bit registers we get from the kernel
51
   to make them look like 32-bit registers.  */
52
#ifdef __s390x__
53
#define SUBOFF(gdbarch, i) \
54
        ((gdbarch_ptr_bit (gdbarch) == 32 \
55
          && ((i) == S390_PSWA_REGNUM \
56
              || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
57
#else
58
#define SUBOFF(gdbarch, i) 0
59
#endif
60
 
61
 
62
/* Fill GDB's register array with the general-purpose register values
63
   in *REGP.  */
64
void
65
supply_gregset (struct regcache *regcache, const gregset_t *regp)
66
{
67
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
68
  int i;
69
  for (i = 0; i < S390_NUM_REGS; i++)
70
    if (regmap_gregset[i] != -1)
71
      regcache_raw_supply (regcache, i,
72
                           (const char *)regp + regmap_gregset[i]
73
                             + SUBOFF (gdbarch, i));
74
}
75
 
76
/* Fill register REGNO (if it is a general-purpose register) in
77
   *REGP with the value in GDB's register array.  If REGNO is -1,
78
   do this for all registers.  */
79
void
80
fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno)
81
{
82
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
83
  int i;
84
  for (i = 0; i < S390_NUM_REGS; i++)
85
    if (regmap_gregset[i] != -1)
86
      if (regno == -1 || regno == i)
87
        regcache_raw_collect (regcache, i,
88
                              (char *)regp + regmap_gregset[i]
89
                                + SUBOFF (gdbarch, i));
90
}
91
 
92
/* Fill GDB's register array with the floating-point register values
93
   in *REGP.  */
94
void
95
supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
96
{
97
  int i;
98
  for (i = 0; i < S390_NUM_REGS; i++)
99
    if (regmap_fpregset[i] != -1)
100
      regcache_raw_supply (regcache, i,
101
                           (const char *)regp + regmap_fpregset[i]);
102
}
103
 
104
/* Fill register REGNO (if it is a general-purpose register) in
105
   *REGP with the value in GDB's register array.  If REGNO is -1,
106
   do this for all registers.  */
107
void
108
fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
109
{
110
  int i;
111
  for (i = 0; i < S390_NUM_REGS; i++)
112
    if (regmap_fpregset[i] != -1)
113
      if (regno == -1 || regno == i)
114
        regcache_raw_collect (regcache, i,
115
                              (char *)regp + regmap_fpregset[i]);
116
}
117
 
118
/* Find the TID for the current inferior thread to use with ptrace.  */
119
static int
120
s390_inferior_tid (void)
121
{
122
  /* GNU/Linux LWP ID's are process ID's.  */
123
  int tid = TIDGET (inferior_ptid);
124
  if (tid == 0)
125
    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
126
 
127
  return tid;
128
}
129
 
130
/* Fetch all general-purpose registers from process/thread TID and
131
   store their values in GDB's register cache.  */
132
static void
133
fetch_regs (struct regcache *regcache, int tid)
134
{
135
  gregset_t regs;
136
  ptrace_area parea;
137
 
138
  parea.len = sizeof (regs);
139
  parea.process_addr = (addr_t) &regs;
140
  parea.kernel_addr = offsetof (struct user_regs_struct, psw);
141
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
142
    perror_with_name (_("Couldn't get registers"));
143
 
144
  supply_gregset (regcache, (const gregset_t *) &regs);
145
}
146
 
147
/* Store all valid general-purpose registers in GDB's register cache
148
   into the process/thread specified by TID.  */
149
static void
150
store_regs (const struct regcache *regcache, int tid, int regnum)
151
{
152
  gregset_t regs;
153
  ptrace_area parea;
154
 
155
  parea.len = sizeof (regs);
156
  parea.process_addr = (addr_t) &regs;
157
  parea.kernel_addr = offsetof (struct user_regs_struct, psw);
158
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
159
    perror_with_name (_("Couldn't get registers"));
160
 
161
  fill_gregset (regcache, &regs, regnum);
162
 
163
  if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
164
    perror_with_name (_("Couldn't write registers"));
165
}
166
 
167
/* Fetch all floating-point registers from process/thread TID and store
168
   their values in GDB's register cache.  */
169
static void
170
fetch_fpregs (struct regcache *regcache, int tid)
171
{
172
  fpregset_t fpregs;
173
  ptrace_area parea;
174
 
175
  parea.len = sizeof (fpregs);
176
  parea.process_addr = (addr_t) &fpregs;
177
  parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
178
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
179
    perror_with_name (_("Couldn't get floating point status"));
180
 
181
  supply_fpregset (regcache, (const fpregset_t *) &fpregs);
182
}
183
 
184
/* Store all valid floating-point registers in GDB's register cache
185
   into the process/thread specified by TID.  */
186
static void
187
store_fpregs (const struct regcache *regcache, int tid, int regnum)
188
{
189
  fpregset_t fpregs;
190
  ptrace_area parea;
191
 
192
  parea.len = sizeof (fpregs);
193
  parea.process_addr = (addr_t) &fpregs;
194
  parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
195
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
196
    perror_with_name (_("Couldn't get floating point status"));
197
 
198
  fill_fpregset (regcache, &fpregs, regnum);
199
 
200
  if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
201
    perror_with_name (_("Couldn't write floating point status"));
202
}
203
 
204
/* Fetch register REGNUM from the child process.  If REGNUM is -1, do
205
   this for all registers.  */
206
static void
207
s390_linux_fetch_inferior_registers (struct regcache *regcache, int regnum)
208
{
209
  int tid = s390_inferior_tid ();
210
 
211
  if (regnum == -1
212
      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
213
    fetch_regs (regcache, tid);
214
 
215
  if (regnum == -1
216
      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
217
    fetch_fpregs (regcache, tid);
218
}
219
 
220
/* Store register REGNUM back into the child process.  If REGNUM is
221
   -1, do this for all registers.  */
222
static void
223
s390_linux_store_inferior_registers (struct regcache *regcache, int regnum)
224
{
225
  int tid = s390_inferior_tid ();
226
 
227
  if (regnum == -1
228
      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
229
    store_regs (regcache, tid, regnum);
230
 
231
  if (regnum == -1
232
      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
233
    store_fpregs (regcache, tid, regnum);
234
}
235
 
236
 
237
/* Hardware-assisted watchpoint handling.  */
238
 
239
/* We maintain a list of all currently active watchpoints in order
240
   to properly handle watchpoint removal.
241
 
242
   The only thing we actually need is the total address space area
243
   spanned by the watchpoints.  */
244
 
245
struct watch_area
246
{
247
  struct watch_area *next;
248
  CORE_ADDR lo_addr;
249
  CORE_ADDR hi_addr;
250
};
251
 
252
static struct watch_area *watch_base = NULL;
253
 
254
static int
255
s390_stopped_by_watchpoint (void)
256
{
257
  per_lowcore_bits per_lowcore;
258
  ptrace_area parea;
259
  int result;
260
 
261
  /* Speed up common case.  */
262
  if (!watch_base)
263
    return 0;
264
 
265
  parea.len = sizeof (per_lowcore);
266
  parea.process_addr = (addr_t) & per_lowcore;
267
  parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
268
  if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
269
    perror_with_name (_("Couldn't retrieve watchpoint status"));
270
 
271
  result = (per_lowcore.perc_storage_alteration == 1
272
            && per_lowcore.perc_store_real_address == 0);
273
 
274
  if (result)
275
    {
276
      /* Do not report this watchpoint again.  */
277
      memset (&per_lowcore, 0, sizeof (per_lowcore));
278
      if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0)
279
        perror_with_name (_("Couldn't clear watchpoint status"));
280
    }
281
 
282
  return result;
283
}
284
 
285
static void
286
s390_fix_watch_points (ptid_t ptid)
287
{
288
  int tid;
289
 
290
  per_struct per_info;
291
  ptrace_area parea;
292
 
293
  CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
294
  struct watch_area *area;
295
 
296
  tid = TIDGET (ptid);
297
  if (tid == 0)
298
    tid = PIDGET (ptid);
299
 
300
  for (area = watch_base; area; area = area->next)
301
    {
302
      watch_lo_addr = min (watch_lo_addr, area->lo_addr);
303
      watch_hi_addr = max (watch_hi_addr, area->hi_addr);
304
    }
305
 
306
  parea.len = sizeof (per_info);
307
  parea.process_addr = (addr_t) & per_info;
308
  parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
309
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
310
    perror_with_name (_("Couldn't retrieve watchpoint status"));
311
 
312
  if (watch_base)
313
    {
314
      per_info.control_regs.bits.em_storage_alteration = 1;
315
      per_info.control_regs.bits.storage_alt_space_ctl = 1;
316
    }
317
  else
318
    {
319
      per_info.control_regs.bits.em_storage_alteration = 0;
320
      per_info.control_regs.bits.storage_alt_space_ctl = 0;
321
    }
322
  per_info.starting_addr = watch_lo_addr;
323
  per_info.ending_addr = watch_hi_addr;
324
 
325
  if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
326
    perror_with_name (_("Couldn't modify watchpoint status"));
327
}
328
 
329
static int
330
s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
331
{
332
  struct lwp_info *lp;
333
  ptid_t ptid;
334
  struct watch_area *area = xmalloc (sizeof (struct watch_area));
335
 
336
  if (!area)
337
    return -1;
338
 
339
  area->lo_addr = addr;
340
  area->hi_addr = addr + len - 1;
341
 
342
  area->next = watch_base;
343
  watch_base = area;
344
 
345
  ALL_LWPS (lp, ptid)
346
    s390_fix_watch_points (ptid);
347
  return 0;
348
}
349
 
350
static int
351
s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
352
{
353
  struct lwp_info *lp;
354
  ptid_t ptid;
355
  struct watch_area *area, **parea;
356
 
357
  for (parea = &watch_base; *parea; parea = &(*parea)->next)
358
    if ((*parea)->lo_addr == addr
359
        && (*parea)->hi_addr == addr + len - 1)
360
      break;
361
 
362
  if (!*parea)
363
    {
364
      fprintf_unfiltered (gdb_stderr,
365
                          "Attempt to remove nonexistent watchpoint.\n");
366
      return -1;
367
    }
368
 
369
  area = *parea;
370
  *parea = area->next;
371
  xfree (area);
372
 
373
  ALL_LWPS (lp, ptid)
374
    s390_fix_watch_points (ptid);
375
  return 0;
376
}
377
 
378
static int
379
s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
380
{
381
  return 1;
382
}
383
 
384
static int
385
s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt)
386
{
387
  return 1;
388
}
389
 
390
 
391
void _initialize_s390_nat (void);
392
 
393
void
394
_initialize_s390_nat (void)
395
{
396
  struct target_ops *t;
397
 
398
  /* Fill in the generic GNU/Linux methods.  */
399
  t = linux_target ();
400
 
401
  /* Add our register access methods.  */
402
  t->to_fetch_registers = s390_linux_fetch_inferior_registers;
403
  t->to_store_registers = s390_linux_store_inferior_registers;
404
 
405
  /* Add our watchpoint methods.  */
406
  t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
407
  t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
408
  t->to_have_continuable_watchpoint = 1;
409
  t->to_stopped_by_watchpoint = s390_stopped_by_watchpoint;
410
  t->to_insert_watchpoint = s390_insert_watchpoint;
411
  t->to_remove_watchpoint = s390_remove_watchpoint;
412
 
413
  /* Register the target.  */
414
  linux_nat_add_target (t);
415
  linux_nat_set_new_thread (t, s390_fix_watch_points);
416
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.