]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl: Add new function dwfl_frame_reg
authorDi Chen <dichen@redhat.com>
Thu, 28 Jul 2022 08:31:05 +0000 (16:31 +0800)
committerMark Wielaard <mark@klomp.org>
Sat, 30 Jul 2022 23:48:48 +0000 (01:48 +0200)
Dwfl has most of the infrastructure to keep the full unwind state,
including the state of unwound registers per frame using
Dwfl_Thread_Callbacks. But there is no public API to access the state,
except for the PC (dwfl_frame_pc).

This commit adds a new function dwfl_frame_reg to get the value of the
DWARF register number in the given frame.

https://sourceware.org/bugzilla/show_bug.cgi?id=28579

Signed-off-by: Di Chen <dichen@redhat.com>
ChangeLog
NEWS
libdw/ChangeLog
libdw/libdw.map
libdwfl/ChangeLog
libdwfl/dwfl_frame_regs.c
libdwfl/frame_unwind.c
libdwfl/libdwfl.h
libdwfl/libdwflP.h
libdwfl/linux-core-attach.c

index eb2a35f53a9c96be1d12eaa209d1ef51778eb5f7..0ececcc9ce6faa1fa97d3d035018458a536edc2c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2022-07-28  Di Chen  <dichen@redhat.com>
+
+       * NEWS: Add dwfl_frame_reg.
+
 2022-07-13  Mark Wielaard  <mark@klomp.org>
 
        * NEWS: Add dwfl_get_debuginfod_client.
diff --git a/NEWS b/NEWS
index 392f2edc04e8903f8f16b6b66638650355fb328a..82c86cb6688e4e9962188b875c212f6b81751485 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ Version 0.188 some time after 0.187
 debuginfod: Add --disable-source-scan option.
 
 libdwfl: Add new function dwfl_get_debuginfod_client.
+         Add new function dwfl_frame_reg.
 
 Version 0.187
 
index 6a8f7e51913c8d822022d10223ce4e7bf6b3d3e3..c9d94e0b88c0754d5c1905297573b88a938771b8 100644 (file)
@@ -1,3 +1,7 @@
+2022-07-28  Di Chen  <dichen@redhat.com>
+
+       * libdw.map (ELFUTILS_0.188): Add dwfl_frame_reg.
+
 2022-07-13  Mark Wielaard  <mark@klomp.org>
 
        * libdw.map (ELFUTILS_0.187): Renamed to...
index 6da25561e88674d54790f8c49b9f8399c4c7f7a3..8f39343885483b344a6b038481d0970d207071fd 100644 (file)
@@ -370,4 +370,5 @@ ELFUTILS_0.186 {
 ELFUTILS_0.188 {
   global:
     dwfl_get_debuginfod_client;
+    dwfl_frame_reg;
 } ELFUTILS_0.186;
index acdaa01383bbfc27f4402f8e23dfad2e469b5b96..30f30b14bfbf01b49e99aa2eda4501e5faa41d7d 100644 (file)
@@ -1,3 +1,18 @@
+2022-07-28  Di Chen  <dichen@redhat.com>
+
+       * libdwfl.h (dwfl_frame_reg): New function.
+       * libdwflP.h (DWFL_E_REGISTER_VAL_UNKNOWN): New error code.
+       (__libdwfl_frame_reg_get): Return an int.
+       (dwfl_frame_reg): INTDECL.
+       * dwfl_frame_regs.c (dwfl_frame_reg): New function.
+       * frame_unwind.c (__libdwfl_frame_reg_get): Return an int.
+       (state_get_reg): Removed.
+       (expr_eval): Use INTUSE (dwfl_frame_reg) instead of state_get_reg.
+       (handle_cfi): Likewise.
+       (getfunc): Likewise.
+       * linux-core-attach.c (core_set_initial_registers): Check
+       __libdwfl_frame_reg_get returns zero.
+
 2022-07-28  Mark Wielaard  <mark@klomp.org>
 
        * core-file.c (elf_begin_rand): Replace struct ar_hdr h with
index 83b1abef1f59ae2a207067e8c7f7f2ea6ef6c591..a4bd38849a9a40199084d4844d98ac159b9e4fd9 100644 (file)
@@ -59,3 +59,15 @@ dwfl_thread_state_register_pc (Dwfl_Thread *thread, Dwarf_Word pc)
   state->pc_state = DWFL_FRAME_STATE_PC_SET;
 }
 INTDEF(dwfl_thread_state_register_pc)
