/*********************************************************************** * toolchain/nxflat/readnxflat.c * * Copyright (C) 2009 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Modified from readxflat (see http://xflat.org): * * Copyright (c) 2002, 2006, Cadenux, LLC. All rights reserved. * Copyright (c) 2002, 2006, Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***********************************************************************/ /*********************************************************************** * Compilation Flags ***********************************************************************/ #define SWAP_BYTES 1 /*********************************************************************** * Included Files ***********************************************************************/ #include #include #include #include #include #include #include /* ntohl and friends */ #include "nxflat.h" /*********************************************************************** * Compilation Switches ***********************************************************************/ /* #define RELOCS_IN_NETWORK_ORDER */ /*********************************************************************** * Definitions ***********************************************************************/ #define NXFLAT_HDR_SIZE sizeof(struct nxflat_hdr_s) /*********************************************************************** * Private Data ***********************************************************************/ static const char *program_name; static const char *nxflat_filename; static int dump_header = 0; static int dump_relocs = 0; static int dump_imports = 0; static int dump_text = 0; static int dump_data = 0; static int verbose = 0; static int num_errors = 0; #ifdef ARCH_BIG_ENDIAN static int big_endian = 1; /* Assume big-endian */ #else static int big_endian = 0; /* Assume little-endian */ #endif /*********************************************************************** * Private Constant Data ***********************************************************************/ static const char unknown[] = "UNKNOWN"; static const char hdr_reloc_rel32i[] = "RELOC_REL32I"; static const char hdr_reloc_rel32d[] = "RELOC_REL32D"; #ifdef NXFLAT_RELOC_TYPE_REL32ID static const char hdr_reloc_rel32id[] = "RELOC_REL32ID"; #endif static const char *reloc_type_string[] = { hdr_reloc_rel32i, hdr_reloc_rel32d, #ifdef NXFLAT_RELOC_TYPE_REL32ID hdr_reloc_rel32id, #else unknown, #endif unknown }; /*********************************************************************** * Public Function Prototypes ***********************************************************************/ extern void __attribute__ ((weak)) print_insn_arm(u_int32_t pc, FILE * stream, u_int32_t given); /*********************************************************************** * Private Functions ***********************************************************************/ /*********************************************************************** * swap32 ***********************************************************************/ static inline u_int32_t nxflat_swap32(u_int32_t little) { u_int32_t big = ((little >> 24) & 0xff) | (((little >> 16) & 0xff) << 8) | (((little >> 8) & 0xff) << 16) | ((little & 0xff) << 24); return big; } /*********************************************************************** * get_nxflat32 ***********************************************************************/ static inline u_int32_t get_nxflat32(u_int32_t * addr32) { return ntohl(*addr32); } /*********************************************************************** * get_nxflat16 ***********************************************************************/ static inline u_int16_t get_nxflat16(u_int16_t * addr16) { return ntohs(*addr16); } /*********************************************************************** * dump_hex_data ***********************************************************************/ static void dump_hex_data(FILE * in_stream, struct nxflat_hdr_s *header) { u_int32_t data_start = get_nxflat32(&header->h_datastart); u_int32_t data_end = get_nxflat32(&header->h_dataend); int32_t words_left = (data_end - data_start) / sizeof(u_int32_t); u_int32_t addr; u_int32_t buffer[64]; printf("\nXFLAT DATA SEGMENT:\n\n"); /* Seek to the beginning of data in the file */ if (fseek(in_stream, data_start, SEEK_SET) != 0) { fprintf(stderr, "ERROR: Failed to seek to data in file: offset: %08x\n", data_start); return; } /* Now dump all of the data reading 64 words at a time */ addr = 0; while (words_left > 0) { size_t nread = fread(buffer, sizeof(u_int32_t), 64, in_stream); if (nread >= 0) { union { u_int32_t l[4]; unsigned char b[16]; } row; int32_t i, j, k; for (i = 0; i < nread; i += 4) { for (j = 0; j < 4; j++) { row.l[j] = buffer[i + j]; } printf("%08x: ", addr); for (j = 0; j < 4; j++) { printf("%08x ", row.l[j]); } printf(" "); for (j = 0; j < 4 * sizeof(u_int32_t); j += sizeof(u_int32_t)) { for (k = 0; k < sizeof(u_int32_t); k++) { if (isprint(row.b[j + k])) putchar(row.b[j + k]); else putchar('.'); } } putchar('\n'); addr += 4 * sizeof(u_int32_t); } words_left -= nread; } else break; } putchar('\n'); } /*********************************************************************** * disassemble_text ***********************************************************************/ static void disassemble_text(FILE * in_stream, struct nxflat_hdr_s *header) { if (print_insn_arm) { u_int32_t text_start = NXFLAT_HDR_SIZE; u_int32_t text_end = get_nxflat32(&header->h_datastart); int32_t insns_left = (text_end - text_start) / sizeof(u_int32_t); u_int32_t addr; u_int32_t buffer[64]; printf("\nXFLAT TEXT:\n\n"); /* Seek to the beginning of text in the file */ if (fseek(in_stream, text_start, SEEK_SET) != 0) { fprintf(stderr, "ERROR: Failed to seek to text in file: offset: %08x\n", text_start); return; } /* Now dump all of the data reading 64 insns at a time */ addr = text_start; while (insns_left > 0) { size_t nread = fread(buffer, sizeof(u_int32_t), 64, in_stream); if (nread > 0) { int i; for (i = 0; i < nread; i++) { u_int32_t insn = buffer[i]; if (big_endian) { insn = nxflat_swap32(insn); } printf("%08x %08x\t", addr, insn); print_insn_arm(addr, stdout, insn); putchar('\n'); addr += sizeof(u_int32_t); } insns_left -= nread; } else break; putchar('\n'); } } } /*********************************************************************** * dump_imported_symbols ***********************************************************************/ static void dump_imported_symbols(FILE *in_stream, struct nxflat_hdr_s *header) { struct nxflat_import_s import; u_int32_t import_offset; u_int32_t data_start; u_int32_t struct_offset; u_int32_t name_offset; char imported_symbol_name[NXFLAT_MAX_STRING_SIZE]; int status; int i; printf("\nIMPORTED SYMBOLS:\n"); printf(" OFFSET ADDRESS SYMBOL NAME\n\n"); import_offset = get_nxflat32(&header->h_importsymbols); data_start = get_nxflat32(&header->h_datastart); for (i = 0; i < get_nxflat16(&header->h_importcount); i++) { /* Seek to the next imported symbol */ struct_offset = i * sizeof(struct nxflat_import_s) + import_offset; if (fseek(in_stream, struct_offset, SEEK_SET) != 0) { fprintf(stderr, "ERROR: fseek to imported symbol %d struct failed\n", i); fprintf(stderr, " struct_offset: %d: %s\n", struct_offset, strerror(errno)); exit(1); } /* Read the next import entry. */ status = fread((void *)&import, sizeof(struct nxflat_import_s), 1, in_stream); if (status != 1) { if (ferror(in_stream)) { fprintf(stderr, "ERROR: Read imported symbol %d struct failed: %s\n", i + 1, strerror(errno)); } else { fprintf(stderr, "ERROR: Read imported symbol %d struct: End-of-file after %d\n", i + 1, struct_offset); } exit(1); } if (big_endian) { import.i_funcname = nxflat_swap32(import.i_funcname); import.i_funcaddress = nxflat_swap32(import.i_funcaddress); } if (verbose) { /* Print the raw info */ printf("[Import: %4d Offset: %08x Name: %08x Address: %08x]\n", i + 1, struct_offset, import.i_funcname, import.i_funcaddress); } /* Seek to the function name in the file */ name_offset = import.i_funcname + NXFLAT_HDR_SIZE; if (fseek(in_stream, name_offset, SEEK_SET) != 0) { fprintf(stderr, "ERROR: fseek to imported symbol %d name failed\n", i); fprintf(stderr, " name_offset: %d %s\n", name_offset, strerror(errno)); exit(1); } /* Then, read the imported symbol name (assuming it is less than * NXFLAT_MAX_STRING_SIZE in length). */ status = fread((void *)imported_symbol_name, NXFLAT_MAX_STRING_SIZE, 1, in_stream); if (status != 1) { if (ferror(in_stream)) { fprintf(stderr, "ERROR: Read imported symbol %d name failed: %s\n", i + 1, strerror(errno)); } else { fprintf(stderr, "ERROR: Read imported symbol %d name: End-of-file after offset=%d\n", i + 1, name_offset); } exit(1); } imported_symbol_name[NXFLAT_MAX_STRING_SIZE - 1] = '\0'; /* And print it */ printf("%5d %08x ", i + 1, (int)struct_offset - data_start); if (import.i_funcaddress) { printf("%08x ", import.i_funcaddress); } else { printf("UNKNOWN "); } printf("%s\n", imported_symbol_name); } } /*********************************************************************** * dump_relocation_entries ***********************************************************************/ static void dump_relocation_entries(FILE * in_stream, struct nxflat_hdr_s *header) { struct nxflat_reloc_s reloc; int status; int i; /* Seek to the beginning of the relocation records. */ if (0 != fseek(in_stream, get_nxflat32(&header->h_relocstart), SEEK_SET)) { fprintf(stderr, "ERROR: fseek to reloc records failed: %s\n", strerror(errno)); exit(1); } printf("\nRELOCATION ENTRIES:\n"); printf(" OFFSET RELOC TYPE\n\n"); for (i = 0; i < get_nxflat16(&header->h_reloccount); i++) { /* Read the next reloction entry. */ status = fread((void *)&reloc, sizeof(struct nxflat_reloc_s), 1, in_stream); if (status != 1) { if (ferror(in_stream)) { fprintf(stderr, "ERROR: Read reloc record %d: %s\n", i + 1, strerror(errno)); } else { fprintf(stderr, "ERROR: Read reloc record %d: End-of-file\n", i + 1); } exit(1); } #ifdef RELOCS_IN_NETWORK_ORDER { u_int32_t *ptmp; ptmp = (u_int32_t *) & reloc; *ptmp = get_nxflat32(ptmp); } #endif if (NXFLAT_RELOC_TYPE(reloc.r_info) >= NXFLAT_RELOC_TYPE_NUM) { printf("%5d %08x UNKNOWN(%d)\n", i + 1, NXFLAT_RELOC_OFFSET(reloc.r_info), NXFLAT_RELOC_TYPE(reloc.r_info)); fprintf(stderr, "Error eloc type out of range(%d)\n", NXFLAT_RELOC_TYPE(reloc.r_info)); num_errors++; } else { printf("%5d %08x %-13s\n", i + 1, NXFLAT_RELOC_OFFSET(reloc.r_info), reloc_type_string[NXFLAT_RELOC_TYPE(reloc.r_info)]); } } } /*********************************************************************** * dump_hdr ***********************************************************************/ static void dump_hdr(struct nxflat_hdr_s *header) { /* Print the contents of the FLT header */ printf("\nXFLAT HEADER:\n"); printf("\nMagic %c%c%c%c\n", header->h_magic[0], header->h_magic[1], header->h_magic[2], header->h_magic[3]); printf("\nMEMORY MAP:\n"); printf(" Text start %08lx\n", (long)NXFLAT_HDR_SIZE); printf(" Entry point %08x\n", get_nxflat32(&header->h_entry)); printf(" Data start %08x\n", get_nxflat32(&header->h_datastart)); printf(" Data end %08x\n", get_nxflat32(&header->h_dataend) - 1); printf(" Bss start %08x\n", get_nxflat32(&header->h_dataend)); printf(" Bss end %08x\n", get_nxflat32(&header->h_bssend) - 1); printf("TOTAL SIZE %08x\n\n", get_nxflat32(&header->h_bssend)); printf("Stack size %08x\n", get_nxflat32(&header->h_stacksize)); printf("\nRELOCATIONS:\n"); printf(" Reloc start %08x\n", get_nxflat32(&header->h_relocstart)); printf(" reloc count %d\n", get_nxflat16(&header->h_reloccount)); printf("\nIMPORTED SYMBOLS:\n"); printf(" Import start %08x\n", get_nxflat32(&header->h_importsymbols)); printf(" Import count %d\n", get_nxflat16(&header->h_importcount)); } /*********************************************************************** * show_usage ***********************************************************************/ static void show_usage(void) { fprintf(stderr, "Usage: %s [options] \n\n", program_name); #if 1 fprintf(stderr, "Where options are one or more of the following:\n\n"); #else fprintf(stderr, "Where options are one or more of the following. Note\n"); fprintf(stderr, "that a space is always required between the option and\n"); fprintf(stderr, "any following arguments\n\n"); #endif fprintf(stderr, " -h Dump the XFLAT file header [not dumped]\n"); fprintf(stderr, " -r Dump relocation entries [not dumped]\n"); fprintf(stderr, " -i Dump the imported symbol table [not dumped]\n"); fprintf(stderr, " -x Dump xFLT loader pathname [not dumped]\n"); fprintf(stderr, " -c Disassemble the text section [not dumped]\n"); fprintf(stderr, " -d Dump data section (hex) [not dumped]\n"); fprintf(stderr, " -a Dump all of the above [not dumped]\n"); #ifdef ARCH_BIG_ENDIAN fprintf(stderr, " -b Assume little-endian byteorder [big endian]\n"); #else fprintf(stderr, " -b Assume big-endian byteorder [little endian]\n"); #endif fprintf(stderr, " -v Output verbose debug info [no output]\n"); fprintf(stderr, "\n"); exit(1); } /*********************************************************************** * parse_args ***********************************************************************/ static void parse_args(int argc, char **argv) { int opt; /* Save our name (for show_usage) */ program_name = argv[0]; /* At least three things must appear on the program line: the program name, * the BFD filname, and at least one option. */ if (argc < 3) { fprintf(stderr, "ERROR: Missing required arguments\n\n"); show_usage(); } /* Get miscellaneous options from the command line. */ while ((opt = getopt(argc, argv, "hrieLlxcbdav")) != -1) { switch (opt) { case 'h': /* Dump the flat file header */ dump_header++; break; case 'r': /* Dump the flat file header */ dump_relocs++; break; case 'i': /* Dump the imported symbol table */ dump_imports++; break; case 'c': /* Disassembly text */ if (print_insn_arm) { dump_text++; } else { printf("-c ignored: No disassembler available\n"); } break; case 'b': /* other-endian */ #ifdef ARCH_BIG_ENDIAN big_endian = 0; #else big_endian++; #endif break; case 'd': /* Dump data */ dump_data++; break; case 'a': /* Dump everying */ dump_header++; dump_relocs++; dump_imports++; dump_text++; dump_data++; break; case 'v': /* Output verbose debug information */ verbose++; break; default: fprintf(stderr, "%s Unknown option\n\n", argv[0]); show_usage(); break; } } /* Get the name of the input BFD file. */ nxflat_filename = argv[argc - 1]; } /*********************************************************************** * Public Functions ***********************************************************************/ /*********************************************************************** * main ***********************************************************************/ int main(int argc, char **argv, char **envp) { FILE *in_stream; struct nxflat_hdr_s header; int status; /* Get the input parameters */ parse_args(argc, argv); /* Open the FLT file */ in_stream = fopen(nxflat_filename, "rb"); if (NULL == in_stream) { fprintf(stderr, "Cannot open file %s for reading\n", nxflat_filename); exit(1); } /* Read the FLT header */ status = fread((void *)&header, sizeof(struct nxflat_hdr_s), 1, in_stream); if (status != 1) { if (ferror(in_stream)) { fprintf(stderr, "ERROR: Read flat header: %s\n", strerror(errno)); } else { fprintf(stderr, "ERROR: Read flat header: End-of-file\n"); } exit(1); } printf("Dumping Flat Binary File: %s\n", nxflat_filename); /* Dump the contents of the FLT header */ if (dump_header) { dump_hdr(&header); } /* Dump the relocation entries */ if (dump_relocs) { dump_relocation_entries(in_stream, &header); } /* Dump all imported symbols */ if (dump_imports) { dump_imported_symbols(in_stream, &header); } if (dump_text) { disassemble_text(in_stream, &header); } if (dump_data) { dump_hex_data(in_stream, &header); } fclose(in_stream); if (num_errors > 0) { fprintf(stderr, "Finished with %d errors\n", num_errors); } return 0; }