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

Subversion Repositories or1k

[/] [or1k/] [tags/] [VER_5_3/] [gdb-5.3/] [gdb/] [m68klinux-nat.c] - Blame information for rev 1778

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

Line No. Rev Author Line
1 1181 sfurman
/* Motorola m68k native support for GNU/Linux.
2
 
3
   Copyright 1996, 1998, 2000, 2001, 2002 Free Software Foundation,
4
   Inc.
5
 
6
   This file is part of GDB.
7
 
8
   This program is free software; you can redistribute it and/or modify
9
   it under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 2 of the License, or
11
   (at your option) any later version.
12
 
13
   This program is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
   GNU General Public License for more details.
17
 
18
   You should have received a copy of the GNU General Public License
19
   along with this program; if not, write to the Free Software
20
   Foundation, Inc., 59 Temple Place - Suite 330,
21
   Boston, MA 02111-1307, USA.  */
22
 
23
#include "defs.h"
24
#include "frame.h"
25
#include "inferior.h"
26
#include "language.h"
27
#include "gdbcore.h"
28
#include "regcache.h"
29
 
30
#ifdef USG
31
#include <sys/types.h>
32
#endif
33
 
34
#include <sys/param.h>
35
#include <sys/dir.h>
36
#include <signal.h>
37
#include <sys/ptrace.h>
38
#include <sys/user.h>
39
#include <sys/ioctl.h>
40
#include <fcntl.h>
41
#include <sys/procfs.h>
42
 
43
#ifdef HAVE_SYS_REG_H
44
#include <sys/reg.h>
45
#endif
46
 
47
#include <sys/file.h>
48
#include "gdb_stat.h"
49
 
50
#include "floatformat.h"
51
 
52
#include "target.h"
53
 
54
 
55
/* This table must line up with REGISTER_NAMES in tm-m68k.h */
56
static const int regmap[] =
57
{
58
  PT_D0, PT_D1, PT_D2, PT_D3, PT_D4, PT_D5, PT_D6, PT_D7,
59
  PT_A0, PT_A1, PT_A2, PT_A3, PT_A4, PT_A5, PT_A6, PT_USP,
60
  PT_SR, PT_PC,
61
  /* PT_FP0, ..., PT_FP7 */
62
  21, 24, 27, 30, 33, 36, 39, 42,
63
  /* PT_FPCR, PT_FPSR, PT_FPIAR */
64
  45, 46, 47
65
};
66
 
67
/* Which ptrace request retrieves which registers?
68
   These apply to the corresponding SET requests as well.  */
69
#define NUM_GREGS (18)
70
#define MAX_NUM_REGS (NUM_GREGS + 11)
71
 
72
int
73
getregs_supplies (int regno)
74
{
75
  return 0 <= regno && regno < NUM_GREGS;
76
}
77
 
78
int
79
getfpregs_supplies (int regno)
80
{
81
  return FP0_REGNUM <= regno && regno <= FPI_REGNUM;
82
}
83
 
84
/* Does the current host support the GETREGS request?  */
85
int have_ptrace_getregs =
86
#ifdef HAVE_PTRACE_GETREGS
87
  1
88
#else
89
 
90
#endif
91
;
92
 
93
 
94
 
95
/* BLOCKEND is the value of u.u_ar0, and points to the place where GS
96
   is stored.  */
97
 
98
int
99
m68k_linux_register_u_addr (int blockend, int regnum)
100
{
101
  return (blockend + 4 * regmap[regnum]);
102
}
103
 
104
 
105
/* Fetching registers directly from the U area, one at a time.  */
106
 
107
/* FIXME: This duplicates code from `inptrace.c'.  The problem is that we
108
   define FETCH_INFERIOR_REGISTERS since we want to use our own versions
109
   of {fetch,store}_inferior_registers that use the GETREGS request.  This
110
   means that the code in `infptrace.c' is #ifdef'd out.  But we need to
111
   fall back on that code when GDB is running on top of a kernel that
112
   doesn't support the GETREGS request.  */
113
 
114
#ifndef PT_READ_U
115
#define PT_READ_U PTRACE_PEEKUSR
116
#endif
117
#ifndef PT_WRITE_U
118
#define PT_WRITE_U PTRACE_POKEUSR
119
#endif
120
 
