[PATCH] PR28873 - Implement eu-readelf -D

2023-02-10 Thread Di Chen via Elfutils-devel
>From bdc19de94bff8f8812611b9ba8c0116a650d0fb5 Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Fri, 13 Jan 2023 20:12:43 +0800
Subject: [PATCH] readelf: display dynamic symtab without section headers

This commit adds a new option "-D/--use-dynamic" to support printing the
dynamic symbol table from the PT_DYNAMIC segment. By using the
PT_DYNAMIC segment, eu-readelf can go through the contents of dynamic
section entries and the values of each tag. From that, we can get the
address and size of the dynamic symbol table, the address of the string
table, etc.

By using the new option "-D/--use-dynamic", eu-readelf can list the
symbols without section headers.

Example:
  $ ./src/readelf -Ds a.out
  0:   0 NOTYPE  LOCAL  DEFAULTUNDEF
  1:   0 FUNCGLOBAL DEFAULTUNDEF
__libc_start_main@GLIBC_2.34 (2)
  2:   0 NOTYPE  WEAK   DEFAULTUNDEF
__gmon_start__

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

Signed-off-by: Di Chen 
---
 src/readelf.c | 289 --
 1 file changed, 283 insertions(+), 6 deletions(-)

diff --git a/src/readelf.c b/src/readelf.c
index 451f8400..9e1e9b73 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -307,7 +307,8 @@ static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr
*ehdr, Elf_Scn *scn,
 static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
  GElf_Shdr *shdr);
 static bool print_symtab (Ebl *ebl, int type);
-static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
+static bool handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
+static bool handle_dynamic_symtab (Ebl *ebl);
 static void print_verinfo (Ebl *ebl);
 static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
 static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
@@ -327,7 +328,9 @@ enum dyn_idx
 {
   i_strsz,
   i_verneed,
+  i_verneednum,
   i_verdef,
+  i_verdefnum,
   i_versym,
   i_symtab,
   i_strtab,
@@ -1042,7 +1045,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
 symtab_printed |= print_symtab (ebl, SHT_DYNSYM);
   if (print_version_info)
 print_verinfo (ebl);
-  if (print_symbol_table)
+  if (print_symbol_table && !use_dynamic_segment)
 symtab_printed |= print_symtab (ebl, SHT_SYMTAB);

   if ((print_symbol_table || print_dynsym_table)
@@ -2442,6 +2445,12 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr,
Elf_Scn *scn, GElf_Shdr *shdr)
 static bool
 print_symtab (Ebl *ebl, int type)
 {
+  /* Use the dynamic section info to display symbol tables.  */
+  if (use_dynamic_segment && type == SHT_DYNSYM)
+  {
+ return handle_dynamic_symtab(ebl);
+  }
+
   /* Find the symbol table(s).  For this we have to search through the
  section table.  */
   Elf_Scn *scn = NULL;
@@ -2480,16 +2489,275 @@ print_symtab (Ebl *ebl, int type)
 _("cannot get section [%zd] header: %s"),
 elf_ndxscn (scn), elf_errmsg (-1));
 }
-  handle_symtab (ebl, scn, shdr);
-  symtab_printed = true;
+  symtab_printed = handle_symtab (ebl, scn, shdr);
  }
 }

   return symtab_printed;
 }

+static bool
+handle_dynamic_symtab (Ebl *ebl)
+{
+  GElf_Phdr *phdr = NULL;
+  /* phnum is a static variable which already fetched in function
process_elf_file.  */
+  for (size_t i = 0; i < phnum; ++i) {
+GElf_Phdr phdr_mem;
+phdr = gelf_getphdr(ebl->elf, i, &phdr_mem);
+if (phdr->p_type == PT_DYNAMIC) {
+  break;
+}
+  }
+  if (phdr == NULL)
+ return false;

-static void
+  GElf_Addr addrs[i_max] = {0,};
+  GElf_Off offs[i_max] = {0,};
+  get_dynscn_addrs(ebl->elf, phdr, addrs);
+  find_offsets(ebl->elf, 0, i_max, addrs, offs);
+
+  size_t syments;
+
+  GElf_Ehdr ehdr_mem;
+  GElf_Ehdr *ehdr = gelf_getehdr(ebl->elf, &ehdr_mem);
+
+  if (offs[i_hash] != 0) {
+/* In the original format, .hash says the size of .dynsym.  */
+
+size_t entsz = SH_ENTSIZE_HASH(ehdr);
+Elf_Data *data =
+elf_getdata_rawchunk(ebl->elf, offs[i_hash] + entsz, entsz,
+ (entsz == 4 ? ELF_T_WORD : ELF_T_XWORD));
+if (data != NULL)
+  syments = (entsz == 4 ? *(const GElf_Word *)data->d_buf
+: *(const GElf_Xword *)data->d_buf);
+  }
+  if (offs[i_gnu_hash] != 0 && syments == 0) {
+/* In the new format, we can derive it with some work.  */
+
+const struct {
+  Elf32_Word nbuckets;
+  Elf32_Word symndx;
+  Elf32_Word maskwords;
+  Elf32_Word shift2;
+} * header;
+
+Elf_Data *data = elf_getdata_rawchunk(ebl->elf, offs[i_gnu_hash],
+  sizeof *header, ELF_T_WORD);
+if (data != NULL) {
+  header = data->d_buf;
+  Elf32_Word nbuckets = header->nbuckets;
+  Elf32_Word symndx = header->symndx;
+  GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header +
+ (gelf_getclass(ebl->elf) * sizeof(Elf32_Word)
*
+  header->maskwords));
+
+  //

Re: [PATCH] PR28873 - Implement eu-readelf -D

2023-04-01 Thread Di Chen via Elfutils-devel
  GElf_Off hasharr_at
+  = (buckets_at + nbuckets * sizeof (Elf32_Word));
+  hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
+  do
+{
+  data = elf_getdata_rawchunk (
+  ebl->elf, hasharr_at, sizeof (Elf32_Word),
ELF_T_WORD);
+  if (data != NULL && (*(const Elf32_Word *)data->d_buf &
1u))
+{
+  syments = maxndx + 1;
+  break;
+}
+  ++maxndx;
+  hasharr_at += sizeof (Elf32_Word);
+}
+  while (data != NULL);
+}
+}
+}
+  if (offs[i_strtab] > offs[i_symtab] && syments == 0)
+syments = ((offs[i_strtab] - offs[i_symtab])
+   / gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT));

-  vd_offset += verdef->vd_next;
-  verdef = (verdef->vd_next == 0
- ? NULL
- : gelf_getverdef (verdef_data, vd_offset,
-  &verdef_mem));
-}
+  if (syments <= 0 || offs[i_strtab] == 0 || offs[i_symtab] == 0)
+{
+  error_exit (0, _ ("Dynamic symbol information is not available for "
+"displaying symbols."));
+}

-  if (verdef != NULL)
-{
-  GElf_Verdaux verdaux_mem;
-  GElf_Verdaux *verdaux
- = gelf_getverdaux (verdef_data,
-   vd_offset + verdef->vd_aux,
-   &verdaux_mem);
-
-  if (verdaux != NULL)
- printf ((*versym & 0x8000) ? "@%s" : "@@%s",
- elf_strptr (ebl->elf, verdef_stridx,
-verdaux->vda_name));
-}
- }
-}
- }
+  /* All the data chunk initializaion.  */
+  Elf_Data *symdata = NULL;
+  Elf_Data *symstrdata = NULL;
+  Elf_Data *versym_data = NULL;
+  Elf_Data *verdef_data = NULL;
+  Elf_Data *verneed_data = NULL;

