+\f
+
+/* Architecture-specific operations. */
+
+/* Per-architecture data key. */
+static struct gdbarch_data *dwarf2_frame_data;
+
+struct dwarf2_frame_ops
+{
+ /* Pre-initialize the register state REG for register REGNUM. */
+ void (*init_reg) (struct gdbarch *, int, struct dwarf2_frame_state_reg *,
+ struct frame_info *);
+
+ /* Check whether the THIS_FRAME is a signal trampoline. */
+ int (*signal_frame_p) (struct gdbarch *, struct frame_info *);
+
+ /* Convert .eh_frame register number to DWARF register number, or
+ adjust .debug_frame register number. */
+ int (*adjust_regnum) (struct gdbarch *, int, int);
+};
+
+/* Default architecture-specific register state initialization
+ function. */
+
+static void
+dwarf2_frame_default_init_reg (struct gdbarch *gdbarch, int regnum,
+ struct dwarf2_frame_state_reg *reg,
+ struct frame_info *this_frame)
+{
+ /* If we have a register that acts as a program counter, mark it as
+ a destination for the return address. If we have a register that
+ serves as the stack pointer, arrange for it to be filled with the
+ call frame address (CFA). The other registers are marked as
+ unspecified.
+
+ We copy the return address to the program counter, since many
+ parts in GDB assume that it is possible to get the return address
+ by unwinding the program counter register. However, on ISA's
+ with a dedicated return address register, the CFI usually only
+ contains information to unwind that return address register.
+
+ The reason we're treating the stack pointer special here is
+ because in many cases GCC doesn't emit CFI for the stack pointer
+ and implicitly assumes that it is equal to the CFA. This makes
+ some sense since the DWARF specification (version 3, draft 8,
+ p. 102) says that:
+
+ "Typically, the CFA is defined to be the value of the stack
+ pointer at the call site in the previous frame (which may be
+ different from its value on entry to the current frame)."
+
+ However, this isn't true for all platforms supported by GCC
+ (e.g. IBM S/390 and zSeries). Those architectures should provide
+ their own architecture-specific initialization function. */
+
+ if (regnum == gdbarch_pc_regnum (gdbarch))
+ reg->how = DWARF2_FRAME_REG_RA;
+ else if (regnum == gdbarch_sp_regnum (gdbarch))
+ reg->how = DWARF2_FRAME_REG_CFA;
+}
+
+/* Return a default for the architecture-specific operations. */
+
+static void *
+dwarf2_frame_init (struct obstack *obstack)
+{
+ struct dwarf2_frame_ops *ops;
+
+ ops = OBSTACK_ZALLOC (obstack, struct dwarf2_frame_ops);
+ ops->init_reg = dwarf2_frame_default_init_reg;
+ return ops;
+}
+
+/* Set the architecture-specific register state initialization
+ function for GDBARCH to INIT_REG. */
+
+void
+dwarf2_frame_set_init_reg (struct gdbarch *gdbarch,
+ void (*init_reg) (struct gdbarch *, int,
+ struct dwarf2_frame_state_reg *,
+ struct frame_info *))
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ ops->init_reg = init_reg;
+}
+
+/* Pre-initialize the register state REG for register REGNUM. */
+
+static void
+dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+ struct dwarf2_frame_state_reg *reg,
+ struct frame_info *this_frame)
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ ops->init_reg (gdbarch, regnum, reg, this_frame);
+}
+
+/* Set the architecture-specific signal trampoline recognition
+ function for GDBARCH to SIGNAL_FRAME_P. */
+
+void
+dwarf2_frame_set_signal_frame_p (struct gdbarch *gdbarch,
+ int (*signal_frame_p) (struct gdbarch *,
+ struct frame_info *))
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ ops->signal_frame_p = signal_frame_p;
+}
+
+/* Query the architecture-specific signal frame recognizer for
+ THIS_FRAME. */
+
+static int
+dwarf2_frame_signal_frame_p (struct gdbarch *gdbarch,
+ struct frame_info *this_frame)
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ if (ops->signal_frame_p == NULL)
+ return 0;
+ return ops->signal_frame_p (gdbarch, this_frame);
+}
+
+/* Set the architecture-specific adjustment of .eh_frame and .debug_frame
+ register numbers. */
+
+void
+dwarf2_frame_set_adjust_regnum (struct gdbarch *gdbarch,
+ int (*adjust_regnum) (struct gdbarch *,
+ int, int))
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ ops->adjust_regnum = adjust_regnum;
+}
+
+/* Translate a .eh_frame register to DWARF register, or adjust a .debug_frame
+ register. */
+
+static int
+dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum, int eh_frame_p)
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ if (ops->adjust_regnum == NULL)
+ return regnum;
+ return ops->adjust_regnum (gdbarch, regnum, eh_frame_p);
+}
+
+static void
+dwarf2_frame_find_quirks (struct dwarf2_frame_state *fs,
+ struct dwarf2_fde *fde)
+{
+ static const char *arm_idents[] = {
+ "ARM C Compiler, ADS",
+ "Thumb C Compiler, ADS",
+ "ARM C++ Compiler, ADS",
+ "Thumb C++ Compiler, ADS",
+ "ARM/Thumb C/C++ Compiler, RVCT"
+ };
+ int i;
+
+ struct symtab *s;
+
+ s = find_pc_symtab (fs->pc);
+ if (s == NULL || s->producer == NULL)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE (arm_idents); i++)
+ if (strncmp (s->producer, arm_idents[i], strlen (arm_idents[i])) == 0)
+ {
+ if (fde->cie->version == 1)
+ fs->armcc_cfa_offsets_sf = 1;
+
+ if (fde->cie->version == 1)
+ fs->armcc_cfa_offsets_reversed = 1;
+
+ /* The reversed offset problem is present in some compilers
+ using DWARF3, but it was eventually fixed. Check the ARM
+ defined augmentations, which are in the format "armcc" followed
+ by a list of one-character options. The "+" option means
+ this problem is fixed (no quirk needed). If the armcc
+ augmentation is missing, the quirk is needed. */
+ if (fde->cie->version == 3
+ && (strncmp (fde->cie->augmentation, "armcc", 5) != 0
+ || strchr (fde->cie->augmentation + 5, '+') == NULL))
+ fs->armcc_cfa_offsets_reversed = 1;
+
+ return;
+ }
+}
+\f