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 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
|
||||
@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
|
||||
|
@ -63,6 +65,11 @@ ifeq ($(ARCH),x86_64)
|
|||
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:
|
||||
#
|
||||
|
@ -95,7 +102,7 @@ ifndef PERF_DEBUG
|
|||
CFLAGS_OPTIMIZE = -O6
|
||||
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
|
||||
ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||||
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;
|
||||
int track = !evsel->idx; /* only the first counter needs these */
|
||||
|
||||
attr->disabled = 1;
|
||||
attr->inherit = !no_inherit;
|
||||
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -561,7 +561,7 @@ static int test__basic_mmap(void)
|
|||
}
|
||||
|
||||
err = perf_event__parse_sample(event, attr.sample_type, sample_size,
|
||||
false, &sample);
|
||||
false, &sample, false);
|
||||
if (err) {
|
||||
pr_err("Can't parse sample, err = %d\n", err);
|
||||
goto out_munmap;
|
||||
|
|
|
@ -191,7 +191,8 @@ static void __zero_source_counters(struct sym_entry *syme)
|
|||
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 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))
|
||||
return;
|
||||
|
||||
ip = syme->map->map_ip(syme->map, ip);
|
||||
symbol__inc_addr_samples(sym, syme->map, counter, ip);
|
||||
ip = map->map_ip(map, ip);
|
||||
symbol__inc_addr_samples(sym, map, counter, ip);
|
||||
|
||||
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);
|
||||
assert(evsel != NULL);
|
||||
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);
|
||||
if (list_empty(&syme->node) || !syme->node.next) {
|
||||
static bool first = true;
|
||||
|
|
|
@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
|
|||
continue;
|
||||
pbf += n + 3;
|
||||
if (*pbf == 'x') { /* vm_exec */
|
||||
char anonstr[] = "//anon\n";
|
||||
char *execname = strchr(bf, '/');
|
||||
|
||||
/* Catch VDSO */
|
||||
if (execname == NULL)
|
||||
execname = strstr(bf, "[vdso]");
|
||||
|
||||
/* Catch anonymous mmaps */
|
||||
if ((execname == NULL) && !strstr(bf, "["))
|
||||
execname = anonstr;
|
||||
|
||||
if (execname == NULL)
|
||||
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 sample_size, bool sample_id_all,
|
||||
struct perf_sample *sample);
|
||||
struct perf_sample *sample, bool swapped);
|
||||
|
||||
#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 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__disable(struct perf_evlist *evlist);
|
||||
void perf_evlist__enable(struct perf_evlist *evlist);
|
||||
|
||||
static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
|
||||
struct cpu_map *cpus,
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
* Released under the GPL v2. (and only v2, not any later version)
|
||||
*/
|
||||
|
||||
#include <byteswap.h>
|
||||
#include "asm/bug.h"
|
||||
#include "evsel.h"
|
||||
#include "evlist.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 sample_size, bool sample_id_all,
|
||||
struct perf_sample *data)
|
||||
struct perf_sample *data, bool swapped)
|
||||
{
|
||||
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->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) {
|
||||
u32 *p = (u32 *)array;
|
||||
data->pid = p[0];
|
||||
data->tid = p[1];
|
||||
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]);
|
||||
u.val32[1] = bswap_32(u.val32[1]);
|
||||
}
|
||||
|
||||
data->pid = u.val32[0];
|
||||
data->tid = u.val32[1];
|
||||
array++;
|
||||
}
|
||||
|
||||
|
@ -395,8 +414,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
|
|||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
|
@ -423,18 +449,24 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
|
|||
}
|
||||
|
||||
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)))
|
||||
return -EFAULT;
|
||||
|
||||
data->raw_size = *p;
|
||||
p++;
|
||||
data->raw_size = u.val32[0];
|
||||
|
||||
if (sample_overlap(event, p, data->raw_size))
|
||||
if (sample_overlap(event, &u.val32[1], data->raw_size))
|
||||
return -EFAULT;
|
||||
|
||||
data->raw_data = p;
|
||||
data->raw_data = &u.val32[1];
|
||||
}
|
||||
|
||||
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))
|
||||
ret = -ENOENT;
|
||||
}
|
||||
if (ret == 0)
|
||||
if (ret >= 0)
|
||||
ret = convert_variable(&vr_die, pf);
|
||||
|
||||
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,
|
||||
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,
|
||||
|
|
|
@ -151,11 +151,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
|
|||
{
|
||||
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)
|
||||
return 0;
|
||||
|
||||
ip_l = left->ms.sym ? left->ms.sym->start : left->ip;
|
||||
ip_r = right->ms.sym ? right->ms.sym->start : right->ip;
|
||||
ip_l = left->ms.sym->start;
|
||||
ip_r = right->ms.sym->start;
|
||||
|
||||
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)
|
||||
{
|
||||
symbol_type = toupper(symbol_type);
|
||||
|
||||
switch (map_type) {
|
||||
case MAP__FUNCTION:
|
||||
return symbol_type == 'T' || symbol_type == 'W';
|
||||
case MAP__VARIABLE:
|
||||
return symbol_type == 'D' || symbol_type == 'd';
|
||||
return symbol_type == 'D';
|
||||
default:
|
||||
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)
|
||||
{
|
||||
struct rb_node *nd, *prevnd = rb_first(symbols);
|
||||
|
@ -438,18 +526,11 @@ int kallsyms__parse(const char *filename, void *arg,
|
|||
char *line = NULL;
|
||||
size_t n;
|
||||
int err = -1;
|
||||
u64 prev_start = 0;
|
||||
char prev_symbol_type = 0;
|
||||
char *prev_symbol_name;
|
||||
FILE *file = fopen(filename, "r");
|
||||
|
||||
if (file == NULL)
|
||||
goto out_failure;
|
||||
|
||||
prev_symbol_name = malloc(KSYM_NAME_LEN);
|
||||
if (prev_symbol_name == NULL)
|
||||
goto out_close;
|
||||
|
||||
err = 0;
|
||||
|
||||
while (!feof(file)) {
|
||||
|
@ -470,7 +551,7 @@ int kallsyms__parse(const char *filename, void *arg,
|
|||
if (len + 2 >= line_len)
|
||||
continue;
|
||||
|
||||
symbol_type = toupper(line[len]);
|
||||
symbol_type = line[len];
|
||||
len += 2;
|
||||
symbol_name = line + len;
|
||||
len = line_len - len;
|
||||
|
@ -480,24 +561,18 @@ int kallsyms__parse(const char *filename, void *arg,
|
|||
break;
|
||||
}
|
||||
|
||||
if (prev_symbol_type) {
|
||||
u64 end = start;
|
||||
if (end != prev_start)
|
||||
--end;
|
||||
err = process_symbol(arg, prev_symbol_name,
|
||||
prev_symbol_type, prev_start, end);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(prev_symbol_name, symbol_name, len + 1);
|
||||
prev_symbol_type = symbol_type;
|
||||
prev_start = start;
|
||||
/*
|
||||
* module symbols are not sorted so we add all
|
||||
* symbols with zero length and rely on
|
||||
* symbols__fixup_end() to fix it up.
|
||||
*/
|
||||
err = process_symbol(arg, symbol_name,
|
||||
symbol_type, start, start);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
free(prev_symbol_name);
|
||||
free(line);
|
||||
out_close:
|
||||
fclose(file);
|
||||
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)
|
||||
return -1;
|
||||
|
||||
symbols__fixup_duplicate(&dso->symbols[map->type]);
|
||||
symbols__fixup_end(&dso->symbols[map->type]);
|
||||
|
||||
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
|
||||
dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
|
||||
else
|
||||
|
@ -1092,8 +1170,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
|
|||
if (dso->has_build_id) {
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
|
||||
if (elf_read_build_id(elf, build_id,
|
||||
BUILD_ID_SIZE) != BUILD_ID_SIZE)
|
||||
if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
|
||||
goto out_elf_end;
|
||||
|
||||
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);
|
||||
if (opdshdr.sh_type != SHT_PROGBITS)
|
||||
opdsec = NULL;
|
||||
if (opdsec)
|
||||
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.
|
||||
*/
|
||||
if (nr > 0) {
|
||||
symbols__fixup_duplicate(&dso->symbols[map->type]);
|
||||
symbols__fixup_end(&dso->symbols[map->type]);
|
||||
if (kmap) {
|
||||
/*
|
||||
|
@ -1362,8 +1442,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
|
|||
ptr = data->d_buf;
|
||||
while (ptr < (data->d_buf + data->d_size)) {
|
||||
GElf_Nhdr *nhdr = ptr;
|
||||
int namesz = NOTE_ALIGN(nhdr->n_namesz),
|
||||
descsz = NOTE_ALIGN(nhdr->n_descsz);
|
||||
size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
|
||||
descsz = NOTE_ALIGN(nhdr->n_descsz);
|
||||
const char *name;
|
||||
|
||||
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 &&
|
||||
nhdr->n_namesz == sizeof("GNU")) {
|
||||
if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
|
||||
memcpy(bf, ptr, BUILD_ID_SIZE);
|
||||
err = BUILD_ID_SIZE;
|
||||
size_t sz = min(size, descsz);
|
||||
memcpy(bf, ptr, sz);
|
||||
memset(bf + sz, 0, size - sz);
|
||||
err = descsz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1425,7 +1507,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
|
|||
while (1) {
|
||||
char bf[BUFSIZ];
|
||||
GElf_Nhdr nhdr;
|
||||
int namesz, descsz;
|
||||
size_t namesz, descsz;
|
||||
|
||||
if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
|
||||
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);
|
||||
if (nhdr.n_type == NT_GNU_BUILD_ID &&
|
||||
nhdr.n_namesz == sizeof("GNU")) {
|
||||
if (read(fd, bf, namesz) != namesz)
|
||||
if (read(fd, bf, namesz) != (ssize_t)namesz)
|
||||
break;
|
||||
if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
|
||||
if (read(fd, build_id,
|
||||
BUILD_ID_SIZE) == BUILD_ID_SIZE) {
|
||||
size_t sz = min(descsz, size);
|
||||
if (read(fd, build_id, sz) == (ssize_t)sz) {
|
||||
memset(build_id + sz, 0, size - sz);
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
} else if (read(fd, bf, descsz) != descsz)
|
||||
} else if (read(fd, bf, descsz) != (ssize_t)descsz)
|
||||
break;
|
||||
} else {
|
||||
int n = namesz + descsz;
|
||||
|
|
Loading…
Reference in a new issue