121
/* Default the type of the ptrace transfer to int.  */
122
#ifndef PTRACE_XFER_TYPE
123
#define PTRACE_XFER_TYPE int
124
#endif
125
 
126
/* Fetch one register.  */
127
 
128
static void
129
fetch_register (int regno)
130
{
131
  /* This isn't really an address.  But ptrace thinks of it as one.  */
132
  CORE_ADDR regaddr;
133
  char mess[128];               /* For messages */
134
  register int i;
135
  unsigned int offset;          /* Offset of registers within the u area.  */
136
  char buf[MAX_REGISTER_RAW_SIZE];
137
  int tid;
138
 
139
  if (CANNOT_FETCH_REGISTER (regno))
140
    {
141
      memset (buf, '\0', REGISTER_RAW_SIZE (regno));    /* Supply zeroes */
142
      supply_register (regno, buf);
143
      return;
144
    }
145
 
146
  /* Overload thread id onto process id */
147
  if ((tid = TIDGET (inferior_ptid)) == 0)
148
    tid = PIDGET (inferior_ptid);       /* no thread id, just use process id */
149
 
150
  offset = U_REGS_OFFSET;
151
 
152
  regaddr = register_addr (regno, offset);
153
  for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
154
    {
155
      errno = 0;
156
      *(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid,
157
                                               (PTRACE_ARG3_TYPE) regaddr, 0);
158
      regaddr += sizeof (PTRACE_XFER_TYPE);
159
      if (errno != 0)
160
        {
161
          sprintf (mess, "reading register %s (#%d)",
162
                   REGISTER_NAME (regno), regno);
163
          perror_with_name (mess);
164
        }
165
    }
166
  supply_register (regno, buf);
167
}
168
 
169
/* Fetch register values from the inferior.
170
   If REGNO is negative, do this for all registers.
171
   Otherwise, REGNO specifies which register (so we can save time). */
172
 
173
void
174
old_fetch_inferior_registers (int regno)
175
{
176
  if (regno >= 0)
177
    {
178
      fetch_register (regno);
179
    }
180
  else
181
    {
182
      for (regno = 0; regno < NUM_REGS; regno++)
183
        {
184
          fetch_register (regno);
185
        }
186
    }
187
}
188
 
189
/* Store one register. */
190
 
191
static void
192
store_register (int regno)
193
{
194
  /* This isn't really an address.  But ptrace thinks of it as one.  */
195
  CORE_ADDR regaddr;
196
  char mess[128];               /* For messages */
197
  register int i;
198
  unsigned int offset;          /* Offset of registers within the u area.  */
199
  int tid;
200
  char *buf = alloca (MAX_REGISTER_RAW_SIZE);
201
 
202
  if (CANNOT_STORE_REGISTER (regno))
203
    {
204
      return;
205
    }
206
 
207
  /* Overload thread id onto process id */
208
  if ((tid = TIDGET (inferior_ptid)) == 0)
209
    tid = PIDGET (inferior_ptid);       /* no thread id, just use process id */
210
 
211
  offset = U_REGS_OFFSET;
212
 
213
  regaddr = register_addr (regno, offset);
214
 
215
  /* Put the contents of regno into a local buffer */
216
  regcache_collect (regno, buf);
217
 
218
  /* Store the local buffer into the inferior a chunk at the time. */
219
  for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
220
    {
221
      errno = 0;
222
      ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr,
223
              *(PTRACE_XFER_TYPE *) (buf + i));
224
      regaddr += sizeof (PTRACE_XFER_TYPE);
225
      if (errno != 0)
226
        {
227
          sprintf (mess, "writing register %s (#%d)",
228
                   REGISTER_NAME (regno), regno);
229
          perror_with_name (mess);
230
        }
231
    }
232
}
233
 
234
/* Store our register values back into the inferior.
235
   If REGNO is negative, do this for all registers.
236
   Otherwise, REGNO specifies which register (so we can save time).  */
237
 
238
void
239
old_store_inferior_registers (int regno)
240
{
241
  if (regno >= 0)
242
    {
243
      store_register (regno);
244
    }
245
  else
246
    {
247
      for (regno = 0; regno < NUM_REGS; regno++)
248
        {
249
          store_register (regno);
250
        }
251
    }
252
}
253
 
