|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
4 | 4 | *
|
5 | 5 | * This code is free software; you can redistribute it and/or modify it
|
|
24 | 24 |
|
25 | 25 | #include <unistd.h>
|
26 | 26 | #include <search.h>
|
| 27 | +#include <stddef.h> |
27 | 28 | #include <stdlib.h>
|
28 | 29 | #include <string.h>
|
29 | 30 | #include <db.h>
|
@@ -57,12 +58,14 @@ typedef struct symtab {
|
57 | 58 |
|
58 | 59 | void build_search_table(symtab_t *symtab) {
|
59 | 60 | int i;
|
| 61 | + print_debug("build_search_table\n"); |
60 | 62 | for (i = 0; i < symtab->num_symbols; i++) {
|
61 | 63 | DBT key, value;
|
62 | 64 | key.data = symtab->symbols[i].name;
|
63 | 65 | key.size = strlen(key.data) + 1;
|
64 | 66 | value.data = &(symtab->symbols[i]);
|
65 | 67 | value.size = sizeof(symtab_symbol);
|
| 68 | + //print_debug("build_search_table: %d 0x%x %s\n", i, symtab->symbols[i].offset, symtab->symbols[i].name); |
66 | 69 | (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);
|
67 | 70 |
|
68 | 71 | // check result
|
@@ -92,10 +95,11 @@ void build_search_table(symtab_t *symtab) {
|
92 | 95 | // read symbol table from given fd.
|
93 | 96 | struct symtab* build_symtab(int fd) {
|
94 | 97 | symtab_t* symtab = NULL;
|
95 |
| - int i; |
| 98 | + int i, j; |
96 | 99 | mach_header_64 header;
|
97 | 100 | off_t image_start;
|
98 | 101 |
|
| 102 | + print_debug("build_symtab\n"); |
99 | 103 | if (!get_arch_off(fd, CPU_TYPE_X86_64, &image_start)) {
|
100 | 104 | print_debug("failed in get fat header\n");
|
101 | 105 | return NULL;
|
@@ -151,46 +155,59 @@ struct symtab* build_symtab(int fd) {
|
151 | 155 | if (symtab->hash_table == NULL)
|
152 | 156 | goto quit;
|
153 | 157 |
|
| 158 | + // allocate the symtab |
154 | 159 | symtab->num_symbols = symtabcmd.nsyms;
|
155 | 160 | symtab->symbols = (symtab_symbol *)malloc(sizeof(symtab_symbol) * symtab->num_symbols);
|
156 | 161 | symtab->strs = (char *)malloc(sizeof(char) * symtabcmd.strsize);
|
157 | 162 | if (symtab->symbols == NULL || symtab->strs == NULL) {
|
158 | 163 | print_debug("out of memory: allocating symtab.symbol or symtab.strs\n");
|
159 | 164 | goto quit;
|
160 | 165 | }
|
161 |
| - lseek(fd, image_start + symtabcmd.symoff, SEEK_SET); |
162 |
| - for (i = 0; i < symtab->num_symbols; i++) { |
163 |
| - if (read(fd, (void *)&lentry, sizeof(nlist_64)) != sizeof(nlist_64)) { |
164 |
| - print_debug("read nlist_64 failed at %i\n", i); |
165 |
| - goto quit; |
166 |
| - } |
167 |
| - symtab->symbols[i].offset = lentry.n_value; |
168 |
| - symtab->symbols[i].size = lentry.n_un.n_strx; // index |
169 |
| - } |
170 | 166 |
|
171 |
| - // string table |
| 167 | + // read in the string table |
172 | 168 | lseek(fd, image_start + symtabcmd.stroff, SEEK_SET);
|
173 | 169 | int size = read(fd, (void *)(symtab->strs), symtabcmd.strsize * sizeof(char));
|
174 | 170 | if (size != symtabcmd.strsize * sizeof(char)) {
|
175 | 171 | print_debug("reading string table failed\n");
|
176 | 172 | goto quit;
|
177 | 173 | }
|
178 | 174 |
|
179 |
| - for (i = 0; i < symtab->num_symbols; i++) { |
180 |
| - symtab->symbols[i].name = symtab->strs + symtab->symbols[i].size; |
181 |
| - if (i > 0) { |
182 |
| - // fix size |
183 |
| - symtab->symbols[i - 1].size = symtab->symbols[i].size - symtab->symbols[i - 1].size; |
184 |
| - print_debug("%s size = %d\n", symtab->symbols[i - 1].name, symtab->symbols[i - 1].size); |
| 175 | + // read in each nlist_64 from the symbol table and use to fill in symtab->symbols |
| 176 | + lseek(fd, image_start + symtabcmd.symoff, SEEK_SET); |
| 177 | + i = 0; |
| 178 | + for (j = 0; j < symtab->num_symbols; j++) { |
| 179 | + if (read(fd, (void *)&lentry, sizeof(nlist_64)) != sizeof(nlist_64)) { |
| 180 | + print_debug("read nlist_64 failed at %j\n", j); |
| 181 | + goto quit; |
| 182 | + } |
| 183 | + |
| 184 | + uintptr_t offset = lentry.n_value; // offset of the symbol code/data in the file |
| 185 | + uintptr_t stridx = lentry.n_un.n_strx; // offset of symbol string in the symtabcmd.symoff section |
185 | 186 |
|
| 187 | + if (stridx == 0 || offset == 0) { |
| 188 | + continue; // Skip this entry. It's not a reference to code or data |
186 | 189 | }
|
| 190 | + symtab->symbols[i].offset = offset; |
| 191 | + symtab->symbols[i].name = symtab->strs + stridx; |
| 192 | + symtab->symbols[i].size = strlen(symtab->symbols[i].name); |
187 | 193 |
|
188 |
| - if (i == symtab->num_symbols - 1) { |
189 |
| - // last index |
190 |
| - symtab->symbols[i].size = |
191 |
| - symtabcmd.strsize - symtab->symbols[i].size; |
192 |
| - print_debug("%s size = %d\n", symtab->symbols[i].name, symtab->symbols[i].size); |
| 194 | + if (symtab->symbols[i].size == 0) { |
| 195 | + continue; // Skip this entry. It points to an empty string. |
193 | 196 | }
|
| 197 | + |
| 198 | + print_debug("symbol read: %d %d n_type=0x%x n_sect=0x%x n_desc=0x%x n_strx=0x%lx offset=0x%lx %s\n", |
| 199 | + j, i, lentry.n_type, lentry.n_sect, lentry.n_desc, stridx, offset, symtab->symbols[i].name); |
| 200 | + i++; |
| 201 | + } |
| 202 | + |
| 203 | + // Update symtab->num_symbols to be the actual number of symbols we added. Since the symbols |
| 204 | + // array was allocated larger, reallocate it to the proper size. |
| 205 | + print_debug("build_symtab: included %d of %d entries.\n", i, symtab->num_symbols); |
| 206 | + symtab->num_symbols = i; |
| 207 | + symtab->symbols = (symtab_symbol *)realloc(symtab->symbols, sizeof(symtab_symbol) * symtab->num_symbols); |
| 208 | + if (symtab->symbols == NULL) { |
| 209 | + print_debug("out of memory: reallocating symtab.symbol\n"); |
| 210 | + goto quit; |
194 | 211 | }
|
195 | 212 |
|
196 | 213 | // build a hashtable for fast query
|
@@ -389,14 +406,37 @@ uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, const char *sym_n
|
389 | 406 | const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
|
390 | 407 | uintptr_t* poffset) {
|
391 | 408 | int n = 0;
|
| 409 | + char* result = NULL; |
| 410 | + ptrdiff_t lowest_offset_from_sym = -1; |
392 | 411 | if (!symtab) return NULL;
|
| 412 | + // Search the symbol table for the symbol that is closest to the specified offset, but is not under. |
| 413 | + // |
| 414 | + // Note we can't just use the first symbol that is >= the offset because the symbols may not be |
| 415 | + // sorted by offset. |
| 416 | + // |
| 417 | + // Note this is a rather slow search that is O(n/2), and libjvm has as many as 250k symbols. |
| 418 | + // Probably would be good to sort the array and do a binary search, or use a hash table like |
| 419 | + // we do for name -> address lookups. However, this functionality is not used often and |
| 420 | + // generally just involves one lookup, such as with the clhsdb "findpc" command. |
393 | 421 | for (; n < symtab->num_symbols; n++) {
|
394 | 422 | symtab_symbol* sym = &(symtab->symbols[n]);
|
395 |
| - if (sym->name != NULL && |
396 |
| - offset >= sym->offset && offset < sym->offset + sym->size) { |
397 |
| - if (poffset) *poffset = (offset - sym->offset); |
398 |
| - return sym->name; |
| 423 | + if (sym->size != 0 && offset >= sym->offset) { |
| 424 | + ptrdiff_t offset_from_sym = offset - sym->offset; |
| 425 | + if (offset_from_sym >= 0) { // ignore symbols that come after "offset" |
| 426 | + if (lowest_offset_from_sym == -1 || offset_from_sym < lowest_offset_from_sym) { |
| 427 | + lowest_offset_from_sym = offset_from_sym; |
| 428 | + result = sym->name; |
| 429 | + //print_debug("nearest_symbol: found %d %s 0x%x 0x%x 0x%x\n", |
| 430 | + // n, sym->name, offset, sym->offset, lowest_offset_from_sym); |
| 431 | + } |
| 432 | + } |
399 | 433 | }
|
400 | 434 | }
|
401 |
| - return NULL; |
| 435 | + print_debug("nearest_symbol: found symbol %d file_offset=0x%lx sym_offset=0x%lx %s\n", |
| 436 | + n, offset, lowest_offset_from_sym, result); |
| 437 | + // Save the offset from the symbol if requested. |
| 438 | + if (result != NULL && poffset) { |
| 439 | + *poffset = lowest_offset_from_sym; |
| 440 | + } |
| 441 | + return result; |
402 | 442 | }
|
0 commit comments