-  putchar_unlocked ('\n');
-}
+  symdata = elf_getdata_rawchunk (
+  ebl->elf, offs[i_symtab],
+  gelf_fsize (ebl->elf, ELF_T_SYM, syments, EV_CURRENT), ELF_T_SYM);
+  symstrdata = elf_getdata_rawchunk (ebl->elf, offs[i_strtab],
addrs[i_strsz],
+ ELF_T_BYTE);
+  versym_data = elf_getdata_rawchunk (
+  ebl->elf, offs[i_versym], syments * sizeof (Elf64_Half), ELF_T_HALF);
+
+  /* Get the verneed_data without vernaux.  */
+  verneed_data = elf_getdata_rawchunk (
+  ebl->elf, offs[i_verneed], addrs[i_verneednum] * sizeof
(Elf64_Verneed),
+  ELF_T_VNEED);
+  size_t vernauxnum = 0;
+  size_t vn_next_offset = 0;
+
+  for (size_t i = 0; i < addrs[i_verneednum]; i++)
+{
+  GElf_Verneed *verneed
+  = (GElf_Verneed *)(verneed_data->d_buf + vn_next_offset);
+  vernauxnum += verneed->vn_cnt;
+  vn_next_offset += verneed->vn_next;
+}
+
+  /* Update the verneed_data to include the vernaux.  */
+  verneed_data = elf_getdata_rawchunk (
+  ebl->elf, offs[i_verneed],
+  (addrs[i_verneednum] + vernauxnum) * sizeof (GElf_Verneed),
ELF_T_VNEED);
+
+  /* Get the verdef_data without verdaux.  */
+  verdef_data = elf_getdata_rawchunk (
+  ebl->elf, offs[i_verdef], addrs[i_verdefnum] * sizeof (Elf64_Verdef),
+  ELF_T_VDEF);
+  size_t verdauxnum = 0;
+  size_t vd_next_offset = 0;
+
+  for (size_t i = 0; i < addrs[i_verdefnum]; i++)
+{
+  GElf_Verdef *verdef
+  = (GElf_Verdef *)(verdef_data->d_buf + vd_next_offset);
+  verdauxnum += verdef->vd_cnt;
+  vd_next_offset += verdef->vd_next;
+}
+
+  /* Update the verdef_data to include the verdaux.  */
+  verdef_data = elf_getdata_rawchunk (
+  ebl->elf, offs[i_verdef],
+  (addrs[i_verdefnum] + verdauxnum) * sizeof (GElf_Verdef),
ELF_T_VDEF);
+
+  unsigned int nsyms = (unsigned int)syments;
+  process_symtab (ebl, nsyms, 0, 0, 0, symdata, versym_data, symstrdata,
+  verneed_data, verdef_data, NULL);
+  return true;
 }


@@ -4990,13 +5208,24 @@ get_dynscn_addrs(Elf *elf, GElf_Phdr *phdr,
GElf_Addr addrs[i_max])
   addrs[i_verdef] = dyn->d_un.d_ptr;
   break;

+case DT_VERDEFNUM:
+  addrs[i_verdefnum] = dyn->d_un.d_val;
+  break;
+
 case DT_VERNEED:
   addrs[i_verneed] = dyn->d_un.d_ptr;
   break;

+case DT_VERNEEDNUM:
+  addrs[i_verneednum] = dyn->d_un.d_val;
+  break;
+
 case DT_STRSZ:
   addrs[i_strsz] = dyn->d_un.d_val;
   break;
+case DT_SYMTAB_SHNDX:
+  addrs[i_symtab_shndx] = dyn->d_un.d_ptr;
+  break;
 }
   }
 }
-- 
2.39.2




On Fri, Feb 17, 2023 at 12:12 AM Mark Wielaard  wrote:

> Hi,
>
> On Sat, 2023-02-11 at 00:17 +0800, Di Chen via Elfutils-devel wrote:
> > From bdc19de94bff8f8812611b9ba8c0116a650d0fb5 Mon Sep 17 00:00:00 2001
> > From: Di Chen 
> > Date: Fri, 13 Jan 2023 20:12:43 +0800
> > Subject: [PATCH] readelf: display dynamic symtab without section headers
> >
> > This commit adds a new 

[PATCH] debuginfod: PR27917 - protect against federation loops

2021-08-12 Thread Di Chen via Elfutils-devel
>From a726d9868f4e02d390b9071180b0c3728da3750e Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Sun, 8 Aug 2021 16:57:12 +0800
Subject: [PATCH] debuginfod: PR27917 - protect against federation loops

If someone misconfigures a debuginfod federation to have loops, and a
nonexistent
buildid lookup is attempted, bad things will happen, as is documented.

This patch aims to reduce the risk by adding an option to debuginfod that
functions
kind of like an IP packet's TTL: a limit on the length of XFF: header that
debuginfod
is willing to process. If X-Forwarded-For: exceeds N hops, it will not
delegate a local
lookup miss to upstream debuginfods.

Commit ab38d167c40c99 causes federation loops for non-existent resources to
result
in multiple temporary livelocks, each lasting for $DEBUGINFOD_TIMEOUT
seconds.
Since concurrent requests for each unique resource are now serialized,
federation
loops can result in one server thread waiting to acquire a lock while the
server
thread holding the lock waits for the first thread to respond to an http
request.

This PR can help protect against the above multiple temporary livelocks
behaviour.
Ex. if --forwarded-ttl-limit=0 then the timeout behaviour of local loops
should
be avoided.

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

Signed-off-by: Di Chen 
---
 debuginfod/debuginfod.cxx| 30 --
 doc/debuginfod.8 |  6 ++
 tests/run-debuginfod-find.sh | 42 +++-
 3 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
index 4ddd9255..bd103d9f 100644
--- a/debuginfod/debuginfod.cxx
+++ b/debuginfod/debuginfod.cxx
@@ -375,6 +375,8 @@ static const struct argp_option options[] =
 #define ARGP_KEY_FDCACHE_PREFETCH_FDS 0x1006
{ "fdcache-prefetch-fds", ARGP_KEY_FDCACHE_PREFETCH_FDS, "NUM",
0,"Number of files allocated to the \
   prefetch cache.", 0},
+#define ARGP_KEY_FORWARDED_TTL_LIMIT 0x1007
+   {"forwarded-ttl-limit", ARGP_KEY_FORWARDED_TTL_LIMIT, "NUM", 0, "Limit
of X-Forwarded-For hops, default 8.", 0},
{ NULL, 0, NULL, 0, NULL, 0 },
   };

@@ -422,6 +424,7 @@ static long fdcache_prefetch;
 static long fdcache_mintmp;
 static long fdcache_prefetch_mbs;
 static long fdcache_prefetch_fds;
+static unsigned forwarded_ttl_limit = 8;
 static string tmpdir;

 static void set_metric(const string& key, double value);
