oops.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * ksymoops v2.0 -- A simple filter to resolve symbols in Linux Oops-logs
  3.  *
  4.  * Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com> (version 1.x)
  5.  * Copyright (C) 1996 Alessandro Rubini <rubini@ipvvis.unipc.it> (upgrades)
  6.  */
  7. /*
  8.  * New features:
  9.  *       strips syslog prefixes
  10.  *       decodes registers and stack
  11.  *       uses %esp to show pointers to local vars
  12.  *       uses symbols in modules from /proc/ksyms
  13.  */ 
  14. /* 
  15.  * Missing features:
  16.  *       check /proc/ksyms against the map for mismatches
  17.  */
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <ctype.h>
  23. #include <linux/module.h>
  24. #define MAX_NAME MOD_MAX_NAME /* quite big, indeed ... */
  25. struct ksym {
  26.   unsigned long address, extent;
  27.   struct ksym *next;
  28.   char name[MAX_NAME];
  29.   char id[MAX_NAME];
  30. };
  31. struct ksym *gsymlist; /* global symlist */
  32. /*----------------------------------------------------------------------*/
  33. /* read a text line into a symbol */
  34. struct  ksym *linesym(char *line)
  35. {
  36.     struct ksym *newsym=malloc(sizeof(struct ksym));
  37.     char s[MAX_NAME];
  38.     int i;
  39.     
  40.     i=sscanf(line,"%lx %s %s",&newsym->address,newsym->name,s);
  41.     switch(i) {
  42.       case 2:
  43.         newsym->id[0]=''; /* no id available, but allright */
  44.         break;
  45.       case 3:
  46.         if (strlen(newsym->name)==1) {        /* a line in the system map */
  47.             strcpy(newsym->id,newsym->name);  /* use segment as id */
  48.             newsym->id[0]=toupper(newsym->id[0]);
  49.             strcpy(newsym->name,s);           /* this was the name */
  50.             break;
  51.         }
  52.         if (s[0]=='[') { /* a module from "ksyms" */
  53.             s[strlen(s)-1]=''; /* trim the bracket */
  54.             strcpy(newsym->id,s+1);
  55.             break;
  56.         }
  57.       default:         /* unknown format */
  58.         free(newsym);
  59.         return NULL;
  60.     }
  61.     newsym->extent = newsym->extent = 0;
  62.     newsym->next = NULL;
  63.     return newsym;
  64. }
  65. /*----------------------------------------------------------------------*/
  66. /*
  67.  * insert a symbol in the list.
  68.  * "trial" is an hint used to speed things  -- it's tenfold faster 
  69.  */
  70. struct ksym *insert(struct ksym *symlist, struct ksym *newsym,
  71.                    struct ksym *trial)
  72. {
  73.     if (!symlist) return newsym;
  74.     if (!trial || trial->address > newsym->address) {
  75.         if (newsym->address < symlist->address) {
  76.             newsym->next = symlist;
  77.             return newsym;
  78.         }
  79.         trial = symlist;
  80.         /* disregard hint */
  81.     }
  82.     for ( ; trial->next; trial=trial->next)
  83.         if (trial->next->address > newsym->address)
  84.             break;
  85.     newsym->next = trial->next;
  86.     trial->next = newsym;
  87.     return symlist;
  88. }
  89. /*----------------------------------------------------------------------*/
  90. /* read a file into a symlist */
  91. struct ksym *filesym(struct ksym *symlist, FILE *f, const char *fname)
  92. {
  93.     char s[80];
  94.     int lineno = 0;
  95.     struct ksym *last = NULL, *sym;
  96.     if (!f) {
  97.         f=fopen(fname,"r");
  98.         if (!f) {
  99.             perror(fname);
  100.             return symlist;
  101.         }
  102.     }
  103.     while (fgets(s,80,f)) {
  104.         lineno++;
  105.         sym = linesym(s);
  106.         if (!sym) {
  107.             fprintf(stderr,"%s:%i: Unknown format for data linen",
  108.                     fname,lineno);
  109.             continue;
  110.         }
  111.         symlist = insert(symlist,sym,last);
  112.         last = sym;
  113.     }
  114.     return symlist;
  115. }
  116. /*----------------------------------------------------------------------*/
  117. /* write extents and remove duplicate items */
  118. struct ksym *fixlist(struct ksym *symlist)
  119.     struct ksym *ptr, *next;
  120.     
  121.     for (ptr=symlist; ptr && ptr->next; ptr = ptr->next) {
  122.         while (ptr->address == ptr->next->address) { /* remove duplicates */
  123.             next=ptr->next;
  124.             if (ptr->id[0] && next->id[0]) /* both valid... hmmm */
  125.                 break;
  126.             if (next->id[0])
  127.                 strcpy(ptr->id,next->id);
  128.             ptr->next=next->next;
  129.             free(next);
  130.         }
  131.         if (!strcmp(ptr->id,ptr->next->id))
  132.             ptr->extent = ptr->next->address - ptr->address;
  133.         else
  134.             ptr->extent = 0;
  135.     }
  136.     ptr->extent=0;
  137.  
  138.     return symlist;
  139. }
  140. /*----------------------------------------------------------------------*/
  141. #ifdef DEBUG
  142. int dumplist(struct ksym *symlist)
  143. {
  144.     for (; symlist; symlist=symlist->next) {
  145.        printf("%08lx %-30s (e %08lx, id "%s")n",
  146.               symlist->address,
  147.               symlist->name, symlist->extent, symlist->id);
  148.        fflush(stdout);
  149.     }
  150.     return 0;
  151. }    
  152. #endif /* DEBUG */                       
  153. /*----------------------------------------------------------------------*/
  154. /* print an address in symbolic form */
  155. char *decode(unsigned int add, unsigned int esp)
  156. {
  157.     static char res[64];
  158.     static struct ksym *symlist=NULL; /* used to remember last time */
  159.     if (!symlist || symlist->address > add) symlist=gsymlist;
  160.     for (;symlist && symlist->next && symlist->next->address <= add;
  161.          symlist=symlist->next)
  162.         /* nothing */;
  163.     if (add < symlist->address || !symlist->extent) { /* out of regions */
  164.         if (abs(add-esp) < 2000) {
  165.             sprintf(res,"<%%esp+%x>",add-esp);
  166.             return res;
  167.         } else
  168.             return "";
  169.     }
  170.     sprintf(res,"<%s+%lx/%lx>",symlist->name,add-symlist->address,
  171.             symlist->extent);
  172.     return res;
  173. }
  174. /*----------------------------------------------------------------------*/
  175. int disass(char *data, unsigned int eip, unsigned int esp)
  176. {
  177.     /*
  178.      * This is a hack to avoid using gcc.  We create an object file by
  179.      * concatenating objfile_head, the twenty bytes of code, and
  180.      * objfile_tail. 
  181.      */
  182.     static unsigned char objfile_head[] = {
  183. 0x07, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
  184. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  185. 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  186. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  187.     };
  188.     static unsigned char objfile_tail[] = {
  189. 0x00, 0x90, 0x90, 0x90,
  190. 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
  191. 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
  192. 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  193. 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
  194. 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
  195. 'g',  'c',  'c',  '2',  '_',  'c',  'o',  'm',  
  196. 'p',  'i',  'l',  'e',  'd',  '.',  '', '_',  
  197. 'E',  'I',  'P',  '', '', '', '', '',
  198. '', '', '', '', '', '', '', '',
  199. '', '', '', '', '', ''
  200.     };
  201.     char * objdump = "objdump -d /tmp/oops_decode.o";
  202.     char * objfile = "/tmp/oops_decode.o";
  203.     char buf[128], *bptr;
  204.     char *s;
  205.     FILE *f;
  206.     long l;
  207.     if (!(f=fopen(objfile,"w"))) {
  208.         perror(objfile); return -1;
  209.     }
  210.     fwrite(objfile_head, 1, sizeof(objfile_head), f);
  211.     fwrite(data, 1, 20, f);
  212.     fwrite(objfile_tail, 1, sizeof(objfile_tail), f);
  213.     fclose(f);
  214.     if (!(f=popen(objdump,"r"))) {
  215.         perror("objdump"); return -1;
  216.     }
  217.     while (fgets(buf,128,f)) {
  218.         if (strncmp(&buf[9], "<_EIP", 5))
  219.             continue;
  220. if (strstr(buf, " is out of bounds"))
  221.     break;
  222.         printf("Code: ");
  223.         /* try to print eip in decoded form */
  224. l = strtol(buf, &bptr, 16);
  225.         s=decode(eip+l,esp);
  226.         if (s[0])
  227.             printf("%s",s); /* the decoded address */
  228.         else
  229.             printf("%08lx",eip+l);
  230.         while (*bptr++ != '>')
  231.             /* skip */ ;
  232.         
  233.         /* print the rest of line, without newline */
  234.         bptr[strlen(bptr)-1]='';
  235.         printf("%s",bptr);
  236.         
  237.         /* and now decode any address it embedded */
  238.         while ( (bptr=strstr(bptr, "0x")) ) {
  239.             l=strtol(bptr, &bptr, 0);
  240.             s=decode(l, esp);
  241.             if (s[0])
  242.                 printf(" %s", s);
  243.         }
  244.         putchar('n');
  245.     }
  246.     pclose(f);
  247.     unlink(objfile);
  248.            
  249.     return 0;
  250. }
  251. /*----------------------------------------------------------------------*/
  252. /*
  253.  * All is there: now use it
  254.  */
  255. int main(int argc, char **argv)
  256. {
  257.     char s[512];
  258.     char *subs=NULL, *savedsubs;
  259.     int status=0, offset;
  260.     unsigned int j, k, esp, eip;
  261.     unsigned int i[16];        /* 8 suffice by now, but who knows... */
  262.     char names[16][8], c[20];  /* [8][8] suffice, but who knows */
  263.     char *ptr;
  264.     char *prgname=argv[0];
  265.     struct ksym *symlist=NULL;
  266.     char defaultmap[]="/usr/src/linux/System.map";
  267.     char *mapname=defaultmap;
  268.     if (argc>2) {
  269.         fprintf(stderr,"%s: Usage: "%s [mapfile_name] < oops-log"n",
  270.                 prgname, prgname);
  271.         exit(1);
  272.     }
  273.     if (argc==2)
  274.         mapname=argv[1];
  275.     fprintf(stderr,"%s: Using %s as mapn", prgname, mapname);
  276.     symlist = filesym(symlist,NULL,mapname);
  277.     symlist = filesym(symlist,NULL,"/proc/ksyms");
  278.     symlist=fixlist(symlist);
  279.     /* dumplist(symlist); */
  280.     gsymlist=symlist;
  281.     /*
  282.      * Ok, the symbol table is there, now get the message
  283.      */
  284.     if (isatty(0)) {
  285.         fprintf(stderr,"%s: please paste the oops on my stdinn",prgname);
  286.     }
  287.     while (fgets(s,512,stdin)) {
  288.         if (!subs) { /* nothing yet */
  289.             savedsubs = subs = strstr(s,"EIP: ");
  290.         }
  291.         switch(status) {
  292.         case 0: /* not found */
  293.             if (!subs) continue;
  294.             status++;
  295.             offset=0;
  296.             esp=0;
  297.             j=sscanf(subs,"%s %x:[<%x>]",s,&i[0],&i[1]);
  298.             if (j!=3) {
  299.                 fprintf(stderr,"Wrong "EIP" linen");
  300.                 continue;
  301.             }
  302.             printf("n%-7s %04x:%08x %sn",s,i[0],i[1],decode(i[1],0));
  303.             eip=i[1]; /* keep to disass */
  304.             break;
  305.             
  306.         case 1: /* before the stack */
  307.             j=sscanf(subs,"%s %x %s %x %s %x %s %x",names[0+offset],i+offset,
  308.                      names[1+offset],i+1+offset,names[2+offset],i+2+offset,
  309.                      names[3+offset],i+3+offset);
  310.             if (j==8 && strlen(names[0])==4) { /* registers */
  311.                 /*
  312.                  * The problem with registers is that I need "esp"
  313.                  * first, on order to refer registers to the stack.
  314.                  * So, I save them, and decode later on
  315.                  */
  316.                 if ( (ptr=strstr(subs,"esp:")) ) {
  317.                     sscanf(ptr,"%*s %x",&esp);
  318.                 }
  319.                 if (esp) { /* decode only when they can be ref'd to stack */
  320.                     for (j=0; j<4+offset; j++)
  321.                         printf("%s %08x %sn",names[j],i[j],decode(i[j],esp));
  322.                     offset=0;
  323.                 } else {
  324.                     offset+=4; /* next time, write after these ones */
  325.                 }
  326.                 continue;
  327.             }
  328.             else if (strncmp(subs,"Stack: ",7)) {
  329.                 printf("%s",subs);
  330.                 continue;
  331.             } else {
  332.                 status++;
  333.                 offset=0;
  334.                 subs+=6; /* skip the string, and fall through */
  335.             }
  336.         case 2: /* stack and trace*/
  337.             if (strncmp(subs,"Call Trace",4) != 0) {
  338.                 k=sscanf(subs,"%x %x %x %x %x %x %x %x",i,i+1,i+2,i+3,
  339.                          i+4,i+5,i+6,i+7);
  340.                 if (k<=0) {
  341.                     fprintf(stderr,"Bad stack line (%i items)n",j);
  342.                 } else {
  343.                     for (j=0; j<k; j++)
  344.                         printf("esp+%02x: %08x %sn",(offset+j)*4,i[j],
  345.                                decode(i[j],esp));
  346.                 }
  347.                 if (!offset) subs = savedsubs; /* restore */
  348.                 offset+=8;
  349.                 continue;
  350.             }
  351.             /* call trace */
  352.             status++;
  353.             offset=0;
  354.             subs+=12; /* skip the string, and fall through */
  355.         case 3: /* the trace */
  356.             if (strncmp(subs,"Code",4)) {
  357.                 k=sscanf(subs," [<%x>] [<%x>] [<%x>] [<%x>] "
  358.                          "[<%x>] [<%x>] [<%x>] [<%x>]",i,i+1,i+2,i+3,
  359.                          i+4,i+5,i+6,i+7);
  360.                 if (k==0) {
  361.                     fprintf(stderr,"Bad trace line %s(no add found)n",subs);
  362.                 } else {
  363.                     for (j=0; j<k; j++)
  364.                         printf("Trace: %08x %sn", i[j], decode(i[j],esp));
  365.                 }
  366.                 subs = savedsubs; /* restore */
  367.                 continue;
  368.             }
  369.             /* the code */
  370.             ptr = subs+5; /* skip "Code:" */
  371.             for (j=0; j<20; j++) {
  372.                 long l=strtol(ptr,&ptr,16);
  373.                 c[j]=(char)l;
  374.             }
  375.    
  376.             disass(c, eip, esp);
  377.             esp=0; status=0; subs=NULL; /* ready for another oops */
  378.         }
  379.         
  380.                 
  381.     }
  382.     return 0;
  383. }