diff options
Diffstat (limited to 'tools/perf')
| -rw-r--r-- | tools/perf/Makefile | 9 | ||||
| -rw-r--r-- | tools/perf/arch/arm/util/dwarf-regs.c | 3 | ||||
| -rw-r--r-- | tools/perf/builtin-record.c | 3 | ||||
| -rw-r--r-- | tools/perf/builtin-test.c | 2 | ||||
| -rw-r--r-- | tools/perf/builtin-top.c | 9 | ||||
| -rw-r--r-- | tools/perf/util/config.c | 4 | ||||
| -rw-r--r-- | tools/perf/util/event.c | 5 | ||||
| -rw-r--r-- | tools/perf/util/event.h | 2 | ||||
| -rw-r--r-- | tools/perf/util/evlist.c | 13 | ||||
| -rw-r--r-- | tools/perf/util/evlist.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 57 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/python.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/session.h | 3 | ||||
| -rw-r--r-- | tools/perf/util/sort.c | 10 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 153 | 
16 files changed, 218 insertions, 60 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 3b8f7b80376..e9d5c271db6 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -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) diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c index fff6450c8c9..e8d5c551c69 100644 --- a/tools/perf/arch/arm/util/dwarf-regs.c +++ b/tools/perf/arch/arm/util/dwarf-regs.c @@ -8,7 +8,10 @@   * published by the Free Software Foundation.   */ +#include <stdlib.h> +#ifndef __UCLIBC__  #include <libio.h> +#endif  #include <dwarf-regs.h>  struct pt_regs_dwarfnum { diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6b0519f885e..f4c3fbee4ba 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -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  	 */ diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 55f4c76f282..efe696f936e 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -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; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a43433f0830..d28013b7d61 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -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; diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index fe02903f7d0..80d9598db31 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -341,7 +341,7 @@ const char *perf_config_dirname(const char *name, const char *value)  static int perf_default_core_config(const char *var __used, const char *value __used)  { -	/* Add other config variables here and to Documentation/config.txt. */ +	/* Add other config variables here. */  	return 0;  } @@ -350,7 +350,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used)  	if (!prefixcmp(var, "core."))  		return perf_default_core_config(var, value); -	/* Add other config variables here and to Documentation/config.txt. */ +	/* Add other config variables here. */  	return 0;  } diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 3c1b8a63210..437f8ca679a 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -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; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1d7f66488a8..357a85b8524 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -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 */ diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c12bd476c6f..72e9f4886b6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -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; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index ce85ae9ae57..f3491500274 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -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, diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a03a36b7908..e389815078d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -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,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,  	}  	if (type & PERF_SAMPLE_RAW) { -		u32 *p = (u32 *)array; +		const u64 *pdata; + +		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]; +		pdata = (void *) array + sizeof(u32); -		if (sample_overlap(event, p, data->raw_size)) +		if (sample_overlap(event, pdata, data->raw_size))  			return -EFAULT; -		data->raw_data = p; +		data->raw_data = (void *) pdata;  	}  	return 0; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 555fc3864b9..5d732621a46 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -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) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index cbc8f215d4b..7624324efad 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -803,7 +803,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,  		first = list_entry(evlist->entries.next, struct perf_evsel, node);  		err = perf_event__parse_sample(event, first->attr.sample_type,  					       perf_evsel__sample_size(first), -					       sample_id_all, &pevent->sample); +					       sample_id_all, &pevent->sample, false);  		if (err)  			return PyErr_Format(PyExc_OSError,  					    "perf: can't parse sample, err=%d", err); diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 170601e67d6..974d0cbee5e 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -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, diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 401e220566f..1ee8f1e40f1 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -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);  } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 469c0264ed2..40eeaf07725 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -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 @@ new_symbol:  	 * 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;  |