@@ -554,6 +557,9 @@ parse_opt (int key, char *arg,
   if( fdcache_mintmp > 100 || fdcache_mintmp < 0 )
 argp_failure(state, 1, EINVAL, "fdcache mintmp percent");
   break;
+case ARGP_KEY_FORWARDED_TTL_LIMIT:
+  forwarded_ttl_limit = (unsigned) atoi(arg);
+  break;
 case ARGP_KEY_ARG:
   source_paths.insert(string(arg));
   break;
@@ -1769,7 +1775,8 @@ handle_buildid (MHD_Connection* conn,
 const string& buildid /* unsafe */,
 const string& artifacttype /* unsafe */,
 const string& suffix /* unsafe */,
-int *result_fd)
+int *result_fd,
+bool disable_query_server = false)
 {
   // validate artifacttype
   string atype_code;
@@ -1862,6 +1869,12 @@ handle_buildid (MHD_Connection* conn,
   // We couldn't find it in the database.  Last ditch effort
   // is to defer to other debuginfo servers.

+  // if X-Forwarded-For: exceeds N hops,
+  // do not delegate a local lookup miss to upstream debuginfods.
+  if (disable_query_server)
+throw reportable_exception(MHD_HTTP_NOT_FOUND, "not found,
--forwared-ttl-limit reached \
+and will not query the upstream servers");
+
   int fd = -1;
   debuginfod_client *client = debuginfod_pool_begin ();
   if (client != NULL)
@@ -2119,6 +2132,7 @@ handler_cb (void * /*cls*/,
   struct timespec ts_start, ts_end;
   clock_gettime (CLOCK_MONOTONIC, &ts_start);
   double afteryou = 0.0;
+  bool disable_query_server = false;

   try
 {
@@ -2131,6 +2145,17 @@ handler_cb (void * /*cls*/,

   if (slash1 != string::npos && url1 == "/buildid")
 {
+  // check if X-Forwarded-For exceeds the limit number of hops.
+  string xff = MHD_lookup_connection_value (connection,
MHD_HEADER_KIND, "X-Forwarded-For") ?: "";
+
+  unsigned int xff_count = 0;
+  for (auto&& i : xff){
+if (i == ',') xff_count++;
+  }
+
+  if (xff_count >= forwarded_ttl_limit)
+disable_query_server = true;
+
   // PR27863: block this thread awhile if another thread is
already busy
   // fetching the exact same thing.  This is better for Everyone.
   // The latecomer says "... after you!" and waits.
@@ -2171,7 +2196,7 @@ handler_cb (void * /*cls*/,

   // get the resulting fd so we can report its size
   int fd;
-  r = handle_buildid(connection, buildid, artifacttype, suffix,
&fd);
+  r = handle_buildid(connection, buildid, artifacttype, suffix,
&fd, disable_query_serve

Re: [PATCH] debuginfod: PR27917 - protect against federation loops

2021-08-20 Thread Di Chen via Elfutils-devel
Hey Frank,

1) moved the XFF check to handle_buildid.
2) replace "livelock" with "deadlock" in the commit message.

- dichen


On Thu, Aug 19, 2021 at 6:55 AM Frank Ch. Eigler  wrote:

> Hi -
>
> > This patch aims to reduce the risk by adding an option to debuginfod
> > that functions kind of like an IP packet's TTL: a limit on the
> > length of XFF: header that debuginfod is willing to process. If
> > X-Forwarded-For: exceeds N hops, it will not delegate a local lookup
> > miss to upstream debuginfods. [...]
>
> Thank you very much!
>
>
> > Commit ab38d167c40c99 causes federation loops for non-existent
> > resources to result in multiple temporary livelocks, each lasting
> > for $DEBUGINFOD_TIMEOUT seconds. [...]
>
> (FWIW, the term "livelock" is not quite right here, try just
> "deadlock".)
>
> The patch looks functional, and thank you also for including the
> docs and test case.  Thorough enough!
>
>
> > @@ -1862,6 +1869,12 @@ handle_buildid (MHD_Connection* conn,
> >// We couldn't find it in the database.  Last ditch effort
> >// is to defer to other debuginfo servers.
> >
> > +  // if X-Forwarded-For: exceeds N hops,
> > +  // do not delegate a local lookup miss to upstream debuginfods.
> > +  if (disable_query_server)
> > +throw reportable_exception(MHD_HTTP_NOT_FOUND, "not found,
> > --forwared-ttl-limit reached \
> > +and will not query the upstream servers");
>
> One part I don't understand is why you added the code to check for XFF
> length into handler_cb(), and then passed the disable_query_server
> result flag to this function.  Was there some reason not to perform
> the XFF comma-counting right here?
>
>
> - FChE
>
>
From a0b3d4ba3d15b83d23d3594b614c8e72b87e626c Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Fri, 20 Aug 2021 13:03:21 +0800
Subject: [PATCH] debuginfod: PR27917 - protect against federation loops

If someone misconfigures a debuginfod federation to have loops, and
a nonexistent buildid lookup is attempted, bad things will happen,
as is documented.

This patch aims to reduce the risk by adding an option to debuginfod
that functions kind of like an IP packet's TTL: a limit on the length of
XFF: header that debuginfod is willing to process. If X-Forwarded-For:
exceeds N hops, it will not delegate a local lookup miss to upstream
debuginfods.

Commit ab38d167c40c99 causes federation loops for non-existent resources
to result in multiple temporary deadlocks, each lasting for $DEBUGINFOD_TIMEOUT
seconds. Since concurrent requests for each unique resource are now
serialized, federation loops can result in one server thread waiting to
acquire a lock while the server thread holding the lock waits for the
first thread to respond to an http request.

This PR can help protect against the above multiple temporary deadlocks
behaviour. Ex. if --forwarded-ttl-limit=0 then the timeout behaviour of
local loops should be avoided.

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

Signed-off-by: Di Chen 
---
 debuginfod/debuginfod.cxx| 18 
 doc/debuginfod.8 |  6 ++
 tests/run-debuginfod-find.sh | 42 +++-
 3 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
index 4ddd9255..261049f2 100644
--- a/debuginfod/debuginfod.cxx
+++ b/debuginfod/debuginfod.cxx
@@ -375,6 +375,8 @@ static const struct argp_option options[] =
 #define ARGP_KEY_FDCACHE_PREFETCH_FDS 0x1006
{ "fdcache-prefetch-fds", ARGP_KEY_FDCACHE_PREFETCH_FDS, "NUM", 0,"Number of files allocated to the \
   prefetch cache.", 0},
+#define ARGP_KEY_FORWARDED_TTL_LIMIT 0x1007
+   {"forwarded-ttl-limit", ARGP_KEY_FORWARDED_TTL_LIMIT, "NUM", 0, "Limit of X-Forwarded-For hops, default 8.", 0},
{ NULL, 0, NULL, 0, NULL, 0 },
   };
 
@@ -422,6 +424,7 @@ static long fdcache_prefetch;
 static long fdcache_mintmp;
 static long fdcache_prefetch_mbs;
 static long fdcache_prefetch_fds;
+static unsigned forwarded_ttl_limit = 8;
 static string tmpdir;
 
 static void set_metric(const string& key, double value);
@@ -554,6 +557,9 @@ parse_opt (int key, char *arg,
   if( fdcache_mintmp > 100 || fdcache_mintmp < 0 )
 argp_failure(state, 1, EINVAL, "fdcache mintmp percent");
   break;
+case ARGP_KEY_FORWARDED_TTL_LIMIT:
+  forwarded_ttl_limit = (unsigned) atoi(arg);
+  break;
 case ARGP_KEY_ARG:
   source_paths.insert(string(arg));
   break;
@@ -1881,6 +1887,17 @@ handle_buildid (MHD_Connection* conn,
   if (xff != "")
 xff += string(", "); // comma separated list
 
+  unsigned int xff_count = 0;
+  for (auto&& i : xff){
+if (i == ',') xff_count++;
+  }
+
+  // if X-Forwarded-For: exceeds N hops,
+  // do not delegate a local lookup miss to upstream debuginfods.
+  if (xff_count >= forwarded_ttl_limit)
+throw reportable_exception(MHD_HTTP_NOT_FOUND, "not found, --forwared-ttl-lim

[PATCH] PR27940 - The /* pc=0x... */ is no longer printed by "stap -v -L 'kernel.function("*")'

2021-09-10 Thread Di Chen via Elfutils-devel
>From a98718a1b97357e53cef966ed9826c69e159f46e Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Thu, 2 Sep 2021 12:52:47 +0800
Subject: [PATCH] The /* pc=0x... */ is no longer printed by "stap -v -L
 'kernel.function("*")'

The disappeared /* pc=0x... */ resulted from the missing implementation
of the function "dwarf_derived_probe::printsig_nonest".
Which makes "p->printsig_nonest(sig)" in main.cxx end up calling
"derived_probe::printsig_nonest", and the type of "p" is

(gdb) ptype /m p
type = /* real type = dwarf_derived_probe * */

This patch added "dwarf_derived_probe::printsig_nonest" for PC value
print.

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

Signed-off-by: Di Chen 
---
 elaborate.h |  2 +-
 tapsets.cxx | 11 +++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/elaborate.h b/elaborate.h
index 9817172a7..baa29e67c 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -204,7 +204,7 @@ struct derived_probe: public probe
   virtual probe_point* sole_location () const;
   virtual probe_point* script_location () const;
   virtual void printsig (std::ostream &o) const cxx_override;
-  void printsig_nonest (std::ostream &o) const;
+  virtual void printsig_nonest (std::ostream &o) const;
   // return arguments of probe if there
   virtual void getargs (std::list &) const {}
   void printsig_nested (std::ostream &o) const;
diff --git a/tapsets.cxx b/tapsets.cxx
index 68b75610e..27d8995ce 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -560,6 +560,7 @@ struct dwarf_derived_probe: public
generic_kprobe_derived_probe
   bool access_vars;

   void printsig (std::ostream &o) const;
+  void printsig_nonest (std::ostream &o) const;
   virtual void join_group (systemtap_session& s);
   void emit_probe_local_init(systemtap_session& s, translator_output * o);
   void getargs(std::list &arg_set) const;
@@ -5386,6 +5387,16 @@ dwarf_derived_probe::printsig (ostream& o) const
 }


+void
+dwarf_derived_probe::printsig_nonest (ostream& o) const
+{
+  sole_location()->print (o);
+  if (symbol_name != "")
+o << " /* pc=<" << symbol_name << "+" << offset << "> */";
+  else
+o << " /* pc=" << section << "+0x" << hex << addr << dec << " */";
+}
+

 void
 dwarf_derived_probe::join_group (systemtap_session& s)
-- 
2.31.1


[PATCH] debuginfod: PR28242 - extend server http-response metrics

2021-10-01 Thread Di Chen via Elfutils-devel
>From a574dfaf5d5636cbb7159a0118eb30e2c4aaa301 Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Fri, 1 Oct 2021 22:03:41 +0800
Subject: [PATCH] debuginfod: PR28242 - extend server http-response metrics

This patch aims to extend http_responses_* metrics with another label
"type" by getting the extra artifact-type content added as a new key=value
tag.

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

Signed-off-by: Di Chen 
---
 debuginfod/debuginfod.cxx  | 55 --
 tests/run-debuginfod-000-permission.sh | 12 +++---
 2 files changed, 49 insertions(+), 18 deletions(-)

diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
index 2b9a1c41..6a469b21 100644
--- a/debuginfod/debuginfod.cxx
+++ b/debuginfod/debuginfod.cxx
@@ -2080,6 +2080,33 @@ add_metric(const string& metric,

 // and more for higher arity labels if needed

+static void
+inc_metric(const string& metric,
+   const string& lname, const string& lvalue,
+   const string& rname, const string& rvalue)
+{
+  string key = (metric + "{" + metric_label(lname, lvalue) + ",");
+  if (rvalue != "debuginfo" && rvalue != "executable" && rvalue !=
"source")
+key = (key + metric_label(rname, "") + "}");
+  else
+key = (key + metric_label(rname, rvalue) + "}");
+  unique_lock lock(metrics_lock);
+  metrics[key] ++;
+}
+static void
+add_metric(const string& metric,
+   const string& lname, const string& lvalue,
+   const string& rname, const string& rvalue,
+   double value)
+{
+  string key = (metric + "{" + metric_label(lname, lvalue) + ",");
+  if (rvalue != "debuginfo" && rvalue != "executable" && rvalue !=
"source")
+key = (key + metric_label(rname, "") + "}");
+  else
+key = (key + metric_label(rname, rvalue) + "}");
+  unique_lock lock(metrics_lock);
+  metrics[key] += value;
+}

 static struct MHD_Response*
 handle_metrics (off_t* size)
@@ -2165,6 +2192,7 @@ handler_cb (void * /*cls*/,
   struct timespec ts_start, ts_end;
   clock_gettime (CLOCK_MONOTONIC, &ts_start);
   double afteryou = 0.0;
+  string artifacttype, suffix;

   try
 {
@@ -2203,7 +2231,7 @@ handler_cb (void * /*cls*/,
   string buildid = url_copy.substr(slash1+1, slash2-slash1-1);

   size_t slash3 = url_copy.find('/', slash2+1);
-  string artifacttype, suffix;
+
   if (slash3 == string::npos)
 {
   artifacttype = url_copy.substr(slash2+1);
@@ -2275,17 +2303,20 @@ handler_cb (void * /*cls*/,
   // related prometheus metrics
   string http_code_str = to_string(http_code);
   if (http_size >= 0)
-add_metric("http_responses_transfer_bytes_sum","code",http_code_str,
-   http_size);
-  inc_metric("http_responses_transfer_bytes_count","code",http_code_str);
-
-
 add_metric("http_responses_duration_milliseconds_sum","code",http_code_str,
- deltas*1000); // prometheus prefers _seconds and floating
point
-
 inc_metric("http_responses_duration_milliseconds_count","code",http_code_str);
-
-
 add_metric("http_responses_after_you_milliseconds_sum","code",http_code_str,
- afteryou*1000);
-
 inc_metric("http_responses_after_you_milliseconds_count","code",http_code_str);
+add_metric("http_responses_transfer_bytes_sum",
+   "code", http_code_str, "type", artifacttype, http_size);
+  inc_metric("http_responses_transfer_bytes_count",
+ "code", http_code_str, "type", artifacttype);
+
+  add_metric("http_responses_duration_milliseconds_sum",
+ "code", http_code_str, "type", artifacttype, deltas*1000); //
prometheus prefers _seconds and floating point
+  inc_metric("http_responses_duration_milliseconds_count",
+ "code", http_code_str, "type", artifacttype);
+
+  add_metric("http_responses_after_you_milliseconds_sum",
+ "code", http_code_str, "type", artifacttype, afteryou*1000);
+  inc_metric("http_responses_after_you_milliseconds_count",
+ "code", http_code_str, "type", artifacttype);

   return rc;
 }
diff --git a/tests/run-debuginfod-000-permission.sh
b/tests/run-debuginfod-000-permission.sh
index 1e92bdb8..afa7e931 100755
--- a/tests/run-debuginfod-000-permission.sh
+++ b/tests/run-debuginfod-000-permission.sh
@@ -61,22 +61,22 @@ if [ -r $DEBUGINFOD_CACHE_PATH/01234567/debuginfo ];
then
   err
 fi

-bytecount_before=`curl -s http://127.0.0.1:$PORT1/metrics | grep
'http_responses_transfer_bytes_count{code="404"}'`
+bytecount_before=`curl -s http://127.0.0.1:$PORT1/metrics | grep
'http_responses_transfer_bytes_count{code="404",type="debuginfo"}'`
 testrun ${abs_top_builddir}/debuginfod/debuginfod-find debuginfo 01234567
|| true
-bytecount_after=`curl -s http://127.0.0.1:$PORT1/metrics | grep
'http_responses_transfer_bytes_count{code="404"}'`
+bytecount_after=`curl -s http://127.0.0.1:$PORT1/metrics | grep
'http_responses_transfer_bytes_count{code="404",type="debuginfo"}'`
 if [ "$bytecount_before" != "$bytecount_after" ]; then
-  ech

[PATCH] readelf: PR28928 - wrong dynamic section entry number

2022-03-01 Thread Di Chen via Elfutils-devel
commit 978663c5323cf402cd35b8614e41f24b587cbdd8 (HEAD -> dichen/DT_NULL,
origin/dichen/DT_NULL)
Author: Di Chen 
Date:   Tue Mar 1 20:44:38 2022 +0800

readelf: PR28928 - wrong dynamic section entry number

when using `$ eu-readelf -d {file}` to get the number of dynamic
section entris, It wrongly counts the padding DT_NULLs as dynamic
section entries. However, DT_NULL Marks end of dynamic section.
They should not be counted as dynamic section entries.

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

Signed-off-by: Di Chen 

diff --git a/src/readelf.c b/src/readelf.c
index 93fb5989..1bec3aa6 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -296,6 +296,7 @@ static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_scngrp (Ebl *ebl);
 static void print_dynamic (Ebl *ebl);
+static void handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
 static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
 static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
   GElf_Shdr *shdr);
@@ -1781,16 +1782,54 @@ print_dt_posflag_1 (int class, GElf_Xword d_val)
[dichen@arpeggio elfutils]$ git format-patch -1 HEAD
0001-readelf-PR28928-wrong-dynamic-section-entry-number.patch
[dichen@arpeggio elfutils]$ vim
0001-readelf-PR28928-wrong-dynamic-section-entry-number.patch
[dichen@arpeggio elfutils]$ cat
0001-readelf-PR28928-wrong-dynamic-section-entry-number.patch
>From 978663c5323cf402cd35b8614e41f24b587cbdd8 Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Tue, 1 Mar 2022 20:44:38 +0800
Subject: [PATCH] readelf: PR28928 - wrong dynamic section entry number

when using `$ eu-readelf -d {file}` to get the number of dynamic
section entris, It wrongly counts the padding DT_NULLs as dynamic
section entries. However, DT_NULL Marks end of dynamic section.
They should not be counted as dynamic section entries.

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

Signed-off-by: Di Chen 
---
 src/readelf.c  | 49 --
 tests/alldts.c |  5 +++--
 tests/run-alldts.sh|  2 +-
 tests/run-readelf-d.sh |  7 +-
 4 files changed, 48 insertions(+), 15 deletions(-)

diff --git a/src/readelf.c b/src/readelf.c
index 93fb5989..1bec3aa6 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -296,6 +296,7 @@ static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_scngrp (Ebl *ebl);
 static void print_dynamic (Ebl *ebl);
+static void handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
 static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
 static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
GElf_Shdr *shdr);
@@ -1781,16 +1782,54 @@ print_dt_posflag_1 (int class, GElf_Xword d_val)
 }


+static GElf_Phdr *
+get_dyn_phdr (Elf *elf)
+{
+  GElf_Phdr *phdr = NULL;
+  for (size_t i = 0; i < phnum; ++i) {
+GElf_Phdr phdr_mem;
+phdr = gelf_getphdr(elf, i, &phdr_mem);
+if (phdr->p_type == PT_DYNAMIC) {
+  break;
+}
+  }
+  return phdr;
+}
+
+
+static size_t
+get_dyn_scnents (Elf *elf, GElf_Phdr * dyn_phdr)
+{
+  Elf_Data *data = elf_getdata_rawchunk(
+   elf, dyn_phdr->p_offset, dyn_phdr->p_filesz, ELF_T_DYN);
+  GElf_Dyn *dyn;
+  size_t dyn_idx = 0;
+  do
+  {
+GElf_Dyn dyn_mem;
+dyn = gelf_getdyn(data, dyn_idx, &dyn_mem);
+++dyn_idx;
+  } while (dyn->d_tag != DT_NULL);
+
+  return dyn_idx;
+}
+
+
 static void
 handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 {
   int class = gelf_getclass (ebl->elf);
+  GElf_Phdr *dyn_phdr;
   GElf_Shdr glink_mem;
   GElf_Shdr *glink;
   Elf_Data *data;
   size_t cnt;
   size_t shstrndx;
-  size_t sh_entsize;
+  size_t dyn_scnents;
+
+  /* Calculate the dynamic section entry number */
+  dyn_phdr = get_dyn_phdr (ebl->elf);
+  dyn_scnents = get_dyn_scnents (ebl->elf, dyn_phdr);

   /* Get the data of the section.  */
   data = elf_getdata (scn, NULL);
@@ -1802,8 +1841,6 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr
*shdr)
 error (EXIT_FAILURE, 0,
_("cannot get section header string table index"));

-  sh_entsize = gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT);
-
   glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink_mem);
   if (glink == NULL)
 error (EXIT_FAILURE, 0, _("invalid sh_link value in section %zu"),
@@ -1813,15 +1850,15 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr
*shdr)
 \nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 "  Offset:
%#08" PRIx64 "  Link to section: [%2u] '%s'\n",
 "\
 \nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 "  Offset:
%#08" PRIx64 "  Link to section: [%2u] '%s'\n",
-shdr->sh_size / sh_entsize),
-  (unsigned long int) (shdr->sh_size / sh_entsize),
+dyn_scnents),
+  (unsigned long int) dyn_scnents,
   class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
   shdr->sh_offset,
   (int) shdr-

Re: [PATCH] readelf: PR28928 - wrong dynamic section entry number

2022-03-22 Thread Di Chen via Elfutils-devel
Hey team,
I made some changes for this patch:
(1) update the commit message to make it more clear
(2) tests/alldts.c needs the padding spaces for output comparison

On Tue, Mar 1, 2022 at 8:54 PM Di Chen  wrote:

> commit 978663c5323cf402cd35b8614e41f24b587cbdd8 (HEAD -> dichen/DT_NULL,
> origin/dichen/DT_NULL)
> Author: Di Chen 
> Date:   Tue Mar 1 20:44:38 2022 +0800
>
> readelf: PR28928 - wrong dynamic section entry number
>
> when using `$ eu-readelf -d {file}` to get the number of dynamic
> section entris, It wrongly counts the padding DT_NULLs as dynamic
> section entries. However, DT_NULL Marks end of dynamic section.
> They should not be counted as dynamic section entries.
>
> https://sourceware.org/bugzilla/show_bug.cgi?id=28928
>
> Signed-off-by: Di Chen 
>
> diff --git a/src/readelf.c b/src/readelf.c
> index 93fb5989..1bec3aa6 100644
> --- a/src/readelf.c
> +++ b/src/readelf.c
> @@ -296,6 +296,7 @@ static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
>  static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
>  static void print_scngrp (Ebl *ebl);
>  static void print_dynamic (Ebl *ebl);
> +static void handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
>  static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
>  static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
>GElf_Shdr *shdr);
> @@ -1781,16 +1782,54 @@ print_dt_posflag_1 (int class, GElf_Xword d_val)
> [dichen@arpeggio elfutils]$ git format-patch -1 HEAD
> 0001-readelf-PR28928-wrong-dynamic-section-entry-number.patch
> [dichen@arpeggio elfutils]$ vim
> 0001-readelf-PR28928-wrong-dynamic-section-entry-number.patch
> [dichen@arpeggio elfutils]$ cat
> 0001-readelf-PR28928-wrong-dynamic-section-entry-number.patch
> From 978663c5323cf402cd35b8614e41f24b587cbdd8 Mon Sep 17 00:00:00 2001
> From: Di Chen 
> Date: Tue, 1 Mar 2022 20:44:38 +0800
> Subject: [PATCH] readelf: PR28928 - wrong dynamic section entry number
>
> when using `$ eu-readelf -d {file}` to get the number of dynamic
> section entris, It wrongly counts the padding DT_NULLs as dynamic
> section entries. However, DT_NULL Marks end of dynamic section.
> They should not be counted as dynamic section entries.
>
> https://sourceware.org/bugzilla/show_bug.cgi?id=28928
>
> Signed-off-by: Di Chen 
> ---
>  src/readelf.c  | 49 --
>  tests/alldts.c |  5 +++--
>  tests/run-alldts.sh|  2 +-
>  tests/run-readelf-d.sh |  7 +-
>  4 files changed, 48 insertions(+), 15 deletions(-)
>
> diff --git a/src/readelf.c b/src/readelf.c
> index 93fb5989..1bec3aa6 100644
> --- a/src/readelf.c
> +++ b/src/readelf.c
> @@ -296,6 +296,7 @@ static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
>  static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
>  static void print_scngrp (Ebl *ebl);
>  static void print_dynamic (Ebl *ebl);
> +static void handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
>  static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
>  static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
> GElf_Shdr *shdr);
> @@ -1781,16 +1782,54 @@ print_dt_posflag_1 (int class, GElf_Xword d_val)
>  }
>
>
> +static GElf_Phdr *
> +get_dyn_phdr (Elf *elf)
> +{
> +  GElf_Phdr *phdr = NULL;
> +  for (size_t i = 0; i < phnum; ++i) {
> +GElf_Phdr phdr_mem;
> +phdr = gelf_getphdr(elf, i, &phdr_mem);
> +if (phdr->p_type == PT_DYNAMIC) {
> +  break;
> +}
> +  }
> +  return phdr;
> +}
> +
> +
> +static size_t
> +get_dyn_scnents (Elf *elf, GElf_Phdr * dyn_phdr)
> +{
> +  Elf_Data *data = elf_getdata_rawchunk(
> +   elf, dyn_phdr->p_offset, dyn_phdr->p_filesz, ELF_T_DYN);
> +  GElf_Dyn *dyn;
> +  size_t dyn_idx = 0;
> +  do
> +  {
> +GElf_Dyn dyn_mem;
> +dyn = gelf_getdyn(data, dyn_idx, &dyn_mem);
> +++dyn_idx;
> +  } while (dyn->d_tag != DT_NULL);
> +
> +  return dyn_idx;
> +}
> +
> +
>  static void
>  handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
>  {
>int class = gelf_getclass (ebl->elf);
> +  GElf_Phdr *dyn_phdr;
>GElf_Shdr glink_mem;
>GElf_Shdr *glink;
>Elf_Data *data;
>size_t cnt;
>size_t shstrndx;
> -  size_t sh_entsize;
> +  size_t dyn_scnents;
> +
> +  /* Calculate the dynamic section entry number */
> +  dyn_phdr = get_dyn_phdr (ebl->elf);
> +  dyn_scnents = get_dyn_scnents (ebl->elf, dyn_phdr);
>
>/* Get the data of the section.  */
>data = elf_getdata (scn, NULL);
> @@ -1802,8 +1841,6 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr
> *shdr)
>  error (EXIT_FAILURE, 0,
> _("cannot get section header string table index"));
>
> -  sh_entsize = gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT);
> -
>glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink_mem);
>if (glink == NULL)
>  error (EXIT_FAILURE, 0, _("invalid sh_link value in section %zu"),
> @@ -1813,15 +1850,15 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr
> *shdr)
>  \

Re: [PATCH] readelf: PR28928 - wrong dynamic section entry number

2022-03-30 Thread Di Chen via Elfutils-devel
>From b0da0a6f6c9a57a37a144a806ecd219a76c66b54 Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Tue, 1 Mar 2022 20:44:38 +0800
Subject: [PATCH] readelf: Don't consider padding DT_NULL as dynamic section
 entry

when using `$ eu-readelf -d {FILE}` to get the number of dynamic
section entris, it wrongly counts the padding DT_NULLs as dynamic
section entries. However, DT_NULL Marks end of dynamic section.
They should not be considered as dynamic section entries.

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

Signed-off-by: Di Chen 
---
 src/readelf.c  | 49 --
 tests/alldts.c |  5 +++--
 tests/run-alldts.sh|  2 +-
 tests/run-readelf-d.sh |  7 +-
 4 files changed, 48 insertions(+), 15 deletions(-)

diff --git a/src/readelf.c b/src/readelf.c
index 93fb5989..0d70bb47 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -296,6 +296,7 @@ static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_scngrp (Ebl *ebl);
 static void print_dynamic (Ebl *ebl);
+static void handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
 static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
 static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
GElf_Shdr *shdr);
@@ -1781,16 +1782,54 @@ print_dt_posflag_1 (int class, GElf_Xword d_val)
 }


+static GElf_Phdr *
+get_dyn_phdr (Elf *elf)
+{
+  GElf_Phdr *phdr = NULL;
+  for (size_t i = 0; i < phnum; ++i) {
+GElf_Phdr phdr_mem;
+phdr = gelf_getphdr(elf, i, &phdr_mem);
+if (phdr->p_type == PT_DYNAMIC) {
+  break;
+}
+  }
+  return phdr;
+}
+
+
+static size_t
+get_dyn_scnents (Elf *elf, GElf_Phdr * dyn_phdr)
+{
+  Elf_Data *data = elf_getdata_rawchunk(
+   elf, dyn_phdr->p_offset, dyn_phdr->p_filesz, ELF_T_DYN);
+  GElf_Dyn *dyn;
+  size_t dyn_idx = 0;
+  do
+  {
+GElf_Dyn dyn_mem;
+dyn = gelf_getdyn(data, dyn_idx, &dyn_mem);
+++dyn_idx;
+  } while (dyn->d_tag != DT_NULL);
+
+  return dyn_idx;
+}
+
+
 static void
 handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
 {
   int class = gelf_getclass (ebl->elf);
+  GElf_Phdr *dyn_phdr;
   GElf_Shdr glink_mem;
   GElf_Shdr *glink;
   Elf_Data *data;
   size_t cnt;
   size_t shstrndx;
-  size_t sh_entsize;
+  size_t dyn_scnents;
+
+  /* Get the dynamic section entry number */
+  dyn_phdr = get_dyn_phdr (ebl->elf);
+  dyn_scnents = get_dyn_scnents (ebl->elf, dyn_phdr);

   /* Get the data of the section.  */
   data = elf_getdata (scn, NULL);
@@ -1802,8 +1841,6 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr
*shdr)
 error (EXIT_FAILURE, 0,
_("cannot get section header string table index"));

-  sh_entsize = gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT);
-
   glink = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &glink_mem);
   if (glink == NULL)
 error (EXIT_FAILURE, 0, _("invalid sh_link value in section %zu"),
@@ -1813,15 +1850,15 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr
*shdr)
 \nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 "  Offset:
