1 /* GNU PIC view object
2 Copyright (C) 2001, 2002, 2003, 2004, 2005
3 Craig Franklin
4
5 Copyright (C) 2016 Molnar Karoly
6
7 This file is part of gputils.
8
9 gputils is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 gputils is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with gputils; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24 #include "stdhdr.h"
25
26 #include "libgputils.h"
27 #include "gpvo.h"
28
29 struct gpvo_state state;
30
31 enum {
32 OPT_STRICT_OPTIONS = 0x100
33 };
34
35 #define GET_OPTIONS "bcfhnstvx:y"
36
37 /* Used: himpsv */
38 static struct option longopts[] =
39 {
40 { "binary", no_argument, NULL, 'b' },
41 { "mnemonics", no_argument, NULL, 'c' },
42 { "file", no_argument, NULL, 'f' },
43 { "help", no_argument, NULL, 'h' },
44 { "no-names", no_argument, NULL, 'n' },
45 { "section", no_argument, NULL, 's' },
46 { "strict-options", no_argument, NULL, OPT_STRICT_OPTIONS },
47 { "symbol", no_argument, NULL, 't' },
48 { "version", no_argument, NULL, 'v' },
49 { "export", required_argument, NULL, 'x' },
50 { "extended", no_argument, NULL, 'y' },
51 { NULL, no_argument, NULL, '\0'}
52 };
53
54 /*------------------------------------------------------------------------------------------------*/
55
56 static void
_show_usage(void)57 _show_usage(void)
58 {
59 printf("Usage: gpvo [options] file\n");
60 printf("Options: [defaults in brackets after descriptions]\n");
61 printf(" -b, --binary Print binary data.\n");
62 printf(" -c, --mnemonics Decode special mnemonics.\n");
63 printf(" -f, --file File header.\n");
64 printf(" -h, --help Show this usage message.\n");
65 printf(" -n, --no-names Suppress filenames.\n");
66 printf(" -s, --section Section data.\n");
67 printf(" --strict-options If this is set, then an option may not be parameter\n"
68 " of an another option. For example: -x --symbol\n");
69 printf(" -t --symbol Symbol table.\n");
70 printf(" -v, --version Show version.\n");
71 printf(" -x FILE, --export FILE Export symbols to include file.\n");
72 printf(" -y, --extended Enable 18xx extended mode.\n\n");
73 printf("Report bugs to:\n");
74 printf("%s\n", PACKAGE_BUGREPORT);
75 exit(0);
76 }
77
78 /*------------------------------------------------------------------------------------------------*/
79
80 static void
_print_header(const gp_object_t * Object)81 _print_header(const gp_object_t *Object)
82 {
83 static struct magic_s {
84 uint16_t magic_num;
85 const char *magic_name;
86 } magic[] = {
87 { 0x1234, "MICROCHIP_MAGIC_v1" },
88 { 0x1240, "MICROCHIP_MAGIC_v2" }
89 };
90
91 time_t time;
92 const char *processor_name;
93 int i;
94 #ifdef HAVE_LOCALE_H
95 char time_str[256];
96 #else
97 char *time_str;
98 #endif
99
100 time = (time_t)Object->time;
101
102 #ifdef HAVE_LOCALE_H
103 setlocale(LC_ALL, "");
104 strftime(time_str, sizeof(time_str), "%c", localtime(&time));
105 setlocale(LC_ALL, "C");
106 #else
107 time_str = ctime(&time);
108 /* strip the newline from time */
109 time_str[strlen(time_str) - 1] = '\0';
110 #endif
111
112 processor_name = gp_processor_name(Object->processor, 2);
113
114 printf("COFF File and Optional Headers\n");
115
116 for (i = 0; i < ARRAY_SIZE(magic); ++i) {
117 if (magic[i].magic_num == Object->version) {
118 break;
119 }
120 }
121
122 printf("COFF version %#x: %s\n", Object->version,
123 (i < ARRAY_SIZE(magic)) ? magic[i].magic_name : "unknown");
124 printf("Processor Type %s\n", processor_name);
125 printf("Time Stamp %s\n", time_str);
126 printf("Number of Sections %zu\n", Object->section_list.num_nodes);
127 printf("Number of Symbols %u\n", Object->num_symbols);
128 printf("Characteristics %#x\n", Object->flags);
129
130 if (Object->flags & F_RELFLG) {
131 printf(" Relocation info has been stripped.\n");
132 }
133
134 if (Object->flags & F_EXEC) {
135 printf(" File is executable.\n");
136 }
137
138 if (Object->flags & F_LINENO) {
139 printf(" Line numbers have been stripped.\n");
140 }
141
142 if (Object->flags & F_ABSOLUTE) {
143 printf(" The MPASM assembler object file is from absolute assembly code.\n");
144 }
145
146 if (Object->flags & L_SYMS) {
147 printf(" Local symbols have been stripped.\n");
148 }
149
150 if (Object->flags & F_EXTENDED18) {
151 printf(" The COFF file produced utilizing the Extended mode.\n");
152 }
153
154 if (Object->flags & F_GENERIC) {
155 printf(" Processor independent file for a core.\n");
156 }
157
158 printf("\n");
159 }
160
161 /*------------------------------------------------------------------------------------------------*/
162
163 static const char *
_format_reloc_type(uint16_t Type,char * Buffer,size_t Sizeof_buffer)164 _format_reloc_type(uint16_t Type, char *Buffer, size_t Sizeof_buffer)
165 {
166 snprintf(Buffer, Sizeof_buffer, "0x%04x %-20s", Type, gp_coffgen_reloc_type_to_str(Type));
167 return Buffer;
168 }
169
170 /*------------------------------------------------------------------------------------------------*/
171
172 static void
_print_relocation_list(proc_class_t Class,const gp_reloc_t * Relocation,const char * Column_gap)173 _print_relocation_list(proc_class_t Class, const gp_reloc_t *Relocation, const char *Column_gap)
174 {
175 char buffer[32];
176 int addr_digits;
177
178 addr_digits = Class->addr_digits;
179
180 printf("Relocations Table\n"
181 "Address Offset Offset Type Symbol\n"
182 " (hex) (dec)\n");
183
184 while (Relocation != NULL) {
185 printf("0x%0*x%s 0x%08x %11d %-25s %-s\n",
186 addr_digits, gp_processor_insn_from_byte_c(Class, Relocation->address), Column_gap,
187 Relocation->offset, Relocation->offset,
188 _format_reloc_type(Relocation->type, buffer, sizeof(buffer)),
189 Relocation->symbol->name);
190
191 Relocation = Relocation->next;
192 }
193
194 printf("\n");
195 }
196
197 /*------------------------------------------------------------------------------------------------*/
198
199 static void
_print_linenum_list(proc_class_t Class,const gp_linenum_t * Linenumber,const char * Column_gap)200 _print_linenum_list(proc_class_t Class, const gp_linenum_t *Linenumber, const char *Column_gap)
201 {
202 const char *filename;
203 int addr_digits;
204
205 addr_digits = Class->addr_digits;
206
207 printf("Line Number Table\n"
208 "Line Address Symbol\n");
209
210 while (Linenumber != NULL) {
211 if (state.suppress_names) {
212 filename = Linenumber->symbol->name;
213 }
214 else {
215 filename = Linenumber->symbol->aux_list.first->_aux_symbol._aux_file.filename;
216 }
217
218 printf("%-8i 0x%0*x%s %s\n",
219 Linenumber->line_number,
220 addr_digits, gp_processor_insn_from_byte_c(Class, Linenumber->address), Column_gap,
221 filename);
222
223 Linenumber = Linenumber->next;
224 }
225
226 printf("\n");
227 }
228
229 /*------------------------------------------------------------------------------------------------*/
230
231 static void
_print_data(pic_processor_t Processor,const gp_section_t * Section)232 _print_data(pic_processor_t Processor, const gp_section_t *Section)
233 {
234 proc_class_t class;
235 char buffer[BUFSIZ];
236 unsigned int address;
237 int num_words;
238 int addr_digits;
239 unsigned int bsr_boundary;
240 uint16_t word;
241 uint8_t byte;
242
243 class = Processor->class;
244 address = Section->address;
245 bsr_boundary = gp_processor_bsr_boundary(Processor);
246 addr_digits = class->addr_digits;
247
248 buffer[0] = '\0';
249
250 printf("Data\n");
251 while (true) {
252 if ((Section->flags & STYP_TEXT) && (class->find_insn != NULL)) {
253 if (class->i_memory_get(Section->data, address, &word, NULL, NULL) != W_USED_ALL) {
254 break;
255 }
256
257 num_words = gp_disassemble(Section->data, address, class, bsr_boundary, 0,
258 GPDIS_SHOW_ALL_BRANCH, buffer, sizeof(buffer), 0);
259 printf("%0*x: %04x %s\n",
260 addr_digits, gp_processor_insn_from_byte_c(class, address), word, buffer);
261
262 if (num_words != 1) {
263 if (class->i_memory_get(Section->data, address + WORD_SIZE, &word, NULL, NULL) != W_USED_ALL) {
264 break;
265 }
266
267 printf("%0*x: %04x\n",
268 addr_digits, gp_processor_insn_from_byte_c(class, address + WORD_SIZE), word);
269 }
270
271 address += num_words * WORD_SIZE;
272 }
273 else if ((Section->flags & STYP_DATA_ROM) || (class == PROC_CLASS_EEPROM16)) {
274 if (class->i_memory_get(Section->data, address, &word, NULL, NULL) != 0) {
275 printf("%0*x: %04x\n", addr_digits, gp_processor_insn_from_byte_c(class, address), word);
276 address += WORD_SIZE;
277 }
278 else {
279 if (gp_mem_b_get(Section->data, address, &byte, NULL, NULL)) {
280 printf("%0*x: %02x\n", addr_digits, gp_processor_insn_from_byte_c(class, address), byte);
281 }
282
283 break;
284 }
285 }
286 else {
287 /* STYP_DATA or STYP_ACTREC, or EEPROM8 */
288 if (!gp_mem_b_get(Section->data, address, &byte, NULL, NULL)) {
289 break;
290 }
291
292 printf("%0*x: %02x\n", addr_digits, address, byte);
293 ++address;
294 }
295 }
296
297 printf("\n");
298 }
299
300 /*------------------------------------------------------------------------------------------------*/
301
302 static void
_print_section_header(proc_class_t Class,const gp_section_t * Section)303 _print_section_header(proc_class_t Class, const gp_section_t *Section)
304 {
305 unsigned int org_to_byte_shift;
306
307 org_to_byte_shift = (Section->flags & STYP_ROM_AREA) ? Class->org_to_byte_shift : 0;
308
309 printf("Section Header\n");
310 printf("Name %s\n", Section->name);
311 printf("Physical address %#x\n", gp_insn_from_byte(org_to_byte_shift, Section->address));
312 printf("Virtual address %#x\n", gp_insn_from_byte(org_to_byte_shift, Section->virtual_address));
313 printf("Size of Section %u\n", Section->size);
314 printf("Number of Relocations %zu\n", Section->relocation_list.num_nodes);
315 printf("Number of Line Numbers %zu\n", Section->line_number_list.num_nodes);
316 printf("Flags %#x\n", Section->flags);
317
318 if (Section->flags & STYP_TEXT) {
319 printf(" Executable code.\n");
320 }
321
322 if (Section->flags & STYP_DATA) {
323 printf(" Initialized data.\n");
324 }
325
326 if (Section->flags & STYP_BSS) {
327 printf(" Uninitialized data.\n");
328 }
329
330 if (Section->flags & STYP_DATA_ROM) {
331 printf(" Initialized data for ROM.\n");
332 }
333
334 if (Section->flags & STYP_ABS) {
335 printf(" Absolute.\n");
336 }
337
338 if (Section->flags & STYP_SHARED) {
339 printf(" Shared across banks.\n");
340 }
341
342 if (Section->flags & STYP_OVERLAY) {
343 printf(" Overlaid with other sections from different objects modules.\n");
344 }
345
346 if (Section->flags & STYP_ACCESS) {
347 printf(" Available using access bit.\n");
348 }
349
350 if (Section->flags & STYP_ACTREC) {
351 printf(" Contains the activation record for a function.\n");
352 }
353
354 printf("\n");
355 }
356
357 /*------------------------------------------------------------------------------------------------*/
358
359 static void
_print_section_list(const gp_object_t * Object)360 _print_section_list(const gp_object_t *Object)
361 {
362 proc_class_t class;
363 const gp_section_t *section;
364 char column_gap[16];
365 unsigned int i;
366
367 class = Object->class;
368 i = class->addr_digits;
369
370 if (i > 6) {
371 i = 6;
372 }
373
374 i = 6 - i;
375
376 if (i >= (sizeof(column_gap) - 1)) {
377 i = (sizeof(column_gap) - 1);
378 }
379
380 if (i > 0) {
381 memset(column_gap, ' ', i);
382 }
383
384 column_gap[i] = '\0';
385
386 section = Object->section_list.first;
387 while (section != NULL) {
388 _print_section_header(class, section);
389
390 if ((section->size > 0) && (section->data_ptr > 0)) {
391 _print_data(Object->processor, section);
392 }
393
394 if (section->relocation_list.num_nodes > 0) {
395 _print_relocation_list(class, section->relocation_list.first, column_gap);
396 }
397
398 if (section->line_number_list.num_nodes > 0) {
399 _print_linenum_list(class, section->line_number_list.first, column_gap);
400 }
401
402 section = section->next;
403 }
404 }
405
406 /*------------------------------------------------------------------------------------------------*/
407
408 static void
_coff_type(unsigned int Type,char * Buffer,size_t Sizeof_buffer)409 _coff_type(unsigned int Type, char *Buffer, size_t Sizeof_buffer)
410 {
411 const char *str;
412
413 switch (Type) {
414 case T_NULL: str = "NULL"; break; /* null */
415 case T_VOID: str = "void"; break; /* void */
416 case T_CHAR: str = "char"; break; /* character */
417 case T_SHORT: str = "short"; break; /* short integer */
418 case T_INT: str = "int"; break; /* integer */
419 case T_LONG: str = "long int"; break; /* long integer */
420 case T_FLOAT: str = "float"; break; /* floating point */
421 case T_DOUBLE: str = "double"; break; /* double length floating point */
422 case T_STRUCT: str = "struct"; break; /* structure */
423 case T_UNION: str = "union"; break; /* union */
424 case T_ENUM: str = "enum"; break; /* enumeration */
425 case T_MOE: str = "enum member"; break; /* member of enumeration */
426 case T_UCHAR: str = "unsigned char"; break; /* unsigned character */
427 case T_USHORT: str = "unsigned short"; break; /* unsigned short */
428 case T_UINT: str = "unsigned int"; break; /* unsigned integer */
429 case T_ULONG: str = "unsigned long"; break; /* unsigned long */
430 case T_LNGDBL: str = "long double"; break; /* long double floating point */
431 case T_SLONG: str = "short long"; break; /* short long */
432 case T_USLONG: str = "unsigned short long"; break; /* unsigned short long */
433 default: str = NULL; break;
434 }
435
436 if (str != NULL) {
437 snprintf(Buffer, Sizeof_buffer, "%s", str);
438 }
439 else {
440 snprintf(Buffer, Sizeof_buffer, "unknown(%u)", Type);
441 }
442 }
443
444 /*------------------------------------------------------------------------------------------------*/
445
446 static const char *
_format_sym_type(unsigned int Type,char * Buffer,size_t Sizeof_buffer)447 _format_sym_type(unsigned int Type, char *Buffer, size_t Sizeof_buffer)
448 {
449 const char *str;
450
451 str = gp_coffgen_symbol_type_to_str(Type);
452 if (str != NULL) {
453 return str;
454 }
455
456 snprintf(Buffer, Sizeof_buffer, "%u", Type);
457 return Buffer;
458 }
459
460 /*------------------------------------------------------------------------------------------------*/
461
462 static const char *
_format_sym_derived_type(unsigned int Type,char * Buffer,size_t Sizeof_buffer)463 _format_sym_derived_type(unsigned int Type, char *Buffer, size_t Sizeof_buffer)
464 {
465 const char *str;
466
467 str = gp_coffgen_symbol_derived_type_to_str(Type);
468 if (str != NULL) {
469 return str;
470 }
471
472 snprintf(Buffer, Sizeof_buffer, "%u", Type);
473 return Buffer;
474 }
475
476 /*------------------------------------------------------------------------------------------------*/
477
478 static const char *
_format_sym_class(unsigned int Class,char * Buffer,size_t Sizeof_buffer)479 _format_sym_class(unsigned int Class, char *Buffer, size_t Sizeof_buffer)
480 {
481 const char *str;
482
483 str = gp_coffgen_symbol_class_to_str(Class);
484 if (str != NULL) {
485 return str;
486 }
487
488 snprintf(Buffer, Sizeof_buffer, "%u", Class);
489 return Buffer;
490 }
491
492 /*------------------------------------------------------------------------------------------------*/
493
494 #define AUX_INDENT " "
495
496 static void
_print_symbol_table(const gp_object_t * Object)497 _print_symbol_table(const gp_object_t *Object)
498 {
499 static char buf[64];
500
501 gp_symbol_t *symbol;
502 gp_symbol_t *callee;
503 gp_aux_t *aux;
504 const char *section;
505 int c;
506 size_t i;
507 unsigned int idx;
508 char buffer_type[8];
509 char buffer_derived_type[8];
510 char buffer_class[8];
511
512 printf("Symbol Table\n");
513 printf("Idx Name Section Value Type DT Class NumAux\n");
514
515 idx = 1;
516 symbol = Object->symbol_list.first;
517 while (symbol != NULL) {
518 if (symbol->section_number == N_DEBUG) {
519 section = "DEBUG";
520 }
521 else if (symbol->section_number == N_ABS) {
522 section = "ABSOLUTE";
523 }
524 else if (symbol->section_number == N_UNDEF) {
525 section = "UNDEFINED";
526 }
527 else {
528 if (symbol->section != NULL) {
529 section = symbol->section->name;
530 }
531 else {
532 snprintf(buf, sizeof(buf), "Bad num.: %u", symbol->section_number);
533 section = buf;
534 }
535 }
536
537 printf("%04u %-24s %-16s 0x%08lx %-8s %-12s %-9s %zu\n",
538 idx,
539 symbol->name,
540 section,
541 symbol->value,
542 _format_sym_type(symbol->type, buffer_type, sizeof(buffer_type)),
543 _format_sym_derived_type(symbol->derived_type, buffer_derived_type, sizeof(buffer_derived_type)),
544 _format_sym_class(symbol->class, buffer_class, sizeof(buffer_class)),
545 symbol->aux_list.num_nodes);
546
547 aux = symbol->aux_list.first;
548 while (aux != NULL) {
549 switch (aux->type) {
550 case AUX_DIRECT:
551 printf(AUX_INDENT "command = '%c'\n", aux->_aux_symbol._aux_direct.command);
552 printf(AUX_INDENT "string = \"%s\"\n", aux->_aux_symbol._aux_direct.string);
553 break;
554
555 case AUX_FILE: {
556 if (!state.suppress_names) {
557 printf(AUX_INDENT "file = %s\n", aux->_aux_symbol._aux_file.filename);
558 }
559 printf(AUX_INDENT "line included = %u\n", aux->_aux_symbol._aux_file.line_number);
560 printf(AUX_INDENT "flags = 0x%08x\n", aux->_aux_symbol._aux_file.flags);
561 break;
562 }
563
564 case AUX_IDENT:
565 printf(AUX_INDENT "string = \"%s\"\n", aux->_aux_symbol._aux_ident.string);
566 break;
567
568 case AUX_SECTION:
569 printf(AUX_INDENT "length = %u\n", aux->_aux_symbol._aux_scn.length);
570 printf(AUX_INDENT "number of relocations = %u\n", aux->_aux_symbol._aux_scn.nreloc);
571 printf(AUX_INDENT "number of line numbers = %u\n", aux->_aux_symbol._aux_scn.nlineno);
572 break;
573
574 case AUX_FCN_CALLS: {
575 callee = aux->_aux_symbol._aux_fcn_calls.callee;
576 printf(AUX_INDENT "callee = %s\n", (callee != NULL) ? callee->name : "higher order");
577 printf(AUX_INDENT "is_interrupt = %u\n", aux->_aux_symbol._aux_fcn_calls.is_interrupt);
578 break;
579 }
580
581 default: {
582 printf("%u ", aux->type);
583 for (i = 0; i < Object->symbol_size; i++) {
584 printf("%02x", aux->_aux_symbol.data[i] & 0xFF);
585
586 if (i & 1) {
587 putchar(' ');
588 }
589 }
590 for (i = 0; i < Object->symbol_size; i++) {
591 c = aux->_aux_symbol.data[i] & 0xFF;
592 putchar((isprint(c)) ? c : '.');
593 }
594 putchar('\n');
595 }
596 } /* switch (aux->type) */
597
598 aux = aux->next;
599 ++idx;
600 }
601
602 symbol = symbol->next;
603 ++idx;
604 }
605
606 putchar('\n');
607 }
608
609 /*------------------------------------------------------------------------------------------------*/
610
611 static void
_export_symbol_table(gp_object_t * Object)612 _export_symbol_table(gp_object_t *Object)
613 {
614 gp_symbol_t *symbol;
615 char buffer[BUFSIZ];
616
617 symbol = Object->symbol_list.first;
618 while (symbol != NULL) {
619 if ((state.export.enabled) && (symbol->class == C_EXT) && (symbol->section_number > N_UNDEF)) {
620 _coff_type(symbol->type, buffer, sizeof(buffer));
621 fprintf(state.export.f, " extern %s ; %s\n", symbol->name, buffer);
622 }
623
624 symbol = symbol->next;
625 }
626 }
627
628 /*------------------------------------------------------------------------------------------------*/
629
630 #define BIN_DATA_LINE_SIZE 16
631
632 static void
_print_binary(const uint8_t * Data,long File_size)633 _print_binary(const uint8_t *Data, long File_size)
634 {
635 long i;
636 long j;
637 unsigned int memory;
638 int c;
639
640 printf("\nObject file size = %li bytes\n", File_size);
641
642 printf("\nBinary object file contents:");
643 for (i = 0; i < File_size; i += BIN_DATA_LINE_SIZE) {
644 printf("\n%06lx", i);
645
646 for (j = 0; j < BIN_DATA_LINE_SIZE; j += 2) {
647 memory = (Data[i + j] << 8) | Data[i + j + 1];
648
649 if ((i + j) >= File_size) {
650 printf(" ");
651 }
652 else {
653 printf(" %04x", memory);
654 }
655 }
656
657 putchar(' ');
658
659 for (j = 0; j < BIN_DATA_LINE_SIZE; j += 2) {
660 if ((i + j) < File_size) {
661 c = Data[i + j];
662 putchar((isprint(c)) ? c : '.');
663
664 c = Data[i + j + 1];
665 putchar((isprint(c)) ? c : '.');
666 }
667 }
668 }
669
670 printf("\n\n");
671 }
672
673 /*------------------------------------------------------------------------------------------------*/
674
main(int argc,char * argv[])675 int main(int argc, char *argv[])
676 {
677 int option_index;
678 int c;
679 const char *command;
680 gp_boolean strict_options = false;
681 gp_boolean usage = false;
682 char buffer[BUFSIZ];
683
684 gp_init();
685
686 /* initalize */
687 state.dump_flags = 0;
688 state.suppress_names = false;
689 state.export.enabled = false;
690
691 /* Scan through the options for the --strict-options flag. */
692 while ((c = getopt_long(argc, argv, GET_OPTIONS, longopts, NULL)) != EOF) {
693 if (c == OPT_STRICT_OPTIONS) {
694 strict_options = true;
695 break;
696 }
697 }
698
699 /* Restores the getopt_long index. */
700 optind = 1;
701 while (true) {
702 /* This is necessary for the gp_exit_is_excluded_arg() function. */
703 option_index = -1;
704 command = argv[optind];
705 if ((c = getopt_long(argc, argv, GET_OPTIONS, longopts, &option_index)) == EOF) {
706 break;
707 }
708
709 if (strict_options) {
710 gp_exit_if_arg_an_option(longopts, ARRAY_SIZE(longopts), option_index, optarg, c, command);
711 }
712
713 switch (c) {
714 case '?':
715 case 'h':
716 usage = true;
717 break;
718
719 case 'b':
720 state.dump_flags |= PRINT_BINARY;
721 break;
722
723 case 'c':
724 gp_decode_mnemonics = true;
725 break;
726
727 case 'f':
728 state.dump_flags |= PRINT_HEADER;
729 break;
730
731 case 'n':
732 state.suppress_names = true;
733 break;
734
735 case 's':
736 state.dump_flags |= PRINT_SECTIONS;
737 break;
738
739 case 't':
740 state.dump_flags |= PRINT_SYMTBL;
741 break;
742
743 case 'y':
744 gp_decode_extended = true;
745 break;
746
747 case 'x':
748 state.export.enabled = true;
749 state.export.filename = optarg;
750 break;
751
752 case 'v':
753 fprintf(stderr, "%s\n", GPVO_VERSION_STRING);
754 exit(0);
755
756 case OPT_STRICT_OPTIONS:
757 /* do nothing */
758 break;
759 } /* switch (c) */
760
761 if (usage)
762 break;
763 }
764
765 if ((optind + 1) == argc) {
766 state.filename = argv[optind];
767 }
768 else {
769 usage = true;
770 }
771
772 if (usage) {
773 _show_usage();
774 }
775
776 if (!state.dump_flags) {
777 /* no command line flags were set so print everything */
778 state.dump_flags = PRINT_HEADER | PRINT_SECTIONS | PRINT_SYMTBL;
779 }
780
781 if ((gp_identify_coff_file(state.filename) != GP_COFF_OBJECT_V2) &&
782 (gp_identify_coff_file(state.filename) != GP_COFF_OBJECT)) {
783 gp_error("The \"%s\" is not a valid object file.", state.filename);
784 exit(1);
785 }
786
787 state.object = gp_read_coff(state.filename);
788 state.file = gp_read_file(state.filename);
789
790 if (state.export.enabled) {
791 state.export.f = fopen(state.export.filename, "w");
792
793 if (state.export.f == NULL) {
794 perror(state.export.filename);
795 exit(1);
796 }
797
798 gp_date_string(buffer, sizeof(buffer));
799
800 fprintf(state.export.f, "; %s\n", state.export.filename);
801 fprintf(state.export.f, "; generated by %s on %s\n", GPVO_VERSION_STRING, buffer);
802 fprintf(state.export.f, "; from %s\n\n", state.filename);
803
804 _export_symbol_table(state.object);
805
806 fclose(state.export.f);
807
808 /* suppress normal output */
809 state.dump_flags = 0;
810 }
811
812 if (state.dump_flags & PRINT_HEADER) {
813 _print_header(state.object);
814 }
815
816 if (state.dump_flags & PRINT_SECTIONS) {
817 _print_section_list(state.object);
818 }
819
820 if (state.dump_flags & PRINT_SYMTBL) {
821 _print_symbol_table(state.object);
822 }
823
824 if (state.dump_flags & PRINT_BINARY) {
825 _print_binary(state.file->file, state.file->size);
826 }
827
828 return EXIT_SUCCESS;
829 }
830