dwarves/dutil.c

229 lines
4.1 KiB
C
Raw Normal View History

/*
SPDX-License-Identifier: GPL-2.0-only
Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com>
*/
#include "dutil.h"
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *zalloc(size_t size)
{
return calloc(1, size);
}
void __zfree(void **ptr)
{
free(*ptr);
*ptr = NULL;
}
struct str_node *str_node__new(const char *s, bool dupstr)
{
struct str_node *snode = malloc(sizeof(*snode));
if (snode != NULL){
if (dupstr) {
s = strdup(s);
if (s == NULL)
goto out_delete;
}
snode->s = s;
}
return snode;
out_delete:
free(snode);
return NULL;
}
static void str_node__delete(struct str_node *snode, bool dupstr)
{
if (snode == NULL)
return;
if (dupstr)
zfree(&snode->s);
free(snode);
}
int __strlist__add(struct strlist *slist, const char *new_entry, void *priv)
{
struct rb_node **p = &slist->entries.rb_node;
struct rb_node *parent = NULL;
struct str_node *sn;
while (*p != NULL) {
int rc;
parent = *p;
sn = rb_entry(parent, struct str_node, rb_node);
rc = strcmp(sn->s, new_entry);
if (rc > 0)
p = &(*p)->rb_left;
else if (rc < 0)
p = &(*p)->rb_right;
else
return -EEXIST;
}
sn = str_node__new(new_entry, slist->dupstr);
if (sn == NULL)
return -ENOMEM;
rb_link_node(&sn->rb_node, parent, p);
rb_insert_color(&sn->rb_node, &slist->entries);
sn->priv = priv;
list_add_tail(&sn->node, &slist->list_entries);
return 0;
}
int strlist__add(struct strlist *slist, const char *new_entry)
{
return __strlist__add(slist, new_entry, NULL);
}
int strlist__load(struct strlist *slist, const char *filename)
{
char entry[1024];
int err = -1;
FILE *fp = fopen(filename, "r");
if (fp == NULL)
return -1;
while (fgets(entry, sizeof(entry), fp) != NULL) {
const size_t len = strlen(entry);
if (len == 0)
continue;
entry[len - 1] = '\0';
if (strlist__add(slist, entry) != 0)
goto out;
}
err = 0;
out:
fclose(fp);
return err;
}
struct strlist *strlist__new(bool dupstr)
{
struct strlist *slist = malloc(sizeof(*slist));
if (slist != NULL) {
slist->entries = RB_ROOT;
INIT_LIST_HEAD(&slist->list_entries);
slist->dupstr = dupstr;
}
return slist;
}
void strlist__delete(struct strlist *slist)
{
if (slist != NULL) {
struct str_node *pos;
struct rb_node *next = rb_first(&slist->entries);
while (next) {
pos = rb_entry(next, struct str_node, rb_node);
next = rb_next(&pos->rb_node);
strlist__remove(slist, pos);
}
slist->entries = RB_ROOT;
free(slist);
}
}
void strlist__remove(struct strlist *slist, struct str_node *sn)
{
rb_erase(&sn->rb_node, &slist->entries);
list_del_init(&sn->node);
str_node__delete(sn, slist->dupstr);
}
bool strlist__has_entry(struct strlist *slist, const char *entry)
{
struct rb_node **p = &slist->entries.rb_node;
struct rb_node *parent = NULL;
while (*p != NULL) {
struct str_node *sn;
int rc;
parent = *p;
sn = rb_entry(parent, struct str_node, rb_node);
rc = strcmp(sn->s, entry);
if (rc > 0)
p = &(*p)->rb_left;
else if (rc < 0)
p = &(*p)->rb_right;
else
return true;
}
return false;
}
Elf_Scn *elf_section_by_name(Elf *elf, GElf_Shdr *shp, const char *name, size_t *index)
{
Elf_Scn *sec = NULL;
size_t cnt = 1;
size_t str_idx;
if (elf_getshdrstrndx(elf, &str_idx))
return NULL;
while ((sec = elf_nextscn(elf, sec)) != NULL) {
char *str;
gelf_getshdr(sec, shp);
str = elf_strptr(elf, str_idx, shp->sh_name);
if (!str)
return NULL;
if (!strcmp(name, str)) {
if (index)
*index = cnt;
break;
}
++cnt;
}
return sec;
}
btf_encoder: Detect kernel module ftrace addresses Add support to detect kernel module ftrace addresses and use it as filter for detected functions. For kernel modules the ftrace addresses are stored in __mcount_loc section. Adding the code that detects this section and reads its data into array, which is then processed as filter by current code. There's one tricky point with kernel modules wrt Elf object, which we get from dwfl_module_getelf function. This function performs all possible relocations, including __mcount_loc section. So addrs array contains relocated values, which we need take into account when we compare them to functions values which are relative to their sections. With this change for example for xfs.ko module in my kernel config, I'm getting slightly bigger number of functions: before: 2373, after: 2601 The ftrace's available_filter_functions still shows 2701, but it includes functions like: suffix_kstrtoint.constprop.0 xchk_btree_check_minrecs.isra.0 xfs_ascii_ci_compname.part.0 which are not part of dwarf data, the rest matches BTF functions. Because of the malfunction DWARF's declaration tag, the 'before' functions contain also functions that are not part of the module. The 'after' functions contain only functions that are traceable and part of xfs.ko. Despite filtering out some declarations, this change also adds static functions, hence the total number of functions is bigger. Committer notes: Andrii test notes: <quote> I've tested locally on bpf_testmod that I'm adding to selftests in [0]. All worked well. I changed the test function from global to non-inlined static, and BTF had it. And the tests passed. So LGTM. [0] https://patchwork.kernel.org/user/todo/netdevbpf/?series=395715&delegate=121173&state=* </> Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Andrii Nakryiko <andrii@kernel.org> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Hao Luo <haoluo@google.com> Cc: Yonghong Song <yhs@fb.com> Cc: bpf@vger.kernel.org Cc: dwarves@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-12-03 23:06:25 +01:00
Elf_Scn *elf_section_by_idx(Elf *elf, GElf_Shdr *shp, int idx)
{
Elf_Scn *sec;
sec = elf_getscn(elf, idx);
if (sec)
gelf_getshdr(sec, shp);
return sec;
}
char *strlwr(char *s)
{
int len = strlen(s), i;
for (i = 0; i < len; ++i)
s[i] = tolower(s[i]);
return s;
}