%#08" PRIx64 "  Link to section: [%2u] '%s'\n",
 "\
 \nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 "  Offset:
%#08" PRIx64 "  Link to section: [%2u] '%s'\n",
-shdr->sh_size / sh_entsize),
-  (unsigned long int) (shdr->sh_size / sh_entsize),
+dyn_scnents),
+  (unsigned long int) dyn_scnents,
   class == ELFCLASS32 ? 10 : 18, shdr->sh_addr,
   shdr->sh_offset,
   (int) shdr->sh_link,
   elf_strptr (ebl->elf, shstrndx, glink->sh_name));
   fputs_unlocked (_("  Type  Value\n"), stdout);

-  for (cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt)
+  for (cnt = 0; cnt < dyn_scnents; ++cnt)
 {
   GElf_Dyn dynmem;
   GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dynmem);
diff --git a/tests/alldts.c b/tests/alldts.c
index 3e9f9fe6..d0fe4f24 100644
--- a/tests/alldts.c
+++ b/tests/alldts.c
@@ -44,7 +44,7 @@ main (void)
   Dwelf_Strent *shstrtabse;
   const Elf32_Sword dtflags[] =
 {
-  DT_NULL, DT_NEEDED, DT_PLTRELSZ, DT_PLTGOT,
+  DT_NEEDED, DT_PLTRELSZ, DT_PLTGOT,
   DT_HASH, DT_STRTAB, DT_SYMTAB, DT_RELA,
   DT_RELASZ, DT_RELAENT, DT_STRSZ, DT_SYMENT,
   DT_INIT, DT_FINI, DT_SONAME, DT_RPATH,
@@ -61,7 +61,8 @@ main (void)
   DT_GNU_LIBLIST, DT_CONFIG, DT_DEPAUDIT, DT_AUDIT,
   DT_PLTPAD, DT_MOVETAB, DT_SYMINFO, DT_RELACOUNT,
   DT_RELCOUNT, DT_FLAGS_1, DT_VERDEF, DT_VERDEFNUM,
-  DT_VERNEED, DT_VERNEEDNUM, DT_AUXILIARY, DT_FILTER
+  DT_VERNEED, DT_VERNEEDNUM, DT_AUXILIARY, DT_FILTER,
+  DT_NULL
 };
   const int ndtflags = sizeof (dtflags) / sizeof (dtflags[0]);

