[PATCH] libdw/libdwfl: Add API for accessing registers

2022-07-19 Thread Di Chen via Elfutils-devel
>From 8325b5311ff5618a7a66e5398652e2177cc53e78 Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Tue, 19 Jul 2022 14:54:45 +0800
Subject: [PATCH] libdw/libdwfl: Add API for accessing registers

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 update renames previous state_get_reg() (in libdwfl/frame_unwind.c)
to dwfl_frame_reg(), adds a regno check, and makes it a public API.

Signed-off-by: Di Chen 
---
 libdw/libdw.map   |  1 +
 libdwfl/dwfl_frame_regs.c | 18 ++
 libdwfl/frame_unwind.c| 21 +
 libdwfl/libdwfl.h |  4 
 libdwfl/libdwflP.h|  2 ++
 5 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/libdw/libdw.map b/libdw/libdw.map
index 6da25561..8f393438 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -370,4 +370,5 @@ ELFUTILS_0.186 {
 ELFUTILS_0.188 {
   global:
 dwfl_get_debuginfod_client;
+dwfl_frame_reg;
 } ELFUTILS_0.186;
diff --git a/libdwfl/dwfl_frame_regs.c b/libdwfl/dwfl_frame_regs.c
index 83b1abef..92c4a692 100644
--- a/libdwfl/dwfl_frame_regs.c
+++ b/libdwfl/dwfl_frame_regs.c
@@ -59,3 +59,21 @@ 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)
+
+bool
+dwfl_frame_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Word *val)
+{
+  if ((state->regs_set[regno / sizeof (*state->regs_set) / 8]
+   & ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8 ==
0)
+{
+  __libdwfl_seterrno (DWFL_E_INVALID_REGNO);
+  return false;
+}
+  if (! __libdwfl_frame_reg_get (state, regno, val))
+{
+  __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
+  return false;
+}
+  return true;
+}
+INTDEF(dwfl_frame_reg)
diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c
index 9ac33833..38f5b332 100644
--- a/libdwfl/frame_unwind.c
+++ b/libdwfl/frame_unwind.c
@@ -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 (! dwfl_frame_reg (state, op->atom - DW_OP_reg0, &val1)
   || ! 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 (! dwfl_frame_reg (state, op->number, &val1) || ! 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 (! dwfl_frame_reg (state, op->atom - DW_OP_breg0, &val1))
 {
   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 (! dwfl_frame_reg (state, op->number, &val1))
 {
   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, ®val))
+  if (! dwfl_frame_reg (state, regno, ®val))
  continue;
 }
   else
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index b323e8fb..7c0dd87d 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -798,6 +798,10 @@ 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);

+/* Return *val (register value) for frame STATE.  */
+bool dwfl_frame_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *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,
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 9f598370..a6d4396a 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -81,6 +81,7 @@ typedef struct Dwfl_Process Dwfl_Process;
   DWFL_ERROR (LIBEBL_BAD, N_("Internal error due to ebl"))  \
   DWFL_ERROR

[PATCH v2] libdw/libdwfl: Add API for accessing registers

2022-07-19 Thread Di Chen via Elfutils-devel
>From 9c25b08e46c2031b569a85f91713d009b83f4c26 Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Tue, 19 Jul 2022 14:54:45 +0800
Subject: [PATCH] libdw/libdwfl: Add API for accessing registers

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 update renames previous state_get_reg() (in libdwfl/frame_unwind.c)
to dwfl_frame_reg(), adds a regno check, and makes it a public API.

Signed-off-by: Di Chen 
---
 libdw/libdw.map   |  1 +
 libdwfl/dwfl_frame_regs.c | 18 ++
 libdwfl/frame_unwind.c| 21 +
 libdwfl/libdwfl.h |  4 
 libdwfl/libdwflP.h|  2 ++
 5 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/libdw/libdw.map b/libdw/libdw.map
index 6da25561..8f393438 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -370,4 +370,5 @@ ELFUTILS_0.186 {
 ELFUTILS_0.188 {
   global:
 dwfl_get_debuginfod_client;
+dwfl_frame_reg;
 } ELFUTILS_0.186;
diff --git a/libdwfl/dwfl_frame_regs.c b/libdwfl/dwfl_frame_regs.c
index 83b1abef..92c4a692 100644
--- a/libdwfl/dwfl_frame_regs.c
+++ b/libdwfl/dwfl_frame_regs.c
@@ -59,3 +59,21 @@ 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)
+
+bool
+dwfl_frame_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Word *val)
+{
+  if ((state->regs_set[regno / sizeof (*state->regs_set) / 8]
+   & ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8 ==
0)
+{
+  __libdwfl_seterrno (DWFL_E_INVALID_REGNO);
+  return false;
+}
+  if (! __libdwfl_frame_reg_get (state, regno, val))
+{
+  __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
+  return false;
+}
+  return true;
+}
+INTDEF(dwfl_frame_reg)
diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c
index 9ac33833..38f5b332 100644
--- a/libdwfl/frame_unwind.c
+++ b/libdwfl/frame_unwind.c
@@ -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 (! dwfl_frame_reg (state, op->atom - DW_OP_reg0, &val1)
   || ! 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 (! dwfl_frame_reg (state, op->number, &val1) || ! 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 (! dwfl_frame_reg (state, op->atom - DW_OP_breg0, &val1))
 {
   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 (! dwfl_frame_reg (state, op->number, &val1))
 {
   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, ®val))
+  if (! dwfl_frame_reg (state, regno, ®val))
  continue;
 }
   else
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index b323e8fb..aba75afe 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -798,6 +798,10 @@ 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);

+/* Return *val (register value) for frame STATE.  */
+bool 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,
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 9f598370..a6d4396a 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -81,6 +81,7 @@ typedef struct Dwfl_Process Dwfl_Process;
   DWFL_ERROR (LIBEBL_BAD, N_("Internal error due to ebl"))  \
   DWFL_ERROR

[Bug libdw/28579] libdwfl api for accessing registers for a thread frame (full register unwinding)

2022-07-19 Thread dichen at redhat dot com via Elfutils-devel
https://sourceware.org/bugzilla/show_bug.cgi?id=28579

--- Comment #3 from Di Chen  ---
Thank you Mark,

I have re-pushed a patch[1] for

1). add dwfl_frame_reg to ELFUTILS_0.188
2). add invalid regno check for dwfl_frame_reg
3). add INTDECL (dwfl_frame_reg)
4). Replace Dwarf_Word with Dwarf_Addr for *val

[1] https://sourceware.org/pipermail/elfutils-devel/2022q3/005206.html

-- 
You are receiving this mail because:
You are on the CC list for the bug.