[PATCH RFC] DWARF2 CFI exploitation for Linux on S/390

Gerhard Tonn
2002-09-24T12:23:30Z

[-- Attachment #1: Type: text/plain, Size: 1740 bytes --]

Hi,
I am working on the DWARF2 CFI exploitation for s390. On s390 there are
some changes to the already existing code necessary.

1) The sequence and number of DWARF2 registers are different from the gdb
registers on s390 for some reason.
2) The DWARF2 CFA value is different from the frame_base value.

In order to adapt the code to the first item, I have introduced #defines
for DWARF2 registers and a REGNUM_TO_DWARF2_REG macro and its
implementation. See the attached patch for details.

In order to consider the second item I have adapted the LOC_REF_ARG symbol
class handling in dwarf2read.c and findvar.c to use the BASEREG value if
DWARF2 is active.

I don't know what to do with LOC_LOCAL yet. At line 6432 in the current
implementation of dwarf2read.c islocal is set to 1, if there's no
identified frame pointer for the function. I am not sure if this is
correct. If it is, I don't know how to handle it when CFA is different from
frame_base. The problem is that I have to consider the LOC_LOCAL symbol
class in findvar.c in this case without knowing the frame pointer.

The following code fragment in dwarf2cfi.c around line 1316 seems to be
intel specific, at least on s390 it doesn't make sense. Should I move it to
a gdbarch function?

if (i == SP_REGNUM)
{
context->reg[i].how = REG_CTX_VALUE;
context->reg[i].loc.addr = cfa;
}

Finally I am interested in how signal frame and dummy frame handling is
supposed to work with DWARF2 CFI support. Does anybody have done already
work in this area?

(See attached file: common-dwarf2.patch)

Regards / Mit freundlichen Gruessen
Gerhard

Gerhard Tonn, Linux for eServer Development, +(49)-7031-16-4716, Lotus
Notes: ton@ibmde,
Internet: ton@de.ibm.com