diff --git a/tests/run-alldts.sh b/tests/run-alldts.sh
index 6a9a9ece..ce3630b0 100755
--- a/tests/run-alldts.sh
+++ b/tests/run-alldts.sh
@@ -27,7 +27,6 @@ testrun_compare ${abs_top_builddir}/src/readelf -d
testfile-alldts <<\EOF
 Dynamic segment contains 66 entries:
  Addr: 0x01a0  Offset: 0x78  Link to section:

Re: Proposing elfutils-0.187 for Monday 25 April

2022-04-15 Thread Di Chen via Elfutils-devel
Hey Mark,

The latest patch for PR28928 locates in bugzilla, and it's attached in
https://sourceware.org/bugzilla/show_bug.cgi?id=28928

Di

On Fri, Apr 15, 2022 at 6:41 PM Mark Wielaard  wrote:

> Hi,
>
> It has been 5 months since elfutils 0.186 was released. There have been
> more than 70 commits since then. And 20 bugs closed.
>
> I propose we do an elfutils 0.187 release Monday 25 April.
>
> There are still a couple of unreviewed patches:
> https://patchwork.sourceware.org/project/elfutils/list/
> I'll try to go over them all before the release.
>
> If there are any other issues left, please let me know.
>
> Lets try to do the next release in 3 months, so there isn't such a big
> gap between releases.
>
> Cheers,
>
> Mark
>
>


