]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarf_frame_return_address_register -> dwarf_frame_info: return address range too
authorRoland McGrath <roland@redhat.com>
Sun, 29 Mar 2009 00:15:23 +0000 (17:15 -0700)
committerRoland McGrath <roland@redhat.com>
Sun, 29 Mar 2009 00:15:23 +0000 (17:15 -0700)
libdw/Makefile.am
libdw/dwarf_frame_info.c [moved from libdw/dwarf_frame_return_address_register.c with 90% similarity]
libdw/libdw.map
libdw/unwind.c
libdw/unwind.h
libdw/unwindP.h
tests/addrcfi.c

index 61852284dcb8c8eeeaad1f185369c2bc3e9ac7c4..852e57c39f16f3e1173afee44a52475eab384e9d 100644 (file)
@@ -86,8 +86,7 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
                  dwarf_entry_breakpoints.c \
                  dwarf_next_cfi.c \
                  cie.c fde.c unwind.c frame-cache.c \
-                 dwarf_frame_cfa.c dwarf_frame_register.c \
-                 dwarf_frame_return_address_register.c \
+                 dwarf_frame_info.c dwarf_frame_cfa.c dwarf_frame_register.c \
                  dwarf_cfi_addrframe.c \
                  dwarf_getcfi.c dwarf_getcfi_elf.c \
                  dwarf_cfi_setebl.c dwarf_cfi_end.c
similarity index 90%
rename from libdw/dwarf_frame_return_address_register.c
rename to libdw/dwarf_frame_info.c
index ef2d7e1127d875e2d7dc643b7d0877729618f4a9..8813c0ad2ba6bf454685a2767a97d89f4cfd49c7 100644 (file)
 #include "unwindP.h"
 
 int
-dwarf_frame_return_address_register (fs, signalp)
+dwarf_frame_info (fs, start, end, signalp)
      Dwarf_Frame *fs;
+     Dwarf_Addr *start;
+     Dwarf_Addr *end;
      bool *signalp;
 {
-  *signalp = fs->fde->cie->signal_frame;
+  /* Maybe there was a previous error.  */
+  if (fs == NULL)
+    return -1;
+
+  if (start != NULL)
+    *start = fs->start;
+  if (end != NULL)
+    *end = fs->end;
+  if (signalp != NULL)
+    *signalp = fs->fde->cie->signal_frame;
   return fs->fde->cie->return_address_register;
 }
index 1195109a7c1d39ae502b2df9043ebb2fa3292dbb..93ca3c97faa47203d5fd78ba3d6268d97fd336bb 100644 (file)
@@ -195,7 +195,7 @@ ELFUTILS_0.138 {
     *;
 } ELFUTILS_0.136;
 
