1 /*
   2  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include <unistd.h>
  26 #include <sys/procfs.h>
  27 #include <search.h>
  28 #include <stdlib.h>
  29 #include <string.h>
  30 #include "symtab.h"
  31 #include "salibelf.h"
  32 
  33 
  34 // ----------------------------------------------------
  35 // functions for symbol lookups
  36 // ----------------------------------------------------
  37 
  38 struct elf_section {
  39   ELF_SHDR   *c_shdr;
  40   void       *c_data;
  41 };
  42 
  43 struct elf_symbol {
  44   char *name;
  45   uintptr_t offset;
  46   uintptr_t size;
  47 };
  48 
  49 typedef struct symtab {
  50   char *strs;
  51   size_t num_symbols;
  52   struct elf_symbol *symbols;
  53   struct hsearch_data *hash_table;
  54 } symtab_t;
  55 
  56 
  57 // Directory that contains global debuginfo files.  In theory it
  58 // should be possible to change this, but in a Java environment there
  59 // is no obvious place to put a user interface to do it.  Maybe this
  60 // could be set with an environment variable.
  61 static const char debug_file_directory[] = "/usr/lib/debug";
  62 
  63 /* The CRC used in gnu_debuglink, retrieved from
  64    http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. */
  65 unsigned int gnu_debuglink_crc32 (unsigned int crc,
  66                                   unsigned char *buf, size_t len)
  67 {
  68   static const unsigned int crc32_table[256] =
  69     {
  70       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
  71       0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
  72       0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
  73       0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
  74       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
  75       0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
  76       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
  77       0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
  78       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
  79       0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
  80       0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
  81       0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
  82       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
  83       0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
  84       0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
  85       0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
  86       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
  87       0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
  88       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
  89       0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
  90       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
  91       0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
  92       0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
  93       0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
  94       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
  95       0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
  96       0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
  97       0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
  98       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
  99       0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
 100       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
 101       0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
 102       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
 103       0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
 104       0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
 105       0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
 106       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
 107       0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
 108       0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
 109       0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
 110       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
 111       0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
 112       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
 113       0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
 114       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
 115       0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
 116       0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
 117       0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
 118       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
 119       0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
 120       0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
 121       0x2d02ef8d
 122     };
 123   unsigned char *end;
 124 
 125   crc = ~crc & 0xffffffff;
 126   for (end = buf + len; buf < end; ++buf)
 127     crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
 128   return ~crc & 0xffffffff;
 129 }
 130 
 131 /* Open a debuginfo file and check its CRC.  If it exists and the CRC
 132    matches return its fd.  */
 133 static int
 134 open_debug_file (const char *pathname, unsigned int crc)
 135 {
 136   unsigned int file_crc = 0;
 137   unsigned char buffer[8 * 1024];
 138 
 139   int fd = pathmap_open(pathname);
 140 
 141   if (fd < 0)
 142     return -1;
 143 
 144   lseek(fd, 0, SEEK_SET);
 145 
 146   for (;;) {
 147     int len = read(fd, buffer, sizeof buffer);
 148     if (len <= 0)
 149       break;
 150     file_crc = gnu_debuglink_crc32(file_crc, buffer, len);
 151   }
 152 
 153   if (crc == file_crc)
 154     return fd;
 155   else {
 156     close(fd);
 157     return -1;
 158   }
 159 }
 160 
 161 /* Find an ELF section.  */
 162 static struct elf_section *find_section_by_name(char *name,
 163                                                 int fd,
 164                                                 ELF_EHDR *ehdr,
 165                                                 ELF_SHDR *shbuf,
 166                                                 struct elf_section *scn_cache)
 167 {
 168   ELF_SHDR* cursct = NULL;
 169   char *strtab;
 170   int cnt;
 171 
 172   if (scn_cache[ehdr->e_shstrndx].c_data == NULL) {
 173     if ((scn_cache[ehdr->e_shstrndx].c_data
 174          = read_section_data(fd, ehdr, cursct)) == NULL) {
 175       return NULL;
 176     }
 177   }
 178 
 179   strtab = scn_cache[ehdr->e_shstrndx].c_data;
 180 
 181   for (cursct = shbuf, cnt = 0;
 182        cnt < ehdr->e_shnum;
 183        cnt++, cursct++) {
 184     if (strcmp(cursct->sh_name + strtab, name) == 0) {
 185       scn_cache[cnt].c_data = read_section_data(fd, ehdr, cursct);
 186       return &scn_cache[cnt];
 187     }
 188   }
 189 
 190   return NULL;
 191 }
 192 
 193 /* Look for a ".gnu_debuglink" section.  If one exists, try to open a
 194    suitable debuginfo file.  */
 195 static int open_file_from_debug_link(const char *name,
 196                                      int fd,
 197                                      ELF_EHDR *ehdr,
 198                                      ELF_SHDR *shbuf,
 199                                      struct elf_section *scn_cache)
 200 {
 201   int debug_fd;
 202   struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr,
 203                                                         shbuf, scn_cache);
 204   if (debug_link == NULL)
 205     return -1;
 206   char *debug_filename = debug_link->c_data;
 207   int offset = (strlen(debug_filename) + 4) >> 2;
 208   static unsigned int crc;
 209   crc = ((unsigned int*)debug_link->c_data)[offset];
 210   char *debug_pathname = malloc(strlen(debug_filename)
 211                                 + strlen(name)
 212                                 + strlen(".debug/")
 213                                 + strlen(debug_file_directory)
 214                                 + 2);
 215   strcpy(debug_pathname, name);
 216   char *last_slash = strrchr(debug_pathname, '/');
 217   if (last_slash == NULL)
 218     free(debug_pathname);
 219     return -1;
 220 
 221   /* Look in the same directory as the object.  */
 222   strcpy(last_slash+1, debug_filename);
 223 
 224   debug_fd = open_debug_file(debug_pathname, crc);
 225   if (debug_fd >= 0) {
 226     free(debug_pathname);
 227     return debug_fd;
 228   }
 229 
 230   /* Look in a subdirectory named ".debug".  */
 231   strcpy(last_slash+1, ".debug/");
 232   strcat(last_slash, debug_filename);
 233 
 234   debug_fd = open_debug_file(debug_pathname, crc);
 235   if (debug_fd >= 0) {
 236     free(debug_pathname);
 237     return debug_fd;
 238   }
 239 
 240   /* Look in /usr/lib/debug + the full pathname.  */
 241   strcpy(debug_pathname, debug_file_directory);
 242   strcat(debug_pathname, name);
 243   last_slash = strrchr(debug_pathname, '/');
 244   strcpy(last_slash+1, debug_filename);
 245 
 246   debug_fd = open_debug_file(debug_pathname, crc);
 247   if (debug_fd >= 0) {
 248     free(debug_pathname);
 249     return debug_fd;
 250   }
 251 
 252   free(debug_pathname);
 253   return -1;
 254 }
 255 
 256 static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo);
 257 
 258 /* Look for a ".gnu_debuglink" section.  If one exists, try to open a
 259    suitable debuginfo file and read a symbol table from it.  */
 260 static struct symtab *build_symtab_from_debug_link(const char *name,
 261                                      int fd,
 262                                      ELF_EHDR *ehdr,
 263                                      ELF_SHDR *shbuf,
 264                                      struct elf_section *scn_cache)
 265 {
 266   fd = open_file_from_debug_link(name, fd, ehdr, shbuf, scn_cache);
 267 
 268   if (fd >= 0) {
 269     struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false);
 270     close(fd);
 271     return symtab;
 272   }
 273 
 274   return NULL;
 275 }
 276 
 277 // Given a build_id, find the associated debuginfo file
 278 static char *
 279 build_id_to_debug_filename (size_t size, unsigned char *data)
 280 {
 281   char *filename, *s;
 282 
 283   filename = malloc(strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1
 284                     + 2 * size + (sizeof ".debug" - 1) + 1);
 285   s = filename + sprintf (filename, "%s/.build-id/", debug_file_directory);
 286   if (size > 0)
 287     {
 288       size--;
 289       s += sprintf (s, "%02x", *data++);
 290     }
 291   if (size > 0)
 292     *s++ = '/';
 293   while (size-- > 0)
 294     s += sprintf (s, "%02x", *data++);
 295   strcpy (s, ".debug");
 296 
 297   return filename;
 298 }
 299 
 300 // Read a build ID note.  Try to open any associated debuginfo file
 301 // and return its symtab
 302 static struct symtab* build_symtab_from_build_id(Elf64_Nhdr *note)
 303 {
 304   int fd;
 305   struct symtab *symtab = NULL;
 306 
 307   unsigned char *bytes
 308     = (unsigned char*)(note+1) + note->n_namesz;
 309   char *filename
 310     = (build_id_to_debug_filename (note->n_descsz, bytes));
 311 
 312   fd = pathmap_open(filename);
 313   if (fd >= 0) {
 314     symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false);
 315     close(fd);
 316   }
 317   free(filename);
 318 
 319   return symtab;
 320 }
 321 
 322 // read symbol table from given fd.  If try_debuginfo) is true, also
 323 // try to open an associated debuginfo file
 324 static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo) {
 325   ELF_EHDR ehdr;
 326   char *names = NULL;
 327   struct symtab* symtab = NULL;
 328 
 329   // Reading of elf header
 330   struct elf_section *scn_cache = NULL;
 331   int cnt = 0;
 332   ELF_SHDR* shbuf = NULL;
 333   ELF_SHDR* cursct = NULL;
 334   ELF_PHDR* phbuf = NULL;
 335   ELF_PHDR* phdr = NULL;
 336   int sym_section = SHT_DYNSYM;
 337 
 338   uintptr_t baseaddr = (uintptr_t)-1;
 339 
 340   lseek(fd, (off_t)0L, SEEK_SET);
 341   if (! read_elf_header(fd, &ehdr)) {
 342     // not an elf
 343     return NULL;
 344   }
 345 
 346   // read ELF header
 347   if ((shbuf = read_section_header_table(fd, &ehdr)) == NULL) {
 348     goto quit;
 349   }
 350 
 351   baseaddr = find_base_address(fd, &ehdr);
 352 
 353   scn_cache = (struct elf_section *)
 354               calloc(ehdr.e_shnum * sizeof(struct elf_section), 1);
 355   if (scn_cache == NULL) {
 356     goto quit;
 357   }
 358 
 359   for (cursct = shbuf, cnt = 0; cnt < ehdr.e_shnum; cnt++) {
 360     scn_cache[cnt].c_shdr = cursct;
 361     if (cursct->sh_type == SHT_SYMTAB || cursct->sh_type == SHT_STRTAB
 362         || cursct->sh_type == SHT_NOTE || cursct->sh_type == SHT_DYNSYM) {
 363       if ( (scn_cache[cnt].c_data = read_section_data(fd, &ehdr, cursct)) == NULL) {
 364          goto quit;
 365       }
 366     }
 367     if (cursct->sh_type == SHT_SYMTAB) {
 368       // Full symbol table available so use that
 369       sym_section = cursct->sh_type;
 370     }
 371     cursct++;
 372   }
 373 
 374   for (cnt = 1; cnt < ehdr.e_shnum; cnt++) {
 375     ELF_SHDR *shdr = scn_cache[cnt].c_shdr;
 376 
 377     if (shdr->sh_type == sym_section) {
 378       ELF_SYM  *syms;
 379       int j, n, rslt;
 380       size_t size;
 381 
 382       // FIXME: there could be multiple data buffers associated with the
 383       // same ELF section. Here we can handle only one buffer. See man page
 384       // for elf_getdata on Solaris.
 385 
 386       // guarantee(symtab == NULL, "multiple symtab");
 387       symtab = (struct symtab*)calloc(1, sizeof(struct symtab));
 388       if (symtab == NULL) {
 389          goto quit;
 390       }
 391       // the symbol table
 392       syms = (ELF_SYM *)scn_cache[cnt].c_data;
 393 
 394       // number of symbols
 395       n = shdr->sh_size / shdr->sh_entsize;
 396 
 397       // create hash table, we use hcreate_r, hsearch_r and hdestroy_r to
 398       // manipulate the hash table.
 399       symtab->hash_table = (struct hsearch_data*) calloc(1, sizeof(struct hsearch_data));
 400       rslt = hcreate_r(n, symtab->hash_table);
 401       // guarantee(rslt, "unexpected failure: hcreate_r");
 402 
 403       // shdr->sh_link points to the section that contains the actual strings
 404       // for symbol names. the st_name field in ELF_SYM is just the
 405       // string table index. we make a copy of the string table so the
 406       // strings will not be destroyed by elf_end.
 407       size = scn_cache[shdr->sh_link].c_shdr->sh_size;
 408       symtab->strs = (char *)malloc(size);
 409       memcpy(symtab->strs, scn_cache[shdr->sh_link].c_data, size);
 410 
 411       // allocate memory for storing symbol offset and size;
 412       symtab->num_symbols = n;
 413       symtab->symbols = (struct elf_symbol *)calloc(n , sizeof(struct elf_symbol));
 414 
 415       // copy symbols info our symtab and enter them info the hash table
 416       for (j = 0; j < n; j++, syms++) {
 417         ENTRY item, *ret;
 418         char *sym_name = symtab->strs + syms->st_name;
 419 
 420         // skip non-object and non-function symbols
 421         int st_type = ELF_ST_TYPE(syms->st_info);
 422         if ( st_type != STT_FUNC && st_type != STT_OBJECT)
 423            continue;
 424         // skip empty strings and undefined symbols
 425         if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue;
 426 
 427         symtab->symbols[j].name   = sym_name;
 428         symtab->symbols[j].offset = syms->st_value - baseaddr;
 429         symtab->symbols[j].size   = syms->st_size;
 430 
 431         item.key = sym_name;
 432         item.data = (void *)&(symtab->symbols[j]);
 433 
 434         hsearch_r(item, ENTER, &ret, symtab->hash_table);
 435       }
 436     }
 437   }
 438 
 439   // Look for a separate debuginfo file.
 440   if (try_debuginfo) {
 441 
 442     // We prefer a debug symtab to an object's own symtab, so look in
 443     // the debuginfo file.  We stash a copy of the old symtab in case
 444     // there is no debuginfo.
 445     struct symtab* prev_symtab = symtab;
 446     symtab = NULL;
 447 
 448 #ifdef NT_GNU_BUILD_ID
 449     // First we look for a Build ID
 450     for (cursct = shbuf, cnt = 0;
 451          symtab == NULL && cnt < ehdr.e_shnum;
 452          cnt++) {
 453       if (cursct->sh_type == SHT_NOTE) {
 454         Elf64_Nhdr *note = (Elf64_Nhdr *)scn_cache[cnt].c_data;
 455         if (note->n_type == NT_GNU_BUILD_ID) {
 456           symtab = build_symtab_from_build_id(note);
 457         }
 458       }
 459       cursct++;
 460     }
 461 #endif
 462 
 463     // Then, if that doesn't work, the debug link
 464     if (symtab == NULL) {
 465       symtab = build_symtab_from_debug_link(filename, fd, &ehdr, shbuf,
 466                                             scn_cache);
 467     }
 468 
 469     // If we still haven't found a symtab, use the object's own symtab.
 470     if (symtab != NULL) {
 471       if (prev_symtab != NULL)
 472         destroy_symtab(prev_symtab);
 473     } else {
 474       symtab = prev_symtab;
 475     }
 476   }
 477 
 478 quit:
 479   if (shbuf) free(shbuf);
 480   if (phbuf) free(phbuf);
 481   if (scn_cache) {
 482     for (cnt = 0; cnt < ehdr.e_shnum; cnt++) {
 483       if (scn_cache[cnt].c_data != NULL) {
 484         free(scn_cache[cnt].c_data);
 485       }
 486     }
 487     free(scn_cache);
 488   }
 489   return symtab;
 490 }
 491 
 492 struct symtab* build_symtab(int fd, const char *filename) {
 493   return build_symtab_internal(fd, filename, /* try_debuginfo */ true);
 494 }
 495 
 496 
 497 void destroy_symtab(struct symtab* symtab) {
 498   if (!symtab) return;
 499   if (symtab->strs) free(symtab->strs);
 500   if (symtab->symbols) free(symtab->symbols);
 501   if (symtab->hash_table) {
 502      hdestroy_r(symtab->hash_table);
 503      free(symtab->hash_table);
 504   }
 505   free(symtab);
 506 }
 507 
 508 uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
 509                       const char *sym_name, int *sym_size) {
 510   ENTRY item;
 511   ENTRY* ret = NULL;
 512 
 513   // library does not have symbol table
 514   if (!symtab || !symtab->hash_table)
 515      return (uintptr_t)NULL;
 516 
 517   item.key = (char*) strdup(sym_name);
 518   hsearch_r(item, FIND, &ret, symtab->hash_table);
 519   if (ret) {
 520     struct elf_symbol * sym = (struct elf_symbol *)(ret->data);
 521     uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);
 522     if (sym_size) *sym_size = sym->size;
 523     free(item.key);
 524     return rslt;
 525   }
 526 
 527 quit:
 528   free(item.key);
 529   return (uintptr_t) NULL;
 530 }
 531 
 532 const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
 533                            uintptr_t* poffset) {
 534   int n = 0;
 535   if (!symtab) return NULL;
 536   for (; n < symtab->num_symbols; n++) {
 537      struct elf_symbol* sym = &(symtab->symbols[n]);
 538      if (sym->name != NULL &&
 539          offset >= sym->offset && offset < sym->offset + sym->size) {
 540         if (poffset) *poffset = (offset - sym->offset);
 541         return sym->name;
 542      }
 543   }
 544   return NULL;
 545 }