patch-1.3.32 linux/scripts/ksymoops.cc
Next file: linux/CREDITS
Previous file: linux/net/ipv4/ip.c
Back to the patch index
Back to the overall index
- Lines: 362
- Date:
Wed Oct 4 14:56:39 1995
- Orig file:
v1.3.31/linux/scripts/ksymoops.cc
- Orig date:
Wed Sep 13 12:45:36 1995
diff -u --recursive --new-file v1.3.31/linux/scripts/ksymoops.cc linux/scripts/ksymoops.cc
@@ -1,31 +1,47 @@
-/* ksymoops.c -- simple Linux Oops-log symbol resolver
- Copyright (C) 1995 Greg McGary
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* This is a simple filter to resolve EIP and call-trace symbols from
- a Linux kernel "Oops" log. Supply the symbol-map file name as a
- command-line argument, and redirect the oops-log into stdin.
- Out will come the EIP and call-trace in symbolic form. */
+// ksymoops.cc v1.7 -- A simple filter to resolve symbols in Linux Oops-logs
+// Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
+// compile like so: g++ -o ksymoops ksymoops.cc -liostream
+
+//////////////////////////////////////////////////////////////////////////////
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; see the file COPYING. If not, write to the
+// Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+// This is a simple filter to resolve EIP and call-trace symbols from
+// a Linux kernel "Oops" log. Supply the symbol-map file name as a
+// command-line argument, and redirect the oops-log into stdin. Out
+// will come the EIP and call-trace in symbolic form.
+
+//////////////////////////////////////////////////////////////////////////////
+
+// BUGS:
+// * Doesn't deal with line-prefixes prepended by syslog--strip
+// these off first, before submitting to ksymoops.
+// * Only resolves operands of jump and call instructions.
#include <fstream.h>
+#include <iomanip.h>
+#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
inline int strequ(char const* x, char const* y) { return (::strcmp(x, y) == 0); }
+inline int strnequ(char const* x, char const* y, size_t n) { return (::strncmp(x, y, n) == 0); }
+
+const int code_size = 20;
//////////////////////////////////////////////////////////////////////////////
@@ -35,37 +51,41 @@
private:
long address_;
- char type_;
char* name_;
long offset_;
long extent_;
- public:
+ private:
+ istream& scan(istream&);
+ ostream& print(ostream&) const;
void set_extent(KSym const& next_ksym) { extent_ = next_ksym.address_ - address_; }
- friend istream& operator >> (istream&, KSym&);
- friend ostream& operator << (ostream&, const KSym&);
+
+ public:
+ friend istream& operator >> (istream& is, KSym& k) { return k.scan(is); }
+ friend ostream& operator << (ostream& os, const KSym& k) { return k.print(os); }
};
istream&
-operator >> (istream& is, KSym& n)
+KSym::scan(istream& is)
{
- is >> hex >> n.address_;
- is >> n.type_;
+ is >> ::hex >> address_;
+ char type;
+ is >> type;
char name[128];
is >> name;
- n.name_ = new char [strlen(name)+1];
- strcpy(n.name_, name);
- n.offset_ = 0;
+ name_ = new char [strlen(name)+1];
+ strcpy(name_, name);
+ offset_ = 0;
return is;
}
ostream&
-operator << (ostream& os, const KSym& n)
+KSym::print(ostream& os) const
{
- os << hex << n.address_ + n.offset_ << ' ' << n.type_ << ' ' << n.name_;
- if (n.offset_)
- os << '+' << hex << n.offset_ << '/' << hex << n.extent_;
- return os;
+ os << ::hex << address_ + offset_ << ' ' << '<' << name_;
+ if (offset_)
+ os << '+' << ::hex << offset_ << '/' << ::hex << extent_;
+ return os << '>';
}
//////////////////////////////////////////////////////////////////////////////
@@ -81,20 +101,30 @@
public:
NameList() : cardinality_(0) { }
+ private:
+ istream& scan(istream&);
+
public:
+ int valid() { return (cardinality_ > 0); }
+
KSym* find(long address);
+ void decode(unsigned char* code, long eip_addr);
public:
- friend istream& operator >> (istream&, NameList&);
+ friend istream& operator >> (istream& is, NameList& n) { return n.scan(is); }
};
KSym*
NameList::find(long address)
{
+ if (!valid())
+ return 0;
KSym* start = ksyms_0_;
- KSym* end = &ksyms_0_[cardinality_];
- KSym* mid;
+ KSym* end = &ksyms_0_[cardinality_ - 1];
+ if (address < start->address_ || address >= end->address_)
+ return 0;
+ KSym* mid;
while (start <= end) {
mid = &start[(end - start) / 2];
if (mid->address_ < address)
@@ -112,18 +142,101 @@
return mid;
}
+void
+NameList::decode(unsigned char* code, long eip_addr)
+{
+ /* This is a hack to avoid using gcc. We create an object file by
+ concatenating objfile_head, the twenty bytes of code, and
+ objfile_tail. */
+ unsigned char objfile_head[] = {
+ 0x07, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ unsigned char objfile_tail[] = {
+ 0x00, 0x90, 0x90, 0x90,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
+ 'g', 'c', 'c', '2', '_', 'c', 'o', 'm',
+ 'p', 'i', 'l', 'e', 'd', '.', '\0', '_',
+ 'E', 'I', 'P', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0'
+ };
+ char const* objdump_command = "objdump -d oops_decode.o";
+ char const* objfile_name = &objdump_command[11];
+ ofstream objfile_stream(objfile_name);
+
+ objfile_stream.write(objfile_head, sizeof(objfile_head));
+ objfile_stream.write(code, code_size);
+ objfile_stream.write(objfile_tail, sizeof(objfile_tail));
+ objfile_stream.close();
+
+ FILE* objdump_FILE = popen(objdump_command, "r");
+ if (objdump_FILE == 0) {
+ clog << "Sorry, without " << objdump_command << ", I can't disassemble the `Code' section." << endl;
+ return;
+ }
+
+ char buf[1024];
+ int lines = 0;
+ while (fgets(buf, sizeof(buf), objdump_FILE)) {
+ if (!strnequ(&buf[9], "<_EIP", 5))
+ continue;
+ if (strstr(buf, " is out of bounds"))
+ break;
+ lines++;
+ cout << "Code: ";
+ if (!valid()) {
+ cout << buf;
+ continue;
+ }
+ long offset = strtol(buf, 0, 16);
+ char* bp_0 = strchr(buf, '>') + 2;
+ KSym* ksym = find(eip_addr + offset);
+ if (ksym)
+ cout << *ksym << ' ';
+ char* bp = bp_0;
+ while (!isspace(*bp))
+ bp++;
+ while (isspace(*bp))
+ bp++;
+ if (*bp != '0') {
+ cout << bp_0;
+ } else if (*bp_0 == 'j' || strnequ(bp_0, "call", 4)) { // a jump or call insn
+ long rel_addr = strtol(bp, 0, 16);
+ ksym = find(eip_addr + rel_addr);
+ if (ksym) {
+ *bp++ = '\0';
+ cout << bp_0 << *ksym << endl;
+ } else
+ cout << bp_0;
+ } else {
+ cout << bp_0;
+ }
+ }
+ if (!lines)
+ clog << "Sorry, your " << objdump_command << " can't disassemble--you must upgrade your binutils." << endl;
+ pclose(objdump_FILE);
+ unlink(objfile_name);
+}
+
istream&
-operator >> (istream& is, NameList& n)
+NameList::scan(istream& is)
{
- KSym* ksyms = n.ksyms_0_;
+ KSym* ksyms = ksyms_0_;
int cardinality = 0;
while (!is.eof()) {
is >> *ksyms;
- ksyms[-1].set_extent(*ksyms);
+ if (cardinality++ > 0)
+ ksyms[-1].set_extent(*ksyms);
ksyms++;
- cardinality++;
}
- n.cardinality_ = --cardinality;
+ cardinality_ = --cardinality;
return is;
}
@@ -134,7 +247,7 @@
void
usage()
{
- clog << "Usage: " << program_name << " system-map-file < oops-log" << endl;
+ clog << "Usage: " << program_name << " [ System.map ] < oops-log" << endl;
exit(1);
}
@@ -142,38 +255,64 @@
main(int argc, char** argv)
{
program_name = (argc--, *argv++);
- if (argc != 1)
- usage();
- char const* map_file_name = (argc--, *argv++);
- ifstream map(map_file_name);
- if (map.bad()) {
- clog << program_name << ": Can't open `" << map_file_name << "'" << endl;
- return 1;
- }
-
NameList names;
- map >> names;
+ if (argc > 1)
+ usage();
+ else if (argc == 1) {
+ char const* map_file_name = (argc--, *argv++);
+ ifstream map(map_file_name);
+ if (map.bad())
+ clog << program_name << ": Can't open `" << map_file_name << "'" << endl;
+ else {
+ map >> names;
+ cout << "Using `" << map_file_name << "' to map addresses to symbols." << endl;
+ }
+ }
+ if (!names.valid())
+ cout << "No symbol map. I'll only show you disassembled code." << endl;
+ cout << endl;
char buffer[1024];
while (!cin.eof())
{
- long address;
+ long eip_addr;
cin >> buffer;
- if (strequ(buffer, "EIP:")) {
- cin >> hex >> address;
+ if (strequ(buffer, "EIP:") && names.valid()) {
+ cin >> ::hex >> eip_addr;
cin >> buffer[0];
- cin >> hex >> address;
- KSym* ksym = names.find(address);
+ cin >> ::hex >> eip_addr;
+ cin >> buffer;
+ if (!strequ(buffer, "EFLAGS:")) {
+ clog << "Please strip the line-prefixes and rerun " << program_name << endl;
+ exit(1);
+ }
+ KSym* ksym = names.find(eip_addr);
if (ksym)
- cout << "EIP: " << *ksym << endl;
- } else if (strequ(buffer, "Trace:")) {
- while ((cin >> address) && address > 0xc) {
+ cout << ">>EIP: " << *ksym << endl;
+ } else if (strequ(buffer, "Trace:") && names.valid()) {
+ long address;
+ while ((cin >> ::hex >> address) && address > 0xc) {
+ cout << "Trace: ";
KSym* ksym = names.find(address);
if (ksym)
- cout << "Trace: " << *ksym << endl;
+ cout << *ksym;
+ else
+ cout << ::hex << address;
+ cout << endl;
}
cout << endl;
+ } else if (strequ(buffer, "ode:") || strequ(buffer, "Code:")) {
+ // The 'C' might have been consumed as a hex number
+ unsigned char code[code_size];
+ unsigned char* cp = code;
+ unsigned char* end = &code[code_size];
+ while (cp < end) {
+ int c;
+ cin >> ::hex >> c;
+ *cp++ = c;
+ }
+ names.decode(code, eip_addr);
}
}
cout << flush;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this