Ksymoops re-written in C, not C++ was Change in kernel "changes" :) , (fwd)

Chris Ricker (kaboom@gatech.edu)
Thu, 25 Jun 1998 18:09:29 -0400 (EDT)


This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.
Send mail to mime@docserver.cac.washington.edu for more info.

--------------167EB0E72781E494446B9B3D
Content-Type: TEXT/PLAIN; CHARSETus-ascii
Content-ID: <Pine.GSO.3.96.980625180148.8754C@oobleck.gatech.edu>

Hello all,

Jean-Francois Bignolles <bignolle@grif.fr> asked me to forward this to the
list as he's not a subscriber. Basically, he's proposing a replacement
scripts/ksymoops written in C instead of C++ to lessen the need to have a
C++ compiler around.... Please direct comments / questions to him, not
me. Thanks.

later,
chris

--
Chris Ricker                                            kaboom@gatech.edu

The time you enjoy wasting is not wasting time. -- T.S. Eliot

---------- Forwarded message ---------- Date: Fri, 12 Jun 1998 13:54:59 +0200 From: Jean-Francois Bignolles <bignolle@grif.fr> To: kaboom@gatech.edu Subject: Change in kernel "changes" :)

Hello,

I want to submit a change. It is said that

Linux C++ Library 2.7.2.8

is needed to compile Linux kernel. In fact, there is only one file (!) which is a C++ source: Scripts/ksymoops.cc (~10K). That's why a rewrite of this file in plain C can remove a dependancy from C++ libs and tools (and save some dowloads:). So I have rewriten it, and I send i to you. Please note that I have not tested it (I'm not a kernel hacker)...

--------------167EB0E72781E494446B9B3D Content-Type: TEXT/PLAIN; CHARSETiso-8859-1; NAME"ksymoops.c" Content-Transfer-Encoding: QUOTED-PRINTABLE Content-ID: <Pine.GSO.3.96.980625180148.8754D@oobleck.gatech.edu> Content-Description:

/* ksymoops.c v1.8 -- A simple filter to resolve symbols in Linux Oops-logs * Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com> * compile like so: gcc -o ksymoops ksymoops.c * * Update to binutils 2.8 and handling of header text on oops lines by * Keith Owens <kaos@ocs.com.au> * * This is a rewrite of ksymoops.cc v1.7 in plain C -- this removes a * dependency from C++ libs/tools (there was only one C++ source in the * kernel tree!). Now room for the namelist is dynamicaly allocated * Jean-François Bignolles <bignolle@grif.fr> */

/* 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: * * Only resolves operands of jump and call instructions. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <ctype.h>

#define KSYM_LEN_MAX 129 #define CODE_SIZE 20

#define strnequ( x, y, n) (strncmp ((x), (y), (n)) == 0)

char const *program_name;

/*------------------------------------------------------------------*/

struct KSym { unsigned long address; char *name; long offset; long extent; }; typedef struct KSym KSym;

struct NameList { KSym *ksyms_0; int cardinality; }; typedef struct NameList NameList;

void KSym_set_extent (KSym*, KSym const*); void KSym_scan (KSym*, FILE*); void KSym_print (KSym*, FILE*);

void NameList_ctor (NameList*); void NameList_init (NameList*, unsigned); int NameList_valid (NameList*); void NameList_scan (NameList*, FILE*); KSym *NameList_find (NameList*, unsigned long); void NameList_decode (NameList*, unsigned char*, long);

/*------------------------------------------------------------------*/

inline void KSym_set_extent (KSym *ksym, KSym const *next_ksym) { ksym->extent = next_ksym->address - ksym->address; }

void KSym_scan (KSym *ksym, FILE *file) { char type; char name[KSYM_LEN_MAX + 1];

fscanf (file, "%lx %c %s", &(ksym->address), &type, name); ksym->name = strdup (name); ksym->offset = 0; }

