Merge branch 'perf-tools-for-linus' of git://github.com/acmel/linux
* 'perf-tools-for-linus' of git://github.com/acmel/linux: perf tools: Add support for disabling -Werror via WERROR=0 perf top: Fix userspace sample addr map offset perf symbols: Fix issue with binaries using 16-bytes buildids (v2) perf tool: Fix endianness handling of u32 data in samples perf sort: Fix symbol sort output by separating unresolved samples by type perf symbols: Synthesize anonymous mmap events perf record: Create events initially disabled and enable after init perf symbols: Add some heuristics for choosing the best duplicate symbol perf symbols: Preserve symbol scope when parsing /proc/kallsyms perf symbols: /proc/kallsyms does not sort module symbols perf symbols: Fix ppc64 SEGV in dso__load_sym with debuginfo files perf probe: Fix regression of variable finder
This commit is contained in:
commit
eab8bcb67a
13 changed files with 209 additions and 57 deletions
|
@ -30,6 +30,8 @@ endif
|
||||||
# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
|
# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
|
||||||
#
|
#
|
||||||
# Define NO_DWARF if you do not want debug-info analysis feature at all.
|
# Define NO_DWARF if you do not want debug-info analysis feature at all.
|
||||||
|
#
|
||||||
|
# Define WERROR=0 to disable treating any warnings as errors.
|
||||||
|
|
||||||
$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
|
$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
|
||||||
@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
|
@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
|
||||||
|
@ -63,6 +65,11 @@ ifeq ($(ARCH),x86_64)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Treat warnings as errors unless directed not to
|
||||||
|
ifneq ($(WERROR),0)
|
||||||
|
CFLAGS_WERROR := -Werror
|
||||||
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
# Include saner warnings here, which can catch bugs:
|
# Include saner warnings here, which can catch bugs:
|
||||||
#
|
#
|
||||||
|
@ -95,7 +102,7 @@ ifndef PERF_DEBUG
|
||||||
CFLAGS_OPTIMIZE = -O6
|
CFLAGS_OPTIMIZE = -O6
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
||||||
EXTLIBS = -lpthread -lrt -lelf -lm
|
EXTLIBS = -lpthread -lrt -lelf -lm
|
||||||
ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||||||
ALL_LDFLAGS = $(LDFLAGS)
|
ALL_LDFLAGS = $(LDFLAGS)
|
||||||
|
|
|
@ -161,6 +161,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
|
||||||
struct perf_event_attr *attr = &evsel->attr;
|
struct perf_event_attr *attr = &evsel->attr;
|
||||||
int track = !evsel->idx; /* only the first counter needs these */
|
int track = !evsel->idx; /* only the first counter needs these */
|
||||||
|
|
||||||
|
attr->disabled = 1;
|
||||||
attr->inherit = !no_inherit;
|
attr->inherit = !no_inherit;
|
||||||
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
|
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
|
||||||
PERF_FORMAT_TOTAL_TIME_RUNNING |
|
PERF_FORMAT_TOTAL_TIME_RUNNING |
|
||||||
|
@ -671,6 +672,8 @@ static int __cmd_record(int argc, const char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
perf_evlist__enable(evsel_list);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Let the child rip
|
* Let the child rip
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -561,7 +561,7 @@ static int test__basic_mmap(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = perf_event__parse_sample(event, attr.sample_type, sample_size,
|
err = perf_event__parse_sample(event, attr.sample_type, sample_size,
|
||||||
false, &sample);
|
false, &sample, false);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_err("Can't parse sample, err = %d\n", err);
|
pr_err("Can't parse sample, err = %d\n", err);
|
||||||
goto out_munmap;
|
goto out_munmap;
|
||||||
|
|
|
@ -191,7 +191,8 @@ static void __zero_source_counters(struct sym_entry *syme)
|
||||||
symbol__annotate_zero_histograms(sym);
|
symbol__annotate_zero_histograms(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
|
static void record_precise_ip(struct sym_entry *syme, struct map *map,
|
||||||
|
int counter, u64 ip)
|
||||||
{
|
{
|
||||||
struct annotation *notes;
|
struct annotation *notes;
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
|
@ -205,8 +206,8 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
|
||||||
if (pthread_mutex_trylock(¬es->lock))
|
if (pthread_mutex_trylock(¬es->lock))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ip = syme->map->map_ip(syme->map, ip);
|
ip = map->map_ip(map, ip);
|
||||||
symbol__inc_addr_samples(sym, syme->map, counter, ip);
|
symbol__inc_addr_samples(sym, map, counter, ip);
|
||||||
|
|
||||||
pthread_mutex_unlock(¬es->lock);
|
pthread_mutex_unlock(¬es->lock);
|
||||||
}
|
}
|
||||||
|
@ -810,7 +811,7 @@ static void perf_event__process_sample(const union perf_event *event,
|
||||||
evsel = perf_evlist__id2evsel(top.evlist, sample->id);
|
evsel = perf_evlist__id2evsel(top.evlist, sample->id);
|
||||||
assert(evsel != NULL);
|
assert(evsel != NULL);
|
||||||
syme->count[evsel->idx]++;
|
syme->count[evsel->idx]++;
|
||||||
record_precise_ip(syme, evsel->idx, ip);
|
record_precise_ip(syme, al.map, evsel->idx, ip);
|
||||||
pthread_mutex_lock(&top.active_symbols_lock);
|
pthread_mutex_lock(&top.active_symbols_lock);
|
||||||
if (list_empty(&syme->node) || !syme->node.next) {
|
if (list_empty(&syme->node) || !syme->node.next) {
|
||||||
static bool first = true;
|
static bool first = true;
|
||||||
|
|
|
@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
|
||||||
continue;
|
continue;
|
||||||
pbf += n + 3;
|
pbf += n + 3;
|
||||||
if (*pbf == 'x') { /* vm_exec */
|
if (*pbf == 'x') { /* vm_exec */
|
||||||
|
char anonstr[] = "//anon\n";
|
||||||
char *execname = strchr(bf, '/');
|
char *execname = strchr(bf, '/');
|
||||||
|
|
||||||
/* Catch VDSO */
|
/* Catch VDSO */
|
||||||
if (execname == NULL)
|
if (execname == NULL)
|
||||||
execname = strstr(bf, "[vdso]");
|
execname = strstr(bf, "[vdso]");
|
||||||
|
|
||||||
|
/* Catch anonymous mmaps */
|
||||||
|
if ((execname == NULL) && !strstr(bf, "["))
|
||||||
|
execname = anonstr;
|
||||||
|
|
||||||
if (execname == NULL)
|
if (execname == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id);
|
||||||
|
|
||||||
int perf_event__parse_sample(const union perf_event *event, u64 type,
|
int perf_event__parse_sample(const union perf_event *event, u64 type,
|
||||||
int sample_size, bool sample_id_all,
|
int sample_size, bool sample_id_all,
|
||||||
struct perf_sample *sample);
|
struct perf_sample *sample, bool swapped);
|
||||||
|
|
||||||
#endif /* __PERF_RECORD_H */
|
#endif /* __PERF_RECORD_H */
|
||||||
|
|
|
@ -113,6 +113,19 @@ void perf_evlist__disable(struct perf_evlist *evlist)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void perf_evlist__enable(struct perf_evlist *evlist)
|
||||||
|
{
|
||||||
|
int cpu, thread;
|
||||||
|
struct perf_evsel *pos;
|
||||||
|
|
||||||
|
for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
|
||||||
|
list_for_each_entry(pos, &evlist->entries, node) {
|
||||||
|
for (thread = 0; thread < evlist->threads->nr; thread++)
|
||||||
|
ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
|
int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
|
||||||
{
|
{
|
||||||
int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
|
int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
|
||||||
|
|
|
@ -54,6 +54,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
|
||||||
void perf_evlist__munmap(struct perf_evlist *evlist);
|
void perf_evlist__munmap(struct perf_evlist *evlist);
|
||||||
|
|
||||||
void perf_evlist__disable(struct perf_evlist *evlist);
|
void perf_evlist__disable(struct perf_evlist *evlist);
|
||||||
|
void perf_evlist__enable(struct perf_evlist *evlist);
|
||||||
|
|
||||||
static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
|
static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
|
||||||
struct cpu_map *cpus,
|
struct cpu_map *cpus,
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
* Released under the GPL v2. (and only v2, not any later version)
|
* Released under the GPL v2. (and only v2, not any later version)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <byteswap.h>
|
||||||
|
#include "asm/bug.h"
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
#include "evlist.h"
|
#include "evlist.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -342,10 +344,20 @@ static bool sample_overlap(const union perf_event *event,
|
||||||
|
|
||||||
int perf_event__parse_sample(const union perf_event *event, u64 type,
|
int perf_event__parse_sample(const union perf_event *event, u64 type,
|
||||||
int sample_size, bool sample_id_all,
|
int sample_size, bool sample_id_all,
|
||||||
struct perf_sample *data)
|
struct perf_sample *data, bool swapped)
|
||||||
{
|
{
|
||||||
const u64 *array;
|
const u64 *array;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* used for cross-endian analysis. See git commit 65014ab3
|
||||||
|
* for why this goofiness is needed.
|
||||||
|
*/
|
||||||
|
union {
|
||||||
|
u64 val64;
|
||||||
|
u32 val32[2];
|
||||||
|
} u;
|
||||||
|
|
||||||
|
|
||||||
data->cpu = data->pid = data->tid = -1;
|
data->cpu = data->pid = data->tid = -1;
|
||||||
data->stream_id = data->id = data->time = -1ULL;
|
data->stream_id = data->id = data->time = -1ULL;
|
||||||
|
|
||||||
|
@ -366,9 +378,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type & PERF_SAMPLE_TID) {
|
if (type & PERF_SAMPLE_TID) {
|
||||||
u32 *p = (u32 *)array;
|
u.val64 = *array;
|
||||||
data->pid = p[0];
|
if (swapped) {
|
||||||
data->tid = p[1];
|
/* undo swap of u64, then swap on individual u32s */
|
||||||
|
u.val64 = bswap_64(u.val64);
|
||||||
|
u.val32[0] = bswap_32(u.val32[0]);
|
||||||
|
u.val32[1] = bswap_32(u.val32[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->pid = u.val32[0];
|
||||||
|
data->tid = u.val32[1];
|
||||||
array++;
|
array++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,8 +414,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type & PERF_SAMPLE_CPU) {
|
if (type & PERF_SAMPLE_CPU) {
|
||||||
u32 *p = (u32 *)array;
|
|
||||||
data->cpu = *p;
|
u.val64 = *array;
|
||||||
|
if (swapped) {
|
||||||
|
/* undo swap of u64, then swap on individual u32s */
|
||||||
|
u.val64 = bswap_64(u.val64);
|
||||||
|
u.val32[0] = bswap_32(u.val32[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->cpu = u.val32[0];
|
||||||
array++;
|
array++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,18 +449,24 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type & PERF_SAMPLE_RAW) {
|
if (type & PERF_SAMPLE_RAW) {
|
||||||
u32 *p = (u32 *)array;
|
u.val64 = *array;
|
||||||
|
if (WARN_ONCE(swapped,
|
||||||
|
"Endianness of raw data not corrected!\n")) {
|
||||||
|
/* undo swap of u64, then swap on individual u32s */
|
||||||
|
u.val64 = bswap_64(u.val64);
|
||||||
|
u.val32[0] = bswap_32(u.val32[0]);
|
||||||
|
u.val32[1] = bswap_32(u.val32[1]);
|
||||||
|
}
|
||||||
|
|
||||||
if (sample_overlap(event, array, sizeof(u32)))
|
if (sample_overlap(event, array, sizeof(u32)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
data->raw_size = *p;
|
data->raw_size = u.val32[0];
|
||||||
p++;
|
|
||||||
|
|
||||||
if (sample_overlap(event, p, data->raw_size))
|
if (sample_overlap(event, &u.val32[1], data->raw_size))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
data->raw_data = p;
|
data->raw_data = &u.val32[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -659,7 +659,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
|
||||||
if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
|
if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
}
|
}
|
||||||
if (ret == 0)
|
if (ret >= 0)
|
||||||
ret = convert_variable(&vr_die, pf);
|
ret = convert_variable(&vr_die, pf);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -162,7 +162,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,
|
||||||
{
|
{
|
||||||
return perf_event__parse_sample(event, session->sample_type,
|
return perf_event__parse_sample(event, session->sample_type,
|
||||||
session->sample_size,
|
session->sample_size,
|
||||||
session->sample_id_all, sample);
|
session->sample_id_all, sample,
|
||||||
|
session->header.needs_swap);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
|
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
|
||||||
|
|
|
@ -151,11 +151,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
|
||||||
{
|
{
|
||||||
u64 ip_l, ip_r;
|
u64 ip_l, ip_r;
|
||||||
|
|
||||||
|
if (!left->ms.sym && !right->ms.sym)
|
||||||
|
return right->level - left->level;
|
||||||
|
|
||||||
|
if (!left->ms.sym || !right->ms.sym)
|
||||||
|
return cmp_null(left->ms.sym, right->ms.sym);
|
||||||
|
|
||||||
if (left->ms.sym == right->ms.sym)
|
if (left->ms.sym == right->ms.sym)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ip_l = left->ms.sym ? left->ms.sym->start : left->ip;
|
ip_l = left->ms.sym->start;
|
||||||
ip_r = right->ms.sym ? right->ms.sym->start : right->ip;
|
ip_r = right->ms.sym->start;
|
||||||
|
|
||||||
return (int64_t)(ip_r - ip_l);
|
return (int64_t)(ip_r - ip_l);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,16 +74,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
|
||||||
|
|
||||||
bool symbol_type__is_a(char symbol_type, enum map_type map_type)
|
bool symbol_type__is_a(char symbol_type, enum map_type map_type)
|
||||||
{
|
{
|
||||||
|
symbol_type = toupper(symbol_type);
|
||||||
|
|
||||||
switch (map_type) {
|
switch (map_type) {
|
||||||
case MAP__FUNCTION:
|
case MAP__FUNCTION:
|
||||||
return symbol_type == 'T' || symbol_type == 'W';
|
return symbol_type == 'T' || symbol_type == 'W';
|
||||||
case MAP__VARIABLE:
|
case MAP__VARIABLE:
|
||||||
return symbol_type == 'D' || symbol_type == 'd';
|
return symbol_type == 'D';
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int prefix_underscores_count(const char *str)
|
||||||
|
{
|
||||||
|
const char *tail = str;
|
||||||
|
|
||||||
|
while (*tail == '_')
|
||||||
|
tail++;
|
||||||
|
|
||||||
|
return tail - str;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SYMBOL_A 0
|
||||||
|
#define SYMBOL_B 1
|
||||||
|
|
||||||
|
static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
|
||||||
|
{
|
||||||
|
s64 a;
|
||||||
|
s64 b;
|
||||||
|
|
||||||
|
/* Prefer a symbol with non zero length */
|
||||||
|
a = syma->end - syma->start;
|
||||||
|
b = symb->end - symb->start;
|
||||||
|
if ((b == 0) && (a > 0))
|
||||||
|
return SYMBOL_A;
|
||||||
|
else if ((a == 0) && (b > 0))
|
||||||
|
return SYMBOL_B;
|
||||||
|
|
||||||
|
/* Prefer a non weak symbol over a weak one */
|
||||||
|
a = syma->binding == STB_WEAK;
|
||||||
|
b = symb->binding == STB_WEAK;
|
||||||
|
if (b && !a)
|
||||||
|
return SYMBOL_A;
|
||||||
|
if (a && !b)
|
||||||
|
return SYMBOL_B;
|
||||||
|
|
||||||
|
/* Prefer a global symbol over a non global one */
|
||||||
|
a = syma->binding == STB_GLOBAL;
|
||||||
|
b = symb->binding == STB_GLOBAL;
|
||||||
|
if (a && !b)
|
||||||
|
return SYMBOL_A;
|
||||||
|
if (b && !a)
|
||||||
|
return SYMBOL_B;
|
||||||
|
|
||||||
|
/* Prefer a symbol with less underscores */
|
||||||
|
a = prefix_underscores_count(syma->name);
|
||||||
|
b = prefix_underscores_count(symb->name);
|
||||||
|
if (b > a)
|
||||||
|
return SYMBOL_A;
|
||||||
|
else if (a > b)
|
||||||
|
return SYMBOL_B;
|
||||||
|
|
||||||
|
/* If all else fails, choose the symbol with the longest name */
|
||||||
|
if (strlen(syma->name) >= strlen(symb->name))
|
||||||
|
return SYMBOL_A;
|
||||||
|
else
|
||||||
|
return SYMBOL_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void symbols__fixup_duplicate(struct rb_root *symbols)
|
||||||
|
{
|
||||||
|
struct rb_node *nd;
|
||||||
|
struct symbol *curr, *next;
|
||||||
|
|
||||||
|
nd = rb_first(symbols);
|
||||||
|
|
||||||
|
while (nd) {
|
||||||
|
curr = rb_entry(nd, struct symbol, rb_node);
|
||||||
|
again:
|
||||||
|
nd = rb_next(&curr->rb_node);
|
||||||
|
next = rb_entry(nd, struct symbol, rb_node);
|
||||||
|
|
||||||
|
if (!nd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (curr->start != next->start)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (choose_best_symbol(curr, next) == SYMBOL_A) {
|
||||||
|
rb_erase(&next->rb_node, symbols);
|
||||||
|
goto again;
|
||||||
|
} else {
|
||||||
|
nd = rb_next(&curr->rb_node);
|
||||||
|
rb_erase(&curr->rb_node, symbols);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void symbols__fixup_end(struct rb_root *symbols)
|
static void symbols__fixup_end(struct rb_root *symbols)
|
||||||
{
|
{
|
||||||
struct rb_node *nd, *prevnd = rb_first(symbols);
|
struct rb_node *nd, *prevnd = rb_first(symbols);
|
||||||
|
@ -438,18 +526,11 @@ int kallsyms__parse(const char *filename, void *arg,
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
size_t n;
|
size_t n;
|
||||||
int err = -1;
|
int err = -1;
|
||||||
u64 prev_start = 0;
|
|
||||||
char prev_symbol_type = 0;
|
|
||||||
char *prev_symbol_name;
|
|
||||||
FILE *file = fopen(filename, "r");
|
FILE *file = fopen(filename, "r");
|
||||||
|
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
goto out_failure;
|
goto out_failure;
|
||||||
|
|
||||||
prev_symbol_name = malloc(KSYM_NAME_LEN);
|
|
||||||
if (prev_symbol_name == NULL)
|
|
||||||
goto out_close;
|
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
while (!feof(file)) {
|
while (!feof(file)) {
|
||||||
|
@ -470,7 +551,7 @@ int kallsyms__parse(const char *filename, void *arg,
|
||||||
if (len + 2 >= line_len)
|
if (len + 2 >= line_len)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
symbol_type = toupper(line[len]);
|
symbol_type = line[len];
|
||||||
len += 2;
|
len += 2;
|
||||||
symbol_name = line + len;
|
symbol_name = line + len;
|
||||||
len = line_len - len;
|
len = line_len - len;
|
||||||
|
@ -480,24 +561,18 @@ int kallsyms__parse(const char *filename, void *arg,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prev_symbol_type) {
|
/*
|
||||||
u64 end = start;
|
* module symbols are not sorted so we add all
|
||||||
if (end != prev_start)
|
* symbols with zero length and rely on
|
||||||
--end;
|
* symbols__fixup_end() to fix it up.
|
||||||
err = process_symbol(arg, prev_symbol_name,
|
*/
|
||||||
prev_symbol_type, prev_start, end);
|
err = process_symbol(arg, symbol_name,
|
||||||
if (err)
|
symbol_type, start, start);
|
||||||
break;
|
if (err)
|
||||||
}
|
break;
|
||||||
|
|
||||||
memcpy(prev_symbol_name, symbol_name, len + 1);
|
|
||||||
prev_symbol_type = symbol_type;
|
|
||||||
prev_start = start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(prev_symbol_name);
|
|
||||||
free(line);
|
free(line);
|
||||||
out_close:
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -703,6 +778,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
|
||||||
if (dso__load_all_kallsyms(dso, filename, map) < 0)
|
if (dso__load_all_kallsyms(dso, filename, map) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
symbols__fixup_duplicate(&dso->symbols[map->type]);
|
||||||
|
symbols__fixup_end(&dso->symbols[map->type]);
|
||||||
|
|
||||||
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
|
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
|
||||||
dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
|
dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
|
||||||
else
|
else
|
||||||
|
@ -1092,8 +1170,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
|
||||||
if (dso->has_build_id) {
|
if (dso->has_build_id) {
|
||||||
u8 build_id[BUILD_ID_SIZE];
|
u8 build_id[BUILD_ID_SIZE];
|
||||||
|
|
||||||
if (elf_read_build_id(elf, build_id,
|
if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
|
||||||
BUILD_ID_SIZE) != BUILD_ID_SIZE)
|
|
||||||
goto out_elf_end;
|
goto out_elf_end;
|
||||||
|
|
||||||
if (!dso__build_id_equal(dso, build_id))
|
if (!dso__build_id_equal(dso, build_id))
|
||||||
|
@ -1111,6 +1188,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
|
opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
|
||||||
|
if (opdshdr.sh_type != SHT_PROGBITS)
|
||||||
|
opdsec = NULL;
|
||||||
if (opdsec)
|
if (opdsec)
|
||||||
opddata = elf_rawdata(opdsec, NULL);
|
opddata = elf_rawdata(opdsec, NULL);
|
||||||
|
|
||||||
|
@ -1276,6 +1355,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
|
||||||
* For misannotated, zeroed, ASM function sizes.
|
* For misannotated, zeroed, ASM function sizes.
|
||||||
*/
|
*/
|
||||||
if (nr > 0) {
|
if (nr > 0) {
|
||||||
|
symbols__fixup_duplicate(&dso->symbols[map->type]);
|
||||||
symbols__fixup_end(&dso->symbols[map->type]);
|
symbols__fixup_end(&dso->symbols[map->type]);
|
||||||
if (kmap) {
|
if (kmap) {
|
||||||
/*
|
/*
|
||||||
|
@ -1362,8 +1442,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
|
||||||
ptr = data->d_buf;
|
ptr = data->d_buf;
|
||||||
while (ptr < (data->d_buf + data->d_size)) {
|
while (ptr < (data->d_buf + data->d_size)) {
|
||||||
GElf_Nhdr *nhdr = ptr;
|
GElf_Nhdr *nhdr = ptr;
|
||||||
int namesz = NOTE_ALIGN(nhdr->n_namesz),
|
size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
|
||||||
descsz = NOTE_ALIGN(nhdr->n_descsz);
|
descsz = NOTE_ALIGN(nhdr->n_descsz);
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
ptr += sizeof(*nhdr);
|
ptr += sizeof(*nhdr);
|
||||||
|
@ -1372,8 +1452,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
|
||||||
if (nhdr->n_type == NT_GNU_BUILD_ID &&
|
if (nhdr->n_type == NT_GNU_BUILD_ID &&
|
||||||
nhdr->n_namesz == sizeof("GNU")) {
|
nhdr->n_namesz == sizeof("GNU")) {
|
||||||
if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
|
if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
|
||||||
memcpy(bf, ptr, BUILD_ID_SIZE);
|
size_t sz = min(size, descsz);
|
||||||
err = BUILD_ID_SIZE;
|
memcpy(bf, ptr, sz);
|
||||||
|
memset(bf + sz, 0, size - sz);
|
||||||
|
err = descsz;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1425,7 +1507,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
|
||||||
while (1) {
|
while (1) {
|
||||||
char bf[BUFSIZ];
|
char bf[BUFSIZ];
|
||||||
GElf_Nhdr nhdr;
|
GElf_Nhdr nhdr;
|
||||||
int namesz, descsz;
|
size_t namesz, descsz;
|
||||||
|
|
||||||
if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
|
if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
|
||||||
break;
|
break;
|
||||||
|
@ -1434,15 +1516,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
|
||||||
descsz = NOTE_ALIGN(nhdr.n_descsz);
|
descsz = NOTE_ALIGN(nhdr.n_descsz);
|
||||||
if (nhdr.n_type == NT_GNU_BUILD_ID &&
|
if (nhdr.n_type == NT_GNU_BUILD_ID &&
|
||||||
nhdr.n_namesz == sizeof("GNU")) {
|
nhdr.n_namesz == sizeof("GNU")) {
|
||||||
if (read(fd, bf, namesz) != namesz)
|
if (read(fd, bf, namesz) != (ssize_t)namesz)
|
||||||
break;
|
break;
|
||||||
if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
|
if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
|
||||||
if (read(fd, build_id,
|
size_t sz = min(descsz, size);
|
||||||
BUILD_ID_SIZE) == BUILD_ID_SIZE) {
|
if (read(fd, build_id, sz) == (ssize_t)sz) {
|
||||||
|
memset(build_id + sz, 0, size - sz);
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (read(fd, bf, descsz) != descsz)
|
} else if (read(fd, bf, descsz) != (ssize_t)descsz)
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
int n = namesz + descsz;
|
int n = namesz + descsz;
|
||||||
|
|
Loading…
Add table
Reference in a new issue