-ELFUTILS_0.138_UNWIND {
+ELFUTILS_0.140_UNWIND {
   global:
     # XXX new unwind stuff not decided yet
     dwarf_next_cfi;
@@ -206,7 +206,7 @@ ELFUTILS_0.138_UNWIND {
     dwarf_cfi_setebl;
     dwarf_frame_cfa;
     dwarf_frame_register;
-    dwarf_frame_return_address_register;
+    dwarf_frame_info;
     dwfl_addrframe;
     dwfl_module_getcfi;
 } ELFUTILS_0.138;
index 82380cb1d7673ee164d4a3a56795d67f6ffee855..487292468c31faf18c8c81937f918a5da5444ebf 100644 (file)
@@ -133,6 +133,8 @@ execute_cfi (Dwarf_CFI *cache,
       Dwarf_Word operand = opcode & CFI_PRIMARY_MAX;
       switch (opcode)
        {
+         /* These cases move LOC, i.e. "create a new table row".  */
+
        case DW_CFA_advance_loc1:
          operand = *program++;
        case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX:
@@ -154,6 +156,10 @@ execute_cfi (Dwarf_CFI *cache,
          loc = read_encoded_value (cache, cie->fde_encoding, &program);
          break;
 
+         /* Now all following cases affect this row, but do not touch LOC.
+            These cases end with 'continue'.  We only get out of the
+            switch block for the row-copying (LOC-moving) cases above.  */
+
        case DW_CFA_def_cfa:
          get_uleb128 (operand, program);
          get_uleb128 (offset, program);
@@ -164,13 +170,13 @@ execute_cfi (Dwarf_CFI *cache,
          /* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it.  */
          fs->cfa_data.offset.atom = DW_OP_bregx;
          fs->cfa_data.offset.offset = 0;
-         break;
+         continue;
 
        case DW_CFA_def_cfa_register:
          get_uleb128 (regno, program);
          cfi_assert (fs->cfa_rule == cfa_offset);
          fs->cfa_val_reg = regno;
-         break;
+         continue;
 
        case DW_CFA_def_cfa_sf:
          get_uleb128 (operand, program);
@@ -183,7 +189,7 @@ execute_cfi (Dwarf_CFI *cache,
        def_cfa_offset:
          cfi_assert (fs->cfa_rule == cfa_offset);
          fs->cfa_val_offset = offset;
-         break;
+         continue;
 
        case DW_CFA_def_cfa_offset_sf:
          get_sleb128 (sf_offset, program);
@@ -198,17 +204,17 @@ execute_cfi (Dwarf_CFI *cache,
          fs->cfa_data.expr.data = (unsigned char *) program;
          fs->cfa_data.expr.length = operand;
          program += operand;
-         break;
+         continue;
 
        case DW_CFA_undefined:
          get_uleb128 (regno, program);
          register_rule (regno, undefined, 0);
-         break;
+         continue;
 
        case DW_CFA_same_value:
          get_uleb128 (regno, program);
          register_rule (regno, same_value, 0);
-         break;
+         continue;
 
        case DW_CFA_offset_extended:
          get_uleb128 (operand, program);
@@ -217,7 +223,7 @@ execute_cfi (Dwarf_CFI *cache,
          offset *= cie->data_alignment_factor;
        offset_extended:
          register_rule (operand, offset, offset);
-         break;
+         continue;
 
        case DW_CFA_offset_extended_sf:
          get_uleb128 (operand, program);
@@ -231,7 +237,7 @@ execute_cfi (Dwarf_CFI *cache,
          offset *= cie->data_alignment_factor;
        val_offset:
          register_rule (operand, val_offset, offset);
-         break;
+         continue;
 
        case DW_CFA_val_offset_sf:
          get_uleb128 (operand, program);
@@ -243,7 +249,7 @@ execute_cfi (Dwarf_CFI *cache,
          get_uleb128 (regno, program);
          get_uleb128 (operand, program);
          register_rule (regno, register, operand);
-         break;
+         continue;
 
        case DW_CFA_expression:
          get_uleb128 (regno, program);
@@ -253,7 +259,7 @@ execute_cfi (Dwarf_CFI *cache,
          cfi_assert (operand <= (Dwarf_Word) (end - program));
          register_rule (regno, expression, offset);
          program += operand;
-         break;
+         continue;
 
        case DW_CFA_val_expression:
          get_uleb128 (regno, program);
@@ -263,7 +269,7 @@ execute_cfi (Dwarf_CFI *cache,
          cfi_assert (operand <= (Dwarf_Word) (end - program));
          register_rule (regno, val_expression, offset);
          program += operand;
-         break;
+         continue;
 
        case DW_CFA_restore_extended:
          get_uleb128 (operand, program);
@@ -273,7 +279,7 @@ execute_cfi (Dwarf_CFI *cache,
            {
              /* Special case hack to give backend abi_cfi a shorthand.  */
              cache->default_same_value = true;
-             break;
+             continue;
            }
 
          /* This can't be used in the CIE's own initial instructions.  */
@@ -286,7 +292,7 @@ execute_cfi (Dwarf_CFI *cache,
            fs->regs[operand] = cie->initial_state->regs[operand];
          else
            fs->regs[operand].rule = reg_unspecified;
-         break;
+         continue;
 
        case DW_CFA_remember_state:
          {
@@ -298,7 +304,7 @@ execute_cfi (Dwarf_CFI *cache,
                goto out;
              }
            fs = copy;
-           break;
+           continue;
          }
 
        case DW_CFA_restore_state:
@@ -309,10 +315,10 @@ execute_cfi (Dwarf_CFI *cache,
            free (fs);
            fs = prev;
          }
-         break;
+         continue;
 
        case DW_CFA_nop:
-         break;
+         continue;
 
        case DW_CFA_GNU_window_save:
          /* This is magic shorthand used only by SPARC.  It's equivalent
@@ -333,22 +339,29 @@ execute_cfi (Dwarf_CFI *cache,
              fs->regs[regno].rule = reg_offset;
              fs->regs[regno].value = (regno - 16) * address_size;
            }
-         break;
+         continue;
 
        case DW_CFA_GNU_args_size:
          /* XXX is this useful for anything? */
          get_uleb128 (operand, program);
-         break;
+         continue;
 
        default:
          cfi_assert (false);
-         break;
+         continue;
        }
 
-      if (find_pc < loc)
-       /* We have just advanced past the address we're looking for.
-          The state currently described is what we want to see.  */
-       break;
+      /* We get here only for the cases that have just moved LOC.  */
+      if (find_pc >= loc)
+       /* This advance has not yet reached FIND_PC.  */
+       fs->start = loc;
+      else
+       {
+         /* We have just advanced past the address we're looking for.
+            The state currently described is what we want to see.  */
+         fs->end = loc;
+         break;
+       }
     }
 
   /* "The end of the instruction stream can be thought of as a
@@ -357,7 +370,8 @@ execute_cfi (Dwarf_CFI *cache,
 
      When we fall off the end of the program without an advance_loc/set_loc
      that put us past FIND_PC, the final state left by the FDE program
-     applies to this address (the caller ensured it was inside the FDE).  */
+     applies to this address (the caller ensured it was inside the FDE).
+     This address (FDE->end) is already in FS->end as set by the caller.  */
 
 #undef register_rule
 #undef cfi_assert
@@ -440,6 +454,8 @@ __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde,
     return DWARF_E_NOMEM;
 
   fs->fde = fde;
+  fs->start = fde->start;
+  fs->end = fde->end;
 
   int result = execute_cfi (cache, fde->cie, &fs,
                            fde->instructions, fde->instructions_end, false,
index 486822a0a9e9783abf8210b34fa291e026ee3210..687a9421692a7b9ca6b0f853dd7b2d4dc8e5bb03 100644 (file)
@@ -120,23 +120,24 @@ extern int dwarf_cfi_addrframe (Dwarf_CFI *cache,
                                Dwarf_Addr address, Dwarf_Frame **frame)
   __nonnull_attribute__ (3);
 
-/* Deliver a DWARF expression that yields the Canonical Frame Address at
-   this frame state.  Returns -1 for errors, or the number of operations
-   stored at *OPS.  That pointer can be used only as long as FRAME is alive
-   and unchanged.  Returns zero if the CFA cannot be determined here.  */
-extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops)
-  __nonnull_attribute__ (2);
-
 /* Return the DWARF register number used in FRAME to denote
-   the return address in FRAME's caller frame.
+   the return address in FRAME's caller frame.  The remaining
+   arguments can be non-null to fill in more information.
 
+   Fill [*START, *END) with the PC range to which FRAME's information applies.
    Fill in *SIGNALP to indicate whether this is a signal-handling frame.
    If true, this is the implicit call frame that calls a signal handler.
    This frame's "caller" is actually the interrupted state, not a call;
    its return address is an exact PC, not a PC after a call instruction.  */
-extern int dwarf_frame_return_address_register (Dwarf_Frame *frame,
-                                               bool *signalp)
-  __nonnull_attribute__ (1, 2);
+extern int dwarf_frame_info (Dwarf_Frame *frame,
+                            Dwarf_Addr *start, Dwarf_Addr *end, bool *signalp);
+
+/* Deliver a DWARF expression that yields the Canonical Frame Address at
+   this frame state.  Returns -1 for errors, or the number of operations
+   stored at *OPS.  That pointer can be used only as long as FRAME is alive
+   and unchanged.  Returns zero if the CFA cannot be determined here.  */
+extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops)
+  __nonnull_attribute__ (2);
 
 /* Deliver a DWARF expression that yields the location or value of
    DWARF register number REGNO in the state described by FRAME.
index b429641970d0f66cc5ca206f60a02eccb1a800c3..6b6fc03e3e5a7bc25d57de17d74224396e6ae600 100644 (file)
@@ -176,6 +176,10 @@ struct dwarf_frame_register
    at a particular PC location described by an FDE.  */
 struct Dwarf_Frame_s
 {
+  /* This frame description covers PC values in [start, end).  */
+  Dwarf_Addr start;
+  Dwarf_Addr end;
+
   Dwarf_CFI *cache;
 
   /* Previous state saved by DW_CFA_remember_state, or .cie->initial_state,
index 79e31e2954ea4e74fb4d99c9fa4583c6a0dc0f87..e2367f2b49a0b55a34755be823a7dcfe509e5c8c 100644 (file)
@@ -1,5 +1,5 @@
 /* Test program for CFI handling.
-   Copyright (C) 2006 Red Hat, Inc.
+   Copyright (C) 2006, 2009 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -94,10 +94,13 @@ handle_address (GElf_Addr pc, Dwfl *dwfl)
   if (result != 0)
     error (EXIT_FAILURE, 0, "dwfl_addrframe: %s", dwfl_errmsg (-1));
 
-  printf ("%#" PRIx64 ":\n", pc);
-
+  Dwarf_Addr start = pc;
+  Dwarf_Addr end = pc;
   bool signalp;
-  int ra_regno = dwarf_frame_return_address_register (frame, &signalp);
+  int ra_regno = dwarf_frame_info (frame, &start, &end, &signalp);
+
+  printf ("%#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "):\n", pc, start, end);
+
   if (ra_regno < 0)
     printf ("\treturn address register unavailable (%s)\n",
            dwarf_errmsg (0));