am 2124afee: Added NEC and PMC\'s USB VIDs upon their request.
Merge commit '2124afeee1f19423e71c52ede6f4926f5389e917' into gingerbread-plus-aosp
* commit '2124afeee1f19423e71c52ede6f4926f5389e917':
Added NEC and PMC's USB VIDs upon their request.
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 3c1cf02..ccc001b 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -5,7 +5,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= debuggerd.c getevent.c unwind-arm.c pr-support.c utility.c
+LOCAL_SRC_FILES:= debuggerd.c getevent.c unwind-arm.c pr-support.c utility.c symbol_table.c
LOCAL_CFLAGS := -Wall
LOCAL_MODULE := debuggerd
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index e850a2e..3b2972a 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -63,7 +63,7 @@
/* Log information onto the tombstone */
void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...)
{
- char buf[128];
+ char buf[512];
va_list ap;
va_start(ap, fmt);
@@ -106,10 +106,11 @@
mi->start = strtoul(line, 0, 16);
mi->end = strtoul(line + 9, 0, 16);
- /* To be filled in parse_exidx_info if the mapped section starts with
+ /* To be filled in parse_elf_info if the mapped section starts with
* elf_header
*/
mi->exidx_start = mi->exidx_end = 0;
+ mi->symbols = 0;
mi->next = 0;
strcpy(mi->name, line + 49);
@@ -353,7 +354,7 @@
if(sig) dump_fault_addr(tfd, tid, sig);
}
-static void parse_exidx_info(mapinfo *milist, pid_t pid)
+static void parse_elf_info(mapinfo *milist, pid_t pid)
{
mapinfo *mi;
for (mi = milist; mi != NULL; mi = mi->next) {
@@ -383,6 +384,9 @@
break;
}
}
+
+ /* Try to load symbols from this file */
+ mi->symbols = symbol_table_create(mi->name);
}
}
}
@@ -420,7 +424,7 @@
fclose(fp);
}
- parse_exidx_info(milist, tid);
+ parse_elf_info(milist, tid);
/* If stack unwinder fails, use the default solution to dump the stack
* content.
@@ -439,6 +443,7 @@
while(milist) {
mapinfo *next = milist->next;
+ symbol_table_free(milist->symbols);
free(milist);
milist = next;
}
diff --git a/debuggerd/symbol_table.c b/debuggerd/symbol_table.c
new file mode 100644
index 0000000..150c058
--- /dev/null
+++ b/debuggerd/symbol_table.c
@@ -0,0 +1,178 @@
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "symbol_table.h"
+
+#include <linux/elf.h>
+
+// Compare func for qsort
+static int qcompar(const void *a, const void *b)
+{
+ return ((struct symbol*)a)->addr - ((struct symbol*)b)->addr;
+}
+
+// Compare func for bsearch
+static int bcompar(const void *addr, const void *element)
+{
+ struct symbol *symbol = (struct symbol*)element;
+
+ if((unsigned int)addr < symbol->addr) {
+ return -1;
+ }
+
+ if((unsigned int)addr - symbol->addr >= symbol->size) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Create a symbol table from a given file
+ *
+ * Parameters:
+ * filename - Filename to process
+ *
+ * Returns:
+ * A newly-allocated SymbolTable structure, or NULL if error.
+ * Free symbol table with symbol_table_free()
+ */
+struct symbol_table *symbol_table_create(const char *filename)
+{
+ struct symbol_table *table = NULL;
+
+ // Open the file, and map it into memory
+ struct stat sb;
+ int length;
+ char *base;
+
+ int fd = open(filename, O_RDONLY);
+
+ if(fd < 0) {
+ goto out;
+ }
+
+ fstat(fd, &sb);
+ length = sb.st_size;
+
+ base = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ if(!base) {
+ goto out_close;
+ }
+
+ // Parse the file header
+ Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
+ Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
+
+ // Search for the dynamic symbols section
+ int dynsym_idx = -1;
+ int i;
+
+ for(i = 0; i < hdr->e_shnum; i++) {
+ if(shdr[i].sh_type == SHT_DYNSYM ) {
+ dynsym_idx = i;
+ }
+ }
+
+ if(dynsym_idx == -1) {
+ goto out_unmap;
+ }
+
+ Elf32_Sym *dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
+ int numsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
+
+ table = malloc(sizeof(struct symbol_table));
+ if(!table) {
+ goto out_unmap;
+ }
+ table->num_symbols = 0;
+
+ // Iterate through the dynamic symbol table, and count how many symbols
+ // are actually defined
+ for(i = 0; i < numsyms; i++) {
+ if(dynsyms[i].st_shndx != SHN_UNDEF) {
+ table->num_symbols++;
+ }
+ }
+
+ int dynstr_idx = shdr[dynsym_idx].sh_link;
+ char *dynstr = base + shdr[dynstr_idx].sh_offset;
+
+ // Now, create an entry in our symbol table structure for each symbol...
+ table->symbols = malloc(table->num_symbols * sizeof(struct symbol));
+ if(!table->symbols) {
+ free(table);
+ table = NULL;
+ goto out_unmap;
+ }
+
+ // ...and populate them
+ int j = 0;
+ for(i = 0; i < numsyms; i++) {
+ if(dynsyms[i].st_shndx != SHN_UNDEF) {
+ table->symbols[j].name = strdup(dynstr + dynsyms[i].st_name);
+ table->symbols[j].addr = dynsyms[i].st_value;
+ table->symbols[j].size = dynsyms[i].st_size;
+ j++;
+ }
+ }
+
+ // Sort the symbol table entries, so they can be bsearched later
+ qsort(table->symbols, table->num_symbols, sizeof(struct symbol), qcompar);
+
+out_unmap:
+ munmap(base, length);
+
+out_close:
+ close(fd);
+
+out:
+ return table;
+}
+
+/*
+ * Free a symbol table
+ *
+ * Parameters:
+ * table - Table to free
+ */
+void symbol_table_free(struct symbol_table *table)
+{
+ int i;
+
+ if(!table) {
+ return;
+ }
+
+ for(i=0; i<table->num_symbols; i++) {
+ free(table->symbols[i].name);
+ }
+
+ free(table->symbols);
+ free(table);
+}
+
+/*
+ * Search for an address in the symbol table
+ *
+ * Parameters:
+ * table - Table to search in
+ * addr - Address to search for.
+ *
+ * Returns:
+ * A pointer to the Symbol structure corresponding to the
+ * symbol which contains this address, or NULL if no symbol
+ * contains it.
+ */
+const struct symbol *symbol_table_lookup(struct symbol_table *table, unsigned int addr)
+{
+ if(!table) {
+ return NULL;
+ }
+
+ return bsearch((void*)addr, table->symbols, table->num_symbols, sizeof(struct symbol), bcompar);
+}
diff --git a/debuggerd/symbol_table.h b/debuggerd/symbol_table.h
new file mode 100644
index 0000000..d9d2520
--- /dev/null
+++ b/debuggerd/symbol_table.h
@@ -0,0 +1,19 @@
+#ifndef SYMBOL_TABLE_H
+#define SYMBOL_TABLE_H
+
+struct symbol {
+ unsigned int addr;
+ unsigned int size;
+ char *name;
+};
+
+struct symbol_table {
+ struct symbol *symbols;
+ int num_symbols;
+};
+
+struct symbol_table *symbol_table_create(const char *filename);
+void symbol_table_free(struct symbol_table *table);
+const struct symbol *symbol_table_lookup(struct symbol_table *table, unsigned int addr);
+
+#endif
diff --git a/debuggerd/unwind-arm.c b/debuggerd/unwind-arm.c
index 9642d2e..b081161 100644
--- a/debuggerd/unwind-arm.c
+++ b/debuggerd/unwind-arm.c
@@ -37,6 +37,8 @@
#include <unwind.h>
#include "utility.h"
+#include "symbol_table.h"
+
typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
@@ -393,6 +395,7 @@
phase2_vrs *vrs = (phase2_vrs*) context;
const mapinfo *mi;
bool only_in_tombstone = !at_fault;
+ const struct symbol* sym = 0;
if (stack_level < STACK_CONTENT_DEPTH) {
sp_list[stack_level] = vrs->core.r[R_SP];
@@ -451,9 +454,20 @@
rel_pc = pc;
mi = pc_to_mapinfo(map, pc, &rel_pc);
- _LOG(tfd, only_in_tombstone,
- " #%02d pc %08x %s\n", stack_level, rel_pc,
- mi ? mi->name : "");
+ /* See if we can determine what symbol this stack frame resides in */
+ if (mi != 0 && mi->symbols != 0) {
+ sym = symbol_table_lookup(mi->symbols, rel_pc);
+ }
+
+ if (sym) {
+ _LOG(tfd, only_in_tombstone,
+ " #%02d pc %08x %s (%s)\n", stack_level, rel_pc,
+ mi ? mi->name : "", sym->name);
+ } else {
+ _LOG(tfd, only_in_tombstone,
+ " #%02d pc %08x %s\n", stack_level, rel_pc,
+ mi ? mi->name : "");
+ }
return _URC_NO_REASON;
}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 49f5951..2ffdf56 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,6 +21,8 @@
#include <stddef.h>
#include <stdbool.h>
+#include "symbol_table.h"
+
#ifndef PT_ARM_EXIDX
#define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */
#endif
@@ -33,6 +35,7 @@
unsigned end;
unsigned exidx_start;
unsigned exidx_end;
+ struct symbol_table *symbols;
char name[];
} mapinfo;
diff --git a/toolbox/ls.c b/toolbox/ls.c
index f340a83..6c8de7a 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -13,6 +13,130 @@
#include <grp.h>
#include <linux/kdev_t.h>
+#include <limits.h>
+
+// dynamic arrays
+typedef struct {
+ int count;
+ int capacity;
+ void** items;
+} dynarray_t;
+
+#define DYNARRAY_INITIALIZER { 0, 0, NULL }
+
+static void dynarray_init( dynarray_t *a )
+{
+ a->count = a->capacity = 0;
+ a->items = NULL;
+}
+
+static void dynarray_reserve_more( dynarray_t *a, int count )
+{
+ int old_cap = a->capacity;
+ int new_cap = old_cap;
+ const int max_cap = INT_MAX/sizeof(void*);
+ void** new_items;
+ int new_count = a->count + count;
+
+ if (count <= 0)
+ return;
+
+ if (count > max_cap - a->count)
+ abort();
+
+ new_count = a->count + count;
+
+ while (new_cap < new_count) {
+ old_cap = new_cap;
+ new_cap += (new_cap >> 2) + 4;
+ if (new_cap < old_cap || new_cap > max_cap) {
+ new_cap = max_cap;
+ }
+ }
+ new_items = realloc(a->items, new_cap*sizeof(void*));
+ if (new_items == NULL)
+ abort();
+
+ a->items = new_items;
+ a->capacity = new_cap;
+}
+
+static void dynarray_append( dynarray_t *a, void* item )
+{
+ if (a->count >= a->capacity)
+ dynarray_reserve_more(a, 1);
+
+ a->items[a->count++] = item;
+}
+
+static void dynarray_done( dynarray_t *a )
+{
+ free(a->items);
+ a->items = NULL;
+ a->count = a->capacity = 0;
+}
+
+#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \
+ do { \
+ int _nn_##__LINE__ = 0; \
+ for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \
+ _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \
+ _stmnt; \
+ } \
+ } while (0)
+
+#define DYNARRAY_FOREACH(_array,_item,_stmnt) \
+ DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt)
+
+// string arrays
+
+typedef dynarray_t strlist_t;
+
+#define STRLIST_INITIALIZER DYNARRAY_INITIALIZER
+
+#define STRLIST_FOREACH(_list,_string,_stmnt) \
+ DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt)
+
+static void strlist_init( strlist_t *list )
+{
+ dynarray_init(list);
+}
+
+static void strlist_append_b( strlist_t *list, const void* str, size_t slen )
+{
+ char *copy = malloc(slen+1);
+ memcpy(copy, str, slen);
+ copy[slen] = '\0';
+ dynarray_append(list, copy);
+}
+
+static void strlist_append_dup( strlist_t *list, const char *str)
+{
+ strlist_append_b(list, str, strlen(str));
+}
+
+static void strlist_done( strlist_t *list )
+{
+ STRLIST_FOREACH(list, string, free(string));
+ dynarray_done(list);
+}
+
+static int strlist_compare_strings(const void* a, const void* b)
+{
+ const char *sa = *(const char **)a;
+ const char *sb = *(const char **)b;
+ return strcmp(sa, sb);
+}
+
+static void strlist_sort( strlist_t *list )
+{
+ if (list->count > 0) {
+ qsort(list->items,
+ (size_t)list->count,
+ sizeof(void*),
+ strlist_compare_strings);
+ }
+}
// bits for flags argument
#define LIST_LONG (1 << 0)
@@ -233,7 +357,8 @@
char tmp[4096];
DIR *d;
struct dirent *de;
-
+ strlist_t files = STRLIST_INITIALIZER;
+
d = opendir(name);
if(d == 0) {
fprintf(stderr, "opendir failed, %s\n", strerror(errno));
@@ -248,10 +373,16 @@
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue;
- listfile(name, de->d_name, flags);
+ strlist_append_dup(&files, de->d_name);
}
+ strlist_sort(&files);
+ STRLIST_FOREACH(&files, filename, listfile(name, filename, flags));
+ strlist_done(&files);
+
if (flags & LIST_RECURSIVE) {
+ strlist_t subdirs = STRLIST_INITIALIZER;
+
rewinddir(d);
while ((de = readdir(d)) != 0) {
@@ -284,10 +415,15 @@
}
if (S_ISDIR(s.st_mode)) {
- printf("\n%s:\n", tmp);
- listdir(tmp, flags);
+ strlist_append_dup(&subdirs, tmp);
}
}
+ strlist_sort(&subdirs);
+ STRLIST_FOREACH(&subdirs, path, {
+ printf("\n%s:\n", path);
+ listdir(path, flags);
+ });
+ strlist_done(&subdirs);
}
closedir(d);
@@ -331,27 +467,40 @@
if(argc > 1) {
int i;
int err = 0;
+ strlist_t files = STRLIST_INITIALIZER;
for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-l")) {
- flags |= LIST_LONG;
- } else if (!strcmp(argv[i], "-s")) {
- flags |= LIST_SIZE;
- } else if (!strcmp(argv[i], "-a")) {
- flags |= LIST_ALL;
- } else if (!strcmp(argv[i], "-R")) {
- flags |= LIST_RECURSIVE;
- } else if (!strcmp(argv[i], "-d")) {
- flags |= LIST_DIRECTORIES;
- } else {
- listed++;
- if(listpath(argv[i], flags) != 0) {
- err = EXIT_FAILURE;
+ if (argv[i][0] == '-') {
+ /* an option ? */
+ const char *arg = argv[i]+1;
+ while (arg[0]) {
+ switch (arg[0]) {
+ case 'l': flags |= LIST_LONG; break;
+ case 's': flags |= LIST_SIZE; break;
+ case 'R': flags |= LIST_RECURSIVE; break;
+ case 'd': flags |= LIST_DIRECTORIES; break;
+ case 'a': flags |= LIST_ALL; break;
+ default:
+ fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
+ exit(1);
+ }
+ arg++;
}
+ } else {
+ /* not an option ? */
+ strlist_append_dup(&files, argv[i]);
}
}
- if (listed > 0) return err;
+ if (files.count > 0) {
+ STRLIST_FOREACH(&files, path, {
+ if (listpath(path, flags) != 0) {
+ err = EXIT_FAILURE;
+ }
+ });
+ strlist_done(&files);
+ return err;
+ }
}
// list working directory if no files or directories were specified