void KSym_print (KSym *ksym, FILE *file) { fprintf (file, "%lx <%s", (ksym->address + ksym->offset), ksym->name);

if (ksym->offset > 0) fprintf (file, "+%lx/%lx", ksym->offset, ksym->extent); putc ('>', file); }

/*------------------------------------------------------------------*/

inline void NameList_ctor (NameList *nlist) { nlist->cardinality = 0; }

void NameList_init (NameList *nlist, unsigned ksym_max) { nlist->ksyms_0 = (KSym*) malloc (ksym_max * sizeof(struct KSym));

if (nlist->ksyms_0 == NULL) { perror (program_name); exit (EXIT_FAILURE); } }

inline int NameList_valid (NameList *nlist) { return (nlist->cardinality > 0); }

KSym *NameList_find (NameList *nlist, unsigned long address) { KSym *start, *end, *mid;

if (!NameList_valid (nlist)) return NULL; start = nlist->ksyms_0; end = start + nlist->cardinality - 1;

if (address < start->address || address >= end->address) return NULL;

while (start <= end) { mid = start + ((end - start) / 2);

if (mid->address < address) start = mid + 1; else if (mid->address > address) end = mid - 1; else return mid; } while (mid->address > address) --mid; mid->offset = address - mid->address;

if (mid->offset > mid->extent) { fputs ("Oops! ", stderr); KSym_print (mid, stderr); putc ('\n', stderr); } return mid; }

void NameList_decode (NameList *nlist, 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;

FILE *file, *dumppipe; KSym *ksym; char buf[1024], newbuf[1024]; char *bp, *bp_0, *bp_1; int lines = 0; int eip_seen = 0; long offset, rel_addr;

if ((file = fopen (objfile_name, "w")) == NULL) { fprintf (stderr, "%s: can't open `%s'\n", program_name, objfile_name); return; } fwrite (objfile_head, sizeof(objfile_head), 1, file); fwrite (code, CODE_SIZE, 1, file); fwrite (objfile_tail, sizeof(objfile_tail), 1, file); fclose (file);

if ((dumppipe = popen (objdump_command, "r")) == NULL) { fprintf (stderr, "%s: can't exec `%s'; `Code' section not" " disassembled\n", program_name, objdump_command); return; } while (fgets (buf, sizeof(buf), dumppipe)) { if (strlen (buf) < 14) continue;

if (eip_seen && buf[4] == ':') { /* assume objdump from binutils 2.8..., reformat to old style */ offset = strtol (buf, 0, 16); sprintf (newbuf, "%8lx <_EIP+%lx>: %s", offset, offset, buf + 6); strcpy (buf, newbuf); } if (!strnequ (buf + 9, "<_EIP", 5)) continue; eip_seen = 1;

if (strstr (buf, " is out of bounds")) break; lines++; fputs ("Code: ", stdout);

if (!NameList_valid (nlist)) { fputs (buf, stdout); continue; } offset = strtol (buf, 0, 16); bp_0 = strchr (buf, '>'); bp_0 = bp_0 != NULL? bp_0 + 2: strchr (buf, ':');

if ((ksym = NameList_find (nlist, eip_addr + offset)) != NULL) { KSym_print (ksym, stdout); putchar (' '); } bp_1 = strstr (bp_0, "\t"); /* objdump from binutils 2.8... */ bp_1 = bp_1 != NULL? bp_1 + 1: bp_0;

for (bp = bp_1; !isspace (*bp); bp++) ; for (; isspace (*bp); bp++) ;

if (!isxdigit (*bp)) fputs (bp_0, stdout); else if (*bp_1 == 'j' || strnequ (bp_1, "call", 4)) { /* a jump or call insn */ rel_addr = strtol (bp, 0, 16);

if ((ksym = NameList_find (nlist, eip_addr + rel_addr)) != NULL) { *bp++ = '\0'; fputs (bp_0, stdout); KSym_print (ksym, stdout); putchar ('\n'); } else fputs (bp_0, stdout); } else fputs (bp_0, stdout); } if (!lines) fprintf (stderr, "%s: `%s' can't disassemble--you must upgrade" " your binutils\n", program_name, objdump_command); pclose (dumppipe); unlink (objfile_name); }