254
/*  Given a pointer to a general register set in /proc format
255
   (elf_gregset_t *), unpack the register contents and supply
256
   them as gdb's idea of the current register values. */
257
 
258
 
259
/* Note both m68k-tdep.c and m68klinux-nat.c contain definitions
260
   for supply_gregset and supply_fpregset. The definitions
261
   in m68k-tdep.c are valid if USE_PROC_FS is defined. Otherwise,
262
   the definitions in m68klinux-nat.c will be used. This is a
263
   bit of a hack. The supply_* routines do not belong in
264
   *_tdep.c files. But, there are several lynx ports that currently
265
   depend on these definitions. */
266
 
267
#ifndef USE_PROC_FS
268
 
269
/* Prototypes for supply_gregset etc. */
270
#include "gregset.h"
271
 
272
void
273
supply_gregset (elf_gregset_t *gregsetp)
274
{
275
  elf_greg_t *regp = (elf_greg_t *) gregsetp;
276
  int regi;
277
 
278
  for (regi = D0_REGNUM; regi <= SP_REGNUM; regi++)
279
    supply_register (regi, (char *) &regp[regmap[regi]]);
280
  supply_register (PS_REGNUM, (char *) &regp[PT_SR]);
281
  supply_register (PC_REGNUM, (char *) &regp[PT_PC]);
282
}
283
 
284
/* Fill register REGNO (if it is a general-purpose register) in
285
   *GREGSETPS with the value in GDB's register array.  If REGNO is -1,
286
   do this for all registers.  */
287
void
288
fill_gregset (elf_gregset_t *gregsetp, int regno)
289
{
290
  elf_greg_t *regp = (elf_greg_t *) gregsetp;
291
  int i;
292
 
293
  for (i = 0; i < NUM_GREGS; i++)
294
    if ((regno == -1 || regno == i))
295
      regcache_collect (i, regp + regmap[i]);
296
}
297
 
298
#ifdef HAVE_PTRACE_GETREGS
299
 
300
/* Fetch all general-purpose registers from process/thread TID and
301
   store their values in GDB's register array.  */
302
 
303
static void
304
fetch_regs (int tid)
305
{
306
  elf_gregset_t regs;
307
 
308
  if (ptrace (PTRACE_GETREGS, tid, 0, (int) &regs) < 0)
309
    {
310
      if (errno == EIO)
311
        {
312
          /* The kernel we're running on doesn't support the GETREGS
313
             request.  Reset `have_ptrace_getregs'.  */
314
          have_ptrace_getregs = 0;
315
          return;
316
        }
317
 
318
      perror_with_name ("Couldn't get registers");
319
    }
320
 
321
  supply_gregset (&regs);
322
}
323
 
324
/* Store all valid general-purpose registers in GDB's register array
325
   into the process/thread specified by TID.  */
326
 
327
static void
328
store_regs (int tid, int regno)
329
{
330
  elf_gregset_t regs;
331
 
332
  if (ptrace (PTRACE_GETREGS, tid, 0, (int) &regs) < 0)
333
    perror_with_name ("Couldn't get registers");
334
 
335
  fill_gregset (&regs, regno);
336
 
337
  if (ptrace (PTRACE_SETREGS, tid, 0, (int) &regs) < 0)
338
    perror_with_name ("Couldn't write registers");
339
}
340
 
341
#else
342
 
343
static void fetch_regs (int tid) {}
344
static void store_regs (int tid, int regno) {}
345
 
346
#endif
347
 
348
 
349
/* Transfering floating-point registers between GDB, inferiors and cores.  */
350
 
351
/* What is the address of fpN within the floating-point register set F?  */
352
#define FPREG_ADDR(f, n) ((char *) &(f)->fpregs[(n) * 3])
353
 
354
/* Fill GDB's register array with the floating-point register values in
355
   *FPREGSETP.  */
356
 
