dspcoreparse: Add files into here as seperate repository
[sdk-tools/dspcoreparse.git] / dspcoreparse.c
1 /* --COPYRIGHT--,BSD
2  * Copyright (c) 2010-2011, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  * --/COPYRIGHT--*/
33 /*
34  * DSP coredump parsing utility.
35  * This utility parses DSP coredump file genereted in ELF format.
36  * This can be used to generete CCS lodable crashdump file from
37  * from the ELF coredump file.
38  * (http://processors.wiki.ti.com/index.php/Crash_Dump_Analysis)
39  * This utility also can be used to get the coredump information.
40  */
43 #include <stdio.h>
44 #include <errno.h>
45 #include <stdint.h>
46 #include <stdlib.h>
47 #include <getopt.h>
48 #include <limits.h>
49 #include "elf32.h"
51 #define VERSION "1.0.0.1"
52 #define SYSBIOS_VERSION "06320554"
54 #define VER_STRING VERSION":"SYSBIOS_VERSION
56 #ifndef EM_TI_C6000
57 #define EM_TI_C6000     140
58 #endif
60 #define perr(...) fprintf(stderr, __VA_ARGS__)
61 #define pinfo(...) fprintf(stdout, __VA_ARGS__)
63 #define check_limit(l) \
64         do {if (--(l) < 0) return 0;} while(0)
66 /* From: http://processors.wiki.ti.com/index.php/Crash_Dump_Analysis */
67 #define CCS_CRASHDUMP_ID (521177)
68 #define CCS_CRASHDUMP_PROC_TYPE_C64XX (0x64)
69 #define CCS_CRASHDUMP_PROC_TYPE_C66XX (0x66)
70 #define CCS_CRASHDUMP_REG_ID "R"
71 #define CCS_CRASHDUMP_MEM_ID "M"
72 #define CCS_CRASHDUMP_MEM_PAGE_NONE (0)
73 #define CCS_CRASHDUMP_REG_FMT "0x0000000B"
75 /* Forward declaration */
76 char *reg_name_map[];
78 struct args {
79         int verbose;
80         long lines;
81         char *infile;
82         char *outfile;
83 };
85 static void usage(FILE * s)
86 {
87         fprintf(s, "Usage: dspcoreparse [option(s)] <coredump file name>\n"
88                 "    --version  Print version information\n"
89                 " -h --help     Display this information\n"
90                 " -v --verbose  Print header information\n"
91                 " -l <lines>    Max number of lines in output file\n"
92                 " -o <file>     Place the ccs format coredump into <file>\n");
93 }
95 static int  parse_args(int argc, char ** argv, struct args *args)
96 {
97         char c;
98         struct option long_opt[] = {
99                 {"help", no_argument, 0, 'h'},
100                 {"verbose", no_argument, 0, 'v'},
101                 {"version", no_argument, 0, 's'},
102                 {0, 0, 0, 0}
103         };
104         int exit = 0;
106         if (argc < 2) {
107                 usage(stderr);
108                 return 1;
109         }
111         args->lines = LONG_MAX; /* Unlimited */
113         while ((c = getopt_long(argc, argv, ":hvsl:o:", long_opt, 0)) != EOF) {
115                 switch(c) {
116                 case 0:
117                         break;
118                 case 'v':
119                         args->verbose = 1;
120                         break;
121                 case 'o':
122                         args->outfile = optarg;
123                         break;
124                 case 'l':
125                         args->lines = atol(optarg);
126                         break;
127                 case ':':
128                         perr("Option -%c requires a parameter\n", optopt);
129                         usage(stderr);
130                         return 1;
131                 case 'h':
132                         usage(stdout);
133                         return 1;
134                 case 's':
135                         pinfo("DSP coredump parsing utility version: %s\n",
136                               VER_STRING);
137                         return 1;
138                 case '?':
139                 default:
140                         perr("Invalid option '-%c'\n", optopt);
141                         usage(stderr);
142                         return 1;
143                 }
144         }
146         if (argc <= optind) {
147                 perr("Input coredump filename not present\n");
148                 usage(stderr);
149                 return 1;
150         }
151         args->infile = argv[optind];
153         return 0;
156 int parse_elf32_header(FILE *fi, struct Elf32_Ehdr *eh)
158         int n;
160         n = fread(eh, 1, sizeof(struct Elf32_Ehdr), fi);
161         if (n != sizeof(*eh)) {
162                 perr("error in reading ELF header (%d)\n", n);
163                 return -1;
164         }
166         if ((eh->e_ident[EI_MAG0] != ELFMAG0) ||
167                 (eh->e_ident[EI_MAG1] != ELFMAG1) ||
168                 (eh->e_ident[EI_MAG2] != ELFMAG2) ||
169                 (eh->e_ident[EI_MAG3] != ELFMAG3)) {
170                 perr("Invalid ELF file, incorrect elf magic\n");
171                 return -1;
172         }
174         /* Support only 32 bit format */
175         if (eh->e_ident[EI_CLASS] != ELFCLASS32) {
176                 perr("Invalid ELF file, incorrect ident:EI_CLASS (%d)\n",
177                      eh->e_ident[EI_CLASS]);
178                 return -1;
179         }
181         /* Support only 2's complement, little endian */
182         if (eh->e_ident[EI_DATA] != ELFDATA2LSB) {
183                 perr("Invalid ELF file, incorrect ident:EI_DATA (%d)\n",
184                      eh->e_ident[EI_DATA]);
185                 return -1;
186         }
188         /* Currently limit to coredump file only */
189         if (eh->e_type != ET_CORE) {
190                 perr("Invalid ELF file, incorrect e_type (%d)\n", eh->e_type);
191                 return -1;
192         }
194         /* Only support C6000 family */
195         if (eh->e_machine != EM_TI_C6000) {
196                 perr("Invalid ELF file, incorrect e_machine (%d)\n",
197                      eh->e_machine);
198                 return -1;
199         }
201         /* Now check for valid program section informations */
202         if (!eh->e_phoff || !eh->e_phnum || !eh->e_phentsize) {
203                 perr("Invalid ELF file, invalid e_phoff|e_phnum|e_phentsize\n");
204                 return -1;
205         }
207         return 0;
210 void print_elf32_header(struct Elf32_Ehdr *eh)
212         pinfo("\nELF Header:\n");
213         pinfo("Identifier\t0x%02x %c%c%c\n",
214               eh->e_ident[EI_MAG0], eh->e_ident[EI_MAG1],
215               eh->e_ident[EI_MAG2], eh->e_ident[EI_MAG3]);
216         pinfo("Class\t\t%d\n", eh->e_ident[EI_CLASS]);
217         pinfo("Data\t\t%d\n", eh->e_ident[EI_DATA]);
218         pinfo("Version\t\t%d\n", eh->e_ident[EI_VERSION]);
219         pinfo("Type\t\t%d\n", eh->e_type);
220         pinfo("Machine\t\t%d\n", eh->e_machine);
221         pinfo("phoff\t\t%d\n", eh->e_phoff);
222         pinfo("phnum\t\t%d\n", eh->e_phnum);
223         pinfo("phentsize\t%d\n", eh->e_phentsize);
226 int parse_phdr(FILE *fi, struct Elf32_Ehdr *eh, struct Elf32_Phdr *ph)
228         int i;
229         int n;
231         for (i = 0; i < eh->e_phnum; i++) {
232                 fseek(fi, eh->e_phoff + (i * eh->e_phentsize), SEEK_SET);
233                 n = fread(&ph[i], 1, sizeof(struct Elf32_Phdr), fi);
234                 if (n < sizeof(struct Elf32_Phdr)) {
235                         perr("Invalid phdr[%d] read (%d)\n", i, n);
236                         return -1;
237                 }
238         }
239         return 0;
242 void print_phdr(struct Elf32_Ehdr *eh, struct Elf32_Phdr *ph)
244         int i;
246         pinfo("\nProgram Header:\n");
248         pinfo("type\toffset\t\tpaddr\t\tfilesz\t\tmemsz\t\tflags\talign\n");
250         for (i = 0; i < eh->e_phnum; i++) {
251                 pinfo("%d\t0x%08x\t0x%08x\t0x%08x\t0x%08x\t0x%x\t0x%x\n",
252                       ph[i].p_type, ph[i].p_offset, ph[i].p_paddr,
253                       ph[i].p_filesz, ph[i].p_memsz, ph[i].p_flags,
254                       ph[i].p_align);
255         }
258 int write_notes_section(FILE *fi, FILE *fo, long *l, struct Elf32_Phdr *ph)
260         struct Elf32_Nhdr nh;
261         int reg_offset;
262         uint32_t reg_val;
263         int offset;
264         int i;
265         int n;
267         fseek(fi, ph->p_offset, SEEK_SET);
268         n = fread(&nh, 1, sizeof(struct Elf32_Nhdr), fi);
269         if (n < sizeof(struct Elf32_Nhdr)) {
270                 perr("Can not read notes header (%d)\n", n);
271                 return -1;
272         }
274         if (!fo) {
275                 char *np;
276                 pinfo("namesz\t0x%x\n", nh.n_namesz);
277                 pinfo("descsz\t0x%x\n", nh.n_descsz);
278                 pinfo("type\t0x%x\n", nh.n_type);
279                 np = calloc(nh.n_namesz + 1, 1);
280                 n = fread(np, 1, nh.n_namesz, fi);
281                 if (n < nh.n_namesz) {
282                         perr("Can not read notes name (%d)\n", n);
283                         return -1;
284                 }
285                 pinfo("name\t%s\n", np);
286                 free (np);
287         }
289         offset = ph->p_offset + sizeof(struct Elf32_Nhdr);
290         offset += ((nh.n_namesz + 3) & ~0x03);
291         /* Jump to descriptor field */
292         fseek(fi, offset, SEEK_SET);
294         for (i = 0; i < (nh.n_descsz / 4); i++){
295                 if (reg_name_map[i] == 0)
296                         return 0;
298                 n = fread(&reg_val, 1, sizeof(uint32_t), fi);
299                 if (n < sizeof(uint32_t)) {
300                         perr("Error in reading notes register (%d)\n", n);
301                         return -1;
302                 }
304                 if (fo) {
305                         check_limit(*l);
306                         fprintf(fo, "%s %s %s 0x%08X\n",
307                                 CCS_CRASHDUMP_REG_ID, reg_name_map[i],
308                                 CCS_CRASHDUMP_REG_FMT, reg_val);
309                         continue;
310                 }
311                 pinfo("%s\t0x%08X", reg_name_map[i], reg_val);
312                 if ((i + 1) % 3 == 0)
313                         pinfo("\n");
314                 else
315                         pinfo("\t\t");
316         }
318         return 0;
321 void print_notes(FILE *fi, struct Elf32_Ehdr *eh, struct Elf32_Phdr *ph)
323         int i;
325         pinfo("\nNotes Section:\n");
327         /* Find notes section */
328         for (i = 0; i < eh->e_phnum; i++) {
329                 if (ph[i].p_type != PT_NOTE)
330                         continue;
331                 write_notes_section(fi, 0, 0, &ph[i]);
332                 return; /* Only support one note section */
333         }
336 int write_program_section(FILE *fi, FILE *fo, long *l, struct Elf32_Phdr *ph)
338         int i;
339         int c;
340         fseek(fi, ph->p_offset, SEEK_SET);
341         check_limit(*l);
342         fprintf(fo, "%s 0x%08x 0x%08x 0x%x\n",
343                 CCS_CRASHDUMP_MEM_ID, CCS_CRASHDUMP_MEM_PAGE_NONE,
344                 ph->p_paddr, ph->p_memsz);
346         for (i = 0; i < ph->p_filesz; i++) {
347                 c = fgetc(fi);
348                 if (c == EOF) {
349                         perr("Unexpected EOF reading program section\n");
350                         return -1;
351                 }
352                 check_limit(*l);
353                 fprintf(fo, "0x%02x\n", c);
354         }
356         if (ph->p_memsz <= ph->p_filesz)
357                 return 0;
359         /* Fill zero for the rest of the area */
360         c = 0;
361         for (i = 0; i < (ph->p_memsz - ph->p_filesz); i++) {
362                 check_limit(*l);
363                 fprintf(fo, "0x%02x\n", c);
364         }
365         return 0;
369 void write_ccs_coredump(FILE *fi, FILE *fo, long l, struct Elf32_Ehdr *eh,
370                                                 struct Elf32_Phdr *ph)
372         int i;
374         /* Write CCS coredump header */
375         if (--l < 0) return;
376         fprintf(fo, "%d %d\n", CCS_CRASHDUMP_ID, CCS_CRASHDUMP_PROC_TYPE_C66XX);
378         /* First write notes section */
379         for (i = 0; i < eh->e_phnum; i++) {
380                 if (ph[i].p_type != PT_NOTE)
381                         continue;
382                 if (write_notes_section(fi, fo, &l, &ph[i]))
383                         return;
384                 if (l < 1) return;
385         }
387         /* Write other program sections */
388         for (i = 0; i < eh->e_phnum; i++) {
389                 if (ph[i].p_type == PT_NOTE)
390                         continue;
391                 if (write_program_section(fi, fo, &l, &ph[i]))
392                         return;
393                 if (l < 1) return;
394         }
397 int main(int argc, char *argv[])
399         struct args args = {0};
400         FILE *fi = 0;
401         FILE *fo = 0;
402         struct Elf32_Ehdr eh;
403         struct Elf32_Phdr *ph = 0;
405         if (parse_args(argc, argv, &args) != 0)
406                 goto done;
408         fi = fopen(args.infile, "rb");
409         if (!fi) {
410                 perr("parsecoredump: can't open file %s (errno:%d)\n",
411                        args.infile, errno);
412                 goto done;
413         }
415         if (parse_elf32_header(fi, &eh))
416                 goto done;
418         if (args.verbose) {
419                 pinfo("DSP coredump parsing utility (version %s)\n",
420                       VER_STRING);
421                 print_elf32_header(&eh);
422         }
424         ph = calloc(sizeof(struct Elf32_Phdr), eh.e_phnum);
425         if (!ph) {
426                 perr("parsecoredump: can't allocate phdr array (errno:%d)\n",
427                        errno);
428                 goto done;
429         }
431         if (parse_phdr(fi, &eh, ph))
432                 goto done;
434         if (args.verbose) {
435                 print_phdr(&eh, ph);
436                 print_notes(fi, &eh, ph);
437                 pinfo("\n");
438         }
440         if (!args.outfile)
441                 goto done;
443         fo = fopen(args.outfile, "w");
444         if (!fo) {
445                 perr("parsecoredump: can't open out file %s (errno:%d)\n",
446                        args.outfile, errno);
447                 goto done;
448         }
450         write_ccs_coredump(fi, fo, args.lines, &eh, ph);
452 done:
453         if (fi)
454                 fclose(fi);
455         if (fo)
456                 fclose(fo);
457         if (ph)
458                 free(ph);
459         return 0;
462 /* Register map from
463  * bios_6_32_05_54\packages\ti\sysbios\family\c64p\Exception.h
464  *
465  * The order of elements should exactly match
466  * ti_sysbios_family_c64p_Exception_Status,
467  * ti_sysbios_family_c64p_Exception_Context and
468  * structures from Exception.h file.
469  * */
471 char *reg_name_map[] = {
473         "PC",
474         "EFR", /* start:ti_sysbios_family_c64p_Exception_Status */
475         "NRP",
476         "NTSR",
477         "IERR", /* end:ti_sysbios_family_c64p_Exception_Status */
479         "ILC", /* start:ti_sysbios_family_c64p_Exception_Context */
480         "RILC",
481         "AMR",
482         "SSR",
483         "IRP",
484         "NRP",
485         "ITSR",
486         "NTSR",
487         "EFR",
488         "IERR",
489         "B30",
490         "B31",
491         "B28",
492         "B29",
493         "B26",
494         "B27",
495         "B24",
496         "B25",
497         "B22",
498         "B23",
499         "B20",
500         "B21",
501         "B18",
502         "B19",
503         "B16",
504         "B17",
505         "B14",
506         "B15",
507         "B12",
508         "B13",
509         "B10",
510         "B11",
511         "B8",
512         "B9",
513         "B6",
514         "B7",
515         "B4",
516         "B5",
517         "B2",
518         "B3",
519         "B0",
520         "B1",
521         "A30",
522         "A31",
523         "A28",
524         "A29",
525         "A26",
526         "A27",
527         "A24",
528         "A25",
529         "A22",
530         "A23",
531         "A20",
532         "A21",
533         "A18",
534         "A19",
535         "A16",
536         "A17",
537         "A14",
538         "A15",
539         "A12",
540         "A13",
541         "A10",
542         "A11",
543         "A8",
544         "A9",
545         "A6",
546         "A7",
547         "A4",
548         "A5",
549         "A2",
550         "A3",
551         "A0",
552         "A1", /* end:ti_sysbios_family_c64p_Exception_Context */
554         0 /* end marker */
555 };