mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 12:21:22 -05:00
gendwarfksyms: Expand base_type
Start making gendwarfksyms more useful by adding support for
expanding DW_TAG_base_type types and basic DWARF attributes.
Example:
$ echo loops_per_jiffy | \
scripts/gendwarfksyms/gendwarfksyms \
--debug --dump-dies vmlinux.o
...
gendwarfksyms: process_symbol: loops_per_jiffy
variable base_type unsigned long byte_size(8) encoding(7)
...
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Reviewed-by: Petr Pavlu <petr.pavlu@suse.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
This commit is contained in:
committed by
Masahiro Yamada
parent
e982abf437
commit
5b7780e868
@@ -3,8 +3,21 @@
|
||||
* Copyright (C) 2024 Google LLC
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include "gendwarfksyms.h"
|
||||
|
||||
#define DEFINE_GET_ATTR(attr, type) \
|
||||
static bool get_##attr##_attr(Dwarf_Die *die, unsigned int id, \
|
||||
type *value) \
|
||||
{ \
|
||||
Dwarf_Attribute da; \
|
||||
return dwarf_attr(die, id, &da) && \
|
||||
!dwarf_form##attr(&da, value); \
|
||||
}
|
||||
|
||||
DEFINE_GET_ATTR(udata, Dwarf_Word)
|
||||
|
||||
static bool get_ref_die_attr(Dwarf_Die *die, unsigned int id, Dwarf_Die *value)
|
||||
{
|
||||
Dwarf_Attribute da;
|
||||
@@ -67,6 +80,109 @@ static void process(const char *s)
|
||||
fputs(s, stderr);
|
||||
}
|
||||
|
||||
#define MAX_FMT_BUFFER_SIZE 128
|
||||
|
||||
static void process_fmt(const char *fmt, ...)
|
||||
{
|
||||
char buf[MAX_FMT_BUFFER_SIZE];
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
if (checkp(vsnprintf(buf, sizeof(buf), fmt, args)) >= sizeof(buf))
|
||||
error("vsnprintf overflow: increase MAX_FMT_BUFFER_SIZE");
|
||||
|
||||
process(buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define MAX_FQN_SIZE 64
|
||||
|
||||
/* Get a fully qualified name from DWARF scopes */
|
||||
static char *get_fqn(Dwarf_Die *die)
|
||||
{
|
||||
const char *list[MAX_FQN_SIZE];
|
||||
Dwarf_Die *scopes = NULL;
|
||||
bool has_name = false;
|
||||
char *fqn = NULL;
|
||||
char *p;
|
||||
int count = 0;
|
||||
int len = 0;
|
||||
int res;
|
||||
int i;
|
||||
|
||||
res = checkp(dwarf_getscopes_die(die, &scopes));
|
||||
if (!res) {
|
||||
list[count] = get_name_attr(die);
|
||||
|
||||
if (!list[count])
|
||||
return NULL;
|
||||
|
||||
len += strlen(list[count]);
|
||||
count++;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = res - 1; i >= 0 && count < MAX_FQN_SIZE; i--) {
|
||||
if (dwarf_tag(&scopes[i]) == DW_TAG_compile_unit)
|
||||
continue;
|
||||
|
||||
list[count] = get_name_attr(&scopes[i]);
|
||||
|
||||
if (list[count]) {
|
||||
has_name = true;
|
||||
} else {
|
||||
list[count] = "<anonymous>";
|
||||
has_name = false;
|
||||
}
|
||||
|
||||
len += strlen(list[count]);
|
||||
count++;
|
||||
|
||||
if (i > 0) {
|
||||
list[count++] = "::";
|
||||
len += 2;
|
||||
}
|
||||
}
|
||||
|
||||
free(scopes);
|
||||
|
||||
if (count == MAX_FQN_SIZE)
|
||||
warn("increase MAX_FQN_SIZE: reached the maximum");
|
||||
|
||||
/* Consider the DIE unnamed if the last scope doesn't have a name */
|
||||
if (!has_name)
|
||||
return NULL;
|
||||
done:
|
||||
fqn = xmalloc(len + 1);
|
||||
*fqn = '\0';
|
||||
|
||||
p = fqn;
|
||||
for (i = 0; i < count; i++)
|
||||
p = stpcpy(p, list[i]);
|
||||
|
||||
return fqn;
|
||||
}
|
||||
|
||||
static void process_fqn(Dwarf_Die *die)
|
||||
{
|
||||
process(" ");
|
||||
process(get_fqn(die) ?: "");
|
||||
}
|
||||
|
||||
#define DEFINE_PROCESS_UDATA_ATTRIBUTE(attribute) \
|
||||
static void process_##attribute##_attr(Dwarf_Die *die) \
|
||||
{ \
|
||||
Dwarf_Word value; \
|
||||
if (get_udata_attr(die, DW_AT_##attribute, &value)) \
|
||||
process_fmt(" " #attribute "(%" PRIu64 ")", value); \
|
||||
}
|
||||
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment)
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size)
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding)
|
||||
|
||||
bool match_all(Dwarf_Die *die)
|
||||
{
|
||||
return true;
|
||||
@@ -93,6 +209,49 @@ int process_die_container(struct state *state, Dwarf_Die *die,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_type(struct state *state, Dwarf_Die *die);
|
||||
|
||||
static void process_type_attr(struct state *state, Dwarf_Die *die)
|
||||
{
|
||||
Dwarf_Die type;
|
||||
|
||||
if (get_ref_die_attr(die, DW_AT_type, &type)) {
|
||||
check(process_type(state, &type));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Compilers can omit DW_AT_type -- print out 'void' to clarify */
|
||||
process("base_type void");
|
||||
}
|
||||
|
||||
static void process_base_type(struct state *state, Dwarf_Die *die)
|
||||
{
|
||||
process("base_type");
|
||||
process_fqn(die);
|
||||
process_byte_size_attr(die);
|
||||
process_encoding_attr(die);
|
||||
process_alignment_attr(die);
|
||||
}
|
||||
|
||||
#define PROCESS_TYPE(type) \
|
||||
case DW_TAG_##type##_type: \
|
||||
process_##type##_type(state, die); \
|
||||
break;
|
||||
|
||||
static int process_type(struct state *state, Dwarf_Die *die)
|
||||
{
|
||||
int tag = dwarf_tag(die);
|
||||
|
||||
switch (tag) {
|
||||
PROCESS_TYPE(base)
|
||||
default:
|
||||
debug("unimplemented type: %x", tag);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported symbol processing
|
||||
*/
|
||||
@@ -119,6 +278,7 @@ static void process_subprogram(struct state *state, Dwarf_Die *die)
|
||||
static int __process_variable(struct state *state, Dwarf_Die *die)
|
||||
{
|
||||
process("variable ");
|
||||
process_type_attr(state, die);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user