[-- Attachment #2: common-dwarf2.patch --]
[-- Type: application/octet-stream, Size: 10164 bytes --]

--- gdb-5.2.cvs20020818/gdb/dwarf2cfi.c 2002-07-23 17:26:54.000000000 +0200
+++ gdb-5.2.cvs20020818.bak2/gdb/dwarf2cfi.c 2002-09-18 16:20:43.000000000 +0200
@@ -32,6 +32,16 @@
#include "dwarf2cfi.h"
#include "gdb_assert.h"

+#ifndef DWARF2_NUM_REGS
+#define DWARF2_NUM_REGS NUM_REGS
+#endif
+#ifndef DWARF2_SP_REGNUM
+#define DWARF2_SP_REGNUM SP_REGNUM
+#endif
+#ifndef DWARF2_PC_REGNUM
+#define DWARF2_PC_REGNUM PC_REGNUM
+#endif
+
/* Common Information Entry - holds information that is shared among many
Frame Descriptors. */
struct cie_unit
@@ -291,7 +301,7 @@
{
struct context *context;

- int regs_size = sizeof (struct context_reg) * NUM_REGS;
+ int regs_size = sizeof (struct context_reg) * DWARF2_NUM_REGS;

context = (struct context *) obstack_alloc (&unwind_tmp_obstack,
sizeof (struct context));
@@ -308,7 +318,7 @@
{
struct frame_state *fs;

- int regs_size = sizeof (struct frame_state_reg) * NUM_REGS;
+ int regs_size = sizeof (struct frame_state_reg) * DWARF2_NUM_REGS;

fs = (struct frame_state *) obstack_alloc (&unwind_tmp_obstack,
sizeof (struct frame_state));
@@ -335,7 +345,7 @@
static void
context_cpy (struct context *dst, struct context *src)
{
- int regs_size = sizeof (struct context_reg) * NUM_REGS;
+ int regs_size = sizeof (struct context_reg) * DWARF2_NUM_REGS;
struct context_reg *dreg;

/* Structure dst contains a pointer to an array of
@@ -867,14 +877,15 @@
switch (context->reg[regnum].how)
{
case REG_CTX_UNSAVED:
- read_register_gen (regnum, reg);
+ read_register_gen (DWARF2_REG_TO_REGNUM(regnum), reg);
break;
case REG_CTX_SAVED_OFFSET:
target_read_memory (context->cfa + context->reg[regnum].loc.offset,
reg, REGISTER_RAW_SIZE (regnum));
break;
case REG_CTX_SAVED_REG:
- read_register_gen (context->reg[regnum].loc.reg, reg);
+ read_register_gen (DWARF2_REG_TO_REGNUM(context->reg[regnum].loc.reg),
+ reg);
break;
case REG_CTX_SAVED_ADDR:
target_read_memory (context->reg[regnum].loc.addr,
@@ -1311,16 +1322,18 @@
orig_context->cfa = cfa;

/* Compute the addresses of all registers saved in this frame. */
- for (i = 0; i < NUM_REGS; ++i)
+ for (i = 0; i < DWARF2_NUM_REGS; ++i)
switch (fs->regs.reg[i].how)
{
case REG_UNSAVED:
- if (i == SP_REGNUM)
+#if 0
+ if (i == DWARF2_SP_REGNUM)
{
context->reg[i].how = REG_CTX_VALUE;
context->reg[i].loc.addr = cfa;
}
else
+#endif
context->reg[i].how = REG_CTX_UNSAVED;
break;
case REG_SAVED_OFFSET:
@@ -1369,6 +1382,7 @@
internal_error (__FILE__, __LINE__, "bad switch");
}
get_reg ((char *) &context->ra, context, fs->retaddr_column);
+ context->ra=ADDR_BITS_REMOVE(context->ra);
unwind_tmp_obstack_free ();
}

@@ -1731,7 +1745,7 @@
if (fs->cfa_how == CFA_REG_OFFSET)
{
val -= fs->cfa_offset;
- write_register_gen (fs->cfa_reg, (char *) &val);
+ write_register_gen (DWARF2_REG_TO_REGNUM(fs->cfa_reg), (char *) &val);
}
else
warning ("Can't write fp.");
@@ -1747,11 +1761,12 @@
char *regbuf = alloca (MAX_REGISTER_RAW_SIZE);
int regnum;

- for (regnum = 0; regnum < NUM_REGS; regnum++)
+ for (regnum = 0; regnum < DWARF2_NUM_REGS; regnum++)
{
get_reg (regbuf, UNWIND_CONTEXT (fi), regnum);
- write_register_bytes (REGISTER_BYTE (regnum), regbuf,
- REGISTER_RAW_SIZE (regnum));
+ write_register_bytes (REGISTER_BYTE (DWARF2_REG_TO_REGNUM(regnum)),
+ regbuf,
+ REGISTER_RAW_SIZE (DWARF2_REG_TO_REGNUM(regnum)));
}
write_register (PC_REGNUM, UNWIND_CONTEXT (fi)->ra);

@@ -1793,7 +1808,7 @@
cfi_init_frame_pc (int fromleaf, struct frame_info *fi)
{
if (fi->next)
- get_reg ((char *) &(fi->pc), UNWIND_CONTEXT (fi->next), PC_REGNUM);
+ fi->pc = cfi_get_ra (fi->next);
else
fi->pc = read_pc ();
}
@@ -1809,9 +1824,9 @@
fs = frame_state_alloc ();
fi->context = frame_obstack_alloc (sizeof (struct context));
UNWIND_CONTEXT (fi)->reg =
- frame_obstack_alloc (sizeof (struct context_reg) * NUM_REGS);
+ frame_obstack_alloc (sizeof (struct context_reg) * DWARF2_NUM_REGS);
memset (UNWIND_CONTEXT (fi)->reg, 0,
- sizeof (struct context_reg) * NUM_REGS);
+ sizeof (struct context_reg) * DWARF2_NUM_REGS);

if (fi->next)
{
@@ -1871,7 +1886,7 @@
else
{
frame = frame->next;
- switch (UNWIND_CONTEXT (frame)->reg[regnum].how)
+ switch (UNWIND_CONTEXT (frame)->reg[REGNUM_TO_DWARF2_REG(regnum)].how)
{
case REG_CTX_UNSAVED:
read_register_gen (regnum, raw_buffer);
@@ -1882,35 +1897,37 @@
break;
case REG_CTX_SAVED_OFFSET:
target_read_memory (UNWIND_CONTEXT (frame)->cfa +
- UNWIND_CONTEXT (frame)->reg[regnum].loc.offset,
- raw_buffer, REGISTER_RAW_SIZE (regnum));
+ UNWIND_CONTEXT (frame)->reg[REGNUM_TO_DWARF2_REG(regnum)].loc.offset,
+ raw_buffer,
+ REGISTER_RAW_SIZE (REGNUM_TO_DWARF2_REG(regnum)));
if (lval != NULL)
*lval = lval_memory;
if (addrp != NULL)
*addrp =
UNWIND_CONTEXT (frame)->cfa +
- UNWIND_CONTEXT (frame)->reg[regnum].loc.offset;
+ UNWIND_CONTEXT (frame)->reg[REGNUM_TO_DWARF2_REG(regnum)].loc.offset;
break;
case REG_CTX_SAVED_REG:
- read_register_gen (UNWIND_CONTEXT (frame)->reg[regnum].loc.reg,
- raw_buffer);
+ read_register_gen (DWARF2_REG_TO_REGNUM(UNWIND_CONTEXT (frame)->reg[REGNUM_TO_DWARF2_REG(regnum)].loc.reg),
+ raw_buffer);
if (lval != NULL)
*lval = lval_register;
if (addrp != NULL)
*addrp =
- REGISTER_BYTE (UNWIND_CONTEXT (frame)->reg[regnum].loc.reg);
+ REGISTER_BYTE (UNWIND_CONTEXT (frame)->reg[REGNUM_TO_DWARF2_REG(regnum)].loc.reg);
break;
case REG_CTX_SAVED_ADDR:
- target_read_memory (UNWIND_CONTEXT (frame)->reg[regnum].loc.addr,
- raw_buffer, REGISTER_RAW_SIZE (regnum));
+ target_read_memory (UNWIND_CONTEXT (frame)->reg[REGNUM_TO_DWARF2_REG(regnum)].loc.addr,
+ raw_buffer,
+ REGISTER_RAW_SIZE (REGNUM_TO_DWARF2_REG(regnum)));
if (lval != NULL)
*lval = lval_memory;
if (addrp != NULL)
- *addrp = UNWIND_CONTEXT (frame)->reg[regnum].loc.addr;
+ *addrp = UNWIND_CONTEXT (frame)->reg[REGNUM_TO_DWARF2_REG(regnum)].loc.addr;
break;
case REG_CTX_VALUE:
- memcpy (raw_buffer, &UNWIND_CONTEXT (frame)->reg[regnum].loc.addr,
- REGISTER_RAW_SIZE (regnum));
+ memcpy (raw_buffer, &UNWIND_CONTEXT (frame)->reg[REGNUM_TO_DWARF2_REG(regnum)].loc.addr,
+ REGISTER_RAW_SIZE (REGNUM_TO_DWARF2_REG(regnum)));
if (lval != NULL)
*lval = not_lval;
if (optimized != NULL)
--- gdb-5.2.cvs20020818/gdb/gdbarch.sh 2002-08-17 07:29:06.000000000 +0200
+++ gdb-5.2.cvs20020818.bak2/gdb/gdbarch.sh 2002-09-18 14:36:52.000000000 +0200
@@ -458,6 +458,7 @@
# to map one to one onto the sdb register numbers.
f:2:SDB_REG_TO_REGNUM:int:sdb_reg_to_regnum:int sdb_regnr:sdb_regnr:::no_op_reg_to_regnum::0
f:2:DWARF2_REG_TO_REGNUM:int:dwarf2_reg_to_regnum:int dwarf2_regnr:dwarf2_regnr:::no_op_reg_to_regnum::0
+f:2:REGNUM_TO_DWARF2_REG:int:regnum_to_dwarf2_reg:int regnum:regnum:::no_op_regnum_to_reg::0
f:2:REGISTER_NAME:const char *:register_name:int regnr:regnr:::legacy_register_name::0
v:2:REGISTER_SIZE:int:register_size::::0:-1
v:2:REGISTER_BYTES:int:register_bytes::::0:-1
--- gdb-5.2.cvs20020818/gdb/arch-utils.c 2002-08-17 07:29:06.000000000 +0200
+++ gdb-5.2.cvs20020818.bak2/gdb/arch-utils.c 2002-09-18 14:36:52.000000000 +0200
@@ -293,6 +293,12 @@
return reg;
}

+int
+no_op_regnum_to_reg (int regnum)
+{
+ return regnum;
+}
+
/* For use by frame_args_address and frame_locals_address. */
CORE_ADDR
default_frame_address (struct frame_info *fi)
--- gdb-5.2.cvs20020818/gdb/dwarf2read.c 2002-08-01 17:15:31.000000000 +0200
+++ gdb-5.2.cvs20020818.bak2/gdb/dwarf2read.c 2002-09-18 14:36:52.000000000 +0200
@@ -4821,6 +4821,7 @@
if (basereg != frame_base_reg)
complain (&dwarf2_complex_location_expr);
SYMBOL_CLASS (sym) = LOC_REF_ARG;
+ SYMBOL_BASEREG (sym) = DWARF2_REG_TO_REGNUM (basereg);
}
else
{
--- gdb-5.2.cvs20020818/gdb/arch-utils.h 2002-08-17 07:29:06.000000000 +0200
+++ gdb-5.2.cvs20020818.bak/arch-utils.h 2002-09-09 15:15:51.000000000 +0200
@@ -106,6 +106,10 @@

extern int no_op_reg_to_regnum (int reg);

+/* No-op conversion of regnum to reg. */
+
+extern int no_op_regnum_to_reg (int regnum);
+
/* Default frame_args_address and frame_locals_address. */

extern CORE_ADDR default_frame_address (struct frame_info *);
--- gdb-5.2.cvs20020818/gdb/findvar.c 2002-07-25 05:11:03.000000000 +0200
+++ gdb-5.2.cvs20020818.bak/gdb/findvar.c 2002-09-24 12:20:14.000000000 +0200
@@ -35,6 +35,8 @@
#include "regcache.h"
#include "builtin-regs.h"

+extern unsigned int dwarf_frame_size;
+
/* Basic byte-swapping routines. GDB has needed these for a long time...
All extract a target-format integer at ADDR which is LEN bytes long. */

@@ -506,13 +508,27 @@

case LOC_REF_ARG:
{
+ struct value *regval;
struct value *ref;
CORE_ADDR argref;
- if (frame == NULL)
- return 0;
- argref = FRAME_ARGS_ADDRESS (frame);
- if (!argref)
- return 0;
+
+ /* Is dwarf2 debug format active? */
+ if(dwarf_frame_size)
+ {
+ regval = value_from_register (lookup_pointer_type (type),
+ SYMBOL_BASEREG (var), frame);
+ if (regval == NULL)
+ error ("Value of base register not available.");
+ argref = value_as_address (regval);
+ }
+ else
+ {
+ if (frame == NULL)
+ return 0;
+ argref = FRAME_ARGS_ADDRESS (frame);
+ if (!argref)
+ return 0;
+ }
argref += SYMBOL_VALUE (var);
ref = value_at (lookup_pointer_type (type), argref, NULL);
addr = value_as_address (ref);