Merge commit 'v3.1-rc9' into perf/core

Merge reason: pick up latest fixes.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Ingo Molnar
2011-10-06 12:48:57 +02:00
169 changed files with 1194 additions and 974 deletions

View File

@ -76,16 +76,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);
@ -440,18 +528,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)) {
@ -472,7 +553,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;
@ -482,24 +563,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;
@ -705,6 +780,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
@ -1094,8 +1172,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))
@ -1113,6 +1190,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);
@ -1278,6 +1357,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) {
/*
@ -1364,8 +1444,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);
@ -1374,8 +1454,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;
}
}
@ -1427,7 +1509,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;
@ -1436,15 +1518,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;