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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gdb-7.2/] [gdb/] [s390-nat.c] - Blame information for rev 866

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

Line No. Rev Author Line
1 330 jeremybenn
/* S390 native-dependent code for GDB, the GNU debugger.
2
   Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2009
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
#include "auxv.h"
29
 
30
#include "s390-tdep.h"
31
 
32
#include <asm/ptrace.h>
33
#include <sys/ptrace.h>
34
#include <asm/types.h>
35
#include <sys/procfs.h>
36
#include <sys/ucontext.h>
37
#include <elf.h>
38
 
39
#ifndef HWCAP_S390_HIGH_GPRS
40
#define HWCAP_S390_HIGH_GPRS 512
41
#endif
42
 
43
 
44
/* Map registers to gregset/ptrace offsets.
45
   These arrays are defined in s390-tdep.c.  */
46
 
47
#ifdef __s390x__
48
#define regmap_gregset s390x_regmap_gregset
49
#else
50
#define regmap_gregset s390_regmap_gregset
51
#endif
52
 
53
#define regmap_fpregset s390_regmap_fpregset
54
 
55
/* When debugging a 32-bit executable running under a 64-bit kernel,
56
   we have to fix up the 64-bit registers we get from the kernel
57
   to make them look like 32-bit registers.  */
58
#ifdef __s390x__
59
#define SUBOFF(gdbarch, i) \
60
        ((gdbarch_ptr_bit (gdbarch) == 32 \
61
          && ((i) == S390_PSWA_REGNUM \
62
              || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
63
#else
64
#define SUBOFF(gdbarch, i) 0
65
#endif
66
 
67
 
68
/* Fill GDB's register array with the general-purpose register values
69
   in *REGP.  */
70
void
71
supply_gregset (struct regcache *regcache, const gregset_t *regp)
72
{
73
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
74
  int i;
75
  for (i = 0; i < S390_NUM_REGS; i++)
76
    if (regmap_gregset[i] != -1)
77
      regcache_raw_supply (regcache, i,
78
                           (const char *)regp + regmap_gregset[i]
79
                             + SUBOFF (gdbarch, i));
80
}
81
 
82
/* Fill register REGNO (if it is a general-purpose register) in
83
   *REGP with the value in GDB's register array.  If REGNO is -1,
84
   do this for all registers.  */
85
void
86
fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno)
87
{
88
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
89
  int i;
90
  for (i = 0; i < S390_NUM_REGS; i++)
91
    if (regmap_gregset[i] != -1)
92
      if (regno == -1 || regno == i)
93
        regcache_raw_collect (regcache, i,
94
                              (char *)regp + regmap_gregset[i]
95
                                + SUBOFF (gdbarch, i));
96
}
97
 
98
/* Fill GDB's register array with the floating-point register values
99
   in *REGP.  */
100
void
101
supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
102
{
103
  int i;
104
  for (i = 0; i < S390_NUM_REGS; i++)
105
    if (regmap_fpregset[i] != -1)
106
      regcache_raw_supply (regcache, i,
107
                           (const char *)regp + regmap_fpregset[i]);
108
}
109
 
110
/* Fill register REGNO (if it is a general-purpose register) in
111
   *REGP with the value in GDB's register array.  If REGNO is -1,
112
   do this for all registers.  */
113
void
114
fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
115
{
116
  int i;
117
  for (i = 0; i < S390_NUM_REGS; i++)
118
    if (regmap_fpregset[i] != -1)
119
      if (regno == -1 || regno == i)
120
        regcache_raw_collect (regcache, i,
121
                              (char *)regp + regmap_fpregset[i]);
122
}
123
 
124
/* Find the TID for the current inferior thread to use with ptrace.  */
125
static int
126
s390_inferior_tid (void)
127
{
128
  /* GNU/Linux LWP ID's are process ID's.  */
129
  int tid = TIDGET (inferior_ptid);
130
  if (tid == 0)
131
    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
132
 
133
  return tid;
134
}
135
 
136
/* Fetch all general-purpose registers from process/thread TID and
137
   store their values in GDB's register cache.  */
138
static void
139
fetch_regs (struct regcache *regcache, int tid)
140
{
141
  gregset_t regs;
142
  ptrace_area parea;
143
 
144
  parea.len = sizeof (regs);
145
  parea.process_addr = (addr_t) &regs;
146
  parea.kernel_addr = offsetof (struct user_regs_struct, psw);
147
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
148
    perror_with_name (_("Couldn't get registers"));
149
 
150
  supply_gregset (regcache, (const gregset_t *) &regs);
151
}
152
 
153
/* Store all valid general-purpose registers in GDB's register cache
154
   into the process/thread specified by TID.  */
155
static void
156
store_regs (const struct regcache *regcache, int tid, int regnum)
157
{
158
  gregset_t regs;
159
  ptrace_area parea;
160
 
161
  parea.len = sizeof (regs);
162
  parea.process_addr = (addr_t) &regs;
163
  parea.kernel_addr = offsetof (struct user_regs_struct, psw);
164
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
165
    perror_with_name (_("Couldn't get registers"));
166
 
167
  fill_gregset (regcache, &regs, regnum);
168
 
169
  if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
170
    perror_with_name (_("Couldn't write registers"));
171
}
172
 
173
/* Fetch all floating-point registers from process/thread TID and store
174
   their values in GDB's register cache.  */
175
static void
176
fetch_fpregs (struct regcache *regcache, int tid)
177
{
178
  fpregset_t fpregs;
179
  ptrace_area parea;
180
 
181
  parea.len = sizeof (fpregs);
182
  parea.process_addr = (addr_t) &fpregs;
183
  parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
184
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
185
    perror_with_name (_("Couldn't get floating point status"));
186
 
187
  supply_fpregset (regcache, (const fpregset_t *) &fpregs);
188
}
189
 
190
/* Store all valid floating-point registers in GDB's register cache
191
   into the process/thread specified by TID.  */
192
static void
193
store_fpregs (const struct regcache *regcache, int tid, int regnum)
194
{
195
  fpregset_t fpregs;
196
  ptrace_area parea;
197
 
198
  parea.len = sizeof (fpregs);
199
  parea.process_addr = (addr_t) &fpregs;
200
  parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
201
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
202
    perror_with_name (_("Couldn't get floating point status"));
203
 
204
  fill_fpregset (regcache, &fpregs, regnum);
205
 
206
  if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
207
    perror_with_name (_("Couldn't write floating point status"));
208
}
209
 
210
/* Fetch register REGNUM from the child process.  If REGNUM is -1, do
211
   this for all registers.  */
212
static void
213
s390_linux_fetch_inferior_registers (struct target_ops *ops,
214
                                     struct regcache *regcache, int regnum)
215
{
216
  int tid = s390_inferior_tid ();
217
 
218
  if (regnum == -1
219
      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
220
    fetch_regs (regcache, tid);
221
 
222
  if (regnum == -1
223
      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
224
    fetch_fpregs (regcache, tid);
225
}
226
 
227
/* Store register REGNUM back into the child process.  If REGNUM is
228
   -1, do this for all registers.  */
229
static void
230
s390_linux_store_inferior_registers (struct target_ops *ops,
231
                                     struct regcache *regcache, int regnum)
232
{
233
  int tid = s390_inferior_tid ();
234
 
235
  if (regnum == -1
236
      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
237
    store_regs (regcache, tid, regnum);
238
 
239
  if (regnum == -1
240
      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
241
    store_fpregs (regcache, tid, regnum);
242
}
243
 
244
 
245
/* Hardware-assisted watchpoint handling.  */
246
 
247
/* We maintain a list of all currently active watchpoints in order
248
   to properly handle watchpoint removal.
249
 
250
   The only thing we actually need is the total address space area
251
   spanned by the watchpoints.  */
252
 
253
struct watch_area
254
{
255
  struct watch_area *next;
256
  CORE_ADDR lo_addr;
257
  CORE_ADDR hi_addr;
258
};
259
 
260
static struct watch_area *watch_base = NULL;
261
 
262
static int
263
s390_stopped_by_watchpoint (void)
264
{
265
  per_lowcore_bits per_lowcore;
266
  ptrace_area parea;
267
  int result;
268
 
269
  /* Speed up common case.  */
270
  if (!watch_base)
271
    return 0;
272
 
273
  parea.len = sizeof (per_lowcore);
274
  parea.process_addr = (addr_t) & per_lowcore;
275
  parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
276
  if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
277
    perror_with_name (_("Couldn't retrieve watchpoint status"));
278
 
279
  result = (per_lowcore.perc_storage_alteration == 1
280
            && per_lowcore.perc_store_real_address == 0);
281
 
282
  if (result)
283
    {
284
      /* Do not report this watchpoint again.  */
285
      memset (&per_lowcore, 0, sizeof (per_lowcore));
286
      if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0)
287
        perror_with_name (_("Couldn't clear watchpoint status"));
288
    }
289
 
290
  return result;
291
}
292
 
293
static void
294
s390_fix_watch_points (ptid_t ptid)
295
{
296
  int tid;
297
 
298
  per_struct per_info;
299
  ptrace_area parea;
300
 
301
  CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
302
  struct watch_area *area;
303
 
304
  tid = TIDGET (ptid);
305
  if (tid == 0)
306
    tid = PIDGET (ptid);
307
 
308
  for (area = watch_base; area; area = area->next)
309
    {
310
      watch_lo_addr = min (watch_lo_addr, area->lo_addr);
311
      watch_hi_addr = max (watch_hi_addr, area->hi_addr);
312
    }
313
 
314
  parea.len = sizeof (per_info);
315
  parea.process_addr = (addr_t) & per_info;
316
  parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
317
  if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
318
    perror_with_name (_("Couldn't retrieve watchpoint status"));
319
 
320
  if (watch_base)
321
    {
322
      per_info.control_regs.bits.em_storage_alteration = 1;
323
      per_info.control_regs.bits.storage_alt_space_ctl = 1;
324
    }
325
  else
326
    {
327
      per_info.control_regs.bits.em_storage_alteration = 0;
328
      per_info.control_regs.bits.storage_alt_space_ctl = 0;
329
    }
330
  per_info.starting_addr = watch_lo_addr;
331
  per_info.ending_addr = watch_hi_addr;
332
 
333
  if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
334
    perror_with_name (_("Couldn't modify watchpoint status"));
335
}
336
 
337
static int
338
s390_insert_watchpoint (CORE_ADDR addr, int len, int type,
339
                        struct expression *cond)
340
{
341
  struct lwp_info *lp;
342
  ptid_t ptid;
343
  struct watch_area *area = xmalloc (sizeof (struct watch_area));
344
 
345
  if (!area)
346
    return -1;
347
 
348
  area->lo_addr = addr;
349
  area->hi_addr = addr + len - 1;
350
 
351
  area->next = watch_base;
352
  watch_base = area;
353
 
354
  ALL_LWPS (lp, ptid)
355
    s390_fix_watch_points (ptid);
356
  return 0;
357
}
358
 
359
static int
360
s390_remove_watchpoint (CORE_ADDR addr, int len, int type,
361
                        struct expression *cond)
362
{
363
  struct lwp_info *lp;
364
  ptid_t ptid;
365
  struct watch_area *area, **parea;
366
 
367
  for (parea = &watch_base; *parea; parea = &(*parea)->next)
368
    if ((*parea)->lo_addr == addr
369
        && (*parea)->hi_addr == addr + len - 1)
370
      break;
371
 
372
  if (!*parea)
373
    {
374
      fprintf_unfiltered (gdb_stderr,
375
                          "Attempt to remove nonexistent watchpoint.\n");
376
      return -1;
377
    }
378
 
379
  area = *parea;
380
  *parea = area->next;
381
  xfree (area);
382
 
383
  ALL_LWPS (lp, ptid)
384
    s390_fix_watch_points (ptid);
385
  return 0;
386
}
387
 
388
static int
389
s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
390
{
391
  return type == bp_hardware_watchpoint;
392
}
393
 
394
static int
395
s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt)
396
{
397
  return 1;
398
}
399
 
400
static int
401
s390_target_wordsize (void)
402
{
403
  int wordsize = 4;
404
 
405
  /* Check for 64-bit inferior process.  This is the case when the host is
406
     64-bit, and in addition bit 32 of the PSW mask is set.  */
407
#ifdef __s390x__
408
  long pswm;
409
 
410
  errno = 0;
411
  pswm = (long) ptrace (PTRACE_PEEKUSER, s390_inferior_tid (), PT_PSWMASK, 0);
412
  if (errno == 0 && (pswm & 0x100000000ul) != 0)
413
    wordsize = 8;
414
#endif
415
 
416
  return wordsize;
417
}
418
 
419
static int
420
s390_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
421
                 gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
422
{
423
  int sizeof_auxv_field = s390_target_wordsize ();
424
  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
425
  gdb_byte *ptr = *readptr;
426
 
427
  if (endptr == ptr)
428
    return 0;
429
 
430
  if (endptr - ptr < sizeof_auxv_field * 2)
431
    return -1;
432
 
433
  *typep = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order);
434
  ptr += sizeof_auxv_field;
435
  *valp = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order);
436
  ptr += sizeof_auxv_field;
437
 
438
  *readptr = ptr;
439
  return 1;
440
}
441
 
442
#ifdef __s390x__
443
static unsigned long
444
s390_get_hwcap (void)
445
{
446
  CORE_ADDR field;
447
 
448
  if (target_auxv_search (&current_target, AT_HWCAP, &field))
449
    return (unsigned long) field;
450
 
451
  return 0;
452
}
453
#endif
454
 
455
static const struct target_desc *
456
s390_read_description (struct target_ops *ops)
457
{
458
#ifdef __s390x__
459
  /* If GDB itself is compiled as 64-bit, we are running on a machine in
460
     z/Architecture mode.  If the target is running in 64-bit addressing
461
     mode, report s390x architecture.  If the target is running in 31-bit
462
     addressing mode, but the kernel supports using 64-bit registers in
463
     that mode, report s390 architecture with 64-bit GPRs.  */
464
 
465
  if (s390_target_wordsize () == 8)
466
    return tdesc_s390x_linux64;
467
 
468
  if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS)
469
    return tdesc_s390_linux64;
470
#endif
471
 
472
  /* If GDB itself is compiled as 31-bit, or if we're running a 31-bit inferior
473
     on a 64-bit kernel that does not support using 64-bit registers in 31-bit
474
     mode, report s390 architecture with 32-bit GPRs.  */
475
  return tdesc_s390_linux32;
476
}
477
 
478
void _initialize_s390_nat (void);
479
 
480
void
481
_initialize_s390_nat (void)
482
{
483
  struct target_ops *t;
484
 
485
  /* Fill in the generic GNU/Linux methods.  */
486
  t = linux_target ();
487
 
488
  /* Add our register access methods.  */
489
  t->to_fetch_registers = s390_linux_fetch_inferior_registers;
490
  t->to_store_registers = s390_linux_store_inferior_registers;
491
 
492
  /* Add our watchpoint methods.  */
493
  t->to_can_use_hw_breakpoint = s390_can_use_hw_breakpoint;
494
  t->to_region_ok_for_hw_watchpoint = s390_region_ok_for_hw_watchpoint;
495
  t->to_have_continuable_watchpoint = 1;
496
  t->to_stopped_by_watchpoint = s390_stopped_by_watchpoint;
497
  t->to_insert_watchpoint = s390_insert_watchpoint;
498
  t->to_remove_watchpoint = s390_remove_watchpoint;
499
 
500
  /* Detect target architecture.  */
501
  t->to_read_description = s390_read_description;
502
  t->to_auxv_parse = s390_auxv_parse;
503
 
504
  /* Register the target.  */
505
  linux_nat_add_target (t);
506
  linux_nat_set_new_thread (t, s390_fix_watch_points);
507
}

powered by: WebSVN 2.1.0

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