Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / elfsym.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: elfsym.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21///////////////////////////////////////////////////////////////
22//
23// elfsym: Extract Symbols for .text, .data and .bss
24// sections of ELF file using libelf interface.
25//
26// Note: use 'Extended ELF Section indexes' if required,
27// decode a corresponding SHT_SYMTAB_SHNDX
28// section.
29//
30// Copyright 2006 Sun Microsystems, Inc. All rights reserved.
31// Use is subject to license terms.
32//
33
34
35#include <stdio.h>
36#include <libelf.h>
37#include <gelf.h>
38#include <fcntl.h>
39#include <unistd.h>
40#include <stdlib.h>
41#include <string.h>
42#include "ui.h"
43
44// only one routine in exported interface
45int load_symbols ( char* elf_fname, uint64_t text_base, uint64_t data_base, uint32_t context );
46
47// set level of debug info
48static int Verbose = 0;
49
50
51
52
53// If you need to build a standalong elf_file utility
54// set STANDALONG to be defined, build it with command
55// CC -o <util_name> elf_file.cc
56// usage: <util_name> <path/elf_file_name>
57// output elf symbol info to the terminal
58#ifndef STANDALONG
59
60#include "symbols.h"
61
62// imported symtable
63extern SymTable *g_sym_table; // symbol table
64
65#else // STANDALONG
66
67int main(int argc, char **argv)
68{
69 int i;
70
71 Verbose = 1;
72
73 if (argc != 2)
74 {
75 ui->output("usage: %s elf_file \n", argv[0]);
76 return(1);
77 }
78
79 char *fname = argv[1];
80
81 return load_symbols(fname,0,0,Symbol::ANY_CONTEXT);
82
83}
84
85#endif // STANDALONG
86
87
88
89
90
91//////////////////////////////////////////////////////
92//
93// Extract defined symbols from
94// .symtab and .dynsym sections
95//
96static void get_symbols
97(
98 Elf *elf,
99 char *file,
100 uint64_t text_base,
101 uint64_t data_base,
102 uint32_t context
103)
104{
105 Elf_Scn *scn;
106 GElf_Shdr shdr;
107 GElf_Ehdr ehdr;
108
109
110 // get module name by stripping path from file name
111 char *path_name=strtok(file, "/");
112 char *module_name = file;
113 while (path_name=strtok(NULL, "/"))
114 {
115 module_name = path_name;
116 }
117
118
119
120
121 if (gelf_getehdr(elf, &ehdr) == 0)
122 {
123 ui->error( "%s: elf_getehdr() failed: %s\n",
124 file, elf_errmsg(0));
125 return;
126 }
127
128
129 // check the file type
130 char *filetype = "Other";
131 switch (ehdr.e_type)
132 {
133 case ET_REL:
134 filetype = "Reallocatable";
135 break;
136 case ET_EXEC:
137 filetype = "Executable";
138 break;
139 case ET_DYN:
140 filetype = "Shared Object";
141 break;
142 default:
143 break;
144 }
145 ui->output("loading symbols for %s - %s file.\n", module_name, filetype);
146
147
148 size_t shstrndx;
149 if (elf_getshstrndx(elf, &shstrndx) == 0)
150 {
151 ui->error( "%s: elf_getshstrndx() failed: %s\n",
152 file, elf_errmsg(0));
153 return;
154 }
155
156 // find .text, .data and .bss section headers
157 GElf_Shdr text_shdr;
158 GElf_Shdr data_shdr;
159 GElf_Shdr bss_shdr;
160 text_shdr.sh_type = SHT_NULL;
161 data_shdr.sh_type = SHT_NULL;
162 bss_shdr.sh_type = SHT_NULL;
163 scn = 0;
164 uint32_t idx = 1;
165 uint32_t text_idx, data_idx, bss_idx;
166
167 while ((scn = elf_nextscn(elf, scn)) != 0)
168 {
169 if (gelf_getshdr(scn, &shdr) == 0)
170 {
171 (void) ui->error(
172 "%s: elf_getshdr() failed: %s\n",
173 file, elf_errmsg(0));
174 return;
175 }
176
177 // get section name
178 char *sname = elf_strptr(elf, shstrndx, shdr.sh_name);
179
180 if (strcmp(sname, ".data")==0)
181 {
182 data_shdr = shdr;
183 data_idx = idx;
184 }
185 else if (strcmp(sname, ".bss" )==0)
186 {
187 bss_shdr = shdr;
188 bss_idx = idx;
189 }
190 else if (strcmp(sname, ".text")==0)
191 {
192 text_shdr = shdr;
193 text_idx = idx;
194 }
195 idx++;
196 continue;
197
198 }
199
200 if (text_shdr.sh_type ==SHT_NULL)
201 {
202 ui->error(" there is no text section \n");
203 return;
204 }
205 else if (Verbose)
206 ui->output(".text #%d sh_addr=0x%llx, sh_size=0x%llx, sh_offset=0x%llx, sh_addralign=0x%llx \n",
207 text_idx,text_shdr.sh_addr, text_shdr.sh_size, text_shdr.sh_offset, text_shdr.sh_addralign );
208
209 if (Verbose && data_shdr.sh_type !=SHT_NULL)
210 ui->output(".data #%d sh_addr=0x%llx, sh_size=0x%llx, sh_offset=0x%llx, sh_addralign=0x%llx \n",
211 data_idx,data_shdr.sh_addr, data_shdr.sh_size, data_shdr.sh_offset, data_shdr.sh_addralign );
212
213 if (Verbose && bss_shdr.sh_type !=SHT_NULL)
214 ui->output(".bss #%d sh_addr=0x%llx, sh_size=0x%llx, sh_offset=0x%llx, sh_addralign=0x%llx \n",
215 bss_idx,bss_shdr.sh_addr, bss_shdr.sh_size, bss_shdr.sh_offset, bss_shdr.sh_addralign );
216
217 // uninitialized data (bss) segment is located immediately
218 // after initialized data segment
219 uint64_t bss_offset = 0;
220
221 if (
222 (data_shdr.sh_type !=SHT_NULL) // data section is present
223 && (bss_shdr.sh_addr == 0) // not absolute address
224 )
225 {
226 bss_offset = (bss_shdr.sh_offset - data_shdr.sh_offset) &
227 ~(uint64_t(bss_shdr.sh_addralign) - 1);
228 }
229
230 if (Verbose)
231 ui->output(".bss addr offset = 0x%llx \n", bss_offset);
232
233
234
235 // find .dynsym and .symtab sections
236 scn = 0;
237 while ((scn = elf_nextscn(elf, scn)) != 0)
238 {
239 uint_t symcnt;
240 uint_t ndx;
241
242 Elf_Data *symdata;
243 Elf_Data *shndxdata;
244
245 if (gelf_getshdr(scn, &shdr) == 0)
246 {
247 ui->error("%s: elf_getshdr() failed: %s\n",
248 file, elf_errmsg(0));
249 return;
250 }
251
252
253 if ((shdr.sh_type != SHT_SYMTAB) &&
254 (shdr.sh_type != SHT_DYNSYM))
255 continue;
256
257 // Get the data associated with the Symbol
258 // section.
259 if ((symdata = elf_getdata(scn, 0)) == 0)
260 {
261 ui->error("%s: elf_getdata() failed: %s\n",
262 file, elf_errmsg(0));
263 return;
264 }
265
266 #ifdef STANDALONG
267 // Print symbol table title and header for symbol display
268 ui->output("\nSymTab: %s:%s\n", file,
269 elf_strptr(elf, shstrndx, shdr.sh_name));
270 ui->output(" index value size type "
271 "bind oth shndx name\n");
272 #endif
273
274 // iterate over the symbol table
275 shndxdata = 0;
276 uint_t nosymshndx = 0;
277 symcnt = shdr.sh_size / shdr.sh_entsize;
278 for (ndx = 0; ndx < symcnt; ndx++)
279 {
280 GElf_Sym sym;
281 Elf32_Word shndx;
282 uint_t type;
283 uint_t bind;
284 uint_t specshndx;
285
286 // Get a symbol entry
287 if (gelf_getsymshndx(symdata, shndxdata, ndx,
288 &sym, &shndx) == NULL)
289 {
290 (void) ui->error(
291 "%s: gelf_getsymshndx() failed: %s\n",
292 file, elf_errmsg(0));
293 return;
294 }
295 // Check to see if this symbol's st_shndx
296 // is using the 'Extended SHNDX table' for
297 // a SYMTAB.
298 // If it is - and we havn't searched before,
299 // go find the associated SHT_SYMTAB_SHNDX
300 // section.
301 if ((sym.st_shndx == SHN_XINDEX) &&
302 (shndxdata == 0) && (nosymshndx == 0))
303 {
304 Elf_Scn *_scn;
305 GElf_Shdr _shdr;
306 GElf_Word symscnndx;
307 _scn = 0;
308 specshndx = 0;
309 symscnndx = elf_ndxscn(scn);
310
311 while ((_scn = elf_nextscn(elf, _scn)) != 0)
312 {
313 if (gelf_getshdr(_scn, &_shdr) == 0)
314 break;
315
316 // We've found the Symtab SHNDX table
317 // if it's of type SHT_SYMTAB_SHNDX
318 // and it's shdr.sh_link points to the
319 // section index for the current symbol
320 // table.
321 if ((_shdr.sh_type ==
322 SHT_SYMTAB_SHNDX) &&
323 (_shdr.sh_link == symscnndx))
324 {
325 if ((shndxdata =
326 elf_getdata(_scn, 0)) != 0)
327 break;
328 }
329 }
330 // Get a symbol entry
331 if (shndxdata &&
332 (gelf_getsymshndx(symdata, shndxdata, ndx,
333 &sym, &shndx) == NULL))
334 {
335 (void) ui->error(
336 "%s: gelf_getsymshndx() "
337 "failed: %s\n",
338 file, elf_errmsg(0));
339 return;
340 }
341 // No Symtab SHNDX table was found. We could
342 // give a fatal error here - instead we'll
343 // just mark that fact and display as much of
344 // the symbol table as we can. Any symbol
345 // displayed with a XINDX section index has
346 // a bogus value - skip it
347 if (shndxdata == 0)
348 nosymshndx = 1;
349 }
350
351 // Decode the type & binding information
352 type = GELF_ST_TYPE(sym.st_info);
353 bind = GELF_ST_BIND(sym.st_info);
354
355
356 // section index to which this symbol refer to
357 specshndx = 0;
358 if (sym.st_shndx < SHN_LORESERVE)
359 shndx = sym.st_shndx;
360 else if ((sym.st_shndx != SHN_XINDEX) ||
361 (shndxdata == NULL))
362 {
363 shndx = sym.st_shndx;
364 specshndx = 1;
365 }
366
367 // skip zero size symbols
368 if (sym.st_size == 0)
369 continue;
370
371 uint64_t va = sym.st_value;
372
373 // check if it is in text section
374 if ((text_shdr.sh_type != SHT_NULL) && (shndx == text_idx))
375 {
376 // text symbol
377 va += text_base;
378 }
379 else if ( type == STT_OBJECT ) //data symbol
380 {
381 if ((data_shdr.sh_type != SHT_NULL) && (shndx == data_idx))
382 {
383 // initialized data
384 va += data_base;
385 }
386 else if ((bss_shdr.sh_type != SHT_NULL) && (shndx == bss_idx))
387 {
388 // uninitialized data
389 if ( bind == STB_GLOBAL )
390 {
391 va += data_base;
392 }
393 else if (bind == STB_LOCAL)
394 {
395 // local uninitialized data is located at the end
396 // of data segment
397 va += (data_base + bss_offset);
398 }
399 else
400 continue;
401 }
402 else
403 continue;
404 }
405 else
406 continue;
407
408
409 // append symbol
410 char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name);
411
412
413 #ifndef STANDALONG
414
415 // check if symbol is already there
416 Symbol *s = g_sym_table->find(sym_name);
417
418 if (s == NULL || s->vaddr() != va || s->size() != sym.st_size)
419 {
420 g_sym_table->add(module_name, sym_name, va, sym.st_size, context);
421 }
422
423 #else // STANDALONG
424
425 // prepare sym type info
426 const int INTSTRLEN = 32;
427 char bindbuf[INTSTRLEN];
428 char typebuf[INTSTRLEN];
429 char shndxbuf[INTSTRLEN];
430 const char *bindstr;
431 const char *typestr;
432 const char *shndxstr;
433
434 static const char *symbind[STB_NUM] = {
435 /* STB_LOCL */ "LOCL",
436 /* STB_GLOBAL */ "GLOB",
437 /* STB_WEAK */ "WEAK"};
438
439 static const char *symtype[STT_NUM] = {
440 /* STT_NOTYPE */ "NOTY",
441 /* STT_OBJECT */ "OBJT",
442 /* STT_FUNC */ "FUNC",
443 /* STT_SECTION */ "SECT",
444 /* STT_FILE */ "FILE",
445 /* STT_COMMON */ "COMM",
446 /* STT_TLS */ "TLS"};
447
448
449
450
451 if (type < STT_NUM)
452 typestr = symtype[type];
453 else
454 {
455 snprintf(typebuf, INTSTRLEN, "%d", type);
456 typestr = typebuf;
457 }
458
459 if (bind < STB_NUM)
460 bindstr = symbind[bind];
461 else
462 {
463 snprintf(bindbuf, INTSTRLEN, "%d", bind);
464 bindstr = bindbuf;
465 }
466
467
468 if (shndx == SHN_UNDEF)
469 {
470 shndxstr = (const char *)"UNDEF";
471
472 }
473 else if (specshndx)
474 {
475 if (shndx == SHN_ABS)
476 shndxstr = (const char *)"ABS";
477 else if (shndx == SHN_COMMON)
478 shndxstr = (const char *)"COMM";
479 else if (shndx == SHN_XINDEX)
480 shndxstr = (const char *)"XIND";
481 else
482 {
483 snprintf(shndxbuf, INTSTRLEN, "%ld", shndx);
484 shndxstr = shndxbuf;
485 }
486 }
487 else
488 {
489 (void) snprintf(shndxbuf, INTSTRLEN,
490 "%ld", shndx);
491 shndxstr = shndxbuf;
492 }
493
494 //char *this_sh_name = elf_strptr(elf, shstrndx, shndx);
495
496 // display the symbol entry
497 ui->otput("[%3d] 0x%08llx 0x%08llx %-4s %-6s %2d %5s %s \n",
498 ndx, va /* sym.st_value */, sym.st_size,
499 typestr, bindstr, sym.st_other, shndxstr,
500 sym_name);
501
502 #endif // STANDALONG
503 }
504 }
505}
506
507//////////////////////////////////////////////////////////////////
508//
509// open an ELF file using
510// elf_begin(ELF_C_READ) and examine search the ELF file
511// for either a SHT_SYMTAB or SHT_DYNSYM symbol table.
512// If it finds either - it will extract the contents of
513// the symbol tables.
514
515static void process_elf
516(
517 Elf *elf,
518 char *file,
519 int fd,
520 int member,
521 uint64_t text_base,
522 uint64_t data_base,
523 uint32_t context
524)
525{
526 Elf_Cmd cmd;
527 Elf *_elf;
528
529 switch (elf_kind(elf))
530 {
531 case ELF_K_ELF:
532 // This is an ELF file
533 get_symbols(elf, file, text_base, data_base,context);
534 break;
535 case ELF_K_AR:
536 // Archives contain multiple ELF files, which can each
537 // in turn be examined with libelf.
538 // Iterate over each member of the
539 // archive and recursivly call process_elf() for processing.
540 cmd = ELF_C_READ;
541 while ((_elf = elf_begin(fd, cmd, elf)) != 0)
542 {
543 Elf_Arhdr *arhdr;
544 char buffer[1024];
545
546 arhdr = elf_getarhdr(_elf);
547
548 // Build up file names based off of
549 // 'archivename(membername)'.
550 snprintf(buffer, 1024, "%s(%s)", file, arhdr->ar_name);
551
552 // recursivly process the ELF members.
553 process_elf(_elf, buffer, fd, 1, text_base, data_base, context);
554 cmd = elf_next(_elf);
555 elf_end(_elf);
556 }
557 break;
558 default:
559 if (!member)
560 ui->error("%s: unexpected elf_kind(): 0x%x\n",
561 file, elf_kind(elf));
562 return;
563 }
564}
565
566
567
568
569////////////////////////////////////////////////////////////////////
570int load_symbols
571(
572 char* elf_fname,
573 uint64_t text_base,
574 uint64_t data_base,
575 uint32_t context
576)
577{
578
579 /*
580 * Initialize the elf library, must be called before elf_begin()
581 * can be called.
582 */
583 if (elf_version(EV_CURRENT) == EV_NONE)
584 {
585 ui->error( "elf_version() failed: %s\n", elf_errmsg(0));
586 return(1);
587 }
588
589 int fd;
590 Elf *elf;
591
592 if ((fd = open(elf_fname, O_RDONLY)) == -1)
593 {
594 ui->perror("open");
595 return 1;
596 }
597
598 // open an Elf descriptor Read-Only
599 if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL)
600 {
601 ui->error( "elf_begin() failed: %s\n", elf_errmsg(0));
602 close(fd);
603 return 1;
604 }
605
606 // Process elf descriptor
607 process_elf(elf, elf_fname, fd, 0, text_base, data_base, context);
608
609 elf_end(elf);
610 close(fd);
611
612 return 0;
613}
614
615
616