[PATCH] readelf: Support --dynamic with --use-dynamic

2022-05-05 Thread Di Chen via Elfutils-devel
>From 3ac23c2584d76114deab0c0af6f4af99068dc7f4 Mon Sep 17 00:00:00 2001
From: Di Chen 
Date: Thu, 28 Apr 2022 19:55:33 +0800
Subject: [PATCH] readelf: Support --dynamic with --use-dynamic

Currently, eu-readelf is using section headers to dump the dynamic
segment information (print_dynamic -> handle_dynamic).

This patch adds new options to eu-readelf (-D, --use-dynamic)
for (-d, --dynamic).

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

Signed-off-by: Di Chen 
---
 src/readelf.c   | 168 +---
 tests/Makefile.am   |   3 +-
 tests/run-readelf-Dd.sh |  65 
 3 files changed, 223 insertions(+), 13 deletions(-)
 create mode 100755 tests/run-readelf-Dd.sh

diff --git a/src/readelf.c b/src/readelf.c
index 4b6aab2b..e578456b 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -137,6 +137,8 @@ static const struct argp_option options[] =
   { "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
   { "archive-index", 'c', NULL, 0,
 N_("Display the symbol index of an archive"), 0 },
+  { "use-dynamic", 'D', NULL, 0,
+N_("Use the dynamic section info when displaying symbols"), 0 },

   { NULL, 0, NULL, 0, N_("Output control:"), 0 },
   { "numeric-addresses", 'N', NULL, 0,
@@ -195,6 +197,9 @@ static bool print_symbol_table;
 /* True if (only) the dynsym table should be printed.  */
 static bool print_dynsym_table;

+/* True if reconstruct dynamic symbol table from the PT_DYNAMIC segment.
 */
+static bool use_dynamic_segment;
+
 /* A specific section name, or NULL to print all symbol tables.  */
 static char *symbol_table_section;

@@ -268,6 +273,19 @@ static enum section_e
  | section_macro | section_addr | section_types)
 } print_debug_sections, implicit_debug_sections;

