* pr-5016.exp: xfail "whatis i" for sparc-sun-sunos4*, same as linux.
[deliverable/binutils-gdb.git] / binutils / objdump.c
CommitLineData
d20f480f 1/* objdump.c -- dump information about an object file.
37853673 2 Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
2fa0b342 3
b3a2b497 4This file is part of GNU Binutils.
2fa0b342 5
b3a2b497 6This program is free software; you can redistribute it and/or modify
2fa0b342 7it under the terms of the GNU General Public License as published by
d20f480f 8the Free Software Foundation; either version 2, or (at your option)
2fa0b342
DHW
9any later version.
10
b3a2b497 11This program is distributed in the hope that it will be useful,
2fa0b342
DHW
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
b3a2b497 17along with this program; if not, write to the Free Software
a65619c8 18Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
2fa0b342 19
2fa0b342
DHW
20#include "bfd.h"
21#include "getopt.h"
be1d162b 22#include "progress.h"
e1ec9f07 23#include "bucomm.h"
2fa0b342
DHW
24#include <stdio.h>
25#include <ctype.h>
2e8adbd7 26#include "dis-asm.h"
105da05c 27#include "libiberty.h"
2fa0b342 28
73b8f102
JG
29/* Internal headers for the ELF .stab-dump code - sorry. */
30#define BYTES_IN_WORD 32
31#include "aout/aout64.h"
bf661056 32
746cffcf
ILT
33#ifdef NEED_DECLARATION_FPRINTF
34/* This is needed by INIT_DISASSEMBLE_INFO. */
35extern int fprintf ();
80d19ec1 36#endif
2fa0b342
DHW
37
38char *default_target = NULL; /* default at runtime */
39
e1ec9f07 40extern char *program_version;
2fa0b342 41
249c6fc0 42int show_version = 0; /* show the version number */
2fa0b342
DHW
43int dump_section_contents; /* -s */
44int dump_section_headers; /* -h */
45boolean dump_file_header; /* -f */
46int dump_symtab; /* -t */
de3b08ac 47int dump_dynamic_symtab; /* -T */
2fa0b342 48int dump_reloc_info; /* -r */
de3b08ac 49int dump_dynamic_reloc_info; /* -R */
2fa0b342 50int dump_ar_hdrs; /* -a */
a65619c8 51int dump_private_headers; /* -p */
aa0a709a 52int with_line_numbers; /* -l */
be1d162b 53boolean with_source_code; /* -S */
9b018ecd 54int dump_stab_section_info; /* --stabs */
aa0a709a 55boolean disassemble; /* -d */
d5464baa 56boolean disassemble_all; /* -D */
e1ec9f07 57boolean formats_info; /* -i */
195d1adf 58char *only; /* -j secname */
13e4db2e 59int wide_output; /* -w */
aa21a2a9
ILT
60bfd_vma start_address = (bfd_vma) -1; /* --start-address */
61bfd_vma stop_address = (bfd_vma) -1; /* --stop-address */
195d1adf 62
cef35d48 63/* Extra info to pass to the disassembler address printing function. */
195d1adf
KR
64struct objdump_disasm_info {
65 bfd *abfd;
66 asection *sec;
8b129785 67 boolean require_sec;
195d1adf 68};
2fa0b342 69
cef35d48 70/* Architecture to disassemble for, or default if NULL. */
aa0a709a 71char *machine = (char *) NULL;
f7b839f7
DM
72
73/* The symbol table. */
aa0a709a 74asymbol **syms;
2fa0b342 75
f7b839f7 76/* Number of symbols in `syms'. */
ae5d2ff5 77long symcount = 0;
2fa0b342 78
be1d162b
ILT
79/* The sorted symbol table. */
80asymbol **sorted_syms;
81
82/* Number of symbols in `sorted_syms'. */
83long sorted_symcount = 0;
84
de3b08ac
ILT
85/* The dynamic symbol table. */
86asymbol **dynsyms;
87
88/* Number of symbols in `dynsyms'. */
89long dynsymcount = 0;
90
d9971b83
KR
91/* Forward declarations. */
92
93static void
94display_file PARAMS ((char *filename, char *target));
95
96static void
97dump_data PARAMS ((bfd *abfd));
98
99static void
100dump_relocs PARAMS ((bfd *abfd));
101
102static void
de3b08ac
ILT
103dump_dynamic_relocs PARAMS ((bfd * abfd));
104
105static void
106dump_reloc_set PARAMS ((bfd *, arelent **, long));
107
108static void
109dump_symbols PARAMS ((bfd *abfd, boolean dynamic));
02a68547
ILT
110
111static void
112display_bfd PARAMS ((bfd *abfd));
8f197c94
ILT
113
114static void
115objdump_print_address PARAMS ((bfd_vma, struct disassemble_info *));
be1d162b
ILT
116
117static void
118show_line PARAMS ((bfd *, asection *, bfd_vma));
d9971b83 119\f
2fa0b342 120void
b3a2b497
ILT
121usage (stream, status)
122 FILE *stream;
123 int status;
2fa0b342 124{
b3a2b497 125 fprintf (stream, "\
a65619c8 126Usage: %s [-ahifdDprRtTxsSlw] [-b bfdname] [-m machine] [-j section-name]\n\
d5464baa
ILT
127 [--archive-headers] [--target=bfdname] [--disassemble]\n\
128 [--disassemble-all] [--file-headers] [--section-headers] [--headers]\n\
13e4db2e
SC
129 [--info] [--section=section-name] [--line-numbers] [--source]\n",
130 program_name);
131 fprintf (stream, "\
d5464baa
ILT
132 [--architecture=machine] [--reloc] [--full-contents] [--stabs]\n\
133 [--syms] [--all-headers] [--dynamic-syms] [--dynamic-reloc]\n\
aa21a2a9
ILT
134 [--wide] [--version] [--help] [--private-headers]\n\
135 [--start-address=addr] [--stop-address=addr] objfile...\n\
13e4db2e 136at least one option besides -l (--line-numbers) must be given\n");
be1d162b 137 list_supported_targets (program_name, stream);
b3a2b497 138 exit (status);
2fa0b342
DHW
139}
140
aa21a2a9
ILT
141/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
142
143#define OPTION_START_ADDRESS (150)
144#define OPTION_STOP_ADDRESS (OPTION_START_ADDRESS + 1)
145
aa0a709a
SC
146static struct option long_options[]=
147{
02a68547 148 {"all-headers", no_argument, NULL, 'x'},
a65619c8 149 {"private-headers", no_argument, NULL, 'p'},
02a68547
ILT
150 {"architecture", required_argument, NULL, 'm'},
151 {"archive-headers", no_argument, NULL, 'a'},
152 {"disassemble", no_argument, NULL, 'd'},
d5464baa 153 {"disassemble-all", no_argument, NULL, 'D'},
de3b08ac
ILT
154 {"dynamic-reloc", no_argument, NULL, 'R'},
155 {"dynamic-syms", no_argument, NULL, 'T'},
02a68547
ILT
156 {"file-headers", no_argument, NULL, 'f'},
157 {"full-contents", no_argument, NULL, 's'},
158 {"headers", no_argument, NULL, 'h'},
159 {"help", no_argument, NULL, 'H'},
160 {"info", no_argument, NULL, 'i'},
161 {"line-numbers", no_argument, NULL, 'l'},
162 {"reloc", no_argument, NULL, 'r'},
163 {"section", required_argument, NULL, 'j'},
164 {"section-headers", no_argument, NULL, 'h'},
be1d162b 165 {"source", no_argument, NULL, 'S'},
73b8f102 166 {"stabs", no_argument, &dump_stab_section_info, 1},
aa21a2a9
ILT
167 {"start-address", required_argument, NULL, OPTION_START_ADDRESS},
168 {"stop-address", required_argument, NULL, OPTION_STOP_ADDRESS},
02a68547
ILT
169 {"syms", no_argument, NULL, 't'},
170 {"target", required_argument, NULL, 'b'},
aa21a2a9 171 {"version", no_argument, &show_version, 1},
13e4db2e 172 {"wide", no_argument, &wide_output, 'w'},
d2442698
DM
173 {0, no_argument, 0, 0}
174};
f7b839f7 175\f
2fa0b342 176static void
f7b839f7 177dump_section_header (abfd, section, ignored)
aa0a709a 178 bfd *abfd;
f7b839f7
DM
179 asection *section;
180 PTR ignored;
2fa0b342 181{
f7b839f7 182 char *comma = "";
aa0a709a 183
2fa0b342 184#define PF(x,y) \
f7b839f7
DM
185 if (section->flags & x) { printf("%s%s",comma,y); comma = ", "; }
186
187
188 printf ("SECTION %d [%s]\t: size %08x",
189 section->index,
190 section->name,
191 (unsigned) bfd_get_section_size_before_reloc (section));
192 printf (" vma ");
193 printf_vma (section->vma);
13e4db2e
SC
194 printf (" lma ");
195 printf_vma (section->lma);
196 printf (" align 2**%u%s ",
197 section->alignment_power, (wide_output) ? "" : "\n");
f7b839f7
DM
198 PF (SEC_ALLOC, "ALLOC");
199 PF (SEC_CONSTRUCTOR, "CONSTRUCTOR");
200 PF (SEC_CONSTRUCTOR_TEXT, "CONSTRUCTOR TEXT");
201 PF (SEC_CONSTRUCTOR_DATA, "CONSTRUCTOR DATA");
202 PF (SEC_CONSTRUCTOR_BSS, "CONSTRUCTOR BSS");
203 PF (SEC_LOAD, "LOAD");
204 PF (SEC_RELOC, "RELOC");
195d1adf 205#ifdef SEC_BALIGN
f7b839f7 206 PF (SEC_BALIGN, "BALIGN");
195d1adf 207#endif
f7b839f7
DM
208 PF (SEC_READONLY, "READONLY");
209 PF (SEC_CODE, "CODE");
210 PF (SEC_DATA, "DATA");
211 PF (SEC_ROM, "ROM");
212 PF (SEC_DEBUGGING, "DEBUGGING");
28d1b01e 213 PF (SEC_NEVER_LOAD, "NEVER_LOAD");
f7b839f7 214 printf ("\n");
2fa0b342 215#undef PF
2fa0b342
DHW
216}
217
f7b839f7
DM
218static void
219dump_headers (abfd)
220 bfd *abfd;
221{
222 bfd_map_over_sections (abfd, dump_section_header, (PTR) NULL);
223}
224\f
2fa0b342 225static asymbol **
abdcac0f
DM
226slurp_symtab (abfd)
227 bfd *abfd;
2fa0b342 228{
aa0a709a 229 asymbol **sy = (asymbol **) NULL;
ae5d2ff5 230 long storage;
2fa0b342 231
aa0a709a
SC
232 if (!(bfd_get_file_flags (abfd) & HAS_SYMS))
233 {
f7b839f7
DM
234 printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
235 return NULL;
aa0a709a
SC
236 }
237
ae5d2ff5
ILT
238 storage = bfd_get_symtab_upper_bound (abfd);
239 if (storage < 0)
240 bfd_fatal (bfd_get_filename (abfd));
241
aa0a709a
SC
242 if (storage)
243 {
02a68547 244 sy = (asymbol **) xmalloc (storage);
aa0a709a
SC
245 }
246 symcount = bfd_canonicalize_symtab (abfd, sy);
ae5d2ff5
ILT
247 if (symcount < 0)
248 bfd_fatal (bfd_get_filename (abfd));
249 if (symcount == 0)
de3b08ac
ILT
250 fprintf (stderr, "%s: %s: No symbols\n",
251 program_name, bfd_get_filename (abfd));
252 return sy;
253}
254
255/* Read in the dynamic symbols. */
256
257static asymbol **
258slurp_dynamic_symtab (abfd)
259 bfd *abfd;
260{
261 asymbol **sy = (asymbol **) NULL;
262 long storage;
263
de3b08ac
ILT
264 storage = bfd_get_dynamic_symtab_upper_bound (abfd);
265 if (storage < 0)
28d1b01e
ILT
266 {
267 if (!(bfd_get_file_flags (abfd) & DYNAMIC))
268 {
269 fprintf (stderr, "%s: %s: not a dynamic object\n",
270 program_name, bfd_get_filename (abfd));
271 return NULL;
272 }
273
274 bfd_fatal (bfd_get_filename (abfd));
275 }
de3b08ac
ILT
276
277 if (storage)
278 {
279 sy = (asymbol **) xmalloc (storage);
280 }
281 dynsymcount = bfd_canonicalize_dynamic_symtab (abfd, sy);
282 if (dynsymcount < 0)
283 bfd_fatal (bfd_get_filename (abfd));
284 if (dynsymcount == 0)
285 fprintf (stderr, "%s: %s: No dynamic symbols\n",
286 program_name, bfd_get_filename (abfd));
aa0a709a 287 return sy;
2fa0b342 288}
aa0a709a 289
f7b839f7
DM
290/* Filter out (in place) symbols that are useless for disassembly.
291 COUNT is the number of elements in SYMBOLS.
292 Return the number of useful symbols. */
3ae36cb6 293
ae5d2ff5 294long
f7b839f7
DM
295remove_useless_symbols (symbols, count)
296 asymbol **symbols;
ae5d2ff5 297 long count;
3ae36cb6 298{
f7b839f7 299 register asymbol **in_ptr = symbols, **out_ptr = symbols;
3ae36cb6 300
f7b839f7 301 while (--count >= 0)
3ae36cb6
PB
302 {
303 asymbol *sym = *in_ptr++;
304
305 if (sym->name == NULL || sym->name[0] == '\0')
306 continue;
307 if (sym->flags & (BSF_DEBUGGING))
308 continue;
28d1b01e 309 if (bfd_is_und_section (sym->section)
3ae36cb6
PB
310 || bfd_is_com_section (sym->section))
311 continue;
312
313 *out_ptr++ = sym;
314 }
f7b839f7 315 return out_ptr - symbols;
3ae36cb6
PB
316}
317
37853673
SS
318/* Sort symbols into value order. */
319
aa0a709a 320static int
37853673 321compare_symbols (ap, bp)
d5464baa
ILT
322 const PTR ap;
323 const PTR bp;
2fa0b342 324{
d5464baa
ILT
325 const asymbol *a = *(const asymbol **)ap;
326 const asymbol *b = *(const asymbol **)bp;
db552bda
ILT
327 const char *an, *bn;
328 size_t anl, bnl;
329 boolean af, bf;
2fa0b342 330
be1d162b 331 if (bfd_asymbol_value (a) > bfd_asymbol_value (b))
3ae36cb6 332 return 1;
be1d162b 333 else if (bfd_asymbol_value (a) < bfd_asymbol_value (b))
3ae36cb6 334 return -1;
2fa0b342 335
3ae36cb6
PB
336 if (a->section > b->section)
337 return 1;
338 else if (a->section < b->section)
339 return -1;
db552bda
ILT
340
341 an = bfd_asymbol_name (a);
342 bn = bfd_asymbol_name (b);
343 anl = strlen (an);
344 bnl = strlen (bn);
345
346 /* The symbols gnu_compiled and gcc2_compiled convey no real
347 information, so put them after other symbols with the same value. */
348
349 af = (strstr (an, "gnu_compiled") != NULL
350 || strstr (an, "gcc2_compiled") != NULL);
351 bf = (strstr (bn, "gnu_compiled") != NULL
352 || strstr (bn, "gcc2_compiled") != NULL);
353
354 if (af && ! bf)
355 return 1;
356 if (! af && bf)
357 return -1;
358
359 /* We use a heuristic for the file name, to try to sort it after
360 more useful symbols. It may not work on non Unix systems, but it
361 doesn't really matter; the only difference is precisely which
362 symbol names get printed. */
363
364#define file_symbol(s, sn, snl) \
365 (((s)->flags & BSF_FILE) != 0 \
366 || ((sn)[(snl) - 2] == '.' \
367 && ((sn)[(snl) - 1] == 'o' \
368 || (sn)[(snl) - 1] == 'a')))
369
370 af = file_symbol (a, an, anl);
371 bf = file_symbol (b, bn, bnl);
372
373 if (af && ! bf)
374 return 1;
375 if (! af && bf)
376 return -1;
377
3ae36cb6 378 return 0;
2fa0b342
DHW
379}
380
d5464baa
ILT
381/* Sort relocs into address order. */
382
383static int
384compare_relocs (ap, bp)
385 const PTR ap;
386 const PTR bp;
387{
388 const arelent *a = *(const arelent **)ap;
389 const arelent *b = *(const arelent **)bp;
390
391 if (a->address > b->address)
392 return 1;
393 else if (a->address < b->address)
394 return -1;
395
a65619c8
SC
396 /* So that associated relocations tied to the same address show up
397 in the correct order, we don't do any further sorting. */
398 if (a > b)
399 return 1;
400 else if (a < b)
401 return -1;
402 else
403 return 0;
d5464baa
ILT
404}
405
f7b839f7
DM
406/* Print VMA symbolically to INFO if possible. */
407
8f197c94 408static void
545a2768 409objdump_print_address (vma, info)
aa0a709a 410 bfd_vma vma;
545a2768 411 struct disassemble_info *info;
2fa0b342 412{
195d1adf
KR
413 /* @@ For relocateable files, should filter out symbols belonging to
414 the wrong section. Unfortunately, not enough information is supplied
415 to this routine to determine the correct section in all cases. */
416 /* @@ Would it speed things up to cache the last two symbols returned,
417 and maybe their address ranges? For many processors, only one memory
418 operand can be present at a time, so the 2-entry cache wouldn't be
419 constantly churned by code doing heavy memory accesses. */
2fa0b342 420
be1d162b 421 /* Indices in `sorted_syms'. */
ae5d2ff5 422 long min = 0;
be1d162b 423 long max = sorted_symcount;
ae5d2ff5 424 long thisplace;
2fa0b342 425
3ae36cb6
PB
426 fprintf_vma (info->stream, vma);
427
be1d162b 428 if (sorted_symcount < 1)
f7b839f7
DM
429 return;
430
8f197c94
ILT
431 /* Perform a binary search looking for the closest symbol to the
432 required value. We are searching the range (min, max]. */
433 while (min + 1 < max)
aa0a709a 434 {
f7b839f7 435 asymbol *sym;
8f197c94 436
f7b839f7 437 thisplace = (max + min) / 2;
be1d162b 438 sym = sorted_syms[thisplace];
8f197c94 439
13e4db2e 440 if (bfd_asymbol_value (sym) > vma)
f7b839f7 441 max = thisplace;
13e4db2e 442 else if (bfd_asymbol_value (sym) < vma)
f7b839f7
DM
443 min = thisplace;
444 else
aa0a709a 445 {
8f197c94
ILT
446 min = thisplace;
447 break;
aa0a709a 448 }
f7b839f7 449 }
fc5d6074 450
8f197c94
ILT
451 /* The symbol we want is now in min, the low end of the range we
452 were searching. */
453 thisplace = min;
db552bda
ILT
454 while (thisplace > 0
455 && (bfd_asymbol_value (sorted_syms[thisplace])
456 == bfd_asymbol_value (sorted_syms[thisplace - 1])))
457 --thisplace;
8f197c94 458
f7b839f7
DM
459 {
460 /* If this symbol isn't global, search for one with the same value
461 that is. */
be1d162b 462 bfd_vma val = bfd_asymbol_value (sorted_syms[thisplace]);
ae5d2ff5 463 long i;
be1d162b 464 if (sorted_syms[thisplace]->flags & (BSF_LOCAL|BSF_DEBUGGING))
f7b839f7 465 for (i = thisplace - 1; i >= 0; i--)
aa0a709a 466 {
be1d162b
ILT
467 if (bfd_asymbol_value (sorted_syms[i]) == val
468 && (!(sorted_syms[i]->flags & (BSF_LOCAL|BSF_DEBUGGING))
469 || ((sorted_syms[thisplace]->flags & BSF_DEBUGGING)
470 && !(sorted_syms[i]->flags & BSF_DEBUGGING))))
aa0a709a 471 {
f7b839f7
DM
472 thisplace = i;
473 break;
aa0a709a
SC
474 }
475 }
be1d162b
ILT
476 if (sorted_syms[thisplace]->flags & (BSF_LOCAL|BSF_DEBUGGING))
477 for (i = thisplace + 1; i < sorted_symcount; i++)
f7b839f7 478 {
be1d162b
ILT
479 if (bfd_asymbol_value (sorted_syms[i]) == val
480 && (!(sorted_syms[i]->flags & (BSF_LOCAL|BSF_DEBUGGING))
481 || ((sorted_syms[thisplace]->flags & BSF_DEBUGGING)
482 && !(sorted_syms[i]->flags & BSF_DEBUGGING))))
195d1adf 483 {
f7b839f7
DM
484 thisplace = i;
485 break;
195d1adf 486 }
f7b839f7
DM
487 }
488 }
489 {
490 /* If the file is relocateable, and the symbol could be from this
491 section, prefer a symbol from this section over symbols from
492 others, even if the other symbol's value might be closer.
493
494 Note that this may be wrong for some symbol references if the
495 sections have overlapping memory ranges, but in that case there's
496 no way to tell what's desired without looking at the relocation
497 table. */
498 struct objdump_disasm_info *aux;
ae5d2ff5 499 long i;
f7b839f7
DM
500
501 aux = (struct objdump_disasm_info *) info->application_data;
be1d162b 502 if (sorted_syms[thisplace]->section != aux->sec
2d054641
ILT
503 && (aux->require_sec
504 || ((aux->abfd->flags & HAS_RELOC) != 0
505 && vma >= bfd_get_section_vma (aux->abfd, aux->sec)
506 && vma < (bfd_get_section_vma (aux->abfd, aux->sec)
507 + bfd_get_section_size_before_reloc (aux->sec)))))
f7b839f7 508 {
be1d162b 509 for (i = thisplace + 1; i < sorted_symcount; i++)
8f197c94 510 {
be1d162b
ILT
511 if (bfd_asymbol_value (sorted_syms[i])
512 != bfd_asymbol_value (sorted_syms[thisplace]))
28d1b01e 513 break;
8f197c94 514 }
28d1b01e 515 --i;
8f197c94
ILT
516 for (; i >= 0; i--)
517 {
db552bda
ILT
518 if (sorted_syms[i]->section == aux->sec
519 && (i == 0
520 || sorted_syms[i - 1]->section != aux->sec
521 || (bfd_asymbol_value (sorted_syms[i])
522 != bfd_asymbol_value (sorted_syms[i - 1]))))
8f197c94
ILT
523 {
524 thisplace = i;
525 break;
526 }
527 }
2d054641 528
be1d162b 529 if (sorted_syms[thisplace]->section != aux->sec)
2d054641
ILT
530 {
531 /* We didn't find a good symbol with a smaller value.
532 Look for one with a larger value. */
be1d162b 533 for (i = thisplace + 1; i < sorted_symcount; i++)
2d054641 534 {
be1d162b 535 if (sorted_syms[i]->section == aux->sec)
2d054641
ILT
536 {
537 thisplace = i;
538 break;
539 }
540 }
541 }
195d1adf 542 }
f7b839f7 543 }
2d054641 544
be1d162b
ILT
545 fprintf (info->stream, " <%s", sorted_syms[thisplace]->name);
546 if (bfd_asymbol_value (sorted_syms[thisplace]) > vma)
f7b839f7
DM
547 {
548 char buf[30], *p = buf;
be1d162b 549 sprintf_vma (buf, bfd_asymbol_value (sorted_syms[thisplace]) - vma);
f7b839f7
DM
550 while (*p == '0')
551 p++;
552 fprintf (info->stream, "-%s", p);
553 }
be1d162b 554 else if (vma > bfd_asymbol_value (sorted_syms[thisplace]))
f7b839f7
DM
555 {
556 char buf[30], *p = buf;
be1d162b 557 sprintf_vma (buf, vma - bfd_asymbol_value (sorted_syms[thisplace]));
f7b839f7
DM
558 while (*p == '0')
559 p++;
560 fprintf (info->stream, "+%s", p);
2fa0b342 561 }
f7b839f7 562 fprintf (info->stream, ">");
2fa0b342
DHW
563}
564
be1d162b
ILT
565/* Hold the last function name and the last line number we displayed
566 in a disassembly. */
567
568static char *prev_functionname;
569static unsigned int prev_line;
570
571/* We keep a list of all files that we have seen when doing a
572 dissassembly with source, so that we know how much of the file to
573 display. This can be important for inlined functions. */
574
575struct print_file_list
576{
577 struct print_file_list *next;
578 char *filename;
579 unsigned int line;
580 FILE *f;
581};
582
583static struct print_file_list *print_files;
584
585/* The number of preceding context lines to show when we start
586 displaying a file for the first time. */
587
588#define SHOW_PRECEDING_CONTEXT_LINES (5)
589
590/* Skip ahead to a given line in a file, optionally printing each
591 line. */
592
593static void
594skip_to_line PARAMS ((struct print_file_list *, unsigned int, boolean));
595
596static void
597skip_to_line (p, line, show)
598 struct print_file_list *p;
599 unsigned int line;
600 boolean show;
601{
602 while (p->line < line)
603 {
604 char buf[100];
605
606 if (fgets (buf, sizeof buf, p->f) == NULL)
607 {
608 fclose (p->f);
609 p->f = NULL;
610 break;
611 }
612
613 if (show)
614 printf ("%s", buf);
615
616 if (strchr (buf, '\n') != NULL)
617 ++p->line;
618 }
619}
620
621/* Show the line number, or the source line, in a dissassembly
622 listing. */
623
624static void
625show_line (abfd, section, off)
aa0a709a 626 bfd *abfd;
be1d162b
ILT
627 asection *section;
628 bfd_vma off;
2fa0b342 629{
be1d162b
ILT
630 CONST char *filename;
631 CONST char *functionname;
632 unsigned int line;
2e8adbd7 633
be1d162b
ILT
634 if (! with_line_numbers && ! with_source_code)
635 return;
d20f480f 636
be1d162b
ILT
637 if (! bfd_find_nearest_line (abfd, section, syms, off, &filename,
638 &functionname, &line))
639 return;
aa0a709a 640
be1d162b
ILT
641 if (filename != NULL && *filename == '\0')
642 filename = NULL;
643 if (functionname != NULL && *functionname == '\0')
644 functionname = NULL;
aa0a709a 645
be1d162b 646 if (with_line_numbers)
d5464baa 647 {
be1d162b
ILT
648 if (functionname != NULL
649 && (prev_functionname == NULL
650 || strcmp (functionname, prev_functionname) != 0))
651 printf ("%s():\n", functionname);
652 if (line > 0 && line != prev_line)
653 printf ("%s:%u\n", filename == NULL ? "???" : filename, line);
654 }
655
656 if (with_source_code
657 && filename != NULL
658 && line > 0)
659 {
660 struct print_file_list **pp, *p;
661
662 for (pp = &print_files; *pp != NULL; pp = &(*pp)->next)
663 if (strcmp ((*pp)->filename, filename) == 0)
664 break;
665 p = *pp;
666
667 if (p != NULL)
d5464baa 668 {
be1d162b
ILT
669 if (p != print_files)
670 {
671 int l;
672
673 /* We have reencountered a file name which we saw
674 earlier. This implies that either we are dumping out
675 code from an included file, or the same file was
676 linked in more than once. There are two common cases
677 of an included file: inline functions in a header
678 file, and a bison or flex skeleton file. In the
679 former case we want to just start printing (but we
680 back up a few lines to give context); in the latter
681 case we want to continue from where we left off. I
682 can't think of a good way to distinguish the cases,
683 so I used a heuristic based on the file name. */
684 if (strcmp (p->filename + strlen (p->filename) - 2, ".h") != 0)
685 l = p->line;
686 else
687 {
688 l = line - SHOW_PRECEDING_CONTEXT_LINES;
689 if (l <= 0)
690 l = 1;
691 }
d5464baa 692
be1d162b
ILT
693 if (p->f == NULL)
694 {
695 p->f = fopen (p->filename, "r");
696 p->line = 0;
697 }
698 if (p->f != NULL)
699 skip_to_line (p, l, false);
d5464baa 700
be1d162b
ILT
701 if (print_files->f != NULL)
702 {
703 fclose (print_files->f);
704 print_files->f = NULL;
705 }
706 }
d5464baa 707
be1d162b
ILT
708 if (p->f != NULL)
709 {
710 skip_to_line (p, line, true);
711 *pp = p->next;
712 p->next = print_files;
713 print_files = p;
714 }
715 }
716 else
717 {
718 FILE *f;
d5464baa 719
be1d162b
ILT
720 f = fopen (filename, "r");
721 if (f != NULL)
d5464baa 722 {
be1d162b 723 int l;
d5464baa 724
be1d162b
ILT
725 p = ((struct print_file_list *)
726 xmalloc (sizeof (struct print_file_list)));
727 p->filename = xmalloc (strlen (filename) + 1);
728 strcpy (p->filename, filename);
729 p->line = 0;
730 p->f = f;
731
732 if (print_files != NULL && print_files->f != NULL)
733 {
734 fclose (print_files->f);
735 print_files->f = NULL;
736 }
737 p->next = print_files;
738 print_files = p;
739
740 l = line - SHOW_PRECEDING_CONTEXT_LINES;
741 if (l <= 0)
742 l = 1;
743 skip_to_line (p, l, false);
744 if (p->f != NULL)
745 skip_to_line (p, line, true);
d5464baa
ILT
746 }
747 }
748 }
749
be1d162b
ILT
750 if (functionname != NULL
751 && (prev_functionname == NULL
752 || strcmp (functionname, prev_functionname) != 0))
aa0a709a 753 {
be1d162b
ILT
754 if (prev_functionname != NULL)
755 free (prev_functionname);
756 prev_functionname = xmalloc (strlen (functionname) + 1);
757 strcpy (prev_functionname, functionname);
aa0a709a 758 }
2fa0b342 759
be1d162b
ILT
760 if (line > 0 && line != prev_line)
761 prev_line = line;
762}
763
764void
765disassemble_data (abfd)
766 bfd *abfd;
767{
768 long i;
be1d162b
ILT
769 disassembler_ftype disassemble_fn = 0; /* New style */
770 struct disassemble_info disasm_info;
771 struct objdump_disasm_info aux;
772 asection *section;
773 boolean done_dot = false;
774
775 print_files = NULL;
776 prev_functionname = NULL;
777 prev_line = -1;
778
779 /* We make a copy of syms to sort. We don't want to sort syms
780 because that will screw up the relocs. */
781 sorted_syms = (asymbol **) xmalloc (symcount * sizeof (asymbol *));
782 memcpy (sorted_syms, syms, symcount * sizeof (asymbol *));
783
784 sorted_symcount = remove_useless_symbols (sorted_syms, symcount);
2fa0b342
DHW
785
786 /* Sort the symbols into section and symbol order */
be1d162b 787 qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols);
2fa0b342 788
cef35d48
DM
789 INIT_DISASSEMBLE_INFO(disasm_info, stdout);
790 disasm_info.application_data = (PTR) &aux;
791 aux.abfd = abfd;
792 disasm_info.print_address_func = objdump_print_address;
793
aa0a709a
SC
794 if (machine != (char *) NULL)
795 {
db552bda 796 const bfd_arch_info_type *info = bfd_scan_arch (machine);
cef35d48 797 if (info == NULL)
aa0a709a
SC
798 {
799 fprintf (stderr, "%s: Can't use supplied machine %s\n",
800 program_name,
801 machine);
802 exit (1);
803 }
804 abfd->arch_info = info;
2fa0b342 805 }
e779a58c 806
db552bda
ILT
807 disassemble_fn = disassembler (abfd);
808 if (!disassemble_fn)
aa0a709a 809 {
db552bda
ILT
810 fprintf (stderr, "%s: Can't disassemble for architecture %s\n",
811 program_name,
812 bfd_printable_arch_mach (bfd_get_arch (abfd), 0));
813 exit (1);
aa0a709a 814 }
2fa0b342
DHW
815
816 for (section = abfd->sections;
aa0a709a
SC
817 section != (asection *) NULL;
818 section = section->next)
65cceb78 819 {
cef35d48
DM
820 bfd_byte *data = NULL;
821 bfd_size_type datasize = 0;
be1d162b 822 arelent **relbuf = NULL;
d5464baa
ILT
823 arelent **relpp = NULL;
824 arelent **relppend = NULL;
aa21a2a9 825 long stop;
2fa0b342 826
d5464baa
ILT
827 if ((section->flags & SEC_LOAD) == 0
828 || (! disassemble_all
829 && only == NULL
830 && (section->flags & SEC_CODE) == 0))
cef35d48
DM
831 continue;
832 if (only != (char *) NULL && strcmp (only, section->name) != 0)
833 continue;
2fa0b342 834
d5464baa
ILT
835 if (dump_reloc_info
836 && (section->flags & SEC_RELOC) != 0)
837 {
be1d162b
ILT
838 long relsize;
839
840 relsize = bfd_get_reloc_upper_bound (abfd, section);
841 if (relsize < 0)
842 bfd_fatal (bfd_get_filename (abfd));
843
844 if (relsize > 0)
845 {
846 long relcount;
847
848 relbuf = (arelent **) xmalloc (relsize);
849 relcount = bfd_canonicalize_reloc (abfd, section, relbuf, syms);
850 if (relcount < 0)
851 bfd_fatal (bfd_get_filename (abfd));
852
853 /* Sort the relocs by address. */
854 qsort (relbuf, relcount, sizeof (arelent *), compare_relocs);
855
856 relpp = relbuf;
857 relppend = relpp + relcount;
858 }
d5464baa
ILT
859 }
860
cef35d48 861 printf ("Disassembly of section %s:\n", section->name);
2fa0b342 862
cef35d48
DM
863 datasize = bfd_get_section_size_before_reloc (section);
864 if (datasize == 0)
865 continue;
2fa0b342 866
cef35d48 867 data = (bfd_byte *) xmalloc ((size_t) datasize);
2fa0b342 868
cef35d48 869 bfd_get_section_contents (abfd, section, data, 0, datasize);
2fa0b342 870
cef35d48
DM
871 aux.sec = section;
872 disasm_info.buffer = data;
873 disasm_info.buffer_vma = section->vma;
874 disasm_info.buffer_length = datasize;
aa21a2a9
ILT
875 if (start_address == (bfd_vma) -1
876 || start_address < disasm_info.buffer_vma)
877 i = 0;
878 else
879 i = start_address - disasm_info.buffer_vma;
880 if (stop_address == (bfd_vma) -1)
881 stop = datasize;
882 else
883 {
884 if (stop_address < disasm_info.buffer_vma)
885 stop = 0;
886 else
887 stop = stop_address - disasm_info.buffer_vma;
888 if (stop > disasm_info.buffer_length)
889 stop = disasm_info.buffer_length;
890 }
891 while (i < stop)
cef35d48 892 {
d5464baa 893 int bytes;
13e4db2e 894 boolean need_nl = false;
d5464baa 895
cef35d48
DM
896 if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 &&
897 data[i + 3] == 0)
aa0a709a 898 {
cef35d48 899 if (done_dot == false)
aa0a709a 900 {
cef35d48
DM
901 printf ("...\n");
902 done_dot = true;
65cceb78 903 }
d5464baa 904 bytes = 4;
cef35d48
DM
905 }
906 else
907 {
908 done_dot = false;
be1d162b
ILT
909 if (with_line_numbers || with_source_code)
910 show_line (abfd, section, i);
8b129785 911 aux.require_sec = true;
cef35d48 912 objdump_print_address (section->vma + i, &disasm_info);
8b129785 913 aux.require_sec = false;
cef35d48 914 putchar (' ');
65cceb78 915
db552bda
ILT
916 bytes = (*disassemble_fn) (section->vma + i, &disasm_info);
917 if (bytes < 0)
918 break;
919
13e4db2e
SC
920 if (!wide_output)
921 putchar ('\n');
922 else
923 need_nl = true;
96d7950b 924 }
d5464baa
ILT
925
926 if (dump_reloc_info
927 && (section->flags & SEC_RELOC) != 0)
928 {
929 while (relpp < relppend
746cffcf
ILT
930 && ((*relpp)->address >= (bfd_vma) i
931 && (*relpp)->address < (bfd_vma) i + bytes))
d5464baa
ILT
932 {
933 arelent *q;
934 const char *sym_name;
935
936 q = *relpp;
937
938 printf ("\t\tRELOC: ");
939
940 printf_vma (section->vma + q->address);
941
942 printf (" %s ", q->howto->name);
943
944 if (q->sym_ptr_ptr != NULL
945 && *q->sym_ptr_ptr != NULL)
946 {
947 sym_name = bfd_asymbol_name (*q->sym_ptr_ptr);
948 if (sym_name == NULL || *sym_name == '\0')
949 {
950 asection *sym_sec;
951
952 sym_sec = bfd_get_section (*q->sym_ptr_ptr);
953 sym_name = bfd_get_section_name (abfd, sym_sec);
954 if (sym_name == NULL || *sym_name == '\0')
955 sym_name = "*unknown*";
956 }
957 }
958
959 printf ("%s", sym_name);
960
961 if (q->addend)
962 {
963 printf ("+0x");
964 printf_vma (q->addend);
965 }
966
967 printf ("\n");
13e4db2e 968 need_nl = false;
d5464baa
ILT
969 ++relpp;
970 }
971 }
972
13e4db2e
SC
973 if (need_nl)
974 printf ("\n");
975
d5464baa 976 i += bytes;
96d7950b 977 }
be1d162b 978
cef35d48 979 free (data);
be1d162b
ILT
980 if (relbuf != NULL)
981 free (relbuf);
2fa0b342 982 }
2fa0b342 983}
73b8f102 984\f
73b8f102
JG
985
986/* Define a table of stab values and print-strings. We wish the initializer
987 could be a direct-mapped table, but instead we build one the first
988 time we need it. */
989
fe2750e1 990char **stab_name;
73b8f102
JG
991
992struct stab_print {
993 int value;
fe2750e1 994 char *string;
73b8f102
JG
995};
996
997struct stab_print stab_print[] = {
998#define __define_stab(NAME, CODE, STRING) {CODE, STRING},
999#include "aout/stab.def"
1000#undef __define_stab
02a68547 1001 {0, ""}
73b8f102
JG
1002};
1003
250e36fe
DM
1004void dump_section_stabs PARAMS ((bfd *abfd, char *stabsect_name,
1005 char *strsect_name));
249c6fc0 1006
250e36fe 1007/* Dump the stabs sections from an object file that has a section that
73b8f102
JG
1008 uses Sun stabs encoding. It has to use some hooks into BFD because
1009 string table sections are not normally visible to BFD callers. */
1010
1011void
9b018ecd 1012dump_stabs (abfd)
73b8f102
JG
1013 bfd *abfd;
1014{
fe2750e1
SS
1015 /* Allocate and initialize stab name array if first time. */
1016 if (stab_name == NULL)
73b8f102 1017 {
250e36fe
DM
1018 int i;
1019
fe2750e1
SS
1020 stab_name = (char **) xmalloc (256 * sizeof(char *));
1021 /* Clear the array. */
73b8f102 1022 for (i = 0; i < 256; i++)
fe2750e1
SS
1023 stab_name[i] = NULL;
1024 /* Fill in the defined stabs. */
1025 for (i = 0; *stab_print[i].string; i++)
1026 stab_name[stab_print[i].value] = stab_print[i].string;
73b8f102
JG
1027 }
1028
250e36fe
DM
1029 dump_section_stabs (abfd, ".stab", ".stabstr");
1030 dump_section_stabs (abfd, ".stab.excl", ".stab.exclstr");
1031 dump_section_stabs (abfd, ".stab.index", ".stab.indexstr");
1032 dump_section_stabs (abfd, "$GDB_SYMBOLS$", "$GDB_STRINGS$");
249c6fc0
RS
1033}
1034
250e36fe
DM
1035static struct internal_nlist *stabs;
1036static bfd_size_type stab_size;
1037
1038static char *strtab;
1039static bfd_size_type stabstr_size;
1040
1041/* Read ABFD's stabs section STABSECT_NAME into `stabs'
1042 and string table section STRSECT_NAME into `strtab'.
1043 If the section exists and was read, allocate the space and return true.
1044 Otherwise return false. */
1045
1046boolean
1047read_section_stabs (abfd, stabsect_name, strsect_name)
249c6fc0 1048 bfd *abfd;
250e36fe
DM
1049 char *stabsect_name;
1050 char *strsect_name;
249c6fc0 1051{
9b018ecd 1052 asection *stabsect, *stabstrsect;
9b018ecd 1053
d5671c53
ILT
1054 stabsect = bfd_get_section_by_name (abfd, stabsect_name);
1055 if (0 == stabsect)
73b8f102 1056 {
250e36fe
DM
1057 printf ("No %s section present\n\n", stabsect_name);
1058 return false;
73b8f102
JG
1059 }
1060
d5671c53
ILT
1061 stabstrsect = bfd_get_section_by_name (abfd, strsect_name);
1062 if (0 == stabstrsect)
73b8f102 1063 {
eae82145 1064 fprintf (stderr, "%s: %s has no %s section\n", program_name,
250e36fe
DM
1065 bfd_get_filename (abfd), strsect_name);
1066 return false;
73b8f102 1067 }
9b018ecd 1068
d5671c53
ILT
1069 stab_size = bfd_section_size (abfd, stabsect);
1070 stabstr_size = bfd_section_size (abfd, stabstrsect);
73b8f102 1071
9b018ecd
ILT
1072 stabs = (struct internal_nlist *) xmalloc (stab_size);
1073 strtab = (char *) xmalloc (stabstr_size);
73b8f102 1074
d5671c53 1075 if (! bfd_get_section_contents (abfd, stabsect, (PTR) stabs, 0, stab_size))
9b018ecd 1076 {
d5671c53
ILT
1077 fprintf (stderr, "%s: Reading %s section of %s failed: %s\n",
1078 program_name, stabsect_name, bfd_get_filename (abfd),
1079 bfd_errmsg (bfd_get_error ()));
1080 free (stabs);
1081 free (strtab);
1082 return false;
73b8f102 1083 }
2fa0b342 1084
d5671c53
ILT
1085 if (! bfd_get_section_contents (abfd, stabstrsect, (PTR) strtab, 0,
1086 stabstr_size))
9b018ecd 1087 {
d5671c53
ILT
1088 fprintf (stderr, "%s: Reading %s section of %s failed: %s\n",
1089 program_name, strsect_name, bfd_get_filename (abfd),
1090 bfd_errmsg (bfd_get_error ()));
1091 free (stabs);
1092 free (strtab);
1093 return false;
73b8f102 1094 }
d5671c53 1095
250e36fe
DM
1096 return true;
1097}
73b8f102
JG
1098
1099#define SWAP_SYMBOL(symp, abfd) \
250e36fe 1100{ \
73b8f102 1101 (symp)->n_strx = bfd_h_get_32(abfd, \
250e36fe 1102 (unsigned char *)&(symp)->n_strx); \
73b8f102 1103 (symp)->n_desc = bfd_h_get_16 (abfd, \
250e36fe 1104 (unsigned char *)&(symp)->n_desc); \
73b8f102 1105 (symp)->n_value = bfd_h_get_32 (abfd, \
250e36fe
DM
1106 (unsigned char *)&(symp)->n_value); \
1107}
73b8f102 1108
250e36fe
DM
1109/* Print ABFD's stabs section STABSECT_NAME (in `stabs'),
1110 using string table section STRSECT_NAME (in `strtab'). */
1111
1112void
1113print_section_stabs (abfd, stabsect_name, strsect_name)
1114 bfd *abfd;
1115 char *stabsect_name;
1116 char *strsect_name;
1117{
1118 int i;
1119 unsigned file_string_table_offset = 0, next_file_string_table_offset = 0;
1120 struct internal_nlist *stabp = stabs,
1121 *stabs_end = (struct internal_nlist *) (stab_size + (char *) stabs);
73b8f102 1122
250e36fe
DM
1123 printf ("Contents of %s section:\n\n", stabsect_name);
1124 printf ("Symnum n_type n_othr n_desc n_value n_strx String\n");
249c6fc0
RS
1125
1126 /* Loop through all symbols and print them.
1127
1128 We start the index at -1 because there is a dummy symbol on
250e36fe 1129 the front of stabs-in-{coff,elf} sections that supplies sizes. */
249c6fc0 1130
250e36fe 1131 for (i = -1; stabp < stabs_end; stabp++, i++)
73b8f102 1132 {
250e36fe 1133 SWAP_SYMBOL (stabp, abfd);
fe2750e1 1134 printf ("\n%-6d ", i);
250e36fe 1135 /* Either print the stab name, or, if unnamed, print its number
fe2750e1 1136 again (makes consistent formatting for tools like awk). */
250e36fe
DM
1137 if (stab_name[stabp->n_type])
1138 printf ("%-6s", stab_name[stabp->n_type]);
105da05c
ILT
1139 else if (stabp->n_type == N_UNDF)
1140 printf ("HdrSym");
fe2750e1 1141 else
105da05c 1142 printf ("%-6d", stabp->n_type);
250e36fe
DM
1143 printf (" %-6d %-6d ", stabp->n_other, stabp->n_desc);
1144 printf_vma (stabp->n_value);
1145 printf (" %-6lu", stabp->n_strx);
249c6fc0
RS
1146
1147 /* Symbols with type == 0 (N_UNDF) specify the length of the
1148 string table associated with this file. We use that info
1149 to know how to relocate the *next* file's string table indices. */
1150
250e36fe 1151 if (stabp->n_type == N_UNDF)
249c6fc0
RS
1152 {
1153 file_string_table_offset = next_file_string_table_offset;
250e36fe 1154 next_file_string_table_offset += stabp->n_value;
249c6fc0 1155 }
249c6fc0 1156 else
e1ec9f07 1157 {
250e36fe 1158 /* Using the (possibly updated) string table offset, print the
e1ec9f07
SS
1159 string (if any) associated with this symbol. */
1160
250e36fe
DM
1161 if ((stabp->n_strx + file_string_table_offset) < stabstr_size)
1162 printf (" %s", &strtab[stabp->n_strx + file_string_table_offset]);
e1ec9f07
SS
1163 else
1164 printf (" *");
1165 }
73b8f102
JG
1166 }
1167 printf ("\n\n");
1168}
249c6fc0 1169
250e36fe
DM
1170void
1171dump_section_stabs (abfd, stabsect_name, strsect_name)
1172 bfd *abfd;
1173 char *stabsect_name;
1174 char *strsect_name;
1175{
13e4db2e 1176 asection *s;
13e4db2e 1177
a65619c8
SC
1178 /* Check for section names for which stabsect_name is a prefix, to
1179 handle .stab0, etc. */
13e4db2e 1180 for (s = abfd->sections;
a65619c8 1181 s != NULL;
13e4db2e
SC
1182 s = s->next)
1183 {
a65619c8
SC
1184 if (strncmp (stabsect_name, s->name, strlen (stabsect_name)) == 0
1185 && strncmp (strsect_name, s->name, strlen (strsect_name)) != 0)
13e4db2e 1186 {
a65619c8
SC
1187 if (read_section_stabs (abfd, s->name, strsect_name))
1188 {
1189 print_section_stabs (abfd, s->name, strsect_name);
1190 free (stabs);
1191 free (strtab);
1192 }
13e4db2e
SC
1193 }
1194 }
250e36fe
DM
1195}
1196\f
eae82145 1197static void
f7b839f7
DM
1198dump_bfd_header (abfd)
1199 bfd *abfd;
1200{
1201 char *comma = "";
1202
1203 printf ("architecture: %s, ",
1204 bfd_printable_arch_mach (bfd_get_arch (abfd),
1205 bfd_get_mach (abfd)));
1206 printf ("flags 0x%08x:\n", abfd->flags);
1207
1208#define PF(x, y) if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";}
1209 PF (HAS_RELOC, "HAS_RELOC");
1210 PF (EXEC_P, "EXEC_P");
1211 PF (HAS_LINENO, "HAS_LINENO");
1212 PF (HAS_DEBUG, "HAS_DEBUG");
1213 PF (HAS_SYMS, "HAS_SYMS");
1214 PF (HAS_LOCALS, "HAS_LOCALS");
1215 PF (DYNAMIC, "DYNAMIC");
1216 PF (WP_TEXT, "WP_TEXT");
1217 PF (D_PAGED, "D_PAGED");
1218 PF (BFD_IS_RELAXABLE, "BFD_IS_RELAXABLE");
1219 printf ("\nstart address 0x");
1220 printf_vma (abfd->start_address);
1221}
a65619c8
SC
1222\f
1223static void
1224dump_bfd_private_header (abfd)
1225bfd *abfd;
1226{
1227 bfd_print_private_bfd_data (abfd, stdout);
1228}
02a68547 1229static void
2fa0b342
DHW
1230display_bfd (abfd)
1231 bfd *abfd;
1232{
209e5610
DM
1233 char **matching;
1234
1235 if (!bfd_check_format_matches (abfd, bfd_object, &matching))
aa0a709a 1236 {
cef35d48 1237 bfd_nonfatal (bfd_get_filename (abfd));
8f197c94 1238 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
209e5610
DM
1239 {
1240 list_matching_formats (matching);
1241 free (matching);
1242 }
aa0a709a
SC
1243 return;
1244 }
f7b839f7 1245
cef35d48
DM
1246 printf ("\n%s: file format %s\n", bfd_get_filename (abfd),
1247 abfd->xvec->name);
aa0a709a
SC
1248 if (dump_ar_hdrs)
1249 print_arelt_descr (stdout, abfd, true);
aa0a709a 1250 if (dump_file_header)
f7b839f7 1251 dump_bfd_header (abfd);
a65619c8
SC
1252 if (dump_private_headers)
1253 dump_bfd_private_header (abfd);
f7b839f7 1254 putchar ('\n');
2fa0b342 1255 if (dump_section_headers)
aa0a709a
SC
1256 dump_headers (abfd);
1257 if (dump_symtab || dump_reloc_info || disassemble)
1258 {
1259 syms = slurp_symtab (abfd);
1260 }
de3b08ac
ILT
1261 if (dump_dynamic_symtab || dump_dynamic_reloc_info)
1262 {
1263 dynsyms = slurp_dynamic_symtab (abfd);
1264 }
aa0a709a 1265 if (dump_symtab)
de3b08ac
ILT
1266 dump_symbols (abfd, false);
1267 if (dump_dynamic_symtab)
1268 dump_symbols (abfd, true);
73b8f102 1269 if (dump_stab_section_info)
9b018ecd 1270 dump_stabs (abfd);
d5464baa 1271 if (dump_reloc_info && ! disassemble)
aa0a709a 1272 dump_relocs (abfd);
de3b08ac
ILT
1273 if (dump_dynamic_reloc_info)
1274 dump_dynamic_relocs (abfd);
aa0a709a
SC
1275 if (dump_section_contents)
1276 dump_data (abfd);
1277 if (disassemble)
1278 disassemble_data (abfd);
2fa0b342
DHW
1279}
1280
d9971b83 1281static void
2fa0b342
DHW
1282display_file (filename, target)
1283 char *filename;
1284 char *target;
1285{
1286 bfd *file, *arfile = (bfd *) NULL;
1287
1288 file = bfd_openr (filename, target);
aa0a709a
SC
1289 if (file == NULL)
1290 {
cef35d48 1291 bfd_nonfatal (filename);
aa0a709a
SC
1292 return;
1293 }
2fa0b342 1294
aa0a709a
SC
1295 if (bfd_check_format (file, bfd_archive) == true)
1296 {
8f197c94
ILT
1297 bfd *last_arfile = NULL;
1298
aa0a709a
SC
1299 printf ("In archive %s:\n", bfd_get_filename (file));
1300 for (;;)
1301 {
8f197c94 1302 bfd_set_error (bfd_error_no_error);
aa0a709a
SC
1303
1304 arfile = bfd_openr_next_archived_file (file, arfile);
1305 if (arfile == NULL)
1306 {
8f197c94 1307 if (bfd_get_error () != bfd_error_no_more_archived_files)
d2442698 1308 {
cef35d48 1309 bfd_nonfatal (bfd_get_filename (file));
d2442698 1310 }
8f197c94 1311 break;
aa0a709a 1312 }
2fa0b342 1313
aa0a709a 1314 display_bfd (arfile);
8f197c94
ILT
1315
1316 if (last_arfile != NULL)
1317 bfd_close (last_arfile);
1318 last_arfile = arfile;
aa0a709a 1319 }
8f197c94
ILT
1320
1321 if (last_arfile != NULL)
1322 bfd_close (last_arfile);
2fa0b342 1323 }
2fa0b342 1324 else
aa0a709a 1325 display_bfd (file);
2fa0b342 1326
aa0a709a 1327 bfd_close (file);
2fa0b342
DHW
1328}
1329\f
1330/* Actually display the various requested regions */
1331
d9971b83 1332static void
2fa0b342
DHW
1333dump_data (abfd)
1334 bfd *abfd;
1335{
1336 asection *section;
aa0a709a 1337 bfd_byte *data = 0;
fc5d6074
SC
1338 bfd_size_type datasize = 0;
1339 bfd_size_type i;
aa21a2a9 1340 bfd_size_type start, stop;
2fa0b342
DHW
1341
1342 for (section = abfd->sections; section != NULL; section =
aa0a709a
SC
1343 section->next)
1344 {
1345 int onaline = 16;
2fa0b342 1346
aa0a709a
SC
1347 if (only == (char *) NULL ||
1348 strcmp (only, section->name) == 0)
60c80016 1349 {
aa0a709a
SC
1350 if (section->flags & SEC_HAS_CONTENTS)
1351 {
1352 printf ("Contents of section %s:\n", section->name);
1353
9b018ecd 1354 if (bfd_section_size (abfd, section) == 0)
aa0a709a 1355 continue;
02a68547 1356 data = (bfd_byte *) xmalloc ((size_t) bfd_section_size (abfd, section));
9b018ecd 1357 datasize = bfd_section_size (abfd, section);
2fa0b342 1358
2fa0b342 1359
9b018ecd 1360 bfd_get_section_contents (abfd, section, (PTR) data, 0, bfd_section_size (abfd, section));
2fa0b342 1361
aa21a2a9
ILT
1362 if (start_address == (bfd_vma) -1
1363 || start_address < section->vma)
1364 start = 0;
1365 else
1366 start = start_address - section->vma;
1367 if (stop_address == (bfd_vma) -1)
1368 stop = bfd_section_size (abfd, section);
1369 else
1370 {
1371 if (stop_address < section->vma)
1372 stop = 0;
1373 else
1374 stop = stop_address - section->vma;
1375 if (stop > bfd_section_size (abfd, section))
1376 stop = bfd_section_size (abfd, section);
1377 }
1378 for (i = start; i < stop; i += onaline)
aa0a709a
SC
1379 {
1380 bfd_size_type j;
1381
1382 printf (" %04lx ", (unsigned long int) (i + section->vma));
1383 for (j = i; j < i + onaline; j++)
1384 {
aa21a2a9 1385 if (j < stop)
aa0a709a
SC
1386 printf ("%02x", (unsigned) (data[j]));
1387 else
1388 printf (" ");
1389 if ((j & 3) == 3)
1390 printf (" ");
1391 }
2fa0b342 1392
aa0a709a
SC
1393 printf (" ");
1394 for (j = i; j < i + onaline; j++)
1395 {
aa21a2a9 1396 if (j >= stop)
aa0a709a
SC
1397 printf (" ");
1398 else
1399 printf ("%c", isprint (data[j]) ? data[j] : '.');
1400 }
1401 putchar ('\n');
1402 }
d9971b83 1403 free (data);
60c80016 1404 }
2fa0b342 1405 }
2fa0b342 1406 }
2fa0b342
DHW
1407}
1408
2fa0b342 1409/* Should perhaps share code and display with nm? */
d9971b83 1410static void
de3b08ac 1411dump_symbols (abfd, dynamic)
2fa0b342 1412 bfd *abfd;
de3b08ac 1413 boolean dynamic;
2fa0b342 1414{
de3b08ac
ILT
1415 asymbol **current;
1416 long max;
ae5d2ff5 1417 long count;
2fa0b342 1418
de3b08ac 1419 if (dynamic)
aa0a709a 1420 {
de3b08ac
ILT
1421 current = dynsyms;
1422 max = dynsymcount;
1423 if (max == 0)
1424 return;
1425 printf ("DYNAMIC SYMBOL TABLE:\n");
1426 }
1427 else
1428 {
1429 current = syms;
1430 max = symcount;
1431 if (max == 0)
1432 return;
1433 printf ("SYMBOL TABLE:\n");
1434 }
2fa0b342 1435
de3b08ac
ILT
1436 for (count = 0; count < max; count++)
1437 {
d9971b83 1438 if (*current)
aa0a709a 1439 {
d9971b83
KR
1440 bfd *cur_bfd = bfd_asymbol_bfd(*current);
1441 if (cur_bfd)
1442 {
1443 bfd_print_symbol (cur_bfd,
1444 stdout,
1445 *current, bfd_print_symbol_all);
1446 printf ("\n");
1447 }
aa0a709a
SC
1448 }
1449 current++;
2fa0b342 1450 }
aa0a709a
SC
1451 printf ("\n");
1452 printf ("\n");
2fa0b342
DHW
1453}
1454
d9971b83 1455static void
aa0a709a
SC
1456dump_relocs (abfd)
1457 bfd *abfd;
2fa0b342
DHW
1458{
1459 arelent **relpp;
ae5d2ff5 1460 long relcount;
2fa0b342 1461 asection *a;
aa0a709a
SC
1462
1463 for (a = abfd->sections; a != (asection *) NULL; a = a->next)
1464 {
ae5d2ff5
ILT
1465 long relsize;
1466
28d1b01e 1467 if (bfd_is_abs_section (a))
aa0a709a 1468 continue;
28d1b01e 1469 if (bfd_is_und_section (a))
aa0a709a 1470 continue;
d9971b83 1471 if (bfd_is_com_section (a))
aa0a709a
SC
1472 continue;
1473
195d1adf
KR
1474 if (only)
1475 {
1476 if (strcmp (only, a->name))
1477 continue;
1478 }
1479 else if ((a->flags & SEC_RELOC) == 0)
1480 continue;
1481
aa0a709a
SC
1482 printf ("RELOCATION RECORDS FOR [%s]:", a->name);
1483
ae5d2ff5
ILT
1484 relsize = bfd_get_reloc_upper_bound (abfd, a);
1485 if (relsize < 0)
1486 bfd_fatal (bfd_get_filename (abfd));
1487
1488 if (relsize == 0)
aa0a709a
SC
1489 {
1490 printf (" (none)\n\n");
d20f480f 1491 }
aa0a709a
SC
1492 else
1493 {
ae5d2ff5 1494 relpp = (arelent **) xmalloc (relsize);
aa0a709a 1495 relcount = bfd_canonicalize_reloc (abfd, a, relpp, syms);
ae5d2ff5
ILT
1496 if (relcount < 0)
1497 bfd_fatal (bfd_get_filename (abfd));
1498 else if (relcount == 0)
aa0a709a
SC
1499 {
1500 printf (" (none)\n\n");
d20f480f 1501 }
aa0a709a
SC
1502 else
1503 {
1504 printf ("\n");
de3b08ac 1505 dump_reloc_set (abfd, relpp, relcount);
aa0a709a 1506 printf ("\n\n");
d20f480f 1507 }
de3b08ac 1508 free (relpp);
2fa0b342 1509 }
de3b08ac
ILT
1510 }
1511}
2fa0b342 1512
de3b08ac
ILT
1513static void
1514dump_dynamic_relocs (abfd)
1515 bfd *abfd;
1516{
1517 long relsize;
1518 arelent **relpp;
1519 long relcount;
1520
1521 printf ("DYNAMIC RELOCATION RECORDS");
1522
1523 relsize = bfd_get_dynamic_reloc_upper_bound (abfd);
1524 if (relsize < 0)
1525 bfd_fatal (bfd_get_filename (abfd));
1526
1527 if (relsize == 0)
1528 {
1529 printf (" (none)\n\n");
1530 }
1531 else
1532 {
1533 relpp = (arelent **) xmalloc (relsize);
1534 relcount = bfd_canonicalize_dynamic_reloc (abfd, relpp, dynsyms);
1535 if (relcount < 0)
1536 bfd_fatal (bfd_get_filename (abfd));
1537 else if (relcount == 0)
1538 {
1539 printf (" (none)\n\n");
1540 }
1541 else
1542 {
1543 printf ("\n");
1544 dump_reloc_set (abfd, relpp, relcount);
1545 printf ("\n\n");
1546 }
1547 free (relpp);
1548 }
1549}
1550
1551static void
1552dump_reloc_set (abfd, relpp, relcount)
1553 bfd *abfd;
1554 arelent **relpp;
1555 long relcount;
1556{
1557 arelent **p;
1558
1559 /* Get column headers lined up reasonably. */
1560 {
1561 static int width;
1562 if (width == 0)
1563 {
1564 char buf[30];
1565 sprintf_vma (buf, (bfd_vma) -1);
1566 width = strlen (buf) - 7;
1567 }
1568 printf ("OFFSET %*s TYPE %*s VALUE \n", width, "", 12, "");
1569 }
1570
1571 for (p = relpp; relcount && *p != (arelent *) NULL; p++, relcount--)
1572 {
1573 arelent *q = *p;
1574 CONST char *sym_name;
1575 CONST char *section_name;
1576
aa21a2a9
ILT
1577 if (start_address != (bfd_vma) -1
1578 && q->address < start_address)
1579 continue;
1580 if (stop_address != (bfd_vma) -1
1581 && q->address > stop_address)
1582 continue;
1583
de3b08ac
ILT
1584 if (q->sym_ptr_ptr && *q->sym_ptr_ptr)
1585 {
1586 sym_name = (*(q->sym_ptr_ptr))->name;
1587 section_name = (*(q->sym_ptr_ptr))->section->name;
1588 }
1589 else
1590 {
1591 sym_name = NULL;
1592 section_name = NULL;
1593 }
1594 if (sym_name)
1595 {
1596 printf_vma (q->address);
1597 printf (" %-16s %s",
1598 q->howto->name,
1599 sym_name);
1600 }
1601 else
1602 {
1603 if (section_name == (CONST char *) NULL)
1604 section_name = "*unknown*";
1605 printf_vma (q->address);
1606 printf (" %-16s [%s]",
1607 q->howto->name,
1608 section_name);
1609 }
1610 if (q->addend)
1611 {
1612 printf ("+0x");
1613 printf_vma (q->addend);
1614 }
1615 printf ("\n");
d20f480f 1616 }
2fa0b342 1617}
f7b839f7 1618\f
f7b839f7
DM
1619/* The length of the longest architecture name + 1. */
1620#define LONGEST_ARCH sizeof("rs6000:6000")
1621
be1d162b
ILT
1622#ifndef L_tmpnam
1623#define L_tmpnam 25
1624#endif
1625
f7b839f7
DM
1626/* List the targets that BFD is configured to support, each followed
1627 by its endianness and the architectures it supports. */
1628
1629static void
1630display_target_list ()
1631{
de04bceb 1632 extern char *tmpnam ();
f7b839f7 1633 extern bfd_target *bfd_target_vector[];
be1d162b 1634 char tmparg[L_tmpnam];
de04bceb 1635 char *dummy_name;
f7b839f7
DM
1636 int t;
1637
be1d162b 1638 dummy_name = tmpnam (tmparg);
f7b839f7
DM
1639 for (t = 0; bfd_target_vector[t]; t++)
1640 {
f7b839f7 1641 bfd_target *p = bfd_target_vector[t];
de04bceb 1642 bfd *abfd = bfd_openw (dummy_name, p->name);
105da05c
ILT
1643 int a;
1644
1645 printf ("%s\n (header %s, data %s)\n", p->name,
1646 p->header_byteorder_big_p ? "big endian" : "little endian",
1647 p->byteorder_big_p ? "big endian" : "little endian");
f7b839f7 1648
334d6e76
SS
1649 if (abfd == NULL)
1650 {
de04bceb 1651 bfd_nonfatal (dummy_name);
105da05c 1652 continue;
334d6e76 1653 }
105da05c
ILT
1654
1655 if (! bfd_set_format (abfd, bfd_object))
1656 {
1657 if (bfd_get_error () != bfd_error_invalid_operation)
1658 bfd_nonfatal (p->name);
1659 continue;
1660 }
1661
f7b839f7
DM
1662 for (a = (int) bfd_arch_obscure + 1; a < (int) bfd_arch_last; a++)
1663 if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0))
1664 printf (" %s\n",
1665 bfd_printable_arch_mach ((enum bfd_architecture) a, 0));
1666 }
de04bceb 1667 unlink (dummy_name);
f7b839f7
DM
1668}
1669
1670/* Print a table showing which architectures are supported for entries
1671 FIRST through LAST-1 of bfd_target_vector (targets across,
1672 architectures down). */
1673
9872a49c 1674static void
abdcac0f
DM
1675display_info_table (first, last)
1676 int first;
1677 int last;
9872a49c 1678{
abdcac0f 1679 extern bfd_target *bfd_target_vector[];
de04bceb 1680 extern char *tmpnam ();
be1d162b 1681 char tmparg[L_tmpnam];
de04bceb
ILT
1682 int t, a;
1683 char *dummy_name;
9872a49c 1684
f7b839f7 1685 /* Print heading of target names. */
ae5d2ff5 1686 printf ("\n%*s", (int) LONGEST_ARCH, " ");
105da05c 1687 for (t = first; t < last && bfd_target_vector[t]; t++)
f7b839f7
DM
1688 printf ("%s ", bfd_target_vector[t]->name);
1689 putchar ('\n');
9872a49c 1690
be1d162b 1691 dummy_name = tmpnam (tmparg);
f7b839f7
DM
1692 for (a = (int) bfd_arch_obscure + 1; a < (int) bfd_arch_last; a++)
1693 if (strcmp (bfd_printable_arch_mach (a, 0), "UNKNOWN!") != 0)
e779a58c 1694 {
ae5d2ff5
ILT
1695 printf ("%*s ", (int) LONGEST_ARCH - 1,
1696 bfd_printable_arch_mach (a, 0));
105da05c 1697 for (t = first; t < last && bfd_target_vector[t]; t++)
aa0a709a 1698 {
f7b839f7 1699 bfd_target *p = bfd_target_vector[t];
105da05c 1700 boolean ok = true;
de04bceb 1701 bfd *abfd = bfd_openw (dummy_name, p->name);
aa0a709a 1702
334d6e76
SS
1703 if (abfd == NULL)
1704 {
105da05c
ILT
1705 bfd_nonfatal (p->name);
1706 ok = false;
1707 }
1708
1709 if (ok)
1710 {
1711 if (! bfd_set_format (abfd, bfd_object))
1712 {
1713 if (bfd_get_error () != bfd_error_invalid_operation)
1714 bfd_nonfatal (p->name);
1715 ok = false;
1716 }
334d6e76 1717 }
105da05c
ILT
1718
1719 if (ok)
1720 {
1721 if (! bfd_set_arch_mach (abfd, a, 0))
1722 ok = false;
1723 }
1724
1725 if (ok)
aa0a709a
SC
1726 printf ("%s ", p->name);
1727 else
e779a58c 1728 {
f7b839f7 1729 int l = strlen (p->name);
aa0a709a 1730 while (l--)
f7b839f7
DM
1731 putchar ('-');
1732 putchar (' ');
e779a58c 1733 }
e779a58c 1734 }
f7b839f7 1735 putchar ('\n');
e779a58c 1736 }
de04bceb 1737 unlink (dummy_name);
9872a49c 1738}
aa0a709a 1739
f7b839f7
DM
1740/* Print tables of all the target-architecture combinations that
1741 BFD has been configured to support. */
1742
aa0a709a 1743static void
f7b839f7 1744display_target_tables ()
aa0a709a 1745{
f7b839f7 1746 int t, columns;
abdcac0f 1747 extern bfd_target *bfd_target_vector[];
f7b839f7 1748 char *colum;
aa0a709a
SC
1749 extern char *getenv ();
1750
aa0a709a 1751 columns = 0;
f7b839f7
DM
1752 colum = getenv ("COLUMNS");
1753 if (colum != NULL)
aa0a709a 1754 columns = atoi (colum);
f7b839f7 1755 if (columns == 0)
aa0a709a 1756 columns = 80;
f7b839f7 1757
105da05c
ILT
1758 t = 0;
1759 while (bfd_target_vector[t] != NULL)
aa0a709a 1760 {
f7b839f7
DM
1761 int oldt = t, wid;
1762
105da05c
ILT
1763 wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1;
1764 ++t;
1765 while (wid < columns && bfd_target_vector[t] != NULL)
1766 {
1767 int newwid;
1768
1769 newwid = wid + strlen (bfd_target_vector[t]->name) + 1;
1770 if (newwid >= columns)
1771 break;
1772 wid = newwid;
1773 ++t;
1774 }
f7b839f7 1775 display_info_table (oldt, t);
aa0a709a
SC
1776 }
1777}
1778
f7b839f7
DM
1779static void
1780display_info ()
1781{
1782 printf ("BFD header file version %s\n", BFD_VERSION);
1783 display_target_list ();
1784 display_target_tables ();
1785}
1786
2fa0b342
DHW
1787int
1788main (argc, argv)
1789 int argc;
1790 char **argv;
1791{
1792 int c;
2fa0b342
DHW
1793 char *target = default_target;
1794 boolean seenflag = false;
2fa0b342
DHW
1795
1796 program_name = *argv;
8f197c94
ILT
1797 xmalloc_set_program_name (program_name);
1798
be1d162b
ILT
1799 START_PROGRESS (program_name, 0);
1800
8f197c94 1801 bfd_init ();
2fa0b342 1802
a65619c8 1803 while ((c = getopt_long (argc, argv, "pib:m:VdDlfahrRtTxsSj:w", long_options,
d2442698 1804 (int *) 0))
aa0a709a
SC
1805 != EOF)
1806 {
aa21a2a9
ILT
1807 if (c != 'l' && c != OPTION_START_ADDRESS && c != OPTION_STOP_ADDRESS)
1808 seenflag = true;
aa0a709a
SC
1809 switch (c)
1810 {
b3a2b497
ILT
1811 case 0:
1812 break; /* we've been given a long option */
aa0a709a
SC
1813 case 'm':
1814 machine = optarg;
1815 break;
1816 case 'j':
1817 only = optarg;
1818 break;
1819 case 'l':
1820 with_line_numbers = 1;
1821 break;
1822 case 'b':
1823 target = optarg;
1824 break;
1825 case 'f':
1826 dump_file_header = true;
1827 break;
1828 case 'i':
e1ec9f07 1829 formats_info = true;
aa0a709a 1830 break;
a65619c8
SC
1831 case 'p':
1832 dump_private_headers = 1;
1833 break;
aa0a709a 1834 case 'x':
a65619c8 1835 dump_private_headers = 1;
aa0a709a
SC
1836 dump_symtab = 1;
1837 dump_reloc_info = 1;
1838 dump_file_header = true;
1839 dump_ar_hdrs = 1;
1840 dump_section_headers = 1;
1841 break;
aa0a709a
SC
1842 case 't':
1843 dump_symtab = 1;
1844 break;
de3b08ac
ILT
1845 case 'T':
1846 dump_dynamic_symtab = 1;
1847 break;
aa0a709a
SC
1848 case 'd':
1849 disassemble = true;
1850 break;
d5464baa
ILT
1851 case 'D':
1852 disassemble = disassemble_all = true;
1853 break;
be1d162b
ILT
1854 case 'S':
1855 disassemble = true;
1856 with_source_code = true;
1857 break;
aa0a709a
SC
1858 case 's':
1859 dump_section_contents = 1;
1860 break;
1861 case 'r':
1862 dump_reloc_info = 1;
1863 break;
de3b08ac
ILT
1864 case 'R':
1865 dump_dynamic_reloc_info = 1;
1866 break;
aa0a709a
SC
1867 case 'a':
1868 dump_ar_hdrs = 1;
1869 break;
1870 case 'h':
1871 dump_section_headers = 1;
1872 break;
b3a2b497
ILT
1873 case 'H':
1874 usage (stdout, 0);
249c6fc0
RS
1875 case 'V':
1876 show_version = 1;
1877 break;
13e4db2e
SC
1878 case 'w':
1879 wide_output = 1;
1880 break;
aa21a2a9
ILT
1881 case OPTION_START_ADDRESS:
1882 start_address = parse_vma (optarg, "--start-address");
1883 break;
1884 case OPTION_STOP_ADDRESS:
1885 stop_address = parse_vma (optarg, "--stop-address");
1886 break;
aa0a709a 1887 default:
b3a2b497 1888 usage (stderr, 1);
aa0a709a 1889 }
2fa0b342 1890 }
2fa0b342 1891
249c6fc0 1892 if (show_version)
b3a2b497
ILT
1893 {
1894 printf ("GNU %s version %s\n", program_name, program_version);
1895 exit (0);
1896 }
249c6fc0 1897
2fa0b342 1898 if (seenflag == false)
b3a2b497 1899 usage (stderr, 1);
2fa0b342 1900
e1ec9f07 1901 if (formats_info)
aa0a709a
SC
1902 {
1903 display_info ();
1904 }
1905 else
1906 {
1907 if (optind == argc)
1908 display_file ("a.out", target);
1909 else
1910 for (; optind < argc;)
1911 display_file (argv[optind++], target);
1912 }
be1d162b
ILT
1913
1914 END_PROGRESS (program_name);
1915
2fa0b342
DHW
1916 return 0;
1917}
This page took 0.243666 seconds and 4 git commands to generate.