root/scripts/ksymoops.cc

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. strequ
  2. strnequ
  3. set_extent
  4. scan
  5. print
  6. valid
  7. find
  8. decode
  9. scan
  10. usage
  11. main

   1 // ksymoops.cc v1.7 -- A simple filter to resolve symbols in Linux Oops-logs
   2 // Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
   3 // compile like so: g++ -o ksymoops ksymoops.cc -liostream
   4 
   5 //////////////////////////////////////////////////////////////////////////////
   6 
   7 // This program is free software; you can redistribute it and/or modify
   8 // it under the terms of the GNU General Public License as published by
   9 // the Free Software Foundation; either version 2, or (at your option)
  10 // any later version.
  11 
  12 // This program is distributed in the hope that it will be useful,
  13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 // GNU General Public License for more details.
  16 
  17 // You should have received a copy of the GNU General Public License
  18 // along with this program; see the file COPYING.  If not, write to the
  19 // Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 
  21 // This is a simple filter to resolve EIP and call-trace symbols from
  22 // a Linux kernel "Oops" log.  Supply the symbol-map file name as a
  23 // command-line argument, and redirect the oops-log into stdin.  Out
  24 // will come the EIP and call-trace in symbolic form.
  25 
  26 //////////////////////////////////////////////////////////////////////////////
  27 
  28 // BUGS:
  29 // * Doesn't deal with line-prefixes prepended by syslog--strip
  30 //   these off first, before submitting to ksymoops.
  31 // * Only resolves operands of jump and call instructions.
  32 
  33 #include <fstream.h>
  34 #include <iomanip.h>
  35 #include <stdio.h>
  36 #include <string.h>
  37 #include <stdlib.h>
  38 #include <unistd.h>
  39 #include <ctype.h>
  40 
  41 inline int strequ(char const* x, char const* y) { return (::strcmp(x, y) == 0); }
     /* [previous][next][first][last][top][bottom][index][help] */
  42 inline int strnequ(char const* x, char const* y, size_t n) { return (::strncmp(x, y, n) == 0); }
     /* [previous][next][first][last][top][bottom][index][help] */
  43 
  44 const int code_size = 20;
  45 
  46 //////////////////////////////////////////////////////////////////////////////
  47 
  48 class KSym
  49 {
  50     friend class NameList;
  51 
  52   private:
  53     long address_;
  54     char* name_;
  55     long offset_;
  56     long extent_;
  57 
  58   private:
  59     istream& scan(istream&);
  60     ostream& print(ostream&) const;
  61     void set_extent(KSym const& next_ksym) { extent_ = next_ksym.address_ - address_; }
     /* [previous][next][first][last][top][bottom][index][help] */
  62 
  63   public:
  64     friend istream& operator >> (istream& is, KSym& k) { return k.scan(is); }
  65     friend ostream& operator << (ostream& os, const KSym& k) { return k.print(os); }
  66 };
  67 
  68 istream&
  69 KSym::scan(istream& is)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71     is >> ::hex >> address_;
  72     char type;
  73     is >> type;
  74     char name[128];
  75     is >> name;
  76     name_ = new char [strlen(name)+1];
  77     strcpy(name_, name);
  78     offset_ = 0;
  79     return is;
  80 }
  81 
  82 ostream&
  83 KSym::print(ostream& os) const
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85     os << ::hex << address_ + offset_ << ' ' << '<' << name_;
  86     if (offset_)
  87         os << '+' << ::hex << offset_ << '/' << ::hex << extent_;
  88     return os << '>';
  89 }
  90 
  91 //////////////////////////////////////////////////////////////////////////////
  92 
  93 class NameList
  94 {
  95   private:
  96     // Caution: Fixed Allocation!
  97     // This should suffice for awhile since 1.1.86 has only 2482 symbols.
  98     KSym ksyms_0_[4096];
  99     int cardinality_;
 100 
 101   public:
 102     NameList() : cardinality_(0) { }
 103     
 104   private:
 105     istream& scan(istream&);
 106 
 107   public:
 108     int valid() { return (cardinality_ > 0); }
     /* [previous][next][first][last][top][bottom][index][help] */
 109         
 110     KSym* find(long address);
 111     void decode(unsigned char* code, long eip_addr);
 112     
 113   public:
 114     friend istream& operator >> (istream& is, NameList& n) { return n.scan(is); }
 115 };
 116 
 117 KSym*
 118 NameList::find(long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120     if (!valid())
 121         return 0;
 122     KSym* start = ksyms_0_;
 123     KSym* end = &ksyms_0_[cardinality_ - 1];
 124     if (address < start->address_ || address >= end->address_)
 125         return 0;
 126 
 127     KSym* mid;
 128     while (start <= end) {
 129         mid = &start[(end - start) / 2];
 130         if (mid->address_ < address)
 131             start = mid + 1;
 132         else if (mid->address_ > address)
 133             end = mid - 1;
 134         else
 135             return mid;
 136     }
 137     while (mid->address_ > address)
 138         --mid;
 139     mid->offset_ = address - mid->address_;
 140     if (mid->offset_ > mid->extent_)
 141         clog << "Oops! " << *mid << endl;
 142     return mid;
 143 }
 144 
 145 void
 146 NameList::decode(unsigned char* code, long eip_addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148     /* This is a hack to avoid using gcc.  We create an object file by
 149        concatenating objfile_head, the twenty bytes of code, and
 150        objfile_tail.  */
 151     unsigned char objfile_head[] = {
 152         0x07, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
 153         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 154         0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 155         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 156     };
 157     unsigned char objfile_tail[] = {
 158         0x00, 0x90, 0x90, 0x90,
 159         0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
 160         0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
 161         0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 162         0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
 163         0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
 164         'g',  'c',  'c',  '2',  '_',  'c',  'o',  'm',  
 165         'p',  'i',  'l',  'e',  'd',  '.',  '\0', '_',  
 166         'E',  'I',  'P',  '\0', '\0', '\0', '\0', '\0',
 167         '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
 168         '\0', '\0', '\0', '\0', '\0', '\0'
 169     };
 170     char const* objdump_command = "objdump -d oops_decode.o";
 171     char const* objfile_name = &objdump_command[11];
 172     ofstream objfile_stream(objfile_name);
 173 
 174     objfile_stream.write(objfile_head, sizeof(objfile_head));
 175     objfile_stream.write(code, code_size);
 176     objfile_stream.write(objfile_tail, sizeof(objfile_tail));
 177     objfile_stream.close();
 178     
 179     FILE* objdump_FILE = popen(objdump_command, "r");
 180     if (objdump_FILE == 0) {
 181         clog << "Sorry, without " << objdump_command << ", I can't disassemble the `Code' section." << endl;
 182         return;
 183     }
 184     
 185     char buf[1024];
 186     int lines = 0;
 187     while (fgets(buf, sizeof(buf), objdump_FILE)) {
 188         if (!strnequ(&buf[9], "<_EIP", 5))
 189             continue;
 190         if (strstr(buf, " is out of bounds"))
 191             break;
 192         lines++;
 193         cout << "Code: ";
 194         if (!valid()) {
 195             cout << buf;
 196             continue;
 197         }
 198         long offset = strtol(buf, 0, 16);
 199         char* bp_0 = strchr(buf, '>') + 2;
 200         KSym* ksym = find(eip_addr + offset);
 201         if (ksym)
 202             cout << *ksym << ' ';
 203         char* bp = bp_0;
 204         while (!isspace(*bp))
 205             bp++;
 206         while (isspace(*bp))
 207             bp++;
 208         if (*bp != '0') {
 209             cout << bp_0;
 210         } else if (*bp_0 == 'j' || strnequ(bp_0, "call", 4)) { // a jump or call insn
 211             long rel_addr = strtol(bp, 0, 16);
 212             ksym = find(eip_addr + rel_addr);
 213             if (ksym) {
 214                 *bp++ = '\0';
 215                 cout << bp_0 << *ksym << endl;
 216             } else
 217                 cout << bp_0;
 218         } else {
 219             cout << bp_0;
 220         }
 221     }
 222     if (!lines)
 223         clog << "Sorry, your " << objdump_command << " can't disassemble--you must upgrade your binutils." << endl;
 224     pclose(objdump_FILE);
 225     unlink(objfile_name);
 226 }
 227 
 228 istream&
 229 NameList::scan(istream& is)
     /* [previous][next][first][last][top][bottom][index][help] */
 230 {
 231     KSym* ksyms = ksyms_0_;
 232     int cardinality = 0;
 233     while (!is.eof()) {
 234         is >> *ksyms;
 235         if (cardinality++ > 0)
 236             ksyms[-1].set_extent(*ksyms);
 237         ksyms++;
 238     }
 239     cardinality_ = --cardinality;
 240     return is;
 241 }
 242 
 243 //////////////////////////////////////////////////////////////////////////////
 244 
 245 char const* program_name;
 246 
 247 void
 248 usage()
     /* [previous][next][first][last][top][bottom][index][help] */
 249 {
 250     clog << "Usage: " << program_name << " [ System.map ] < oops-log" << endl;
 251     exit(1);
 252 }
 253 
 254 int
 255 main(int argc, char** argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 256 {
 257     char c;
 258     program_name = (argc--, *argv++);
 259 
 260     NameList names;
 261     if (argc > 1)
 262         usage();
 263     else if (argc == 1) {
 264         char const* map_file_name = (argc--, *argv++);
 265         ifstream map(map_file_name);
 266         if (map.bad())
 267             clog << program_name << ": Can't open `" << map_file_name << "'" << endl;
 268         else {
 269             map >> names;
 270             cout << "Using `" << map_file_name << "' to map addresses to symbols." << endl;
 271         }
 272     }
 273     if (!names.valid())
 274         cout << "No symbol map.  I'll only show you disassembled code." << endl;
 275     cout << endl;
 276 
 277     char buffer[1024];
 278     while (!cin.eof())
 279     {
 280         long eip_addr;
 281         cin >> buffer;
 282         if (strequ(buffer, "EIP:") && names.valid()) {
 283             cin >> ::hex >> eip_addr;
 284             cin >> c >> c >> c;
 285             cin >> ::hex >> eip_addr;
 286             cin >> c >> c >> buffer;
 287             if (!strequ(buffer, "EFLAGS:")) {
 288                 clog << "Please strip the line-prefixes and rerun " << program_name << endl;
 289                 exit(1);
 290             }
 291             KSym* ksym = names.find(eip_addr);
 292             if (ksym)
 293                 cout << ">>EIP: " << *ksym << endl;
 294         } else if (strequ(buffer, "Trace:") && names.valid()) {
 295             long address;
 296             while ((cin >> buffer) && 
 297                    (sscanf(buffer, " [<%x>]", &address) == 1) &&
 298                    address > 0xc) {
 299                 cout << "Trace: ";
 300                 KSym* ksym = names.find(address);
 301                 if (ksym)
 302                     cout << *ksym;
 303                 else
 304                     cout << ::hex << address;
 305                 cout << endl;
 306             }
 307             cout << endl;
 308         }
 309         if (strequ(buffer, "ode:") || strequ(buffer, "Code:")) {
 310             // The 'C' might have been consumed as a hex number
 311             unsigned char code[code_size];
 312             unsigned char* cp = code;
 313             unsigned char* end = &code[code_size];
 314             while (cp < end) {
 315                 int c;
 316                 cin >> ::hex >> c;
 317                 *cp++ = c;
 318             }
 319             names.decode(code, eip_addr);
 320         }
 321     }
 322     cout << flush;
 323 
 324     return 0;
 325 }

/* [previous][next][first][last][top][bottom][index][help] */