+enum dyn_idx
+{
+  i_strsz,
+  i_verneed,
+  i_verdef,
+  i_versym,
+  i_symtab,
+  i_strtab,
+  i_hash,
+  i_gnu_hash,
+  i_max
+};
+
 /* Select hex dumping of sections.  */
 static struct section_argument *dump_data_sections;
 static struct section_argument **dump_data_sections_tail =
&dump_data_sections;
@@ -318,6 +336,11 @@ static void dump_strings (Ebl *ebl);
 static void print_strings (Ebl *ebl);
 static void dump_archive_index (Elf *, const char *);

+/* Declarations of local functions for use-dynamic.  */
+static Elf_Data * get_dynscn_strtab(Elf *elf, GElf_Phdr *phdr);
+static void get_dynscn_addrs(Elf *elf, GElf_Phdr *phdr, GElf_Addr
addrs[i_max]);
+static void find_offsets(Elf *elf, GElf_Addr main_bias, size_t n,
+GElf_Addr addrs[n], GElf_Off offs[n]);

 /* Looked up once with gettext in main.  */
 static char *yes_str;
@@ -429,6 +452,9 @@ parse_opt (int key, char *arg,
   print_dynamic_table = true;
   any_control_option = true;
   break;
+case 'D':
+  use_dynamic_segment = true;
+  break;
 case 'e':
   print_debug_sections |= section_exception;
   any_control_option = true;
@@ -1791,7 +1817,7 @@ get_dyn_ents (Elf_Data * dyn_data)


 static void
-handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, GElf_Phdr *phdr)
 {
   int class = gelf_getclass (ebl->elf);
   GElf_Shdr glink_mem;
@@ -1802,13 +1828,20 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr
*shdr)
   size_t dyn_ents;

   /* Get the data of the section.  */
-  data = elf_getdata (scn, NULL);
+  if (use_dynamic_segment)
+data = elf_getdata_rawchunk(
+  ebl->elf, phdr->p_offset, phdr->p_filesz, ELF_T_DYN);
+  else
+data = elf_getdata (scn, NULL);
+
   if (data == NULL)
 return;

   /* Get the dynamic section entry number */
   dyn_ents = get_dyn_ents (data);

+  if (!use_dynamic_segment)
+{
   /* Get the section header string table index.  */
   if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0))
 error_exit (0, _("cannot get section header string table index"));
@@ -1828,8 +1861,25 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr
*shdr)
   shdr->sh_offset,
   (int) shdr->sh_link,
   elf_strptr (ebl->elf, shstrndx, glink->sh_name));
+} else {
+  printf (ngettext ("\
+\nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 "  Offset:
%#08" PRIx64 "\n",
+"\
+\nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 "  Offset:
%#08" PRIx64 "\n",
+dyn_ents),
+  (unsigned long int) dyn_ents,
+  class == ELFCLASS32 ? 10 : 18, phdr->p_paddr,
+  phdr->p_offset);
+}
+
   fputs_unlocked (_("  Type  Value\n"), stdout);

+  /* if --use-dynamic option is enabled,
+ use the string table to get the related library info.  */
+  Elf_Data *strtab_data = NULL;
+  if (use_dynamic_segment)
+strtab_data = get_dynscn_strtab(ebl->elf, phdr);
+
   for (cnt = 0; cnt < dyn_ents; ++cnt)
 {
   GElf_Dyn dynmem;
@@ -1841,6 +1891,12 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr
*shdr)
   printf ("  %-17s ",
   ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf)));