357
void
358
supply_fpregset (elf_fpregset_t *fpregsetp)
359
{
360
  int regi;
361
 
362
  for (regi = FP0_REGNUM; regi < FPC_REGNUM; regi++)
363
    supply_register (regi, FPREG_ADDR (fpregsetp, regi - FP0_REGNUM));
364
  supply_register (FPC_REGNUM, (char *) &fpregsetp->fpcntl[0]);
365
  supply_register (FPS_REGNUM, (char *) &fpregsetp->fpcntl[1]);
366
  supply_register (FPI_REGNUM, (char *) &fpregsetp->fpcntl[2]);
367
}
368
 
369
/* Fill register REGNO (if it is a floating-point register) in
370
   *FPREGSETP with the value in GDB's register array.  If REGNO is -1,
371
   do this for all registers.  */
372
 
373
void
374
fill_fpregset (elf_fpregset_t *fpregsetp, int regno)
375
{
376
  int i;
377
 
378
  /* Fill in the floating-point registers.  */
379
  for (i = FP0_REGNUM; i < FP0_REGNUM + 8; i++)
380
    if (regno == -1 || regno == i)
381
      regcache_collect (regno, FPREG_ADDR (fpregsetp, regno - FP0_REGNUM));
382
 
383
  /* Fill in the floating-point control registers.  */
384
  for (i = FPC_REGNUM; i <= FPI_REGNUM; i++)
385
    if (regno == -1 || regno == i)
386
      regcache_collect (regno, (char *) &fpregsetp->fpcntl[regno - FPC_REGNUM]);
387
}
388
 
389
#ifdef HAVE_PTRACE_GETREGS
390
 
391
/* Fetch all floating-point registers from process/thread TID and store
392
   thier values in GDB's register array.  */
393
 
394
static void
395
fetch_fpregs (int tid)
396
{
397
  elf_fpregset_t fpregs;
398
 
399
  if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
400
    perror_with_name ("Couldn't get floating point status");
401
 
402
  supply_fpregset (&fpregs);
403
}
404
 
405
/* Store all valid floating-point registers in GDB's register array
406
   into the process/thread specified by TID.  */
407
 
408
static void
409
store_fpregs (int tid, int regno)
410
{
411
  elf_fpregset_t fpregs;
412
 
413
  if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
414
    perror_with_name ("Couldn't get floating point status");
415
 
416
  fill_fpregset (&fpregs, regno);
417
 
418
  if (ptrace (PTRACE_SETFPREGS, tid, 0, (int) &fpregs) < 0)
419
    perror_with_name ("Couldn't write floating point status");
420
}
421
 
422
#else
423
 
424
static void fetch_fpregs (int tid) {}
425
static void store_fpregs (int tid, int regno) {}
426
 
427
#endif
428
 
429
#endif
430
 
431
/* Transferring arbitrary registers between GDB and inferior.  */
432
 
433
/* Fetch register REGNO from the child process.  If REGNO is -1, do
434
   this for all registers (including the floating point and SSE
435
   registers).  */
436
 
437
void
438
fetch_inferior_registers (int regno)
439
{
440
  int tid;
441
 
442
  /* Use the old method of peeking around in `struct user' if the
443
     GETREGS request isn't available.  */
444
  if (! have_ptrace_getregs)
445
    {
446
      old_fetch_inferior_registers (regno);
447
      return;
448
    }
449
 
450
  /* GNU/Linux LWP ID's are process ID's.  */
451
  if ((tid = TIDGET (inferior_ptid)) == 0)
452
    tid = PIDGET (inferior_ptid);               /* Not a threaded program.  */
453
 
454
  /* Use the PTRACE_GETFPXREGS request whenever possible, since it
455
     transfers more registers in one system call, and we'll cache the
456
     results.  But remember that fetch_fpxregs can fail, and return
457
     zero.  */
458
  if (regno == -1)
459
    {
460
      fetch_regs (tid);
461
 
462
      /* The call above might reset `have_ptrace_getregs'.  */
463
      if (! have_ptrace_getregs)
464
        {
465
          old_fetch_inferior_registers (-1);
466
          return;
467
        }
468
 
469
      fetch_fpregs (tid);
470
      return;
471
    }
472
 
473
  if (getregs_supplies (regno))
474
    {
475
      fetch_regs (tid);
476
      return;
477
    }
478
 
479
  if (getfpregs_supplies (regno))
480
    {
481
      fetch_fpregs (tid);
482
      return;
483
    }
484
 
485
  internal_error (__FILE__, __LINE__,
486
                  "Got request for bad register number %d.", regno);
487
}
488
 