+
+int
+dwfl_frame_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Word *val)
+{
+  int res = __libdwfl_frame_reg_get (state, regno, val);
+  if (res == -1)
+      __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
+  else if (res == 1)
+      __libdwfl_seterrno (DWFL_E_REGISTER_VAL_UNKNOWN);
+  return res;
+}
+INTDEF(dwfl_frame_reg)
index 9ac338337fb41cc5c579e9f3a0e0a811c6fa245c..8185d84b27619dd7a413dc5921e034070da72df0 100644 (file)
    error.  */
 #define DWARF_EXPR_STEPS_MAX 0x1000
 
-bool
+int
 internal_function
 __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val)
 {
   Ebl *ebl = state->thread->process->ebl;
   if (! ebl_dwarf_to_regno (ebl, &regno))
-    return false;
+    return -1;
   if (regno >= ebl_frame_nregs (ebl))
-    return false;
+    return -1;
   if ((state->regs_set[regno / sizeof (*state->regs_set) / 8]
        & ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8)))) == 0)
-    return false;
+    return 1;
   if (val)
     *val = state->regs[regno];
-  return true;
+  return 0;
 }
 
 bool
@@ -78,17 +78,6 @@ __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, Dwarf_Addr val)
   return true;
 }
 
-static bool
-state_get_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val)
-{
-  if (! __libdwfl_frame_reg_get (state, regno, val))
-    {
-      __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
-      return false;
-    }
-  return true;
-}
-
 static int
 bra_compar (const void *key_voidp, const void *elem_voidp)
 {
@@ -211,7 +200,7 @@ expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
            }
          break;
        case DW_OP_reg0 ... DW_OP_reg31:
-         if (! state_get_reg (state, op->atom - DW_OP_reg0, &val1)
+         if (INTUSE (dwfl_frame_reg) (state, op->atom - DW_OP_reg0, &val1) != 0
              || ! push (val1))
            {
              free (stack.addrs);
@@ -219,14 +208,14 @@ expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
            }
          break;
        case DW_OP_regx:
-         if (! state_get_reg (state, op->number, &val1) || ! push (val1))
+         if (INTUSE (dwfl_frame_reg) (state, op->number, &val1) != 0 || ! push (val1))
            {
              free (stack.addrs);
              return false;
            }
          break;
        case DW_OP_breg0 ... DW_OP_breg31:
-         if (! state_get_reg (state, op->atom - DW_OP_breg0, &val1))
+         if (INTUSE (dwfl_frame_reg) (state, op->atom - DW_OP_breg0, &val1) != 0)
            {
              free (stack.addrs);
              return false;
@@ -239,7 +228,7 @@ expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
            }
          break;
        case DW_OP_bregx:
-         if (! state_get_reg (state, op->number, &val1))
+         if (INTUSE (dwfl_frame_reg) (state, op->number, &val1) != 0)
            {
              free (stack.addrs);
              return false;
@@ -591,7 +580,7 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
          else if (reg_ops == NULL)
            {
              /* REGNO is same-value.  */
-             if (! state_get_reg (state, regno, &regval))
+             if (INTUSE (dwfl_frame_reg) (state, regno, &regval) != 0)
                continue;
            }
          else
@@ -638,9 +627,10 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
     }
   if (unwound->pc_state == DWFL_FRAME_STATE_ERROR)
     {
-      if (__libdwfl_frame_reg_get (unwound,
-                                  frame->fde->cie->return_address_register,
-                                  &unwound->pc))
+      int res = INTUSE (dwfl_frame_reg) (unwound,
+          frame->fde->cie->return_address_register,
+          &unwound->pc);
+      if (res == 0)
        {
          /* PPC32 __libc_start_main properly CFI-unwinds PC as zero.
             Currently none of the archs supported for unwinding have
@@ -698,7 +688,7 @@ getfunc (int firstreg, unsigned nregs, Dwarf_Word *regs, void *arg)
   Dwfl_Frame *state = arg;
   assert (firstreg >= 0);
   while (nregs--)
-    if (! __libdwfl_frame_reg_get (state, firstreg++, regs++))
+    if (INTUSE (dwfl_frame_reg) (state, firstreg++, regs++) != 0)
       return false;
   return true;
 }
index b323e8fb9f017363ad71cf1c1f89650750cea52e..edb537c21e6cb70637fd53c27a56c484982801b2 100644 (file)
@@ -798,6 +798,12 @@ int dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
 bool dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation)
   __nonnull_attribute__ (1, 2);
 
+/* Get the value of the DWARF register number in the given frame.
+   Returns zero on success, -1 on error (invalid DWARF register
+   number) or 1 if the value of the register in the frame is unknown.  */
+int dwfl_frame_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Word *val)
+  __nonnull_attribute__ (1);
+
 /* Return the internal debuginfod-client connection handle for the DWFL session.
    When the client connection has not yet been initialized, it will be done on the
    first call to this function. If elfutils is compiled without support for debuginfod,
index 9f598370f9d3703a8d88fb4eb939db3d3fa365cc..a2949e74c871bb3b6007a2365b51510d04ca6c0b 100644 (file)
@@ -81,6 +81,7 @@ typedef struct Dwfl_Process Dwfl_Process;
   DWFL_ERROR (LIBEBL_BAD, N_("Internal error due to ebl"))                   \
   DWFL_ERROR (CORE_MISSING, N_("Missing data in core file"))                 \
   DWFL_ERROR (INVALID_REGISTER, N_("Invalid register"))                              \
+  DWFL_ERROR (REGISTER_VAL_UNKNOWN, N_("Unknown register value"))                            \
   DWFL_ERROR (PROCESS_MEMORY_READ, N_("Error reading process memory"))       \
   DWFL_ERROR (PROCESS_NO_ARCH, N_("Couldn't find architecture of any ELF"))   \
   DWFL_ERROR (PARSE_PROC, N_("Error parsing /proc filesystem"))                      \
@@ -276,9 +277,11 @@ struct Dwfl_Frame
   Dwarf_Addr regs[];
 };
 
-/* Fetch value from Dwfl_Frame->regs indexed by DWARF REGNO.
-   No error code is set if the function returns FALSE.  */
-bool __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno,
+/* Fetch value from Dwfl_Frame->regs indexed by DWARF REGNO.  The
+   function returns 0 on success, -1 on error (invalid DWARF register
+   number), 1 if the value of the register in the frame is unknown.
+   Even on error, no error code is set.  */
+int __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno,
                              Dwarf_Addr *val)
   internal_function;
 
@@ -786,6 +789,7 @@ INTDECL (dwfl_getthread_frames)
 INTDECL (dwfl_getthreads)
 INTDECL (dwfl_thread_getframes)
 INTDECL (dwfl_frame_pc)
+INTDECL (dwfl_frame_reg)
 INTDECL (dwfl_get_debuginfod_client)
 
 /* Leading arguments standard to callbacks passed a Dwfl_Module.  */
index f68062f0d060985d03d2473a9b7611940f9a3e21..ee7afa400208c51f0fcc830b5676fed9372009a1 100644 (file)
@@ -257,7 +257,7 @@ core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp)
             FIXME: It depends now on their order in core notes.
             FIXME: It uses private function.  */
          if (regno < nregs
-             && __libdwfl_frame_reg_get (thread->unwound, regno, NULL))
+             && __libdwfl_frame_reg_get (thread->unwound, regno, NULL) == 0)
            continue;
          Dwarf_Word val;
          switch (regloc->bits)