commit 9c99dbdee8a1543ec0376eac65e478a293e129f1
parent cae81184b5b5bea7341d40adc9a9d19314aa63aa
Author: Christos Margiolis <christos@margiolis.net>
Date: Sun, 12 Feb 2023 23:16:15 +0200
fixed bugs, packed info into a struct
Diffstat:
M | inlinecall.c | | | 307 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
1 file changed, 186 insertions(+), 121 deletions(-)
diff --git a/inlinecall.c b/inlinecall.c
@@ -1,9 +1,12 @@
+#include <sys/queue.h>
+
#include <dwarf.h>
#include <err.h>
#include <fcntl.h>
#include <libdwarf.h>
#include <libelf.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -12,127 +15,28 @@ enum {
F_INLINE_COPY,
};
-static char **srcfiles;
+TAILQ_HEAD(, die_info) diehead = TAILQ_HEAD_INITIALIZER(diehead);
-static void
-print_info(Dwarf_Debug dbg, Dwarf_Die die_root, Dwarf_Die die,
- Dwarf_Off dieoff, int flag)
-{
- Dwarf_Ranges *ranges, *rp;
- Dwarf_Attribute attp;
- Dwarf_Addr v_addr;
- Dwarf_Off v_off;
- Dwarf_Unsigned v_udata, line, nbytes;
- Dwarf_Signed nranges;
- Dwarf_Half attr;
- Dwarf_Bool v_flag;
- Dwarf_Error error;
- char *file = NULL;
- int res, i;
+struct die_info {
+ Dwarf_Off *addr_lo;
+ Dwarf_Off *addr_hi;
+ int naddrs;
+ Dwarf_Unsigned line;
+ const char *file;
+ int flag;
+ TAILQ_ENTRY(die_info) next;
+};
- attr = (flag == F_SUBPROGRAM) ? DW_AT_decl_file : DW_AT_call_file;
- res = dwarf_attr(die, attr, &attp, &error);
- if (res != DW_DLV_OK) {
- if (res == DW_DLV_ERROR)
- warnx("%s", dwarf_errmsg(error));
- goto skip;
- }
- if (dwarf_formudata(attp, &v_udata, &error) != DW_DLV_OK) {
- warnx("%s", dwarf_errmsg(error));
- return;
- }
- file = srcfiles[v_udata - 1];
+static char **srcfiles;
- attr = (flag == F_SUBPROGRAM) ? DW_AT_decl_line: DW_AT_call_line;
- res = dwarf_attr(die, attr, &attp, &error);
- if (res != DW_DLV_OK) {
- if (res == DW_DLV_ERROR)
- warnx("%s", dwarf_errmsg(error));
- goto skip;
- }
- if (dwarf_formudata(attp, &line, &error) != DW_DLV_OK) {
- warnx("%s", dwarf_errmsg(error));
- return;
- }
+static void *
+emalloc(size_t nb)
+{
+ void *p;
-skip:
- if (flag == F_INLINE_COPY) {
- if (dwarf_hasattr(die, DW_AT_ranges, &v_flag, &error) !=
- DW_DLV_OK) {
- warnx("%s", dwarf_errmsg(error));
- return;
- }
- if (v_flag) {
- /* DIE has ranges */
- res = dwarf_attr(die, DW_AT_ranges, &attp, &error);
- if (res != DW_DLV_OK) {
- if (res == DW_DLV_ERROR)
- warnx("%s", dwarf_errmsg(error));
- return;
- }
- if (dwarf_global_formref(attp, &v_off, &error) !=
- DW_DLV_OK) {
- warnx("%s", dwarf_errmsg(error));
- return;
- }
- if (dwarf_get_ranges(dbg, v_off, &ranges, &nranges,
- &nbytes, &error) != DW_DLV_OK) {
- warnx("%s", dwarf_errmsg(error));
- return;
- }
- for (i = 0; i < nranges - 1; i++) {
- rp = &ranges[i];
- res = dwarf_attr(die_root, DW_AT_low_pc, &attp,
- &error);
- if (res != DW_DLV_OK) {
- if (res == DW_DLV_ERROR)
- warnx("%s", dwarf_errmsg(error));
- break;
- }
- if (dwarf_formaddr(attp, &v_addr, &error) !=
- DW_DLV_OK) {
- warnx("%s", dwarf_errmsg(error));
- break;
- }
- printf("\t[0x%jx - 0x%jx]",
- v_addr + rp->dwr_addr1,
- v_addr + rp->dwr_addr2);
- if (file != NULL)
- printf("\t%s:%lu\n", file, line);
- }
- dwarf_ranges_dealloc(dbg, ranges, nranges);
- } else {
- /* DIE has high/low PC boundaries */
- res = dwarf_attr(die, DW_AT_low_pc, &attp, &error);
- if (res != DW_DLV_OK) {
- if (res == DW_DLV_ERROR)
- warnx("%s", dwarf_errmsg(error));
- return;
- }
- if (dwarf_formaddr(attp, &v_addr, &error) != DW_DLV_OK) {
- warnx("%s", dwarf_errmsg(error));
- return;
- }
- res = dwarf_attr(die, DW_AT_high_pc, &attp, &error);
- if (res != DW_DLV_OK) {
- if (res == DW_DLV_ERROR)
- warnx("%s", dwarf_errmsg(error));
- return;
- }
- if (dwarf_formudata(attp, &v_udata, &error) !=
- DW_DLV_OK) {
- warnx("%s", dwarf_errmsg(error));
- return;
- }
- printf("\t[0x%jx - 0x%jx]", v_addr, v_addr + v_udata);
- if (file != NULL)
- printf("\t%s:%lu\n", file, line);
- else
- putchar('\n');
- }
- } else {
- printf("%s:%lu\n", file, line);
- }
+ if ((p = malloc(nb)) == NULL)
+ err(1, "malloc");
+ return (p);
}
static void
@@ -140,16 +44,21 @@ parse_die(Dwarf_Debug dbg, Dwarf_Die die, void *data, int level, int flag)
{
static Dwarf_Die die_root;
Dwarf_Die die_next;
+ Dwarf_Ranges *ranges, *rp;
Dwarf_Attribute attp, *attr_list;
Dwarf_Off dieoff, cuoff, culen, v_off;
Dwarf_Addr v_addr;
- Dwarf_Unsigned v_udata;
- Dwarf_Signed nattr, v_sdata;
+ Dwarf_Addr *addr_lo, *addr_hi;
+ Dwarf_Unsigned v_udata, line, nbytes;
+ Dwarf_Signed nattr, v_sdata, nranges;
Dwarf_Half tag, attr, form;
Dwarf_Bool v_flag;
Dwarf_Error error;
+ struct die_info *di;
const char *str;
+ char *file = NULL;
char *v_str;
+ int naddrs;
int res, i, found = 0;
/* Save the root DIE so that we can re-parse it. */
@@ -210,13 +119,137 @@ parse_die(Dwarf_Debug dbg, Dwarf_Die die, void *data, int level, int flag)
v_off += cuoff;
if (v_off != (Dwarf_Off)data)
goto cont;
+ if (dwarf_hasattr(die, DW_AT_ranges, &v_flag, &error) !=
+ DW_DLV_OK) {
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+ if (v_flag) {
+ /* DIE has ranges */
+ res = dwarf_attr(die, DW_AT_ranges, &attp, &error);
+ if (res != DW_DLV_OK) {
+ if (res == DW_DLV_ERROR)
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+ if (dwarf_global_formref(attp, &v_off, &error) !=
+ DW_DLV_OK) {
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+ if (dwarf_get_ranges(dbg, v_off, &ranges, &nranges,
+ &nbytes, &error) != DW_DLV_OK) {
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+ naddrs = nranges - 1;
+ addr_lo = emalloc(naddrs * sizeof(Dwarf_Off));
+ addr_hi = emalloc(naddrs * sizeof(Dwarf_Off));
+ for (i = 0; i < naddrs; i++) {
+ rp = &ranges[i];
+ res = dwarf_attr(die_root, DW_AT_low_pc, &attp,
+ &error);
+ if (res != DW_DLV_OK) {
+ if (res == DW_DLV_ERROR)
+ warnx("%s", dwarf_errmsg(error));
+ break;
+ }
+ if (dwarf_formaddr(attp, &v_addr, &error) !=
+ DW_DLV_OK) {
+ warnx("%s", dwarf_errmsg(error));
+ break;
+ }
+ addr_lo[i] = v_addr + rp->dwr_addr1;
+ addr_hi[i] = v_addr + rp->dwr_addr2;
+ }
+ dwarf_ranges_dealloc(dbg, ranges, nranges);
+ } else {
+ /* DIE has high/low PC boundaries */
+ res = dwarf_attr(die, DW_AT_low_pc, &attp, &error);
+ if (res != DW_DLV_OK) {
+ if (res == DW_DLV_ERROR)
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+ if (dwarf_formaddr(attp, &v_addr, &error) != DW_DLV_OK) {
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+ res = dwarf_attr(die, DW_AT_high_pc, &attp, &error);
+ if (res != DW_DLV_OK) {
+ if (res == DW_DLV_ERROR)
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+ if (dwarf_formudata(attp, &v_udata, &error) !=
+ DW_DLV_OK) {
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+ naddrs = 1;
+ addr_lo = emalloc(sizeof(Dwarf_Off));
+ addr_hi = emalloc(sizeof(Dwarf_Off));
+ addr_lo[0] = v_addr;
+ addr_hi[0] = v_addr + v_udata;
+ }
} else
goto cont;
- print_info(dbg, die_root, die, dieoff, flag);
+
+ /* Get file:line */
+ attr = (flag == F_SUBPROGRAM) ? DW_AT_decl_file : DW_AT_call_file;
+ res = dwarf_attr(die, attr, &attp, &error);
+ if (res != DW_DLV_OK) {
+ if (res == DW_DLV_ERROR)
+ warnx("%s", dwarf_errmsg(error));
+ goto skip;
+ }
+ if (dwarf_formudata(attp, &v_udata, &error) != DW_DLV_OK) {
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+ file = srcfiles[v_udata - 1];
+
+ attr = (flag == F_SUBPROGRAM) ? DW_AT_decl_line: DW_AT_call_line;
+ res = dwarf_attr(die, attr, &attp, &error);
+ if (res != DW_DLV_OK) {
+ if (res == DW_DLV_ERROR)
+ warnx("%s", dwarf_errmsg(error));
+ goto skip;
+ }
+ if (dwarf_formudata(attp, &line, &error) != DW_DLV_OK) {
+ warnx("%s", dwarf_errmsg(error));
+ goto cont;
+ }
+skip:
+ di = emalloc(sizeof(struct die_info));
+ di->flag = flag;
+ if (file != NULL) {
+ di->file = file;
+ di->line = line;
+ } else
+ di->file = NULL;
+ if (di->flag == F_INLINE_COPY) {
+ di->naddrs = naddrs;
+ di->addr_lo = addr_lo;
+ di->addr_hi = addr_hi;
+ }
+ TAILQ_INSERT_TAIL(&diehead, di, next);
cont:
/*
* Inline copies might appear before the declaration, so we need to
* re-parse the CU.
+ *
+ * The rationale for choosing to re-parse the CU instead of using a
+ * hash table of DIEs is that, because we re-parse only when an inline
+ * definition of the function we want is found. This means that,
+ * statistically, we won't have to re-parse many times at all
+ * considering that only a handful of CUs will define the function,
+ * whereas if we have used a hash table, we would first need to parse
+ * the whole CU at once and store all DW_TAG_inlined_subroutine DIEs
+ * (so that we can match them afterwards). In this case, we always have
+ * to "parse" twice -- first the CU, then the DIE table -- and also,
+ * the program would use much more memory since we would have allocated
+ * DIEs, which most of them would never be used.
*/
if (found) {
die = die_root;
@@ -245,6 +278,36 @@ cont:
dwarf_dealloc(dbg, die, DW_DLA_DIE);
}
+static void
+print_info(void)
+{
+ struct die_info *di;
+ int i;
+
+ /* Clean up as well */
+ while (!TAILQ_EMPTY(&diehead)) {
+ di = TAILQ_FIRST(&diehead);
+ TAILQ_REMOVE(&diehead, di, next);
+ if (di->flag == F_INLINE_COPY) {
+ for (i = 0; i < di->naddrs; i++) {
+ printf("\t[0x%jx - 0x%jx]",
+ di->addr_lo[i],
+ di->addr_hi[i]);
+ if (di->file != NULL) {
+ printf("\t%s:%lu\n",
+ di->file, di->line);
+ } else
+ putchar('\n');
+ }
+ free(di->addr_lo);
+ free(di->addr_hi);
+ } else if (di->flag == F_SUBPROGRAM) {
+ printf("%s:%lu\n", di->file, di->line);
+ }
+ free(di);
+ }
+}
+
int
main(int argc, char *argv[])
{
@@ -280,6 +343,7 @@ main(int argc, char *argv[])
while ((res = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL,
NULL, &error)) == DW_DLV_OK) {
die = NULL;
+ TAILQ_INIT(&diehead);
while (dwarf_siblingof(dbg, die, &die, &error) ==
DW_DLV_OK) {
srcfiles = NULL;
@@ -287,8 +351,9 @@ main(int argc, char *argv[])
&error) != DW_DLV_OK)
warnx("%s", dwarf_errmsg(error));
parse_die(dbg, die, func, 0, F_SUBPROGRAM);
- dwarf_dealloc(dbg, die, DW_DLA_DIE);
}
+ dwarf_dealloc(dbg, die, DW_DLA_DIE);
+ print_info();
}
if (res == DW_DLV_ERROR)
warnx("%s", dwarf_errmsg(error));