489
/* Store register REGNO back into the child process.  If REGNO is -1,
490
   do this for all registers (including the floating point and SSE
491
   registers).  */
492
void
493
store_inferior_registers (int regno)
494
{
495
  int tid;
496
 
497
  /* Use the old method of poking around in `struct user' if the
498
     SETREGS request isn't available.  */
499
  if (! have_ptrace_getregs)
500
    {
501
      old_store_inferior_registers (regno);
502
      return;
503
    }
504
 
505
  /* GNU/Linux LWP ID's are process ID's.  */
506
  if ((tid = TIDGET (inferior_ptid)) == 0)
507
    tid = PIDGET (inferior_ptid);       /* Not a threaded program.  */
508
 
509
  /* Use the PTRACE_SETFPREGS requests whenever possible, since it
510
     transfers more registers in one system call.  But remember that
511
     store_fpregs can fail, and return zero.  */
512
  if (regno == -1)
513
    {
514
      store_regs (tid, regno);
515
      store_fpregs (tid, regno);
516
      return;
517
    }
518
 
519
  if (getregs_supplies (regno))
520
    {
521
      store_regs (tid, regno);
522
      return;
523
    }
524
 
525
  if (getfpregs_supplies (regno))
526
    {
527
      store_fpregs (tid, regno);
528
      return;
529
    }
530
 
531
  internal_error (__FILE__, __LINE__,
532
                  "Got request to store bad register number %d.", regno);
533
}
534
 
535
/* Interpreting register set info found in core files.  */
536
 
537
/* Provide registers to GDB from a core file.
538
 
539
   (We can't use the generic version of this function in
540
   core-regset.c, because we need to use elf_gregset_t instead of
541
   gregset_t.)
542
 
543
   CORE_REG_SECT points to an array of bytes, which are the contents
544
   of a `note' from a core file which BFD thinks might contain
545
   register contents.  CORE_REG_SIZE is its size.
546
 
547
   WHICH says which register set corelow suspects this is:
548
 
549
     2 --- the floating-point register set, in elf_fpregset_t format
550
 
551
   REG_ADDR isn't used on GNU/Linux.  */
552
 
553
static void
554
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
555
                      int which, CORE_ADDR reg_addr)
556
{
557
  elf_gregset_t gregset;
558
  elf_fpregset_t fpregset;
559
 
560
  switch (which)
561
    {
562
    case 0:
563
      if (core_reg_size != sizeof (gregset))
564
        warning ("Wrong size gregset in core file.");
565
      else
566
        {
567
          memcpy (&gregset, core_reg_sect, sizeof (gregset));
568
          supply_gregset (&gregset);
569
        }
570
      break;
571
 
572
    case 2:
573
      if (core_reg_size != sizeof (fpregset))
574
        warning ("Wrong size fpregset in core file.");
575
      else
576
        {
577
          memcpy (&fpregset, core_reg_sect, sizeof (fpregset));
578
          supply_fpregset (&fpregset);
579
        }
580
      break;
581
 
582
    default:
583
      /* We've covered all the kinds of registers we know about here,
584
         so this must be something we wouldn't know what to do with
585
         anyway.  Just ignore it.  */
586
      break;
587
    }
588
}
589
 
590
 
591
int
592
kernel_u_size (void)
593
{
594
  return (sizeof (struct user));
595
}
596
 
597
/* Check whether insn1 and insn2 are parts of a signal trampoline.  */
598
 
599
#define IS_SIGTRAMP(insn1, insn2)                                       \
600
  (/* addaw #20,sp; moveq #119,d0; trap #0 */                           \
601
   (insn1 == 0xdefc0014 && insn2 == 0x70774e40)                         \
602
   /* moveq #119,d0; trap #0 */                                         \
603
   || insn1 == 0x70774e40)
604
 
605
#define IS_RT_SIGTRAMP(insn1, insn2)                                    \
606
  (/* movel #173,d0; trap #0 */                                         \
607
   (insn1 == 0x203c0000 && insn2 == 0x00ad4e40)                         \
608
   /* moveq #82,d0; notb d0; trap #0 */                                 \
609
   || (insn1 == 0x70524600 && (insn2 >> 16) == 0x4e40))
610
 
611
/* Return non-zero if PC points into the signal trampoline.  For the sake
612
   of m68k_linux_frame_saved_pc we also distinguish between non-RT and RT
613
   signal trampolines.  */
614
 
615
int
616
m68k_linux_in_sigtramp (CORE_ADDR pc)
617
{
618
  CORE_ADDR sp;
619
  char buf[12];
620
  unsigned long insn0, insn1, insn2;
621
 
622
  if (read_memory_nobpt (pc - 4, buf, sizeof (buf)))
623
    return 0;
624
  insn1 = extract_unsigned_integer (buf + 4, 4);
625
  insn2 = extract_unsigned_integer (buf + 8, 4);
626
  if (IS_SIGTRAMP (insn1, insn2))
627
    return 1;
628
  if (IS_RT_SIGTRAMP (insn1, insn2))
629
    return 2;
630
 
631
  insn0 = extract_unsigned_integer (buf, 4);
632
  if (IS_SIGTRAMP (insn0, insn1))
633
    return 1;
634
  if (IS_RT_SIGTRAMP (insn0, insn1))
635
    return 2;
636
 
637
  insn0 = (insn0 << 16) | (insn1 >> 16);
638
  insn1 = (insn1 << 16) | (insn2 >> 16);
639
  if (IS_SIGTRAMP (insn0, insn1))
640
    return 1;
641
  if (IS_RT_SIGTRAMP (insn0, insn1))
642
    return 2;
643
 
644
  return 0;
645
}
646
 
647
/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>.  */
648
#define SIGCONTEXT_PC_OFFSET 26
649
 
650
/* Offset to saved PC in ucontext, from <asm/ucontext.h>.  */
651
#define UCONTEXT_PC_OFFSET 88
652
 
653
/* Get saved user PC for sigtramp from sigcontext or ucontext.  */
654
 
655
static CORE_ADDR
656
m68k_linux_sigtramp_saved_pc (struct frame_info *frame)
657
{
658
  CORE_ADDR sigcontext_addr;
659
  char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
660
  int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT;
661
  int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT;
662
 
663
  /* Get sigcontext address, it is the third parameter on the stack.  */
664
  if (frame->next)
665
    sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (frame->next)
666
                                           + FRAME_ARGS_SKIP
667
                                           + sigcontext_offs,
668
                                           ptrbytes);
669
  else
670
    sigcontext_addr = read_memory_integer (read_register (SP_REGNUM)
671
                                           + sigcontext_offs,
672
                                           ptrbytes);
673
 
674
  /* Don't cause a memory_error when accessing sigcontext in case the
675
     stack layout has changed or the stack is corrupt.  */
676
  if (m68k_linux_in_sigtramp (frame->pc) == 2)
677
    target_read_memory (sigcontext_addr + UCONTEXT_PC_OFFSET, buf, ptrbytes);
678
  else
679
    target_read_memory (sigcontext_addr + SIGCONTEXT_PC_OFFSET, buf, ptrbytes);
680
  return extract_unsigned_integer (buf, ptrbytes);
681
}
682
 
683
/* Return the saved program counter for FRAME.  */
684
 
685
CORE_ADDR
686
m68k_linux_frame_saved_pc (struct frame_info *frame)
687
{
688
  if (frame->signal_handler_caller)
689
    return m68k_linux_sigtramp_saved_pc (frame);
690
 
691
  return read_memory_integer (frame->frame + 4, 4);
692
}
693
 
694
/* Register that we are able to handle GNU/Linux ELF core file
695
   formats.  */
696
 
697
static struct core_fns linux_elf_core_fns =
698
{
699
  bfd_target_elf_flavour,               /* core_flavour */
700
  default_check_format,                 /* check_format */
701
  default_core_sniffer,                 /* core_sniffer */
702
  fetch_core_registers,                 /* core_read_registers */
703
  NULL                                  /* next */
704
};
705
 
706
void
707
_initialize_m68k_linux_nat (void)
708
{
709
  add_core_fns (&linux_elf_core_fns);
710
}

powered by: WebSVN 2.1.0

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