+  char *lib_name = NULL;
+  if (use_dynamic_seg

Re: [PATCH] readelf: Support --dynamic with --use-dynamic

2022-05-24 Thread Di Chen via Elfutils-devel
Thanks Mark,

All the request changes are fixed, ready for review again.

1. help message updated: "Use the dynamic segment when possible for
displaying info"
2. move enum dyn_idx to a proper place
3. add strtab_data's NULL check in function: handle_dynamic()
4. add phdr's NULL check in function: print_dynamic()
5. add comments for function: find_offsets()
6. remove redundant return-statement in function: get_dynscn_addrs()
7. add run-readelf-Dd.sh to EXTRA_DISTS
8. check strsz in (dyn->d_un.d_ptr < strtab_data->d_size) in function:
handle_dynamic()


On Fri, May 20, 2022 at 8:41 AM Mark Wielaard  wrote:

> Hi,
>
> On Thu, May 05, 2022 at 09:01:24PM +0800, Di Chen via Elfutils-devel wrote:
> > From 3ac23c2584d76114deab0c0af6f4af99068dc7f4 Mon Sep 17 00:00:00 2001
> > From: Di Chen 
> > Date: Thu, 28 Apr 2022 19:55:33 +0800
> > Subject: [PATCH] readelf: Support --dynamic with --use-dynamic
> >
> > Currently, eu-readelf is using section headers to dump the dynamic
> > segment information (print_dynamic -> handle_dynamic).
> >
> > This patch adds new options to eu-readelf (-D, --use-dynamic)
> > for (-d, --dynamic).
> >
> > https://sourceware.org/bugzilla/show_bug.cgi?id=28873
>
> This looks pretty good. But there are lots of white-space issues which
> make it hard to apply the patch. Could you sent it again preferrably
> using git send-email ?
>
> > Signed-off-by: Di Chen 
> > ---
> >  src/readelf.c   | 168 +---
> >  tests/Makefile.am   |   3 +-
> >  tests/run-readelf-Dd.sh |  65 
> >  3 files changed, 223 insertions(+), 13 deletions(-)
> >  create mode 100755 tests/run-readelf-Dd.sh
> >
> > diff --git a/src/readelf.c b/src/readelf.c
> > index 4b6aab2b..e578456b 100644
> > --- a/src/readelf.c
> > +++ b/src/readelf.c
> > @@ -137,6 +137,8 @@ static const struct argp_option options[] =
> >{ "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 },
> >{ "archive-index", 'c', NULL, 0,
> >  N_("Display the symbol index of an archive"), 0 },
> > +  { "use-dynamic", 'D', NULL, 0,
> > +N_("Use the dynamic section info when displaying symbols"), 0 },
>
> This doesn't handle symbols yet. Should it simply say:
> "Use the dynamic segment when possible for displaying info"
>
> >{ NULL, 0, NULL, 0, N_("Output control:"), 0 },
> >{ "numeric-addresses", 'N', NULL, 0,
> > @@ -195,6 +197,9 @@ static bool print_symbol_table;
> >  /* True if (only) the dynsym table should be printed.  */
> >  static bool print_dynsym_table;
> >
> > +/* True if reconstruct dynamic symbol table from the PT_DYNAMIC segment.
> >  */
> > +static bool use_dynamic_segment;
> > +
> >  /* A specific section name, or NULL to print all symbol tables.  */
> >  static char *symbol_table_section;
> >
> > @@ -268,6 +273,19 @@ static enum section_e
> >   | section_macro | section_addr | section_types)
> >  } print_debug_sections, implicit_debug_sections;
> >
> > +enum dyn_idx
> > +{
> > +  i_strsz,
> > +  i_verneed,
> > +  i_verdef,
> > +  i_versym,
> > +  i_symtab,
> > +  i_strtab,
> > +  i_hash,
> > +  i_gnu_hash,
> > +  i_max
> > +};
>
> Maybe move this just before it is used in declarations of the
> get_dyn... functions?
>
> >  /* Select hex dumping of sections.  */
> >  static struct section_argument *dump_data_sections;
> >  static struct section_argument **dump_data_sections_tail =
> > &dump_data_sections;
> > @@ -318,6 +336,11 @@ static void dump_strings (Ebl *ebl);
> >  static void print_strings (Ebl *ebl);
> >  static void dump_archive_index (Elf *, const char *);
> >
> > +/* Declarations of local functions for use-dynamic.  */
> > +static Elf_Data * get_dynscn_strtab(Elf *elf, GElf_Phdr *phdr);
> > +static void get_dynscn_addrs(Elf *elf, GElf_Phdr *phdr, GElf_Addr
> > addrs[i_max]);
> > +static void find_offsets(Elf *elf, GElf_Addr main_bias, size_t n,
> > +GElf_Addr addrs[n], GElf_Off offs[n]);
>
> I mean, just before these.
>
> >  /* Looked up once with gettext in main.  */
> >  static char *yes_str;
> > @@ -429,6 +452,9 @@ parse_opt (int key, char *arg,
> >print_dynamic_table = true;
> >any_control_option = true;
> >break;
> > +case 'D':
> > +  use_dynamic_segment = true;
> > +  break;
>

[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

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

2022-07-29 Thread Di Chen via Elfutils-devel
Thanks for the review, Mark.

Re-pushed a patch for it.

1. NEWS entry added.
2. __libdwfl_frame_reg_get/dwfl_frame_reg updated with return int.
3. New DWFL_ERROR added: REGISTER_VAL_UNKNOWN.


On Thu, Jul 21, 2022 at 10:32 PM Mark Wielaard  wrote:

> Hi,
>
> On Tue, Jul 19, 2022 at 10:21:21PM +0800, Di Chen via Elfutils-devel wrote:
> > 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.
>
> This looks mostly fine, some comments below. But it is hard to apply
> since your mailer seems to break up lines. If you cannot use git
> send-email to send patches it might be easier to use git format-patch
> and attach the result. Or to use the sourcehut mirror to create a
> fork, push your patches there and let sourcehut sent the patches as
> email: https://git.sr.ht/~sourceware/elfutils
>
> > 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;
>
> Good. Could you also add a NEWS entry for the new public function?
>
> > 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;
> > +}
>
> I see what you want to do here.  First check if the register is
> actually saved in the frame, if not return an DWFL_E_INVALID_REGNO. If
> it is set, then get the value and return it (or if that fails, return
> a different error DWFL_E_INVALID_REGISTER).
>
> But dwfl_frame_reg takes a DWARF register number, but the regs_set
> array uses an internal numbering. You first have to translate the
> numbering using ebl_dwarf_to_regno.
>
> Also we might want to give a better error than DWFL_E_INVALID_REGNO
> when the register is simply unknown. DWFL_E_REGISTER_VAL_UNKNOWN
> maybe?
>
> The real problem is that __libdwfl_frame_reg_get returns a boolean,
> true if things worked fine and the register value is known, false if
> the register value is unknown or the DWARF register number was invalid
> or some other error occured.
>
> It might be an idea to change the interface of __libdwfl_frame_reg_get
> (and dwfl_frame_reg) to return an int. With zero as success. -1 for an
> error (invalid register number) and 1 for a valid DWARF register
> value, but the register value for the given frame is
> unknown. __libdwfl_frame_reg_get could then also call
> __libdwfl_seterrno itself.
>
> This does need a few more code changes though. Changing all calls to
> __libdwfl_frame_reg_get with if (__libdwfl_frame_reg_get (state,
> regno, &val) == 0). And remove any redundant __libdwfl_seterrno calls.
>
> > +INTDEF(dwfl_frame_reg)
>
> Good. Now you can use INTUSE (dwfl_frame_reg) for internal calls.
&

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

2022-07-29 Thread Di Chen via Elfutils-devel
Re-pushed for fixing run-backtrace-core-sparc.sh failure which resulted
from some wrong register number.

On Fri, Jul 29, 2022 at 9:27 PM Di Chen  wrote:

> Thanks for the review, Mark.
>
> Re-pushed a patch for it.
>
> 1. NEWS entry added.
> 2. __libdwfl_frame_reg_get/dwfl_frame_reg updated with return int.
> 3. New DWFL_ERROR added: REGISTER_VAL_UNKNOWN.
>
>
> On Thu, Jul 21, 2022 at 10:32 PM Mark Wielaard  wrote:
>
>> Hi,
>>
>> On Tue, Jul 19, 2022 at 10:21:21PM +0800, Di Chen via Elfutils-devel
>> wrote:
>> > 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.
>>
>> This looks mostly fine, some comments below. But it is hard to apply
>> since your mailer seems to break up lines. If you cannot use git
>> send-email to send patches it might be easier to use git format-patch
>> and attach the result. Or to use the sourcehut mirror to create a
>> fork, push your patches there and let sourcehut sent the patches as
>> email: https://git.sr.ht/~sourceware/elfutils
>>
>> > 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;
>>
>> Good. Could you also add a NEWS entry for the new public function?
>>
>> > 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;
>> > +}
>>
>> I see what you want to do here.  First check if the register is
>> actually saved in the frame, if not return an DWFL_E_INVALID_REGNO. If
>> it is set, then get the value and return it (or if that fails, return
>> a different error DWFL_E_INVALID_REGISTER).
>>
>> But dwfl_frame_reg takes a DWARF register number, but the regs_set
>> array uses an internal numbering. You first have to translate the
>> numbering using ebl_dwarf_to_regno.
>>
>> Also we might want to give a better error than DWFL_E_INVALID_REGNO
>> when the register is simply unknown. DWFL_E_REGISTER_VAL_UNKNOWN
>> maybe?
>>
>> The real problem is that __libdwfl_frame_reg_get returns a boolean,
>> true if things worked fine and the register value is known, false if
>> the register value is unknown or the DWARF register number was invalid
>> or some other error occured.
>>
>> It might be an idea to change the interface of __libdwfl_frame_reg_get
>> (and dwfl_frame_reg) to return an int. With zero as su