[CLASSES]: Handle DW_AT_abstract_origin in DW_TAG_subprogram
We have to check for a possible alias (abstract origin attribute) and handle that when we want the function name, if it is an alias, do the lookup and cache the result in ->name, that after all doesn't have a value in the first place. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
This commit is contained in:
parent
fddb3f4e15
commit
29103e42be
28
classes.c
28
classes.c
|
@ -745,6 +745,8 @@ const char *tag__name(const struct tag *self, const struct cu *cu,
|
|||
strncpy(bf, "void", len);
|
||||
else if (self->tag == DW_TAG_base_type)
|
||||
strncpy(bf, tag__base_type(self)->name, len);
|
||||
else if (self->tag == DW_TAG_subprogram)
|
||||
strncpy(bf, function__name(tag__function(self), cu), len);
|
||||
else if (self->tag == DW_TAG_pointer_type) {
|
||||
if (self->type == 0) /* No type == void */
|
||||
strncpy(bf, "void *", len);
|
||||
|
@ -1210,11 +1212,28 @@ static struct function *function__new(Dwarf_Die *die)
|
|||
self->name = strings__add(attr_string(die, DW_AT_name));
|
||||
self->inlined = attr_numeric(die, DW_AT_inline);
|
||||
self->external = dwarf_hasattr(die, DW_AT_external);
|
||||
self->abstract_origin = attr_numeric(die,
|
||||
DW_AT_abstract_origin);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
const char *function__name(struct function *self, const struct cu *cu)
|
||||
{
|
||||
/* Check if the tag doesn't comes with a DW_AT_name attribute... */
|
||||
if (self->name == NULL) {
|
||||
/* No? So it must have a DW_AT_abstract_origin... */
|
||||
struct tag *tag = cu__find_tag_by_id(cu,
|
||||
self->abstract_origin);
|
||||
assert(tag != NULL);
|
||||
/* ... and now we cache the result in this tag ->name field */
|
||||
self->name = tag__function(tag)->name;
|
||||
}
|
||||
|
||||
return self->name;
|
||||
}
|
||||
|
||||
int ftype__has_parm_of_type(const struct ftype *self, const struct tag *target,
|
||||
const struct cu *cu)
|
||||
{
|
||||
|
@ -1444,12 +1463,12 @@ static void function__tag_print(const struct tag *tag, const struct cu *cu,
|
|||
const struct inline_expansion *exp = vtag;
|
||||
const struct tag *talias =
|
||||
cu__find_tag_by_id(cu, exp->tag.type);
|
||||
const struct function *alias = tag__function(talias);
|
||||
struct function *alias = tag__function(talias);
|
||||
|
||||
assert(alias != NULL);
|
||||
printf("%.*s", indent, tabs);
|
||||
c += printf("%s(); /* low_pc=%#llx */",
|
||||
alias->name, exp->low_pc);
|
||||
function__name(alias, cu), exp->low_pc);
|
||||
}
|
||||
break;
|
||||
case DW_TAG_variable:
|
||||
|
@ -1548,7 +1567,7 @@ size_t ftype__snprintf(const struct ftype *self, const struct cu *cu,
|
|||
return len - (l - n);
|
||||
}
|
||||
|
||||
void function__print(const struct function *self, const struct cu *cu,
|
||||
void function__print(struct function *self, const struct cu *cu,
|
||||
int show_stats, const int show_variables,
|
||||
const int show_inline_expansions)
|
||||
{
|
||||
|
@ -1560,7 +1579,8 @@ void function__print(const struct function *self, const struct cu *cu,
|
|||
self->proto.tag.decl_line);
|
||||
|
||||
ftype__snprintf(&self->proto, cu, bf, sizeof(bf),
|
||||
self->name, function__declared_inline(self), 0, 0);
|
||||
function__name(self, cu),
|
||||
function__declared_inline(self), 0, 0);
|
||||
fputs(bf, stdout);
|
||||
|
||||
if (show_variables || show_inline_expansions) {
|
||||
|
|
|
@ -169,6 +169,7 @@ struct function {
|
|||
struct ftype proto;
|
||||
struct lexblock lexblock;
|
||||
const char *name;
|
||||
Dwarf_Off abstract_origin;
|
||||
size_t cu_total_size_inline_expansions;
|
||||
uint16_t cu_total_nr_inline_expansions;
|
||||
uint8_t inlined; /* two bits used */
|
||||
|
@ -241,7 +242,9 @@ struct enumerator {
|
|||
extern void class__find_holes(struct class *self, const struct cu *cu);
|
||||
extern void tag__print(const struct tag *self, const struct cu *cu,
|
||||
const char *prefix, const char *suffix);
|
||||
extern void function__print(const struct function *self, const struct cu *cu,
|
||||
|
||||
extern const char *function__name(struct function *self, const struct cu *cu);
|
||||
extern void function__print(struct function *self, const struct cu *cu,
|
||||
const int show_stats,
|
||||
const int show_variables,
|
||||
const int show_inline_expansions);
|
||||
|
|
19
codiff.c
19
codiff.c
|
@ -83,18 +83,20 @@ static void diff_function(const struct cu *new_cu, struct function *function,
|
|||
struct cu *cu)
|
||||
{
|
||||
struct function *new_function;
|
||||
const char *name;
|
||||
|
||||
assert(function->proto.tag.tag == DW_TAG_subprogram);
|
||||
|
||||
if (function->inlined)
|
||||
return;
|
||||
|
||||
new_function = cu__find_function_by_name(new_cu, function->name);
|
||||
name = function__name(function, cu);
|
||||
new_function = cu__find_function_by_name(new_cu, name);
|
||||
if (new_function != NULL) {
|
||||
int32_t diff = (function__size(new_function) -
|
||||
function__size(function));
|
||||
if (diff != 0) {
|
||||
const size_t len = strlen(function->name);
|
||||
const size_t len = strlen(name);
|
||||
|
||||
function->priv = diff_info__new(&new_function->proto.tag, new_cu,
|
||||
diff);
|
||||
|
@ -108,7 +110,7 @@ static void diff_function(const struct cu *new_cu, struct function *function,
|
|||
cu->function_bytes_removed += -diff;
|
||||
}
|
||||
} else {
|
||||
const size_t len = strlen(function->name);
|
||||
const size_t len = strlen(name);
|
||||
const uint32_t diff = -function__size(function);
|
||||
|
||||
if (len > cu->max_len_changed_item)
|
||||
|
@ -269,15 +271,17 @@ static int find_new_functions_iterator(struct tag *tfunction, struct cu *cu,
|
|||
{
|
||||
struct function *function = tag__function(tfunction);
|
||||
struct function *old_function;
|
||||
const char *name;
|
||||
|
||||
assert(function->proto.tag.tag == DW_TAG_subprogram);
|
||||
|
||||
if (function->inlined)
|
||||
return 0;
|
||||
|
||||
old_function = cu__find_function_by_name(old_cu, function->name);
|
||||
name = function__name(function, cu);
|
||||
old_function = cu__find_function_by_name(old_cu, name);
|
||||
if (old_function == NULL) {
|
||||
const size_t len = strlen(function->name);
|
||||
const size_t len = strlen(name);
|
||||
const int32_t diff = function__size(function);
|
||||
|
||||
if (len > cu->max_len_changed_item)
|
||||
|
@ -345,14 +349,13 @@ static int cu_diff_iterator(struct cu *cu, void *new_cus)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void show_diffs_function(const struct function *function,
|
||||
const struct cu *cu)
|
||||
static void show_diffs_function(struct function *function, const struct cu *cu)
|
||||
{
|
||||
const struct diff_info *di = function->priv;
|
||||
|
||||
printf(" %-*.*s | %+4d\n",
|
||||
cu->max_len_changed_item, cu->max_len_changed_item,
|
||||
function->name, di->diff);
|
||||
function__name(function, cu), di->diff);
|
||||
}
|
||||
|
||||
static void show_changed_member(char change, const struct class_member *member,
|
||||
|
|
25
ctracer.c
25
ctracer.c
|
@ -60,8 +60,7 @@ static int cu_find_methods_iterator(struct cu *cu, void *cookie)
|
|||
return cu__for_each_tag(cu, find_methods_iterator, target, function__filter);
|
||||
}
|
||||
|
||||
static int function__emit_kprobes(const struct function *self,
|
||||
const struct cu *cu,
|
||||
static int function__emit_kprobes(struct function *self, const struct cu *cu,
|
||||
const struct tag *target)
|
||||
{
|
||||
char bf[128];
|
||||
|
@ -71,11 +70,12 @@ static int function__emit_kprobes(const struct function *self,
|
|||
struct parameter *pos;
|
||||
struct tag *type = cu__find_tag_by_id(cu, self->proto.tag.type);
|
||||
const char *stype = tag__name(type, cu, bf, sizeof(bf));
|
||||
const char *name = function__name(self, cu);
|
||||
int first = 1;
|
||||
|
||||
body[0] = '\0';
|
||||
|
||||
printf("static %s jprobe_entry__%s(", stype, self->name);
|
||||
printf("static %s jprobe_entry__%s(", stype, name);
|
||||
|
||||
list_for_each_entry(pos, &self->proto.parms, tag.node) {
|
||||
type = cu__find_tag_by_id(cu, pos->tag.type);
|
||||
|
@ -98,7 +98,7 @@ static int function__emit_kprobes(const struct function *self,
|
|||
|
||||
printed = snprintf(bodyp, bodyl,
|
||||
"\tprintk(\"-> %s: %s=%%p\\n\", %s);\n",
|
||||
self->name, pos->name, pos->name);
|
||||
name, pos->name, pos->name);
|
||||
bodyp += printed;
|
||||
bodyl -= printed;
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ static int function__emit_kprobes(const struct function *self,
|
|||
printf("static struct jprobe jprobe__%s = {\n"
|
||||
"\t.kp = { .symbol_name = \"%s\", },\n"
|
||||
"\t.entry = (kprobe_opcode_t *)jprobe_entry__%s,\n"
|
||||
"};\n\n", self->name, self->name, self->name);
|
||||
"};\n\n", name, name, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -129,24 +129,27 @@ static int cu_emit_kprobes_table_iterator(struct cu *cu, void *cookie)
|
|||
struct function *pos;
|
||||
|
||||
list_for_each_entry(pos, &cu->tool_list, tool_node)
|
||||
printf("\t&jprobe__%s,\n", pos->name);
|
||||
printf("\t&jprobe__%s,\n", function__name(pos, cu));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int function__emit_kretprobes(const struct function *self)
|
||||
static int function__emit_kretprobes(struct function *self,
|
||||
const struct cu *cu)
|
||||
{
|
||||
const char *name = function__name(self, cu);
|
||||
|
||||
printf("static int kretprobe_handler__%s(struct kretprobe_instance *ri, "
|
||||
"struct pt_regs *regs)\n"
|
||||
"{\n"
|
||||
"\tprintk(\"<- %s\\n\");\n"
|
||||
"\treturn 0;\n"
|
||||
"}\n\n", self->name, self->name);
|
||||
"}\n\n", name, name);
|
||||
printf("static struct kretprobe kretprobe__%s = {\n"
|
||||
"\t.kp = { .symbol_name = \"%s\", },\n"
|
||||
"\t.handler = (kretprobe_handler_t)kretprobe_handler__%s,\n"
|
||||
"\t.maxactive = -1,\n\n"
|
||||
"};\n\n", self->name, self->name, self->name);
|
||||
"};\n\n", name, name, name);
|
||||
}
|
||||
|
||||
static int cu_emit_kretprobes_iterator(struct cu *cu, void *cookie)
|
||||
|
@ -154,7 +157,7 @@ static int cu_emit_kretprobes_iterator(struct cu *cu, void *cookie)
|
|||
struct function *pos;
|
||||
|
||||
list_for_each_entry(pos, &cu->tool_list, tool_node)
|
||||
function__emit_kretprobes(pos);
|
||||
function__emit_kretprobes(pos, cu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -164,7 +167,7 @@ static int cu_emit_kretprobes_table_iterator(struct cu *cu, void *cookie)
|
|||
struct function *pos;
|
||||
|
||||
list_for_each_entry(pos, &cu->tool_list, tool_node)
|
||||
printf("\t&kretprobe__%s,\n", pos->name);
|
||||
printf("\t&kretprobe__%s,\n", function__name(pos, cu));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
60
pfunct.c
60
pfunct.c
|
@ -23,15 +23,15 @@ static int show_cc_inlined;
|
|||
static int show_cc_uninlined;
|
||||
|
||||
struct fn_stats {
|
||||
struct list_head node;
|
||||
const struct function *function;
|
||||
const struct cu *cu;
|
||||
uint32_t nr_expansions;
|
||||
uint32_t size_expansions;
|
||||
uint32_t nr_files;
|
||||
struct list_head node;
|
||||
struct function *function;
|
||||
const struct cu *cu;
|
||||
uint32_t nr_expansions;
|
||||
uint32_t size_expansions;
|
||||
uint32_t nr_files;
|
||||
};
|
||||
|
||||
static struct fn_stats *fn_stats__new(const struct function *function,
|
||||
static struct fn_stats *fn_stats__new(struct function *function,
|
||||
const struct cu *cu)
|
||||
{
|
||||
struct fn_stats *self = malloc(sizeof(*self));
|
||||
|
@ -54,12 +54,12 @@ static struct fn_stats *fn_stats__find(const char *name)
|
|||
struct fn_stats *pos;
|
||||
|
||||
list_for_each_entry(pos, &fn_stats__list, node)
|
||||
if (strcmp(pos->function->name, name) == 0)
|
||||
if (strcmp(function__name(pos->function, pos->cu), name) == 0)
|
||||
return pos;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void fn_stats__add(const struct function *function, const struct cu *cu)
|
||||
static void fn_stats__add(struct function *function, const struct cu *cu)
|
||||
{
|
||||
struct fn_stats *inl = fn_stats__new(function, cu);
|
||||
if (inl != NULL)
|
||||
|
@ -69,7 +69,7 @@ static void fn_stats__add(const struct function *function, const struct cu *cu)
|
|||
static void fn_stats_inline_exps_fmtr(const struct fn_stats *self)
|
||||
{
|
||||
if (self->function->lexblock.nr_inline_expansions > 0)
|
||||
printf("%s: %u %u\n", self->function->name,
|
||||
printf("%s: %u %u\n", function__name(self->function, self->cu),
|
||||
self->function->lexblock.nr_inline_expansions,
|
||||
self->function->lexblock.size_inline_expansions);
|
||||
}
|
||||
|
@ -77,33 +77,35 @@ static void fn_stats_inline_exps_fmtr(const struct fn_stats *self)
|
|||
static void fn_stats_labels_fmtr(const struct fn_stats *self)
|
||||
{
|
||||
if (self->function->lexblock.nr_labels > 0)
|
||||
printf("%s: %u\n", self->function->name,
|
||||
printf("%s: %u\n", function__name(self->function, self->cu),
|
||||
self->function->lexblock.nr_labels);
|
||||
}
|
||||
|
||||
static void fn_stats_variables_fmtr(const struct fn_stats *self)
|
||||
{
|
||||
if (self->function->lexblock.nr_variables > 0)
|
||||
printf("%s: %u\n", self->function->name,
|
||||
printf("%s: %u\n", function__name(self->function, self->cu),
|
||||
self->function->lexblock.nr_variables);
|
||||
}
|
||||
|
||||
static void fn_stats_nr_parms_fmtr(const struct fn_stats *self)
|
||||
{
|
||||
printf("%s: %u\n", self->function->name,
|
||||
printf("%s: %u\n", function__name(self->function, self->cu),
|
||||
self->function->proto.nr_parms);
|
||||
}
|
||||
|
||||
static void fn_stats_name_len_fmtr(const struct fn_stats *self)
|
||||
{
|
||||
printf("%s: %u\n", self->function->name, strlen(self->function->name));
|
||||
const char *name = function__name(self->function, self->cu);
|
||||
printf("%s: %u\n", name, strlen(name));
|
||||
}
|
||||
|
||||
static void fn_stats_size_fmtr(const struct fn_stats *self)
|
||||
{
|
||||
const size_t size = function__size(self->function);
|
||||
if (size != 0)
|
||||
printf("%s: %u\n", self->function->name, size);
|
||||
printf("%s: %u\n", function__name(self->function, self->cu),
|
||||
size);
|
||||
}
|
||||
|
||||
static void fn_stats_fmtr(const struct fn_stats *self)
|
||||
|
@ -114,7 +116,7 @@ static void fn_stats_fmtr(const struct fn_stats *self)
|
|||
printf("/* definitions: %u */\n", self->nr_files);
|
||||
putchar('\n');
|
||||
} else
|
||||
puts(self->function->name);
|
||||
puts(function__name(self->function, self->cu));
|
||||
}
|
||||
|
||||
static void print_fn_stats(void (*formatter)(const struct fn_stats *f))
|
||||
|
@ -128,7 +130,8 @@ static void print_fn_stats(void (*formatter)(const struct fn_stats *f))
|
|||
static void fn_stats_inline_stats_fmtr(const struct fn_stats *self)
|
||||
{
|
||||
if (self->nr_expansions > 1)
|
||||
printf("%-31.31s %6lu %7lu %6lu %6u\n", self->function->name,
|
||||
printf("%-31.31s %6lu %7lu %6lu %6u\n",
|
||||
function__name(self->function, self->cu),
|
||||
self->size_expansions, self->nr_expansions,
|
||||
self->size_expansions / self->nr_expansions,
|
||||
self->nr_files);
|
||||
|
@ -141,9 +144,9 @@ static void print_total_inline_stats(void)
|
|||
print_fn_stats(fn_stats_inline_stats_fmtr);
|
||||
}
|
||||
|
||||
static void fn_stats__dupmsg(const struct function *self,
|
||||
static void fn_stats__dupmsg(struct function *self,
|
||||
const struct cu *self_cu,
|
||||
const struct function *dup,
|
||||
struct function *dup,
|
||||
const struct cu *dup_cu,
|
||||
char *hdr, const char *fmt, ...)
|
||||
{
|
||||
|
@ -151,7 +154,9 @@ static void fn_stats__dupmsg(const struct function *self,
|
|||
|
||||
if (!*hdr)
|
||||
printf("function: %s\nfirst: %s\ncurrent: %s\n",
|
||||
self->name, self_cu->name, dup_cu->name);
|
||||
function__name(self, self_cu),
|
||||
self_cu->name,
|
||||
function__name(dup, dup_cu));
|
||||
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
|
@ -159,9 +164,9 @@ static void fn_stats__dupmsg(const struct function *self,
|
|||
*hdr = 1;
|
||||
}
|
||||
|
||||
static void fn_stats__chkdupdef(const struct function *self,
|
||||
static void fn_stats__chkdupdef(struct function *self,
|
||||
const struct cu *self_cu,
|
||||
const struct function *dup,
|
||||
struct function *dup,
|
||||
const struct cu *dup_cu)
|
||||
{
|
||||
char hdr = 0;
|
||||
|
@ -189,12 +194,14 @@ static struct tag *function__filter(struct tag *tag, struct cu *cu,
|
|||
{
|
||||
struct function *function;
|
||||
struct fn_stats *fstats;
|
||||
const char *name;
|
||||
|
||||
if (tag->tag != DW_TAG_subprogram)
|
||||
return NULL;
|
||||
|
||||
function = tag__function(tag);
|
||||
if (function->name == NULL)
|
||||
name = function__name(function, cu);
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
if (show_externals && !function->external)
|
||||
|
@ -207,7 +214,7 @@ static struct tag *function__filter(struct tag *tag, struct cu *cu,
|
|||
if (show_cc_inlined && function->inlined != DW_INL_inlined)
|
||||
return NULL;
|
||||
|
||||
fstats = fn_stats__find(function->name);
|
||||
fstats = fn_stats__find(name);
|
||||
if (fstats != NULL && fstats->function->external) {
|
||||
fn_stats__chkdupdef(fstats->function, fstats->cu, function, cu);
|
||||
fstats->nr_expansions += function->cu_total_nr_inline_expansions;
|
||||
|
@ -247,7 +254,7 @@ static int class_iterator(struct tag *tag, struct cu *cu, void *cookie)
|
|||
if (verbose)
|
||||
function__print(function, cu, 1, 0, 0);
|
||||
else
|
||||
printf("%s\n", function->name ?: "");
|
||||
printf("%s\n", function__name(function, cu));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -270,8 +277,7 @@ static int function_iterator(struct tag *tag, struct cu *cu, void *cookie)
|
|||
return 0;
|
||||
|
||||
function = tag__function(tag);
|
||||
if (function->name != NULL &&
|
||||
strcmp(function->name, cookie) == 0) {
|
||||
if (strcmp(function__name(function, cu), cookie) == 0) {
|
||||
function__print(function, cu, 1, show_variables,
|
||||
show_inline_expansions);
|
||||
return 1;
|
||||
|
|
Loading…
Reference in New Issue