diff --git a/include/libunwind-coredump.h b/include/libunwind-coredump.h index a44536f1..d2b05e71 100644 --- a/include/libunwind-coredump.h +++ b/include/libunwind-coredump.h @@ -40,6 +40,8 @@ struct UCD_info; extern struct UCD_info *_UCD_create(const char *filename); extern void _UCD_destroy(struct UCD_info *); +extern int _UCD_get_num_threads(struct UCD_info *); +extern void _UCD_select_thread(struct UCD_info *, int); extern pid_t _UCD_get_pid(struct UCD_info *); extern int _UCD_get_cursig(struct UCD_info *); extern int _UCD_add_backing_file_at_segment(struct UCD_info *, int phdr_no, const char *filename); diff --git a/src/coredump/_UCD_create.c b/src/coredump/_UCD_create.c index ec0dfb54..02df5e5e 100644 --- a/src/coredump/_UCD_create.c +++ b/src/coredump/_UCD_create.c @@ -206,6 +206,9 @@ _UCD_create(const char *filename) Debug(2, "phdr[%03d]: type:%d", i, cur->p_type); if (cur->p_type == PT_NOTE) { + unsigned char *p, *note_end; + unsigned n_threads; + ui->note_phdr = malloc(cur->p_filesz); if (lseek(fd, cur->p_offset, SEEK_SET) != (off_t)cur->p_offset || (uoff_t)read(fd, ui->note_phdr, cur->p_filesz) != cur->p_filesz @@ -215,33 +218,46 @@ _UCD_create(const char *filename) goto err; } - /* Note is three 32-bit words: */ - /* Elf32_Word n_namesz; Length of the note's name */ - /* Elf32_Word n_descsz; Length of the note's descriptor */ - /* Elf32_Word n_type; Type */ - /* followed by name (padded to 32 bits(?)) and then descr */ - Elf32_Nhdr *note_hdr = ui->note_phdr; - if (cur->p_filesz >= 3*4 - && note_hdr->n_type == NT_PRSTATUS - && cur->p_filesz >= (3*4 + note_hdr->n_namesz + note_hdr->n_descsz + sizeof(*ui->prstatus)) - ) + note_end = (unsigned char *)ui->note_phdr + cur->p_filesz; + + /* Count number of threads */ + n_threads = 0; + p = ui->note_phdr; + while (p + sizeof (Elf32_Nhdr) <= note_end) { - ui->prstatus = (void*) ((((long)note_hdr + sizeof(*note_hdr) + note_hdr->n_namesz) + 3) & ~3L); -#if 0 - printf("pid:%d\n", ui->prstatus->pr_pid); - printf("ebx:%ld\n", (long)ui->prstatus->pr_reg[0]); - printf("ecx:%ld\n", (long)ui->prstatus->pr_reg[1]); - printf("edx:%ld\n", (long)ui->prstatus->pr_reg[2]); - printf("esi:%ld\n", (long)ui->prstatus->pr_reg[3]); - printf("edi:%ld\n", (long)ui->prstatus->pr_reg[4]); - printf("ebp:%ld\n", (long)ui->prstatus->pr_reg[5]); - printf("eax:%ld\n", (long)ui->prstatus->pr_reg[6]); - printf("xds:%ld\n", (long)ui->prstatus->pr_reg[7]); - printf("xes:%ld\n", (long)ui->prstatus->pr_reg[8]); - printf("xfs:%ld\n", (long)ui->prstatus->pr_reg[9]); - printf("xgs:%ld\n", (long)ui->prstatus->pr_reg[10]); - printf("orig_eax:%ld\n", (long)ui->prstatus->pr_reg[11]); -#endif + Elf32_Nhdr *note_hdr = (Elf32_Nhdr *)p; + unsigned char *p_next; + + p_next = p + sizeof (Elf32_Nhdr) + ((note_hdr->n_namesz + 3) & ~3L) + note_hdr->n_descsz; + + if (p_next >= note_end) + break; + + if (note_hdr->n_type == NT_PRSTATUS) + n_threads++; + + p = p_next; + } + + ui->n_threads = n_threads; + ui->threads = malloc(sizeof (void *) * n_threads); + + n_threads = 0; + p = ui->note_phdr; + while (p + sizeof (Elf32_Nhdr) <= note_end) + { + Elf32_Nhdr *note_hdr = (Elf32_Nhdr *)p; + unsigned char *p_next; + + p_next = p + sizeof (Elf32_Nhdr) + ((note_hdr->n_namesz + 3) & ~3L) + note_hdr->n_descsz; + + if (p_next >= note_end) + break; + + if (note_hdr->n_type == NT_PRSTATUS) + ui->threads[n_threads++] = (void*) ((((long)note_hdr + sizeof(*note_hdr) + note_hdr->n_namesz) + 3) & ~3L); + + p = p_next; } } if (cur->p_type == PT_LOAD) @@ -263,12 +279,14 @@ _UCD_create(const char *filename) cur++; } - if (!ui->prstatus) + if (ui->n_threads == 0) { Debug(0, "No NT_PRSTATUS note found in '%s'\n", filename); goto err; } + ui->prstatus = ui->threads[0]; + return ui; err: @@ -276,6 +294,17 @@ _UCD_create(const char *filename) return NULL; } +int _UCD_get_num_threads(struct UCD_info *ui) +{ + return ui->n_threads; +} + +void _UCD_select_thread(struct UCD_info *ui, int n) +{ + if (n >= 0 && n < ui->n_threads) + ui->prstatus = ui->threads[n]; +} + pid_t _UCD_get_pid(struct UCD_info *ui) { return ui->prstatus->pr_pid; diff --git a/src/coredump/_UCD_internal.h b/src/coredump/_UCD_internal.h index ecad0bde..8b36729b 100644 --- a/src/coredump/_UCD_internal.h +++ b/src/coredump/_UCD_internal.h @@ -91,6 +91,8 @@ struct UCD_info unsigned phdrs_count; void *note_phdr; /* allocated or NULL */ struct PRSTATUS_STRUCT *prstatus; /* points inside note_phdr */ + int n_threads; + struct PRSTATUS_STRUCT **threads; struct elf_dyn_info edi; };