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;
154 }
156 int parse_elf32_header(FILE *fi, struct Elf32_Ehdr *eh)
157 {
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;
208 }
210 void print_elf32_header(struct Elf32_Ehdr *eh)
211 {
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);
224 }
226 int parse_phdr(FILE *fi, struct Elf32_Ehdr *eh, struct Elf32_Phdr *ph)
227 {
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;
240 }
242 void print_phdr(struct Elf32_Ehdr *eh, struct Elf32_Phdr *ph)
243 {
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 }
256 }
258 int write_notes_section(FILE *fi, FILE *fo, long *l, struct Elf32_Phdr *ph)
259 {
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(®_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;
319 }
321 void print_notes(FILE *fi, struct Elf32_Ehdr *eh, struct Elf32_Phdr *ph)
322 {
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 }
334 }
336 int write_program_section(FILE *fi, FILE *fo, long *l, struct Elf32_Phdr *ph)
337 {
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;
367 }
369 void write_ccs_coredump(FILE *fi, FILE *fo, long l, struct Elf32_Ehdr *eh,
370 struct Elf32_Phdr *ph)
371 {
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 }
395 }
397 int main(int argc, char *argv[])
398 {
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;
460 }
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 };