void NameList_scan (NameList *nlist, FILE *file) { KSym *ksyms; int cardinality;

for (ksyms = nlist->ksyms_0, cardinality = 0; !feof (file); ksyms++) { KSym_scan (ksyms, file);

if (cardinality++ > 0) KSym_set_extent (ksyms - 1, ksyms); } nlist->cardinality = cardinality - 1; }

/*------------------------------------------------------------------*/

void usage () { fprintf (stderr, "Usage: %s [System.map] < oops-log\n", program_name); exit (EXIT_FAILURE); }

int file_line_count (char *file_name) { const char *wc_opt_l = "wc -l "; char command [129]; FILE *wc_pipe; int line_count;

strcpy (command, wc_opt_l); strcat (command, file_name);

if ((wc_pipe = popen (command, "r")) == NULL) return -1;

fscanf (wc_pipe, " %d", &line_count); pclose (wc_pipe); return line_count; }

int main (int argc, char *argv[]) { FILE *map; KSym *ksym; int ksym_max; int c; char *p, *cp, *end; char *oops_column = NULL; char *map_file_name; char buffer[1024]; unsigned char code[CODE_SIZE]; long eip_addr; unsigned long address; NameList names;

NameList_ctor (&names); program_name = (argc--, *argv++);

if (argc > 1) usage (); else if (argc == 1) { map_file_name = (argc--, *argv++);

if ((ksym_max = file_line_count (map_file_name)) < 0) fprintf (stderr, "%s: can't open `%s'\n", program_name, map_file_name); else { printf ("using `%s' to map addresses to symbols\n", map_file_name); map = fopen (map_file_name, "r"); NameList_init (&names, ksym_max); NameList_scan (&names, map); } } if (!NameList_valid (&names)) printf ("no symbol map. I'll only show you disassembled code.\n"); putchar ('\n');

for (;;) { if (fgets (buffer, sizeof(buffer), stdin) == NULL) break;

if (strstr (buffer, "EIP:") && NameList_valid (&names)) { oops_column = strstr (buffer, "EIP:");

if (sscanf (oops_column + 13, "[<%lx>]", &eip_addr) != 1) { fprintf (stderr, "Cannot read eip address from EIP: line." " Is this a valid oops file?\n"); exit (EXIT_FAILURE); } printf (">>EIP: ");

if ((ksym = NameList_find (&names, eip_addr)) != NULL) { KSym_print (ksym, stdout); putchar ('\n'); } else printf ("%lx cannot be resolved\n", eip_addr); } else if (oops_column && strstr (oops_column, "[<") && NameList_valid (&names)) { while (strstr (oops_column, "[<")) { for (p = oops_column;;) { while (*p && *p++ != '[') ; if (sscanf (p, "<%lx>]", &address) != 1) break; printf ("Trace: ");

if ((ksym = NameList_find (&names, address)) != NULL) KSym_print (ksym, stdout); else printf ("%lx", address); putchar ('\n'); } if (fgets (buffer, sizeof(buffer), stdin) == NULL) break; } } if (oops_column && strnequ (oops_column, "Code:", 5)) { p = oops_column + 5; cp = code; end = code + CODE_SIZE; memset (code, '\0', sizeof(code));

while (*p && cp < end) { while (*p == ' ') ++p;

if (sscanf (p, "%x", &c) != 1) break; *cp++ = c; while (*p && *p++ != ' ') ; } NameList_decode (&names, code, eip_addr); } } fflush (stdout); exit (EXIT_SUCCESS); }

/* end ksymoops.c */

--------------167EB0E72781E494446B9B3D--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu