#define yytoks ada_toks /* With YYDEBUG defined */
#ifndef YYDEBUG
-#define YYDEBUG 0 /* Default to no yydebug support */
+#define YYDEBUG 1 /* Default to yydebug support */
#endif
+#define YYFPRINTF parser_fprintf
+
struct name_info {
struct symbol* sym;
struct minimal_symbol* msym;
#define yycheck c_yycheck
#ifndef YYDEBUG
-#define YYDEBUG 0 /* Default to no yydebug support */
+#define YYDEBUG 1 /* Default to yydebug support */
#endif
+#define YYFPRINTF parser_fprintf
+
int yyparse (void);
static int yylex (void);
some instructions. */
struct frame_info;
-struct frame_saved_regs;
extern CORE_ADDR m68k_saved_pc_after_call (struct frame_info *);
-extern void m68k_find_saved_regs (struct frame_info *,
- struct frame_saved_regs *);
#define SAVED_PC_AFTER_CALL(frame) \
m68k_saved_pc_after_call(frame)
/* Return number of bytes at start of arglist that are not really args. */
#define FRAME_ARGS_SKIP 8
-
-/* Put here the code to store, into a struct frame_saved_regs,
- the addresses of the saved registers of frame described by FRAME_INFO.
- This includes special registers such as pc and fp saved in special
- ways in the stack frame. sp is even more special:
- the address we return for it IS the sp for the next frame. */
-
-#if !defined (FRAME_FIND_SAVED_REGS)
-#define FRAME_FIND_SAVED_REGS(fi,fsr) m68k_find_saved_regs ((fi), &(fsr))
-#endif /* no FIND_FRAME_SAVED_REGS. */
\f
/* Things needed for making the inferior call functions. */
/* FIXME: Wrong to hardwire this as BPT_VECTOR when sometimes it
should be REMOTE_BPT_VECTOR. Best way to fix it would be to define
CALL_DUMMY_BREAKPOINT_OFFSET. */
-
+#if !GDB_MULTI_ARCH_PARTIAL
#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, (0x4e404e71 | (BPT_VECTOR << 16))}
#define CALL_DUMMY_LENGTH 28 /* Size of CALL_DUMMY */
#define CALL_DUMMY_START_OFFSET 12 /* Offset to jsr instruction */
/* Discard from the stack the innermost frame, restoring all registers. */
#define POP_FRAME { m68k_pop_frame (); }
-
+#endif
/* Offset from SP to first arg on stack at first instruction of a function */
#define SP_ARG0 (1 * 4)
Frame Descriptors. */
struct cie_unit
{
- /* Offset of this unit in dwarf_frame_buffer. */
+ /* Offset of this unit in .debug_frame or .eh_frame. */
ULONGEST offset;
/* A null-terminated string that identifies the augmentation to this CIE or
struct objfile *objfile;
};
+enum ptr_encoding
+{
+ PE_absptr = DW_EH_PE_absptr,
+ PE_pcrel = DW_EH_PE_pcrel,
+ PE_textrel = DW_EH_PE_textrel,
+ PE_datarel = DW_EH_PE_datarel,
+ PE_funcrel = DW_EH_PE_funcrel
+};
+
#define UNWIND_CONTEXT(fi) ((struct context *) (fi->context))
\f
extern unsigned int dwarf_frame_size;
extern file_ptr dwarf_eh_frame_offset;
extern unsigned int dwarf_eh_frame_size;
-
-static char *dwarf_frame_buffer;
\f
extern char *dwarf2_read_section (struct objfile *objfile, file_ptr offset,
static CORE_ADDR read_pointer (bfd * abfd, char **p);
static CORE_ADDR read_encoded_pointer (bfd * abfd, char **p,
unsigned char encoding);
+static enum ptr_encoding pointer_encoding (unsigned char encoding);
static LONGEST read_initial_length (bfd * abfd, char *buf, int *bytes_read);
static ULONGEST read_length (bfd * abfd, char *buf, int *bytes_read,
}
}
+/* This functions only reads appropriate amount of data from *p
+ * and returns the resulting value. Calling function must handle
+ * different encoding possibilities itself! */
static CORE_ADDR
read_encoded_pointer (bfd * abfd, char **p, unsigned char encoding)
{
"read_encoded_pointer: unknown pointer encoding");
}
- if (ret != 0)
- switch (encoding & 0xf0)
- {
- case DW_EH_PE_absptr:
- break;
- case DW_EH_PE_pcrel:
- ret += (CORE_ADDR) * p;
- break;
- case DW_EH_PE_textrel:
- case DW_EH_PE_datarel:
- case DW_EH_PE_funcrel:
- default:
- internal_error (__FILE__, __LINE__,
- "read_encoded_pointer: unknown pointer encoding");
- }
+ return ret;
+}
+/* Variable 'encoding' carries 3 different flags:
+ * - encoding & 0x0f : size of the address (handled in read_encoded_pointer())
+ * - encoding & 0x70 : type (absolute, relative, ...)
+ * - encoding & 0x80 : indirect flag (DW_EH_PE_indirect == 0x80). */
+enum ptr_encoding
+pointer_encoding (unsigned char encoding)
+{
+ int ret;
+
+ if (encoding & DW_EH_PE_indirect)
+ warning ("CFI: Unsupported pointer encoding: DW_EH_PE_indirect");
+
+ switch (encoding & 0x70)
+ {
+ case DW_EH_PE_absptr:
+ case DW_EH_PE_pcrel:
+ case DW_EH_PE_textrel:
+ case DW_EH_PE_datarel:
+ case DW_EH_PE_funcrel:
+ ret = encoding & 0x70;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "CFI: unknown pointer encoding");
+ }
return ret;
}
case DW_CFA_set_loc:
fs->pc = read_encoded_pointer (objfile->obfd, &insn_ptr,
fs->addr_encoding);
+
+ if (pointer_encoding (fs->addr_encoding) != PE_absptr)
+ warning ("CFI: DW_CFA_set_loc uses relative addressing");
+
break;
case DW_CFA_advance_loc1:
}
/* Build the cie_chunks and fde_chunks tables from informations
- in .debug_frame section. */
-void
-dwarf2_build_frame_info (struct objfile *objfile)
+ found in .debug_frame and .eh_frame sections. */
+/* We can handle both of these sections almost in the same way, however there
+ are some exceptions:
+ - CIE ID is -1 in debug_frame, but 0 in eh_frame
+ - eh_frame may contain some more information that are used only by gcc
+ (eg. personality pointer, LSDA pointer, ...). Most of them we can ignore.
+ - In debug_frame FDE's item cie_id contains offset of it's parent CIE.
+ In eh_frame FDE's item cie_id is a relative pointer to the parent CIE.
+ Anyway we don't need to bother with this, because we are smart enough
+ to keep the pointer to the parent CIE of oncomming FDEs in 'last_cie'.
+ - Although debug_frame items can contain Augmentation as well as
+ eh_frame ones, I have never seen them non-empty. Thus only in eh_frame
+ we can encounter for example non-absolute pointers (Aug. 'R').
+ -- mludvig */
+static void
+parse_frame_info (struct objfile *objfile, file_ptr frame_offset,
+ unsigned int frame_size, int eh_frame)
{
bfd *abfd = objfile->obfd;
+ asection *curr_section_ptr;
char *start = NULL;
char *end = NULL;
- int from_eh = 0;
+ char *frame_buffer = NULL;
+ char *curr_section_name, *aug_data;
+ struct cie_unit *last_cie = NULL;
+ int last_dup_fde = 0;
+ int aug_len, i;
+ CORE_ADDR curr_section_vma = 0;
unwind_tmp_obstack_init ();
- dwarf_frame_buffer = 0;
-
- if (dwarf_frame_offset)
- {
- dwarf_frame_buffer = dwarf2_read_section (objfile,
- dwarf_frame_offset,
- dwarf_frame_size);
+ frame_buffer = dwarf2_read_section (objfile, frame_offset, frame_size);
- start = dwarf_frame_buffer;
- end = dwarf_frame_buffer + dwarf_frame_size;
- }
- else if (dwarf_eh_frame_offset)
- {
- dwarf_frame_buffer = dwarf2_read_section (objfile,
- dwarf_eh_frame_offset,
- dwarf_eh_frame_size);
+ start = frame_buffer;
+ end = frame_buffer + frame_size;
- start = dwarf_frame_buffer;
- end = dwarf_frame_buffer + dwarf_eh_frame_size;
-
- from_eh = 1;
- }
+ curr_section_name = eh_frame ? ".eh_frame" : ".debug_frame";
+ curr_section_ptr = bfd_get_section_by_name (abfd, curr_section_name);
+ if (curr_section_ptr)
+ curr_section_vma = curr_section_ptr->vma;
if (start)
{
{
unsigned long length;
ULONGEST cie_id;
- ULONGEST unit_offset = start - dwarf_frame_buffer;
- int bytes_read;
- int dwarf64;
+ ULONGEST unit_offset = start - frame_buffer;
+ int bytes_read, dwarf64;
char *block_end;
length = read_initial_length (abfd, start, &bytes_read);
dwarf64 = (bytes_read == 12);
block_end = start + length;
+ if (length == 0)
+ {
+ start = block_end;
+ continue;
+ }
+
cie_id = read_length (abfd, start, &bytes_read, dwarf64);
start += bytes_read;
- if ((from_eh && cie_id == 0) || is_cie (cie_id, dwarf64))
+ if ((eh_frame && cie_id == 0) || is_cie (cie_id, dwarf64))
{
struct cie_unit *cie = cie_unit_alloc ();
char *aug;
start++; /* version */
cie->augmentation = aug = start;
- while (*start)
- start++;
- start++; /* skip past NUL */
+ while (*start++); /* Skips last NULL as well */
cie->code_align = read_uleb128 (abfd, &start);
cie->data_align = read_sleb128 (abfd, &start);
cie->ra = read_1u (abfd, &start);
+ /* Augmentation:
+ z Indicates that a uleb128 is present to size the
+ augmentation section.
+ L Indicates the encoding (and thus presence) of
+ an LSDA pointer in the FDE augmentation.
+ R Indicates a non-default pointer encoding for
+ FDE code pointers.
+ P Indicates the presence of an encoding + language
+ personality routine in the CIE augmentation.
+
+ [This info comes from GCC's dwarf2out.c]
+ */
if (*aug == 'z')
{
- int xtra = read_uleb128 (abfd, &start);
- start += xtra;
+ aug_len = read_uleb128 (abfd, &start);
+ aug_data = start;
+ start += aug_len;
++aug;
}
+ cie->data = start;
+ cie->data_length = block_end - cie->data;
+
while (*aug != '\0')
{
if (aug[0] == 'e' && aug[1] == 'h')
{
- start += sizeof (void *);
- aug += 2;
+ aug_data += sizeof (void *);
+ aug++;
}
else if (aug[0] == 'R')
+ cie->addr_encoding = *aug_data++;
+ else if (aug[0] == 'P')
{
- cie->addr_encoding = *start++;
- aug += 1;
+ CORE_ADDR pers_addr;
+ int pers_addr_enc;
+
+ pers_addr_enc = *aug_data++;
+ /* We don't need pers_addr value and so we
+ don't care about it's encoding. */
+ pers_addr = read_encoded_pointer (abfd, &aug_data,
+ pers_addr_enc);
}
- else if (aug[0] == 'P')
+ else if (aug[0] == 'L' && eh_frame)
{
- CORE_ADDR ptr;
- ptr = read_encoded_pointer (abfd, &start,
- cie->addr_encoding);
- aug += 1;
+ int lsda_addr_enc;
+
+ /* Perhaps we should save this to CIE for later use?
+ Do we need it for something in GDB? */
+ lsda_addr_enc = *aug_data++;
}
else
- warning ("%s(): unknown augmentation", __func__);
+ warning ("CFI warning: unknown augmentation \"%c\""
+ " in \"%s\" of\n"
+ "\t%s", aug[0], curr_section_name,
+ objfile->name);
+ aug++;
}
- cie->data = start;
- cie->data_length = block_end - start;
+ last_cie = cie;
}
else
{
struct fde_unit *fde;
struct cie_unit *cie;
+ int dup = 0;
+ CORE_ADDR init_loc;
+
+ /* We assume that debug_frame is in order
+ CIE,FDE,CIE,FDE,FDE,... and thus the CIE for this FDE
+ should be stored in last_cie pointer. If not, we'll
+ try to find it by the older way. */
+ if (last_cie)
+ cie = last_cie;
+ else
+ {
+ warning ("CFI: last_cie == NULL. "
+ "Perhaps a malformed %s section in '%s'...?\n",
+ curr_section_name, objfile->name);
- fde_chunks_need_space ();
- fde = fde_unit_alloc ();
-
- fde_chunks.array[fde_chunks.elems++] = fde;
+ cie = cie_chunks;
+ while (cie)
+ {
+ if (cie->objfile == objfile)
+ {
+ if (eh_frame &&
+ (cie->offset ==
+ (unit_offset + bytes_read - cie_id)))
+ break;
+ if (!eh_frame && (cie->offset == cie_id))
+ break;
+ }
+
+ cie = cie->next;
+ }
+ if (!cie)
+ error ("CFI: can't find CIE pointer");
+ }
- fde->initial_location = read_pointer (abfd, &start)
- + ANOFFSET (objfile->section_offsets,
- SECT_OFF_TEXT (objfile));
- fde->address_range = read_pointer (abfd, &start);
+ init_loc = read_encoded_pointer (abfd, &start,
+ cie->addr_encoding);
- cie = cie_chunks;
- while (cie)
+ switch (pointer_encoding (cie->addr_encoding))
{
- if (cie->objfile == objfile)
- {
- if (from_eh
- && (cie->offset ==
- (unit_offset + bytes_read - cie_id)))
- break;
- if (!from_eh && (cie->offset == cie_id))
+ case PE_absptr:
+ break;
+ case PE_pcrel:
+ /* start-frame_buffer gives offset from
+ the beginning of actual section. */
+ init_loc += curr_section_vma + start - frame_buffer;
+ break;
+ default:
+ warning ("CFI: Unsupported pointer encoding\n");
+ }
+
+ /* For relocatable objects we must add an offset telling
+ where the section is actually mapped in the memory. */
+ init_loc += ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile));
+
+ /* If we have both .debug_frame and .eh_frame present in
+ a file, we must eliminate duplicate FDEs. For now we'll
+ run through all entries in fde_chunks and check it one
+ by one. Perhaps in the future we can implement a faster
+ searching algorithm. */
+ /* eh_frame==2 indicates, that this file has an already
+ parsed .debug_frame too. When eh_frame==1 it means, that no
+ .debug_frame is present and thus we don't need to check for
+ duplicities. eh_frame==0 means, that we parse .debug_frame
+ and don't need to care about duplicate FDEs, because
+ .debug_frame is parsed first. */
+ if (eh_frame == 2)
+ for (i = 0; eh_frame == 2 && i < fde_chunks.elems; i++)
+ {
+ /* We assume that FDEs in .debug_frame and .eh_frame
+ have the same order (if they are present, of course).
+ If we find a duplicate entry for one FDE and save
+ it's index to last_dup_fde it's very likely, that
+ we'll find an entry for the following FDE right after
+ the previous one. Thus in many cases we'll run this
+ loop only once. */
+ last_dup_fde = (last_dup_fde + i) % fde_chunks.elems;
+ if (fde_chunks.array[last_dup_fde]->initial_location
+ == init_loc)
+ {
+ dup = 1;
break;
- }
+ }
+ }
- cie = cie->next;
- }
+ /* Allocate a new entry only if this FDE isn't a duplicate of
+ something we have already seen. */
+ if (!dup)
+ {
+ fde_chunks_need_space ();
+ fde = fde_unit_alloc ();
+
+ fde_chunks.array[fde_chunks.elems++] = fde;
+
+ fde->initial_location = init_loc;
+ fde->address_range = read_encoded_pointer (abfd, &start,
+ cie->
+ addr_encoding);
- if (!cie)
- error ("%s(): can't find CIE pointer", __func__);
- fde->cie_ptr = cie;
+ fde->cie_ptr = cie;
- if (cie->augmentation[0] == 'z')
- read_uleb128 (abfd, &start);
+ /* Here we intentionally ignore augmentation data
+ from FDE, because we don't need them. */
+ if (cie->augmentation[0] == 'z')
+ start += read_uleb128 (abfd, &start);
- fde->data = start;
- fde->data_length = block_end - start;
+ fde->data = start;
+ fde->data_length = block_end - start;
+ }
}
start = block_end;
}
sizeof (struct fde_unit *), compare_fde_unit);
}
}
-\f
+
+/* We must parse both .debug_frame section and .eh_frame because
+ * not all frames must be present in both of these sections. */
+void
+dwarf2_build_frame_info (struct objfile *objfile)
+{
+ int after_debug_frame = 0;
+
+ /* If we have .debug_frame then the parser is called with
+ eh_frame==0 for .debug_frame and eh_frame==2 for .eh_frame,
+ otherwise it's only called once for .eh_frame with argument
+ eh_frame==1. */
+
+ if (dwarf_frame_offset)
+ {
+ parse_frame_info (objfile, dwarf_frame_offset,
+ dwarf_frame_size, 0 /* = debug_frame */ );
+ after_debug_frame = 1;
+ }
+
+ if (dwarf_eh_frame_offset)
+ parse_frame_info (objfile, dwarf_eh_frame_offset, dwarf_eh_frame_size,
+ 1 /* = eh_frame */ + after_debug_frame);
+}
/* Return the frame address. */
CORE_ADDR
void
cfi_get_saved_register (char *raw_buffer,
int *optimized,
- CORE_ADDR * addrp,
+ CORE_ADDR *addrp,
struct frame_info *frame,
int regnum, enum lval_type *lval)
{
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg1->next = arg2;
arg2->next = NULL;
- arg1->data.integer = time_at_cmd_start;
- arg2->data.integer = space_at_cmd_start;
+ arg1->data.longint = time_at_cmd_start;
+#ifdef HAVE_SBRK
+ arg2->data.longint = space_at_cmd_start;
+#endif
add_continuation (command_line_handler_continuation, arg1);
}
#define yycheck f_yycheck
#ifndef YYDEBUG
-#define YYDEBUG 1 /* Default to no yydebug support */
+#define YYDEBUG 1 /* Default to yydebug support */
#endif
+#define YYFPRINTF parser_fprintf
+
int yyparse (void);
static int yylex (void);
#define yycheck java_yycheck
#ifndef YYDEBUG
-#define YYDEBUG 0 /* Default to no yydebug support */
+#define YYDEBUG 1 /* Default to yydebug support */
#endif
+#define YYFPRINTF parser_fprintf
+
int yyparse (void);
static int yylex (void);
#define yycheck m2_yycheck
#ifndef YYDEBUG
-#define YYDEBUG 0 /* Default to no yydebug support */
+#define YYDEBUG 1 /* Default to yydebug support */
#endif
+#define YYFPRINTF parser_fprintf
+
int yyparse (void);
static int yylex (void);
#define P_FMOVM 0xf237
#define P_TRAP 0x4e40
+void m68k_frame_init_saved_regs (struct frame_info *frame_info);
+
/* The only reason this is here is the tm-altos.h reference below. It
was moved back here from tm-m68k.h. FIXME? */
return val;
}
+/* Insert the specified number of args and function address
+ into a call sequence of the above form stored at DUMMYNAME.
+ We use the BFD routines to store a big-endian value of known size. */
+
+void
+m68k_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+ struct value **args, struct type *type, int gcc_p)
+{
+ bfd_putb32 (fun, (unsigned char *) dummy + CALL_DUMMY_START_OFFSET + 2);
+ bfd_putb32 (nargs * 4,
+ (unsigned char *) dummy + CALL_DUMMY_START_OFFSET + 8);
+}
+
+
/* Push an empty stack frame, to record the current PC, etc. */
void
register struct frame_info *frame = get_current_frame ();
register CORE_ADDR fp;
register int regnum;
- struct frame_saved_regs fsr;
char raw_buffer[12];
fp = FRAME_FP (frame);
- get_frame_saved_regs (frame, &fsr);
+ m68k_frame_init_saved_regs (frame);
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--)
{
- if (fsr.regs[regnum])
+ if (frame->saved_regs[regnum])
{
- read_memory (fsr.regs[regnum], raw_buffer, 12);
+ read_memory (frame->saved_regs[regnum], raw_buffer, 12);
write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12);
}
}
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--)
{
- if (fsr.regs[regnum])
+ if (frame->saved_regs[regnum])
{
- write_register (regnum, read_memory_integer (fsr.regs[regnum], 4));
+ write_register (regnum,
+ read_memory_integer (frame->saved_regs[regnum], 4));
}
}
- if (fsr.regs[PS_REGNUM])
+ if (frame->saved_regs[PS_REGNUM])
{
write_register (PS_REGNUM,
- read_memory_integer (fsr.regs[PS_REGNUM], 4));
+ read_memory_integer (frame->saved_regs[PS_REGNUM], 4));
}
write_register (FP_REGNUM, read_memory_integer (fp, 4));
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
return (ip);
}
+/* Store the addresses of the saved registers of the frame described by
+ FRAME_INFO in its saved_regs field.
+ This includes special registers such as pc and fp saved in special
+ ways in the stack frame. sp is even more special:
+ the address we return for it IS the sp for the next frame. */
+
void
-m68k_find_saved_regs (struct frame_info *frame_info,
- struct frame_saved_regs *saved_regs)
+m68k_frame_init_saved_regs (struct frame_info *frame_info)
{
register int regnum;
register int regmask;
/* First possible address for a pc in a call dummy for this frame. */
CORE_ADDR possible_call_dummy_start =
- (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4 - 8 * 12;
+ (frame_info)->frame - 28 - FP_REGNUM * 4 - 4 - 8 * 12;
int nextinsn;
- memset (saved_regs, 0, sizeof (*saved_regs));
+
+ if (frame_info->saved_regs)
+ return;
+
+ frame_saved_regs_zalloc (frame_info);
+
+ memset (frame_info->saved_regs, 0, SIZEOF_FRAME_SAVED_REGS);
+
if ((frame_info)->pc >= possible_call_dummy_start
&& (frame_info)->pc <= (frame_info)->frame)
{
/* Regmask's low bit is for register fp7, the first pushed */
for (regnum = FP0_REGNUM + 8; --regnum >= FP0_REGNUM; regmask >>= 1)
if (regmask & 1)
- saved_regs->regs[regnum] = (next_addr -= 12);
+ frame_info->saved_regs[regnum] = (next_addr -= 12);
pc += 4;
}
/* fmovemx to (fp + displacement) */
for (regnum = FP0_REGNUM + 8; --regnum >= FP0_REGNUM; regmask >>= 1)
if (regmask & 1)
{
- saved_regs->regs[regnum] = addr;
+ frame_info->saved_regs[regnum] = addr;
addr += 12;
}
pc += 6;
for (regnum = 0; regnum < 16; regnum++, regmask >>= 1)
if (regmask & 1)
{
- saved_regs->regs[regnum] = next_addr;
+ frame_info->saved_regs[regnum] = next_addr;
next_addr += 4;
}
pc += 4;
for (regnum = 0; regnum < 16; regnum++, regmask >>= 1)
if (regmask & 1)
{
- saved_regs->regs[regnum] = addr;
+ frame_info->saved_regs[regnum] = addr;
addr += 4;
}
pc += 6;
/* Regmask's low bit is for register 15, the first pushed */
for (regnum = 16; --regnum >= 0; regmask >>= 1)
if (regmask & 1)
- saved_regs->regs[regnum] = (next_addr -= 4);
+ frame_info->saved_regs[regnum] = (next_addr -= 4);
pc += 4;
}
/* movl r,-(sp) */
else if (0x2f00 == (0xfff0 & nextinsn))
{
regnum = 0xf & nextinsn;
- saved_regs->regs[regnum] = (next_addr -= 4);
+ frame_info->saved_regs[regnum] = (next_addr -= 4);
pc += 2;
}
/* fmovemx to index of sp */
for (regnum = FP0_REGNUM + 8; --regnum >= FP0_REGNUM; regmask >>= 1)
if (regmask & 1)
{
- saved_regs->regs[regnum] = next_addr;
+ frame_info->saved_regs[regnum] = next_addr;
next_addr += 12;
}
pc += 10;
/* clrw -(sp); movw ccr,-(sp) */
else if (0x4267 == nextinsn && 0x42e7 == regmask)
{
- saved_regs->regs[PS_REGNUM] = (next_addr -= 4);
+ frame_info->saved_regs[PS_REGNUM] = (next_addr -= 4);
pc += 4;
}
else
break;
}
lose:;
- saved_regs->regs[SP_REGNUM] = (frame_info)->frame + 8;
- saved_regs->regs[FP_REGNUM] = (frame_info)->frame;
- saved_regs->regs[PC_REGNUM] = (frame_info)->frame + 4;
+ frame_info->saved_regs[SP_REGNUM] = (frame_info)->frame + 8;
+ frame_info->saved_regs[FP_REGNUM] = (frame_info)->frame;
+ frame_info->saved_regs[PC_REGNUM] = (frame_info)->frame + 4;
#ifdef SIG_SP_FP_OFFSET
/* Adjust saved SP_REGNUM for fake _sigtramp frames. */
if (frame_info->signal_handler_caller && frame_info->next)
- saved_regs->regs[SP_REGNUM] = frame_info->next->frame + SIG_SP_FP_OFFSET;
+ frame_info->saved_regs[SP_REGNUM] =
+ frame_info->next->frame + SIG_SP_FP_OFFSET;
#endif
}
static struct gdbarch *
m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
+ static LONGEST call_dummy_words[7] = { 0xf227e0ff, 0x48e7fffc, 0x426742e7,
+ 0x4eb93232, 0x3232dffc, 0x69696969,
+ (0x4e404e71 | (BPT_VECTOR << 16))
+ };
struct gdbarch_tdep *tdep = NULL;
struct gdbarch *gdbarch;
gdbarch = gdbarch_alloc (&info, 0);
+ set_gdbarch_frame_init_saved_regs (gdbarch, m68k_frame_init_saved_regs);
+
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 24);
+ set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack);
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+ set_gdbarch_call_dummy_length (gdbarch, 28);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 12);
+
+ set_gdbarch_call_dummy_words (gdbarch, call_dummy_words);
+ set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (call_dummy_words));
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+ set_gdbarch_fix_call_dummy (gdbarch, m68k_fix_call_dummy);
+ set_gdbarch_push_dummy_frame (gdbarch, m68k_push_dummy_frame);
+ set_gdbarch_pop_frame (gdbarch, m68k_pop_frame);
+
return gdbarch;
}
"Windows CE",
"DJGPP",
"NetWare",
+ "LynxOS",
"ARM EABI v1",
"ARM EABI v2",
GDB_OSABI_WINCE,
GDB_OSABI_GO32,
GDB_OSABI_NETWARE,
+ GDB_OSABI_LYNXOS,
GDB_OSABI_ARM_EABI_V1,
GDB_OSABI_ARM_EABI_V2,
#define yycheck pascal_yycheck
#ifndef YYDEBUG
-#define YYDEBUG 0 /* Default to no yydebug support */
+#define YYDEBUG 1 /* Default to yydebug support */
#endif
+#define YYFPRINTF parser_fprintf
+
int yyparse (void);
static int yylex (void);
NULL);
}
+/* This function avoids direct calls to fprintf
+ in the parser generated debug code. */
+void
+parser_fprintf (FILE *x, const char *y, ...)
+{
+ va_list args;
+ va_start (args, y);
+ if (x == stderr)
+ vfprintf_unfiltered (gdb_stderr, y, args);
+ else
+ {
+ fprintf_unfiltered (gdb_stderr, " Unknown FILE used.\n");
+ vfprintf_unfiltered (gdb_stderr, y, args);
+ }
+ va_end (args);
+}
+
void
_initialize_parse (void)
{
extern int target_map_name_to_register (char *, int);
+/* Function used to avoid direct calls to fprintf
+ in the code generated by the bison parser. */
+
+extern void parser_fprintf (FILE *, const char *, ...) ATTR_FORMAT (printf, 2 ,3);
+
#endif /* PARSER_DEFS_H */
/* Cache and manage the values of registers for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001
- Free Software Foundation, Inc.
+
+ Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
+ 2001, 2002 Free Software Foundation, Inc.
This file is part of GDB.
* Here is the actual register cache.
*/
+/* Per-architecture object describing the layout of a register cache.
+ Computed once when the architecture is created */
+
+struct gdbarch_data *regcache_descr_handle;
+
+struct regcache_descr
+{
+ /* The architecture this descriptor belongs to. */
+ struct gdbarch *gdbarch;
+
+ /* Is this a ``legacy'' register cache? Such caches reserve space
+ for raw and pseudo registers and allow access to both. */
+ int legacy_p;
+
+ /* The raw register cache. This should contain just [0
+ .. NUM_RAW_REGISTERS). However, for older targets, it contains
+ space for the full [0 .. NUM_RAW_REGISTERS +
+ NUM_PSEUDO_REGISTERS). */
+ int nr_raw_registers;
+ long sizeof_raw_registers;
+ long sizeof_raw_register_valid_p;
+
+ /* Offset, in bytes, of reach register in the raw register cache.
+ Pseudo registers have an offset even though they don't
+ (shouldn't) have a correspoinding space in the register cache.
+ It is to keep existing code, that relies on
+ write/write_register_bytes working. */
+ long *register_offset;
+
+ /* The cooked / frame / virtual register space. The registers in
+ the range [0..NR_RAW_REGISTERS) should be mapped directly onto
+ the corresponding raw register. The next [NR_RAW_REGISTERS
+ .. NR_REGISTERS) should have been mapped, via
+ gdbarch_register_read/write onto either raw registers or memory. */
+ int nr_registers;
+ long *sizeof_register;
+ long max_register_size;
+
+};
+
+static void *
+init_legacy_regcache_descr (struct gdbarch *gdbarch)
+{
+ int i;
+ struct regcache_descr *descr;
+ /* FIXME: cagney/2002-05-11: gdbarch_data() should take that
+ ``gdbarch'' as a parameter. */
+ gdb_assert (gdbarch != NULL);
+
+ descr = XMALLOC (struct regcache_descr);
+ descr->gdbarch = gdbarch;
+ descr->legacy_p = 1;
+
+ /* FIXME: cagney/2002-05-11: Shouldn't be including pseudo-registers
+ in the register buffer. Unfortunatly some architectures do. */
+ descr->nr_registers = NUM_REGS + NUM_PSEUDO_REGS;
+ descr->nr_raw_registers = descr->nr_registers;
+ descr->sizeof_raw_register_valid_p = descr->nr_registers;
+
+ /* FIXME: cagney/2002-05-11: Instead of using REGISTER_BYTE() this
+ code should compute the offets et.al. at runtime. This currently
+ isn't possible because some targets overlap register locations -
+ see the mess in read_register_bytes() and write_register_bytes()
+ registers. */
+ descr->sizeof_register = XCALLOC (descr->nr_registers, long);
+ descr->register_offset = XCALLOC (descr->nr_registers, long);
+ descr->max_register_size = 0;
+ for (i = 0; i < descr->nr_registers; i++)
+ {
+ descr->register_offset[i] = REGISTER_BYTE (i);
+ descr->sizeof_register[i] = REGISTER_RAW_SIZE (i);
+ if (descr->max_register_size < REGISTER_RAW_SIZE (i))
+ descr->max_register_size = REGISTER_RAW_SIZE (i);
+ }
+
+ /* Come up with the real size of the registers buffer. */
+ descr->sizeof_raw_registers = REGISTER_BYTES; /* OK use. */
+ for (i = 0; i < descr->nr_registers; i++)
+ {
+ long regend;
+ /* Keep extending the buffer so that there is always enough
+ space for all registers. The comparison is necessary since
+ legacy code is free to put registers in random places in the
+ buffer separated by holes. Once REGISTER_BYTE() is killed
+ this can be greatly simplified. */
+ /* FIXME: cagney/2001-12-04: This code shouldn't need to use
+ REGISTER_BYTE(). Unfortunatly, legacy code likes to lay the
+ buffer out so that certain registers just happen to overlap.
+ Ulgh! New targets use gdbarch's register read/write and
+ entirely avoid this uglyness. */
+ regend = descr->register_offset[i] + descr->sizeof_register[i];
+ if (descr->sizeof_raw_registers < regend)
+ descr->sizeof_raw_registers = regend;
+ }
+ return descr;
+}
+
+static void *
+init_regcache_descr (struct gdbarch *gdbarch)
+{
+ int i;
+ struct regcache_descr *descr;
+ gdb_assert (gdbarch != NULL);
+
+ /* If an old style architecture, construct the register cache
+ description using all the register macros. */
+ if (!gdbarch_register_read_p (gdbarch)
+ && !gdbarch_register_write_p (gdbarch))
+ return init_legacy_regcache_descr (gdbarch);
+
+ descr = XMALLOC (struct regcache_descr);
+ descr->gdbarch = gdbarch;
+ descr->legacy_p = 0;
+
+ /* Total size of the register space. The raw registers should
+ directly map onto the raw register cache while the pseudo's are
+ either mapped onto raw-registers or memory. */
+ descr->nr_registers = NUM_REGS + NUM_PSEUDO_REGS;
+
+ /* Construct a strictly RAW register cache. Don't allow pseudo's
+ into the register cache. */
+ descr->nr_raw_registers = NUM_REGS;
+ descr->sizeof_raw_register_valid_p = NUM_REGS;
+
+ /* Lay out the register cache. The pseud-registers are included in
+ the layout even though their value isn't stored in the register
+ cache. Some code, via read_register_bytes() access a register
+ using an offset/length rather than a register number.
+
+ NOTE: cagney/2002-05-22: Only REGISTER_VIRTUAL_TYPE() needs to be
+ used when constructing the register cache. It is assumed that
+ register raw size, virtual size and type length of the type are
+ all the same. */
+
+ {
+ long offset = 0;
+ descr->sizeof_register = XCALLOC (descr->nr_registers, long);
+ descr->register_offset = XCALLOC (descr->nr_registers, long);
+ descr->max_register_size = 0;
+ for (i = 0; i < descr->nr_registers; i++)
+ {
+ descr->sizeof_register[i] = TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (i));
+ descr->register_offset[i] = offset;
+ offset += descr->sizeof_register[i];
+ if (descr->max_register_size < descr->sizeof_register[i])
+ descr->max_register_size = descr->sizeof_register[i];
+ }
+ /* Set the real size of the register cache buffer. */
+ /* FIXME: cagney/2002-05-22: Should only need to allocate space
+ for the raw registers. Unfortunatly some code still accesses
+ the register array directly using the global registers[].
+ Until that code has been purged, play safe and over allocating
+ the register buffer. Ulgh! */
+ descr->sizeof_raw_registers = offset;
+ /* = descr->register_offset[descr->nr_raw_registers]; */
+ }
+
+#if 0
+ /* Sanity check. Confirm that the assumptions about gdbarch are
+ true. The REGCACHE_DESCR_HANDLE is set before doing the checks
+ so that targets using the generic methods supplied by regcache
+ don't go into infinite recursion trying to, again, create the
+ regcache. */
+ set_gdbarch_data (gdbarch, regcache_descr_handle, descr);
+ for (i = 0; i < descr->nr_registers; i++)
+ {
+ gdb_assert (descr->sizeof_register[i] == REGISTER_RAW_SIZE (i));
+ gdb_assert (descr->sizeof_register[i] == REGISTER_VIRTUAL_SIZE (i));
+ gdb_assert (descr->register_offset[i] == REGISTER_BYTE (i));
+ }
+ /* gdb_assert (descr->sizeof_raw_registers == REGISTER_BYTES (i)); */
+#endif
+
+ return descr;
+}
+
+static struct regcache_descr *
+regcache_descr (struct gdbarch *gdbarch)
+{
+ return gdbarch_data (gdbarch, regcache_descr_handle);
+}
+
+static void
+xfree_regcache_descr (struct gdbarch *gdbarch, void *ptr)
+{
+ struct regcache_descr *descr = ptr;
+ if (descr == NULL)
+ return;
+ xfree (descr->register_offset);
+ xfree (descr->sizeof_register);
+ descr->register_offset = NULL;
+ descr->sizeof_register = NULL;
+ xfree (descr);
+}
+
+/* The register cache for storing raw register values. */
+
+struct regcache
+{
+ struct regcache_descr *descr;
+ char *raw_registers;
+ char *raw_register_valid_p;
+ /* If a value isn't in the cache should the corresponding target be
+ queried for a value. */
+ int passthrough_p;
+};
+
+struct regcache *
+regcache_xmalloc (struct gdbarch *gdbarch)
+{
+ struct regcache_descr *descr;
+ struct regcache *regcache;
+ gdb_assert (gdbarch != NULL);
+ descr = regcache_descr (gdbarch);
+ regcache = XMALLOC (struct regcache);
+ regcache->descr = descr;
+ regcache->raw_registers
+ = XCALLOC (descr->sizeof_raw_registers, char);
+ regcache->raw_register_valid_p
+ = XCALLOC (descr->sizeof_raw_register_valid_p, char);
+ regcache->passthrough_p = 0;
+ return regcache;
+}
+
+void
+regcache_xfree (struct regcache *regcache)
+{
+ if (regcache == NULL)
+ return;
+ xfree (regcache->raw_registers);
+ xfree (regcache->raw_register_valid_p);
+ xfree (regcache);
+}
+
+void
+regcache_cpy (struct regcache *dst, struct regcache *src)
+{
+ int i;
+ char *buf;
+ gdb_assert (src != NULL && dst != NULL);
+ gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
+ gdb_assert (src != dst);
+ /* FIXME: cagney/2002-05-17: To say this bit is bad is being polite.
+ It keeps the existing code working where things rely on going
+ through to the register cache. */
+ if (src == current_regcache && src->descr->legacy_p)
+ {
+ /* ULGH!!!! Old way. Use REGISTER bytes and let code below
+ untangle fetch. */
+ read_register_bytes (0, dst->raw_registers, REGISTER_BYTES);
+ return;
+ }
+ /* FIXME: cagney/2002-05-17: To say this bit is bad is being polite.
+ It keeps the existing code working where things rely on going
+ through to the register cache. */
+ if (dst == current_regcache && dst->descr->legacy_p)
+ {
+ /* ULGH!!!! Old way. Use REGISTER bytes and let code below
+ untangle fetch. */
+ write_register_bytes (0, src->raw_registers, REGISTER_BYTES);
+ return;
+ }
+ buf = alloca (src->descr->max_register_size);
+ for (i = 0; i < src->descr->nr_raw_registers; i++)
+ {
+ /* Should we worry about the valid bit here? */
+ regcache_read (src, i, buf);
+ regcache_write (dst, i, buf);
+ }
+}
+
+void
+regcache_cpy_no_passthrough (struct regcache *dst, struct regcache *src)
+{
+ int i;
+ gdb_assert (src != NULL && dst != NULL);
+ gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
+ /* NOTE: cagney/2002-05-17: Don't let the caller do a no-passthrough
+ move of data into the current_regcache(). Doing this would be
+ silly - it would mean that valid_p would be completly invalid. */
+ gdb_assert (dst != current_regcache);
+ memcpy (dst->raw_registers, src->raw_registers,
+ dst->descr->sizeof_raw_registers);
+ memcpy (dst->raw_register_valid_p, src->raw_register_valid_p,
+ dst->descr->sizeof_raw_register_valid_p);
+}
+
+struct regcache *
+regcache_dup (struct regcache *src)
+{
+ struct regcache *newbuf;
+ gdb_assert (current_regcache != NULL);
+ newbuf = regcache_xmalloc (src->descr->gdbarch);
+ regcache_cpy (newbuf, src);
+ return newbuf;
+}
+
+struct regcache *
+regcache_dup_no_passthrough (struct regcache *src)
+{
+ struct regcache *newbuf;
+ gdb_assert (current_regcache != NULL);
+ newbuf = regcache_xmalloc (src->descr->gdbarch);
+ regcache_cpy_no_passthrough (newbuf, src);
+ return newbuf;
+}
+
+int
+regcache_valid_p (struct regcache *regcache, int regnum)
+{
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ return regcache->raw_register_valid_p[regnum];
+}
+
+CORE_ADDR
+regcache_read_as_address (struct regcache *regcache, int regnum)
+{
+ char *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ regcache_read (regcache, regnum, buf);
+ return extract_address (buf, regcache->descr->sizeof_register[regnum]);
+}
+
+char *
+deprecated_grub_regcache_for_registers (struct regcache *regcache)
+{
+ return regcache->raw_registers;
+}
+
+char *
+deprecated_grub_regcache_for_register_valid (struct regcache *regcache)
+{
+ return regcache->raw_register_valid_p;
+}
+
+/* Global structure containing the current regcache. */
+/* FIXME: cagney/2002-05-11: The two global arrays registers[] and
+ register_valid[] currently point into this structure. */
+struct regcache *current_regcache;
+
/* NOTE: this is a write-through cache. There is no "dirty" bit for
recording if the register values have been changed (eg. by the
user). Therefore all registers must be written back to the
else return a pointer to the start of the cache buffer. */
static char *
-register_buffer (int regnum)
+register_buffer (struct regcache *regcache, int regnum)
{
- gdb_assert (regnum >= 0 && regnum < (NUM_REGS + NUM_PSEUDO_REGS));
- return ®isters[REGISTER_BYTE (regnum)];
+ return regcache->raw_registers + regcache->descr->register_offset[regnum];
}
/* Return whether register REGNUM is a real register. */
if (!register_cached (regnum))
fetch_register (regnum);
- memcpy (myaddr, register_buffer (regnum),
+ memcpy (myaddr, register_buffer (current_regcache, regnum),
REGISTER_RAW_SIZE (regnum));
}
void
-regcache_read (int rawnum, char *buf)
+regcache_read (struct regcache *regcache, int regnum, char *buf)
{
- gdb_assert (rawnum >= 0 && rawnum < (NUM_REGS + NUM_PSEUDO_REGS));
- /* For moment, just use underlying legacy code. Ulgh!!! */
- legacy_read_register_gen (rawnum, buf);
+ gdb_assert (regcache != NULL && buf != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ if (regcache->descr->legacy_p
+ && regcache->passthrough_p)
+ {
+ gdb_assert (regcache == current_regcache);
+ /* For moment, just use underlying legacy code. Ulgh!!! This
+ silently and very indirectly updates the regcache's regcache
+ via the global register_valid[]. */
+ legacy_read_register_gen (regnum, buf);
+ return;
+ }
+ /* Make certain that the register cache is up-to-date with respect
+ to the current thread. This switching shouldn't be necessary
+ only there is still only one target side register cache. Sigh!
+ On the bright side, at least there is a regcache object. */
+ if (regcache->passthrough_p)
+ {
+ gdb_assert (regcache == current_regcache);
+ if (! ptid_equal (registers_ptid, inferior_ptid))
+ {
+ registers_changed ();
+ registers_ptid = inferior_ptid;
+ }
+ if (!register_cached (regnum))
+ fetch_register (regnum);
+ }
+ /* Copy the value directly into the register cache. */
+ memcpy (buf, (regcache->raw_registers
+ + regcache->descr->register_offset[regnum]),
+ regcache->descr->sizeof_register[regnum]);
}
void
read_register_gen (int regnum, char *buf)
{
- if (! gdbarch_register_read_p (current_gdbarch))
+ gdb_assert (current_regcache != NULL);
+ gdb_assert (current_regcache->descr->gdbarch == current_gdbarch);
+ if (current_regcache->descr->legacy_p)
{
legacy_read_register_gen (regnum, buf);
return;
/* If we have a valid copy of the register, and new value == old
value, then don't bother doing the actual store. */
if (register_cached (regnum)
- && memcmp (register_buffer (regnum), myaddr, size) == 0)
+ && (memcmp (register_buffer (current_regcache, regnum), myaddr, size)
+ == 0))
return;
else
target_prepare_to_store ();
}
- memcpy (register_buffer (regnum), myaddr, size);
+ memcpy (register_buffer (current_regcache, regnum), myaddr, size);
set_register_cached (regnum, 1);
store_register (regnum);
}
void
-regcache_write (int rawnum, char *buf)
+regcache_write (struct regcache *regcache, int regnum, char *buf)
{
- gdb_assert (rawnum >= 0 && rawnum < (NUM_REGS + NUM_PSEUDO_REGS));
- /* For moment, just use underlying legacy code. Ulgh!!! */
- legacy_write_register_gen (rawnum, buf);
+ gdb_assert (regcache != NULL && buf != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+
+ if (regcache->passthrough_p
+ && regcache->descr->legacy_p)
+ {
+ /* For moment, just use underlying legacy code. Ulgh!!! This
+ silently and very indirectly updates the regcache's buffers
+ via the globals register_valid[] and registers[]. */
+ gdb_assert (regcache == current_regcache);
+ legacy_write_register_gen (regnum, buf);
+ return;
+ }
+
+ /* On the sparc, writing %g0 is a no-op, so we don't even want to
+ change the registers array if something writes to this register. */
+ if (CANNOT_STORE_REGISTER (regnum))
+ return;
+
+ /* Handle the simple case first -> not write through so just store
+ value in cache. */
+ if (!regcache->passthrough_p)
+ {
+ memcpy ((regcache->raw_registers
+ + regcache->descr->register_offset[regnum]), buf,
+ regcache->descr->sizeof_register[regnum]);
+ regcache->raw_register_valid_p[regnum] = 1;
+ return;
+ }
+
+ /* Make certain that the correct cache is selected. */
+ gdb_assert (regcache == current_regcache);
+ if (! ptid_equal (registers_ptid, inferior_ptid))
+ {
+ registers_changed ();
+ registers_ptid = inferior_ptid;
+ }
+
+ /* If we have a valid copy of the register, and new value == old
+ value, then don't bother doing the actual store. */
+ if (regcache_valid_p (regcache, regnum)
+ && (memcmp (register_buffer (regcache, regnum), buf,
+ regcache->descr->sizeof_register[regnum]) == 0))
+ return;
+
+ target_prepare_to_store ();
+ memcpy (register_buffer (regcache, regnum), buf,
+ regcache->descr->sizeof_register[regnum]);
+ regcache->raw_register_valid_p[regnum] = 1;
+ store_register (regnum);
}
void
write_register_gen (int regnum, char *buf)
{
- if (! gdbarch_register_write_p (current_gdbarch))
+ gdb_assert (current_regcache != NULL);
+ gdb_assert (current_regcache->descr->gdbarch == current_gdbarch);
+ if (current_regcache->descr->legacy_p)
{
legacy_write_register_gen (regnum, buf);
return;
set_register_cached (regnum, 1);
if (val)
- memcpy (register_buffer (regnum), val,
+ memcpy (register_buffer (current_regcache, regnum), val,
REGISTER_RAW_SIZE (regnum));
else
- memset (register_buffer (regnum), '\000',
+ memset (register_buffer (current_regcache, regnum), '\000',
REGISTER_RAW_SIZE (regnum));
/* On some architectures, e.g. HPPA, there are a few stray bits in
void
regcache_collect (int regnum, void *buf)
{
- memcpy (buf, register_buffer (regnum), REGISTER_RAW_SIZE (regnum));
+ memcpy (buf, register_buffer (current_regcache, regnum),
+ REGISTER_RAW_SIZE (regnum));
}
static void
build_regcache (void)
+{
+ current_regcache = regcache_xmalloc (current_gdbarch);
+ current_regcache->passthrough_p = 1;
+ registers = deprecated_grub_regcache_for_registers (current_regcache);
+ register_valid = deprecated_grub_regcache_for_register_valid (current_regcache);
+}
+
+void
+regcache_save (struct regcache *regcache)
{
int i;
- int sizeof_register_valid;
- /* Come up with the real size of the registers buffer. */
- int sizeof_registers = REGISTER_BYTES; /* OK use. */
- for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
- {
- long regend;
- /* Keep extending the buffer so that there is always enough
- space for all registers. The comparison is necessary since
- legacy code is free to put registers in random places in the
- buffer separated by holes. Once REGISTER_BYTE() is killed
- this can be greatly simplified. */
- /* FIXME: cagney/2001-12-04: This code shouldn't need to use
- REGISTER_BYTE(). Unfortunatly, legacy code likes to lay the
- buffer out so that certain registers just happen to overlap.
- Ulgh! New targets use gdbarch's register read/write and
- entirely avoid this uglyness. */
- regend = REGISTER_BYTE (i) + REGISTER_RAW_SIZE (i);
- if (sizeof_registers < regend)
- sizeof_registers = regend;
- }
- registers = xmalloc (sizeof_registers);
- sizeof_register_valid = ((NUM_REGS + NUM_PSEUDO_REGS)
- * sizeof (*register_valid));
- register_valid = xmalloc (sizeof_register_valid);
- memset (register_valid, 0, sizeof_register_valid);
+ gdb_assert (current_regcache != NULL && regcache != NULL);
+ gdb_assert (current_regcache->descr->gdbarch == regcache->descr->gdbarch);
+ regcache_cpy (regcache, current_regcache);
+}
+
+void
+regcache_save_no_passthrough (struct regcache *regcache)
+{
+ gdb_assert (current_regcache != NULL && regcache != NULL);
+ gdb_assert (current_regcache->descr->gdbarch == regcache->descr->gdbarch);
+ regcache_cpy_no_passthrough (regcache, current_regcache);
+}
+
+void
+regcache_restore (struct regcache *regcache)
+{
+ int i;
+ gdb_assert (current_regcache != NULL && regcache != NULL);
+ gdb_assert (current_regcache->descr->gdbarch == regcache->descr->gdbarch);
+ regcache_cpy (current_regcache, regcache);
+}
+
+void
+regcache_restore_no_passthrough (struct regcache *regcache)
+{
+ char *regcache_registers;
+ gdb_assert (current_regcache != NULL && regcache != NULL);
+ gdb_assert (current_regcache->descr->gdbarch == regcache->descr->gdbarch);
+ regcache_cpy_no_passthrough (current_regcache, regcache);
}
void
_initialize_regcache (void)
{
+ regcache_descr_handle = register_gdbarch_data (init_regcache_descr,
+ xfree_regcache_descr);
+ REGISTER_GDBARCH_SWAP (current_regcache);
register_gdbarch_swap (®isters, sizeof (registers), NULL);
register_gdbarch_swap (®ister_valid, sizeof (register_valid), NULL);
register_gdbarch_swap (NULL, 0, build_regcache);
/* Cache and manage the values of registers for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001
- Free Software Foundation, Inc.
+
+ Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
+ 2001, 2002 Free Software Foundation, Inc.
This file is part of GDB.
#ifndef REGCACHE_H
#define REGCACHE_H
+struct regcache;
+struct gdbarch;
+
+extern struct regcache *current_regcache;
+
+void regcache_xfree (struct regcache *regcache);
+struct regcache *regcache_xmalloc (struct gdbarch *gdbarch);
+
/* Transfer a raw register [0..NUM_REGS) between core-gdb and the
regcache. */
-void regcache_read (int rawnum, char *buf);
-void regcache_write (int rawnum, char *buf);
+void regcache_read (struct regcache *regcache, int rawnum, char *buf);
+void regcache_write (struct regcache *regcache, int rawnum, char *buf);
+int regcache_valid_p (struct regcache *regcache, int regnum);
+CORE_ADDR regcache_read_as_address (struct regcache *regcache, int rawnum);
/* Transfer a raw register [0..NUM_REGS) between the regcache and the
target. These functions are called by the target in response to a
extern signed char *register_valid;
+/* Save/restore the register cache using the regbuf. The operation is
+ write through - it is strictly for code that needs to restore the
+ target's registers to a previous state.
+
+ ``no passthrough'' versions do not go through to the target. They
+ only save values already in the cache. */
+
+extern void regcache_save (struct regcache *regcache);
+extern void regcache_restore (struct regcache *regcache);
+extern struct regcache *regcache_dup (struct regcache *regcache);
+extern void regcache_save_no_passthrough (struct regcache *regcache);
+extern void regcache_restore_no_passthrough (struct regcache *regcache);
+extern struct regcache *regcache_dup_no_passthrough (struct regcache *regcache);
+extern void regcache_cpy (struct regcache *dest, struct regcache *src);
+extern void regcache_cpy_no_passthrough (struct regcache *dest, struct regcache *src);
+
+extern char *deprecated_grub_regcache_for_registers (struct regcache *);
+extern char *deprecated_grub_regcache_for_register_valid (struct regcache *);
+
extern int register_cached (int regnum);
extern void set_register_cached (int regnum, int state);
static void *
x86_64_fxsave_offset (elf_fpregset_t * fxsave, int regnum)
{
- char *reg_name;
+ const char *reg_name;
int reg_index;
gdb_assert (x86_64_num_gregs - 1 < regnum && regnum < x86_64_num_regs);
- reg_name = x86_64_register_nr2name (regnum);
+ reg_name = x86_64_register_name (regnum);
if (reg_name[0] == 's' && reg_name[1] == 't')
{
{
int i, reg_st0, reg_mxcsr;
- reg_st0 = x86_64_register_name2nr ("st0");
- reg_mxcsr = x86_64_register_name2nr ("mxcsr");
+ reg_st0 = x86_64_register_number ("st0");
+ reg_mxcsr = x86_64_register_number ("mxcsr");
gdb_assert (reg_st0 > 0 && reg_mxcsr > reg_st0);
}
\f
-char *
-x86_64_register_nr2name (int reg_nr)
+const char *
+x86_64_register_name (int reg_nr)
{
if (reg_nr < 0 || reg_nr >= X86_64_NUM_REGS)
return NULL;
}
int
-x86_64_register_name2nr (const char *name)
+x86_64_register_number (const char *name)
{
int reg_nr;
set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext);
set_gdbarch_num_regs (gdbarch, X86_64_NUM_REGS);
- set_gdbarch_register_name (gdbarch, x86_64_register_nr2name);
+ set_gdbarch_register_name (gdbarch, x86_64_register_name);
set_gdbarch_register_size (gdbarch, 8);
set_gdbarch_register_raw_size (gdbarch, x86_64_register_raw_size);
set_gdbarch_max_register_raw_size (gdbarch, 16);
extern int x86_64_num_regs;
extern int x86_64_num_gregs;
-int x86_64_register_name2nr (const char *name);
-char *x86_64_register_nr2name (int reg_nr);
+int x86_64_register_number (const char *name);
+const char *x86_64_register_name (int reg_nr);
+
gdbarch_frame_saved_pc_ftype x86_64_linux_frame_saved_pc;
gdbarch_saved_pc_after_call_ftype x86_64_linux_saved_pc_after_call;