source: gpfs_3.1_ker2.6.20/lpp/mmfs/src/gpl-linux/kdump.c @ 223

Last change on this file since 223 was 16, checked in by rock, 17 years ago
File size: 37.2 KB
Line 
1/***************************************************************************
2 *
3 * Copyright (C) 2001 International Business Machines
4 * All rights reserved.
5 *
6 * This file is part of the GPFS mmfslinux kernel module.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 *  1. Redistributions of source code must retain the above copyright notice,
13 *     this list of conditions and the following disclaimer.
14 *  2. Redistributions in binary form must reproduce the above copyright
15 *     notice, this list of conditions and the following disclaimer in the
16 *     documentation and/or other materials provided with the distribution.
17 *  3. The name of the author may not be used to endorse or promote products
18 *     derived from this software without specific prior written
19 *     permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, 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, EVEN IF
30 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *************************************************************************** */
33/* @(#)64       1.24  src/avs/fs/mmfs/ts/kernext/gpl-linux/kdump.c, mmfs, avs_rgpfs24, rgpfs24s011a 3/14/07 10:53:37 */
34/* Program to dump kernel memory by address or symbol on a running system.
35   Can also get formatted dumps of some kernel data structures.  Invoke
36   as 'kdump /var/mmfs/tmp/complete.map.'. */
37
38/*
39 * Contents:
40 *   Init
41 *   CopyString
42 *   SymbolHash
43 *   LookupSymbolByName
44 *   AddUniqueSymbol
45 *   AddSymbol
46 *   SymbolAddrCompare
47 *   SortSymbols
48 *   LookupSymbolByAddr
49 *   ExactAddrToSymbol
50 *   ReadKernelMap
51 *   ReadKernel
52 *   GetSymbolValue
53 *   kMalloc
54 *   kFree
55 *   CondFree
56 *   DumpMemory
57 *   GetHex
58 *   PrintCxiNode_t
59 *   Usage
60 *   DoHelp
61 *   main
62 *
63 */
64
65#include <stdio.h>
66#include <stdlib.h>
67#include <unistd.h>
68#include <assert.h>
69#include <ctype.h>
70#include <string.h>
71#include <fcntl.h>
72#include <termios.h>
73#include <regex.h>
74#include <stdarg.h>
75
76#include <cxiTypes.h>
77
78#include <kdump.h>
79#include <kdump-kern.h>
80
81/* String storage area.  Strings are allocated at successively higher
82 * addresses within this area, and are never deallocated.
83 */
84char* StringAreaP = NULL;
85#define STRING_AREA_SIZE (4*1024*1024)
86int StringAreaSizeLeft;
87
88/* Symbol storage area.  Each symbol has an address, some flags, and
89 * a name.  Symbols are linked into a hash table by name.  Although the
90 * symbol array itself is not sorted, the auxiliary array SymsByAddrPP is
91 * sorted by address to allow fast binary search by address.
92 */
93int NSymbols = 0;
94int SymbolTableSorted = 0;
95
96#define MAX_SYMBOLS (128*1024)
97struct Symbol* SymbolAreaP = NULL;
98struct Symbol** SymsByAddrPP = NULL;
99
100#define SYM_HASH_BUCKETS 4093
101struct Symbol* SymbolHashAnchor[SYM_HASH_BUCKETS];
102
103/* Stab area.  Structure sizes and member offset for
104 * dump data formatting.
105 */
106int NStabs = 0;
107#define MAX_STABS (128*1024)
108struct Stab *StabAreaP = NULL;
109
110#define STAB_HASH_BUCKETS 4093
111struct Stab* StabHashAnchor[STAB_HASH_BUCKETS];
112
113/* Handle of /dev/kmem */
114int KmemHandle = -1;
115
116/* Bounds of the initial portion of kernel virtual memory.  These are
117   initialized to liberal values, then tightened by reading kernel
118   variables. */
119unsigned long LowKernelAddr = 4096;
120unsigned long HighKernelAddr = -1L;
121
122unsigned long HighSymbolAddr = 0;
123
124/* Head of list of vm_struct structs copied from the kernel.  These define
125   which areas of kernel virtual memory are legal to access through
126   /dev/kmem. */
127struct vmStruct* vmListHeadP = NULL;
128
129/* Are we reading a core file or /dev/kmem ? */
130int isCore = 0;
131
132/* core file descriptor */
133int coreFD = -1;
134
135int savefdout = -1;
136int savefdin  = -1;
137
138/* 2.6.5 ppc64/x86_64 /dev/kmem can't read high memory */
139
140#if LINUX_KERNEL_VERSION >= 2060900 \
141   || ( LINUX_KERNEL_VERSION > 2060000 && (defined(GPFS_ARCH_PPC64) || defined(GPFS_ARCH_X86_64)))
142#define USE_KDUMP0
143#endif
144
145void
146cmdpclose(FILE *fp)
147{
148  if (fp)
149  {
150    /* reconnect stdout/stdin */
151    if (savefdout >= 0)
152    {
153      fflush(stdout);
154      dup2(savefdout, fileno(stdout));
155
156      close(savefdout);
157      savefdout = -1;
158    }
159    if (savefdin >= 0)
160    {
161      fflush(stdin);
162      dup2(savefdin, fileno(stdin));
163
164      close(savefdin);
165      savefdin = -1;
166    }
167
168    fflush(fp);
169    pclose(fp);
170    fflush(NULL);
171  }
172} 
173 
174FILE *
175cmdpopen(char *cmd)
176{
177  FILE *fp;
178
179  fp = popen(cmd, "w");
180  if (fp)
181  {
182    /* save current connections to stdout/stdin */ 
183    savefdout = dup(fileno(stdout));
184    savefdin  = dup(fileno(stdin));
185
186    /* close stdout and redirect stdout messages to cmd */
187    if (dup2(fileno(fp), fileno(stdout)) < 0)
188    {
189      perror("cmdpopen: dup2()");
190      cmdpclose(fp);
191      return NULL;
192    }
193
194    /* close stdin and redirect stdin messages to cmd */
195    if (dup2(fileno(fp), fileno(stdin)) < 0)
196    {
197      perror("cmdpopen: dup2()");
198      cmdpclose(fp);
199      return NULL;   
200    }
201  }
202  return fp;
203} 
204   
205/* Initialize */
206void Init()
207{
208  int i;
209
210  /* Initialize string area */
211  StringAreaP = (char*) malloc(STRING_AREA_SIZE);
212  assert(StringAreaP != NULL);
213  StringAreaSizeLeft = STRING_AREA_SIZE;
214
215  /* Allocate storage for symbols and put one symbol in the
216   * table at address 0
217  */
218  SymbolAreaP = (struct Symbol *)malloc(MAX_SYMBOLS*sizeof(struct Symbol));
219  assert(SymbolAreaP != NULL);
220
221  for (i=0; i < SYM_HASH_BUCKETS ; i++)
222    SymbolHashAnchor[i] = NULL;
223
224  StabAreaP = (struct Stab *)malloc(MAX_STABS*sizeof(struct Stab));
225  assert(StabAreaP != NULL);
226
227  for (i=0; i < STAB_HASH_BUCKETS ; i++)
228    StabHashAnchor[i] = NULL;
229
230  AddUniqueSymbol(0, 0, "NULL");
231
232  if (!isCore)
233  {
234    /* Open /dev/kmem */
235#ifdef USE_KDUMP0
236    KmemHandle = open("/dev/kdump0", O_RDONLY, 0);
237#else
238    KmemHandle = open("/dev/kmem", O_RDONLY, 0);
239#endif
240    if (KmemHandle == -1)
241    {
242#ifdef USE_KDUMP0
243      fprintf(stderr, "Cannot open /dev/kdump0\n");
244#else
245      fprintf(stderr, "Cannot open /dev/kmem\n");
246#endif
247      perror("open");
248      exit(1);
249    }
250  }
251}
252
253/* Copy a string into the string storage area and return a
254 * pointer to the copy of the string
255 */
256static char * 
257CopyString(const char* p)
258{
259  char* newStrP = StringAreaP;
260  int len = strlen(p);
261
262  assert(len < StringAreaSizeLeft);
263  strcpy(newStrP, p);
264  StringAreaP += len+1;
265  StringAreaSizeLeft -= len+1;
266
267  return newStrP;
268}
269
270/* Hash function for symbol table names */
271static int 
272SymbolHash(const char* nameP)
273{
274  int i;
275  unsigned int hash = 0;
276  int len = strlen(nameP);
277
278  for (i=0 ; i<len ; i++)
279    hash = (hash << 4) ^ nameP[i];
280
281  return hash % SYM_HASH_BUCKETS;
282}
283
284/* Look up symbol by name.  Returns a pointer to the symbol table
285 * entry if a matching name is found, otherwise NULL.
286 */
287struct Symbol * 
288LookupSymbolByName(const char* nameP)
289{
290  struct Symbol* p;
291  int h = SymbolHash(nameP);
292
293  p = SymbolHashAnchor[h];
294  while (p != NULL)
295  {
296    if (strcmp(p->nameP, nameP) == 0)
297    {
298      DBG(printf("LookupSymbolByName: found '%s' addr 0x%lX\n", 
299                 nameP, p->addr));
300      return p;
301    }
302    p = p->hashNextP;
303  }
304  return NULL;
305}
306
307/* Add a symbol to the table.  The symbol name must not already be
308 * present.  Returns the address of the new symbol table entry.
309 */
310struct Symbol * 
311AddUniqueSymbol(unsigned long addr, int flags, char* nameP)
312{
313  struct Symbol* p;
314  int h = SymbolHash(nameP);
315
316  p = SymbolHashAnchor[h];
317  while (p != NULL)
318  {
319    if (strcmp(p->nameP, nameP) == 0)
320    {
321      fprintf(stderr, "Symbol %s already in table with addr 0x%lX\n"
322              "Failed to add symbol at addr 0x%lX\n", nameP, p->addr, addr);
323      assert(!"symbol not unique in AddUniqueSymbol");
324    }
325    p = p->hashNextP;
326  }
327
328  assert(NSymbols < MAX_SYMBOLS);
329  p = &SymbolAreaP[NSymbols];
330  NSymbols += 1;
331  p->addr = addr;
332  p->flags = flags;
333  p->nameP = CopyString(nameP);
334  p->hashNextP = SymbolHashAnchor[h];
335  SymbolHashAnchor[h] = p;
336  SymbolTableSorted = 0;
337
338  if (addr > HighSymbolAddr)
339    HighSymbolAddr = addr;
340
341  return p;
342}
343
344/* Add a symbol to the table.  If the symbol name is already present,
345 * append the address of the symbol to the symbol name to make it
346 * unique.  Returns the address of the new symbol table entry.
347 */
348struct Symbol * 
349AddSymbol(unsigned long addr, int flags, char* nameP)
350{
351  struct Symbol* p = LookupSymbolByName(nameP);
352  char* uniqueNameP;
353  int i;
354
355  if (p == NULL)
356    return AddUniqueSymbol(addr, flags, nameP);
357
358  uniqueNameP = (char*) malloc(strlen(nameP) + 32);
359  assert (uniqueNameP != NULL);
360  sprintf(uniqueNameP, "%s.%lX", nameP, addr);
361  for (i=1 ; ; i++)
362  {
363    p = LookupSymbolByName(uniqueNameP);
364    if (p == NULL)
365      break;
366    sprintf(uniqueNameP, "%s.%lX.%d", nameP, addr, i);
367  }
368
369  p = AddUniqueSymbol(addr, flags, uniqueNameP);
370  free(uniqueNameP);
371  return p;
372}
373
374/* Stab processing.  Creates structure name and member
375 * offsets for dump formatting.
376 */
377static int
378StabHash(const char *nameP)
379{
380  int i;
381  unsigned int hash = 0;
382  int len = strlen(nameP);
383
384  for (i=0 ; i<len ; i++)
385    hash = (hash << 4) ^ nameP[i];
386
387  return hash % STAB_HASH_BUCKETS;
388}
389
390/* Look up a structure definition in the stab hash table */
391struct Stab * 
392LookupStabByName(const char* nameP)
393{
394  struct Stab* p;
395  int h = StabHash(nameP);
396
397  p = StabHashAnchor[h];
398  while (p != NULL)
399  {
400    if (strcmp(p->nameP, nameP) == 0)
401    {
402      DBG(printf("LookupStabByName: found '%s'\n", nameP));
403      return p;
404    }
405    p = p->hashNextP;
406  }
407  return NULL;
408}
409
410struct Stab * 
411AllocStab(int boff, int blen, char *nameP)
412{
413  struct Stab* p;
414
415  assert(NStabs < MAX_STABS);
416  p = &StabAreaP[NStabs];
417  NStabs += 1;
418
419  p->boff = (unsigned short)boff;
420  p->blen = (unsigned short)blen;
421  p->nameP = CopyString(nameP);
422  p->memNextP = NULL;
423  p->hashNextP = NULL;
424
425  return p;
426}
427
428struct Stab *
429AddStab(struct Stab *stabP)
430{
431  struct Stab *p;
432  int h = StabHash(stabP->nameP);
433
434  DBG(printf("AddStab: name %s\n", stabP->nameP));
435
436  p = StabHashAnchor[h];
437  while (p != NULL)
438  {
439    if (strcmp(p->nameP, stabP->nameP) == 0)
440    {
441      fprintf(stderr, "Stab %s already in table.\n", p->nameP);
442      return NULL;
443    }
444    p = p->hashNextP;
445  }
446
447  stabP->hashNextP = StabHashAnchor[h];
448  StabHashAnchor[h] = stabP;
449
450  return StabHashAnchor[h];
451}
452
453/* Parse a stab string read from the output of "objdump --stabs <prog>" */
454void
455ParseStabString(char *lineP, regex_t *stabPatP, regex_t *namePatP,
456                regex_t *offPatP)
457{
458  int rc;
459  regmatch_t pmatch[8];
460  struct Stab *stabHeadP, *stabP, **tailPP;
461
462  /* Match this line against struct definition regexp */
463  rc = regexec(stabPatP, lineP, 8, pmatch, 0);
464  if (rc != 0)
465    return;
466  assert(pmatch[5].rm_so >= 0);
467
468  /* Extract struct name and length from matched patterns and use them to
469     create a Stab entry. */
470  lineP[pmatch[2].rm_eo] = '\0';
471  stabHeadP = AllocStab(0, atoi(&lineP[pmatch[4].rm_so]),
472                        &lineP[pmatch[2].rm_so]);
473  AddStab(stabHeadP);
474  tailPP = &stabHeadP->memNextP;
475
476  /* Parse structure member definitions */
477  lineP += pmatch[5].rm_so;
478  while (regexec(namePatP, lineP, 8, pmatch, 0) == 0)
479  {
480    /* Extract symbol name */
481    char *sym = &lineP[pmatch[1].rm_so];
482    lineP[pmatch[1].rm_eo] = '\0';
483    lineP += pmatch[0].rm_eo;
484    if (*lineP == '\0')
485      break;
486
487    /* Skip over embedded struct definitions.  We look for a double
488       semicolon to mark the end of the struct.  That's not correct if this
489       struct has another embedded struct, but it's good enough. */
490    if (strncmp(lineP, "=s", 2) == 0)
491    {
492      while (true)
493      {
494        char *p = strchr(lineP, ';');
495        if (p == NULL)
496          break;
497        lineP = p + 1;
498        if (*lineP == ';')
499        {
500          lineP++;
501          break;
502        }
503      }
504    }
505   
506    /* Extract offset and size */
507    rc = regexec(offPatP, lineP, 8, pmatch, 0);
508    if (rc != 0)
509      break;
510    assert(pmatch[2].rm_so >= 0);
511    lineP[pmatch[1].rm_eo] = '\0';
512
513    /* Create new stab entry for this struct member */
514    stabP = AllocStab(atoi(&lineP[pmatch[1].rm_so]),
515                      atoi(&lineP[pmatch[2].rm_so]),
516                      sym);
517    *tailPP = stabP;
518    tailPP = &stabP->memNextP;
519
520    lineP += pmatch[0].rm_eo;
521  }
522
523  DBG(printf("%s len %d\n", stabHeadP->nameP, stabHeadP->blen);
524      for (stabP = stabHeadP->memNextP; stabP != NULL; stabP = stabP->memNextP)
525        printf("%4d %4d  %s\n", stabP->boff, stabP->blen, stabP->nameP);
526     );
527}
528
529/* The kdump program is compiled with -gstabs+ and thus
530 * we run objdump against it to retrieve all the stabs info.
531 * Since kdump-kern.c also includes kernel headers we should
532 * have stabs info for all the relevent kernel structures.
533 */
534int
535GenerateStabs(char *stabProg)
536{
537  int rc;
538  FILE *fP;
539  regex_t stabPat, namePat, offPat;
540  char buff[512];
541  char *lineP;
542   
543  /* Sample struct definition line in objdump output:
544
545       523    LSYM   0      0      00000000 38929  timezone:T(94,3)=s8tz_minuteswest:(0,1),0,32;tz_dsttime:(0,1),32,32;;
546  */
547
548  /* Compile regexp for parsing a struct definition */
549  rc = regcomp(&stabPat,
550               "^[0-9]+[ \t]+"
551               "(LSYM|GSYM)[ \t]+"                // Only LSYM or GSYM lines
552               "[0-9]+[ \t]+"
553               "[0-9]+[ \t]+"
554               "[0-9a-zA-Z]+[ \t]+"
555               "[0-9]+[ \t]+"
556               "([a-zA-Z_][a-zA-Z0-9_]*)"         // Symbol name
557               ":T([0-9]+|\\([0-9]+,[0-9]+\\))=s" // Only struct definitions
558               "([0-9]+)"                         // Size of struct
559               "(.*)$",                           // Member definitions
560               REG_EXTENDED);
561  if (rc != 0)
562  {
563    regerror(rc, &stabPat, buff, sizeof(buff));
564    fprintf(stderr, "regcomp failed: %s\n", buff);
565    return -1;
566  }
567
568  /* Compile regexp for extracting symbol name from member definitions */
569  rc = regcomp(&namePat,
570               "([a-zA-Z_][a-zA-Z0-9_]*):"      // Symbol name
571               "([0-9]+|\\([0-9]+,[0-9]+\\))",  // Type number
572               REG_EXTENDED);
573  if (rc != 0)
574  {
575    regerror(rc, &namePat, buff, sizeof(buff));
576    fprintf(stderr, "regcomp failed: %s\n", buff);
577    return -1;
578  }
579
580  /* Compile regexp for extracting offset/size from member definition */
581  rc = regcomp(&offPat,
582               "([0-9]+),([0-9]+);",            // Bit offset, size
583               REG_EXTENDED);
584  if (rc != 0)
585  {
586    regerror(rc, &offPat, buff, sizeof(buff));
587    fprintf(stderr, "regcomp failed: %s\n", buff);
588    return -1;
589  }
590
591  snprintf(buff, sizeof(buff), "/usr/bin/objdump --stabs %s", stabProg);
592  DBG(printf("popen(%s)\n", buff));
593  fP = popen(buff, "r");
594  if (fP == NULL)
595  {
596    perror("popen()");
597    return -1;
598  }
599
600  lineP = malloc(1000000);
601  assert(lineP != NULL);
602
603  while (fgets(lineP, 1000000, fP) != NULL)
604    ParseStabString(lineP, &stabPat, &namePat, &offPat);
605
606  free(lineP);
607  pclose(fP);
608  regfree(&stabPat);
609  regfree(&namePat);
610  regfree(&offPat);
611  return 0;
612}
613
614/* Comparision routine used by SortSymbols.  Compares the addr fields
615 * of the Symbol objects reachable through the pointers given as arguments.
616 */
617static int 
618SymbolAddrCompare(const void* arg1P, const void* arg2P)
619{
620  struct Symbol** s1PP = (struct Symbol**) arg1P;
621  struct Symbol** s2PP = (struct Symbol**) arg2P;
622  unsigned long addr1 = (*s1PP)->addr;
623  unsigned long addr2 = (*s2PP)->addr;
624
625  if (addr1 < addr2) return -1;
626  if (addr1 > addr2) return 1;
627
628  return 0;
629}
630
631
632/* Build an up-to-date copy of the SymsByAddrPP array and sort it in order
633   by the addr fields of the associated symbols */
634static void SortSymbols()
635{
636  int i;
637
638  if (SymbolTableSorted)
639    return;
640
641  if (SymsByAddrPP != NULL)
642    free(SymsByAddrPP);
643
644  SymsByAddrPP = (struct Symbol**) malloc(NSymbols * sizeof(struct Symbol**));
645  assert(SymsByAddrPP != NULL);
646  for (i=0 ; i<NSymbols ; i++)
647    SymsByAddrPP[i] = &SymbolAreaP[i];
648
649  qsort((void*)SymsByAddrPP, NSymbols, sizeof(struct Symbol*), 
650        SymbolAddrCompare);
651  SymbolTableSorted = 1;
652}
653
654
655/* Look up symbol by address.  Returns a pointer to the symbol table entry
656   with the largest address that is less than or equal to the given
657   address.  There will always be a symbol in the table with address 0,
658   so this can always return a pointer to some Symbol object. */
659struct Symbol* LookupSymbolByAddr(unsigned long addr)
660{
661  int low, high, mid;
662  unsigned long addrMid;
663
664  SortSymbols();
665
666  /* Binary search */
667  low = 0;
668  high = NSymbols - 1;
669  while (low < high)
670  {
671    mid = (low+high+1) / 2;
672    addrMid = SymsByAddrPP[mid]->addr;
673    if (addrMid > addr)
674      high = mid - 1;
675    else
676      low = mid;
677  }
678  return SymsByAddrPP[low];
679}
680
681
682/* Look up a symbol by address.  If an exact match for the address is
683   found, return a pointer to the symbol name, otherwise return a pointer
684   to an empty string. */
685const char* ExactAddrToSymbol(unsigned long addr)
686{
687  static const char* emptyStringP = "";
688  struct Symbol* sP;
689
690  if (addr == 0)
691    return emptyStringP;
692  sP = LookupSymbolByAddr(addr);
693  if (sP == NULL)
694    return emptyStringP;
695  else
696    return sP->nameP;
697}
698
699
700/* Read in the map file containing kernel and kernel module symbols */
701static void ReadKernelMap(const char* filenameP)
702{
703  FILE* mapFileP;
704  char lineP[4096];
705  char* p;
706  int len;
707  int n;
708  unsigned long addr;
709  char flagChar;
710  int flags;
711  char symbolName[4096];
712
713  mapFileP = fopen(filenameP, "r");
714  if (mapFileP == NULL)
715  {
716    fprintf(stderr, "Cannot open kernel map file %s\n", filenameP);
717    exit(1);
718  }
719
720  for(;;)
721  {
722    p = fgets(lineP, sizeof(lineP), mapFileP);
723    if (p != lineP)
724      break;
725    len = strlen(lineP);
726    if (lineP[len-1] != '\n')
727    {
728      fprintf(stderr, "Line overflow reading map file: '%s'\n",
729              lineP);
730      exit(1);
731    }
732    /* Examples of input lines:
733       c0100000 A _text
734       c0314030 B vmlist
735       c88cc364 T lockStateToString__5LkObjUxPc
736     */
737    n = sscanf(lineP, "%lX %c %s\n", &addr, &flagChar, symbolName);
738    if (n != 3)
739    {
740      fprintf(stderr, "Parse error in map file: '%s'\n", lineP);
741      exit(1);
742    }
743    DBG(printf("map line: 0x%lX flag '%c' symbol '%s'\n",
744               addr, flagChar, symbolName));
745    switch (flagChar)
746    {
747      case 't':
748      case 'T':
749        flags = FL_TEXT;
750        break;
751
752      case 'b':
753      case 'B':
754        flags = FL_BSS;
755        break;
756
757      case 'd':
758      case 'D':
759        flags = FL_DATA;
760        break;
761
762      case 'r':
763      case 'R':
764        flags = FL_RODATA;
765        break;
766
767      case 'A':
768        flags = FL_SECTION;
769        break;
770
771      case '?':
772        flags = FL_KSTRTAB;
773        break;
774
775      default:
776        flags = 0;
777    }
778#ifdef GPFS_ARCH_PPC64
779    if (addr < 0xC000000000000000)
780      addr |= 0xd000000000000000L;
781#endif
782    AddSymbol(addr, flags, symbolName);
783  }
784  fclose(mapFileP);
785}
786
787
788/* Read kernel memory after checking the address for validity.  If the address
789   is invalid, return -1, otherwise return 0. */
790int ReadKernel(unsigned long addr, void* bufP, int len, int fMap)
791{
792  long long desiredOffset;
793  long long actualOffset;
794  int lenRead;
795  struct vmStruct* aListP;
796  int fd;
797
798  /* Check address for validity */
799  if (addr < LowKernelAddr)
800  {
801    DBG(printf("ReadKernel: addr 0x%lX < LowKernelAddr 0x%lX\n",
802               addr, LowKernelAddr));
803    return -1;
804  }
805  if (addr > HighKernelAddr || isCore)
806  {
807    aListP = vmListHeadP;
808    while (aListP != NULL)
809    {
810      if (addr >= aListP->startAddr  &&
811          addr+len < aListP->startAddr+aListP->areaLen)
812      {
813        DBG(printf("ReadKernel: addr 0x%lX in range starting at 0x%lX\n",
814                   addr, aListP->startAddr));
815        goto addrOK;
816      }
817      aListP = aListP->nextAreaP;
818    }
819    DBG(printf("ReadKernel: addr 0x%lX out of range\n", addr));
820    return -1;
821  }
822
823addrOK:
824  if (isCore)
825  {
826    desiredOffset = aListP->file_offset + (addr - aListP->startAddr);
827    fd = coreFD;
828  }
829  else
830  {
831    desiredOffset = addr - GetOffset(fMap);
832    fd = KmemHandle;
833  }
834
835  actualOffset = lseek64(fd, desiredOffset, SEEK_SET);
836  if (actualOffset != desiredOffset
837#ifdef GPFS_ARCH_PPC64
838      && actualOffset != (desiredOffset & 0x00000000FFFFFFFFL) )
839#else
840      )
841#endif
842  {
843    fprintf(stderr, "offset set to 0x%llX instead of 0x%llX\n",
844            actualOffset, desiredOffset);
845    perror("llseek");
846    exit(1);
847  }
848  lenRead = read(fd, bufP, len);
849  if (lenRead != len)
850  {
851    fprintf(stderr, "%d bytes read at addr 0x%lX\n", lenRead, addr);
852    if (lenRead == -1)
853      perror("read");
854    return -1;
855  }
856  return 0;
857}
858
859
860/* Read the current value of a kernel symbol.  Returns 0 on success, -1
861   on failure. */
862int GetSymbolValue(const char* nameP, void* bufP, int len)
863{
864  int rc;
865  struct Symbol* sP;
866  sP = LookupSymbolByName(nameP);
867  if (sP == NULL)
868    return -1;
869  rc = ReadKernel(sP->addr, bufP, len, 1);
870  DBG(if (len == sizeof(long))
871        printf("GetSymbolValue: symbol %s has value 0x%lX\n",
872               nameP, *((long*)bufP)));
873  return rc;
874}
875
876
877/* Wrapper around malloc so it can be called from modules that include
878   kernel files */
879void* kMalloc(int len)
880{
881  return malloc(len);
882}
883
884
885/* Wrapper around free so it can be called from modules that include
886   kernel files */
887void kFree(void* p)
888{
889  free(p);
890}
891
892
893/* Conditional free.  Free storage if p is not NULL. */
894void CondFree(void* p)
895{
896  if (p != NULL)
897    free(p);
898}
899
900
901/* Dump a block of memory.  Duplicate lines are supressed. */
902void 
903DumpMemory(char* p, int nBytes, unsigned long origin, int dumpFlags)
904{
905  char* origP;
906  union
907  {
908    unsigned char i1[16];
909    unsigned short i2[8];
910    unsigned int i4[4];
911    unsigned long long int i8[2];
912  } buf;
913  int row, col, lineLen, oLen;
914  char ch;
915  Boolean showedDots;
916  int i;
917  char line[128];
918
919  origP = p;
920  if (dumpFlags & DUMPMEM_ROUND)
921  {
922    p -= origin & 0x00000003;
923    nBytes += origP - p;
924    origin -= origP - p;
925  }
926  nBytes = 16 * ((nBytes+15) / 16);
927
928  buf.i1[0] = *p + 1;
929
930  showedDots = false;
931  for (row=0 ; row<nBytes/16 ; row++)
932  {
933    if (memcmp(p, &buf, 16) != 0)
934    {
935      memcpy(&buf, p, 16);
936
937      /* Dump label of this line.  Save length to indent later lines. */
938      lineLen = sprintf(line, "%p: ", origin + row*16);
939      oLen = lineLen;
940
941      /* Dump 16 bytes in hex, in address order */
942      lineLen += sprintf(line+lineLen,
943                         "%02x%02x%02x%02x %02x%02x%02x%02x "
944                         "%02x%02x%02x%02x %02x%02x%02x%02x  *",
945                         buf.i1[0], buf.i1[1], buf.i1[2], buf.i1[3],
946                         buf.i1[4], buf.i1[5], buf.i1[6], buf.i1[7],
947                         buf.i1[8], buf.i1[9], buf.i1[10], buf.i1[11],
948                         buf.i1[12], buf.i1[13], buf.i1[14], buf.i1[15]);
949
950      /* Dump 16 bytes as chars, translating unprintable chars to . */
951      for (col=0 ; col<16 ; col++)
952      {
953        ch = buf.i1[col];
954        if (!isalnum (ch)  &&
955            !ispunct (ch))
956          line[lineLen] = '.';
957        else
958        {
959          line[lineLen] = ch;
960          if (ch == '%')
961          {
962            lineLen += 1;
963            line[lineLen] = '%';
964          }
965        }
966        lineLen += 1;
967      }
968      sprintf(line+lineLen, "*\n");
969      printf(line);
970
971      /* If requested, dump 16 bytes as 8 shorts */
972      if (dumpFlags & DUMPMEM_I2)
973      {
974        for (i=0 ; i<oLen ; i++)
975          line[i] = ' ';
976        lineLen = oLen;
977        lineLen += sprintf(line+lineLen,
978                           "%04x %04x %04x %04x %04x %04x %04x %04x",
979                           buf.i2[0], buf.i2[1], buf.i2[2], buf.i2[3],
980                           buf.i2[4], buf.i2[5], buf.i2[6], buf.i2[7]);
981        sprintf(line+lineLen, "\n");
982        printf(line);
983      }
984
985      /* If requested, dump 16 bytes as 4 ints */
986      if (dumpFlags & DUMPMEM_I4)
987      {
988        for (i=0 ; i<oLen ; i++)
989          line[i] = ' ';
990        lineLen = oLen;
991        lineLen += sprintf(line+lineLen, "%08x %08x %08x %08x",
992                           buf.i4[0], buf.i4[1], buf.i4[2], buf.i4[3]);
993        sprintf(line+lineLen, "\n");
994        printf(line);
995      }
996
997      /* If requested, dump 16 bytes as 2 long long ints */
998      if (dumpFlags & DUMPMEM_I8)
999      {
1000        for (i=0 ; i<oLen ; i++)
1001          line[i] = ' ';
1002        lineLen = oLen;
1003        lineLen += sprintf(line+lineLen, "%016llx  %016llx",
1004                           buf.i8[0], buf.i8[1]);
1005        sprintf(line+lineLen, "\n");
1006        printf(line);
1007      }
1008
1009      showedDots = false;
1010    }
1011    else
1012    {
1013      if (!showedDots)
1014      {
1015        printf(" ...\n");
1016        showedDots = true;
1017      }
1018    }
1019    p += 16;
1020  }
1021
1022} /* end of DumpMemory */
1023
1024int
1025DumpMemoryCast(unsigned long addr, char *symNameP)
1026{
1027  union
1028  {
1029    unsigned char  i1[4];
1030    unsigned short i2[2];
1031    unsigned int   i4;
1032  } buf;
1033
1034  char *p, *kmemP;
1035  struct Stab *stabHeadP, *stabP;
1036  int rc, i, kmemLen, maxsym, indent, offchar, len, pos, toCopy, nwords;
1037
1038  stabHeadP = LookupStabByName(symNameP);
1039  if (stabHeadP == NULL)
1040  {
1041    fprintf(stderr, "Stab: %s not found\n", symNameP);
1042    return -1;
1043  }
1044
1045  kmemLen = stabHeadP->blen;
1046  kmemP = malloc(kmemLen);
1047  if (kmemP == NULL)
1048    return -1;
1049 
1050  rc = ReadKernel(addr, kmemP, kmemLen, 0);
1051  if (rc != 0)
1052  {
1053    fprintf(stderr, "Error reading from 0x%lX for %d bytes\n", addr, kmemLen);
1054    goto xerror;
1055  }
1056
1057  maxsym = 0;
1058  for (stabP = stabHeadP->memNextP; stabP != NULL; stabP = stabP->memNextP)
1059    if (strlen(stabP->nameP) > maxsym)
1060      maxsym = strlen(stabP->nameP);
1061  if (maxsym > 30)
1062    maxsym = 30;
1063  indent = maxsym + 2;
1064
1065  for (stabP = stabHeadP->memNextP; stabP != NULL; stabP = stabP->memNextP)
1066  {
1067    offchar = stabP->boff / 8;
1068    if (offchar >= kmemLen)
1069      continue;
1070
1071    len = (stabP->blen + 7) / 8;
1072    if (offchar + len > kmemLen)
1073      len = kmemLen - offchar;
1074
1075    printf(" %s ", stabP->nameP);
1076
1077    pos = strlen(stabP->nameP) + 2;
1078    i = (pos < indent) ? indent - pos
1079      : (pos - indent) % 9 == 0 ? 0
1080      : 9 - (pos - indent) % 9;
1081    printf("%*.0s", i, "");
1082    pos += i;
1083    nwords = 0;
1084
1085    p = kmemP + offchar;
1086    while (len > 0)
1087    {
1088      toCopy = (len > 4) ? 4 : len;
1089
1090      memcpy(&buf, p, toCopy);
1091      p += toCopy;
1092      len -= toCopy;
1093   
1094      if (nwords >= 6 || pos > 70)
1095      {
1096        printf("\n%*.0s", indent, "");
1097        pos = indent;
1098        nwords = 0;
1099      }
1100
1101      if (nwords > 0)
1102        printf(" ");
1103
1104      if (toCopy == 4)
1105      {
1106        printf("%08x", buf.i4);
1107        pos += 9;
1108        nwords++;
1109      }
1110      else if (toCopy == 2)
1111      {
1112        printf("%04x", buf.i2[0]);
1113      }
1114      else
1115      {
1116        for (i = 0; i < toCopy; i++)
1117          printf("%02x ", buf.i1[i]);
1118      }
1119    }
1120    printf("\n");
1121  }
1122
1123xerror:
1124  free(kmemP);
1125  return rc;
1126}
1127
1128/* Convert a hex string to a number.  Sets *rcP to 0 if successful, nonzero
1129   otherwise */
1130static unsigned long GetHex(const char* argP, int* rcP)
1131{
1132  char* p = NULL;
1133  unsigned long result;
1134
1135  result = strtoul(argP, &p, 16);
1136  if (*p != '\0')
1137    *rcP = 1;
1138  else
1139    *rcP = 0;
1140  DBG(printf("strtoul argP 0x%lX arg '%s' result 0x%lX p 0x%lX *rcP %d\n",
1141             argP, argP, result, p, *rcP));
1142  return result;
1143}
1144
1145
1146/* Print a GPFS cxiNode_t.  Parameter may be NULL. */
1147void 
1148PrintCxiNode_t(void* parm, unsigned long addr)
1149{
1150  cxiNode_t* cP = (cxiNode_t*) parm;
1151
1152  if (cP == NULL)
1153  {
1154    fprintf(stderr, "NULL cxiNode_t\n");
1155    return;
1156  }
1157
1158  printf("cxiNode_t 0x%lX:\n", addr);
1159
1160  printf("  osNodeP         inode 0x%lX\n", cP->osNodeP);
1161  printf("  nType           %s\n",
1162         cP->nType == cxiVNON  ? "cxiVNON" :
1163         cP->nType == cxiVREG  ? "cxiVREG" :
1164         cP->nType == cxiVDIR  ? "cxiVDIR" :
1165         cP->nType == cxiVBLK  ? "cxiVBLK" :
1166         cP->nType == cxiVCHR  ? "cxiVCHR" :
1167         cP->nType == cxiVLNK  ? "cxiVLNK" :
1168         cP->nType == cxiVSOCK ? "cxiVSOCK" :
1169         cP->nType == cxiVBAD  ? "cxiVBAD" :
1170         cP->nType == cxiVFIFO ? "cxiVFIFO" :
1171         cP->nType == cxiVMPC  ? "cxiVMPC" :
1172         "??");
1173  printf("  mapReadCount      %d\n", cP->mapReadCount);
1174  printf("  mapWriteCount     %d\n", cP->mapWriteCount);
1175  printf("  readCount         %d\n", cP->readCount);
1176  printf("  icValid           0x%X", cP->icValid);
1177  if (cP->icValid & CXI_IC_PERM) printf(" CXI_IC_PERM");
1178  if (cP->icValid & CXI_IC_ATTR) printf(" CXI_IC_ATTR");
1179  printf("\n");
1180  printf("  xinfo             0x%X\n", cP->xinfo);
1181  printf("  nfsP              0x%lX\n", cP->nfsP);
1182  printf("  ctFlags           %d\n", cP->ctFlags);
1183}
1184
1185void openCore(char* corefile)
1186{
1187  coreFD = open(corefile, O_RDONLY, 0);
1188  if (coreFD == -1)
1189  {
1190    fprintf(stderr, "Cannot open kernel core file %s\n", corefile);
1191    perror("open");
1192    exit(1);
1193  }
1194}
1195
1196void readCore(void* bufP, int len)
1197{
1198  int lenActual;
1199
1200  assert(coreFD != -1);
1201  lenActual = read(coreFD, bufP, len);
1202  if (len != lenActual)
1203  {
1204    fprintf(stderr,
1205      "Error trying to read %d bytes from core, only %d bytes read\n",
1206      len, lenActual);
1207    perror("read");
1208    exit(1);
1209  }
1210}
1211
1212void seekCore(off_t pos)
1213{
1214  off_t curPos; 
1215 
1216  assert(coreFD != -1);
1217
1218  curPos = lseek(coreFD, pos, SEEK_SET);
1219  if (curPos != pos)
1220  {
1221    fprintf(stderr,
1222      "Error trying to seek to pos %X in core, current pos %X\n",
1223      pos, curPos);
1224    perror("seek");
1225    exit(1);
1226  }
1227}
1228
1229
1230static void Usage()
1231{
1232  fprintf(stderr, "Usage: kdump map-file [corefile]\n");
1233  exit(1);
1234}
1235
1236static void DoHelp()
1237{
1238  printf("Commands:\n"
1239    "  address_space addr  - dump address_space\n"
1240    "  cxiNode_t addr      - dump cxiNode_t\n"
1241    "  dentry addr         - dump dcache dentry\n"
1242    "  dentry_tree addr    - show dcache dentry and all of its descendants\n"
1243    "  fs addr             - dump fs_struct \n"
1244    "  inode addr          - dump inode\n"
1245    "  mm_struct addr      - dump mm_struct\n"
1246    "  page addr           - dump struct page\n"
1247    "  pgd addr vaddr      - translate vaddr using pgd at addr\n"
1248    "  super_block [addr]  - dump super_block (if no addr: root superblock)\n"
1249    "  task pid            - dump task_struct for pid\n"
1250    "  task_struct addr    - dump task_struct\n"
1251    "  vfsmount addr       - dump vfsmount struct\n"
1252    "  vfsmount_list addr  - dump all vfsmount structs starting with addr\n"
1253    "  vm_area_struct addr - dump vm_area_struct\n"
1254    "  mem addr len        - dump memory at addr\n"
1255    "  mem addr stab       - dump memory formatted to stab struct name\n"
1256    "  mem symbol len      - dump memory at address of symbol\n"
1257    "  ps                  - display the list of running processes\n"
1258    "  btp pid             - display kernel stack traceback for process pid\n"
1259    "  bta                 - display stack tracebacks for all processes\n"
1260    "  q                   - quit\n");
1261}
1262
1263main(int argc, char* argvPP[])
1264{
1265  struct Symbol* sP;
1266  char lineP[1024];
1267  char* p;
1268  char* cmdP;
1269  char* arg1P;
1270  char* arg2P;
1271  char* arg3P;
1272  char* arg4P;
1273  char* arg5P;
1274  unsigned long addr;
1275  unsigned long vaddr;
1276  unsigned long pid;
1277  int len;
1278  void* x;
1279  int rc;
1280  FILE *outfp = NULL;
1281
1282  if (argc < 2)
1283    Usage();
1284
1285  if (argc == 3)
1286    ReadKernelCore(argvPP[2]);
1287
1288  Init();
1289  ReadKernelMap(argvPP[1]);
1290  GenerateStabs(argvPP[0]);
1291  KernInit();
1292
1293  for (;;)
1294  {
1295    if (outfp)
1296    {
1297      cmdpclose(outfp);
1298      outfp = NULL;
1299    }
1300
1301    printf("> ");
1302    p = fgets(lineP, sizeof(lineP), stdin);
1303    if (p == NULL)
1304      break;
1305
1306    p = lineP;
1307    while (isspace(*p)) p += 1;
1308    if (*p == '\0')
1309      continue;
1310
1311    cmdP = strtok(lineP, " \t\n");
1312    arg1P = strtok(NULL, " \t\n");
1313    arg2P = strtok(NULL, " \t\n");
1314    arg3P = strtok(NULL, " \t\n");
1315    arg4P = strtok(NULL, " \t\n");
1316    arg5P = strtok(NULL, " \t\n");
1317
1318    if (arg1P && *arg1P == '|' && arg2P)
1319    {
1320      outfp = cmdpopen(arg2P);
1321      arg1P = arg2P = arg3P = arg4P = arg5P = NULL;
1322    }
1323    else if (arg2P && *arg2P == '|' && arg3P)
1324    {
1325      outfp = cmdpopen(arg3P);
1326      arg2P = arg3P = arg4P = arg5P = NULL;
1327    }
1328    else if (arg3P && *arg3P == '|' && arg4P)
1329    {
1330      outfp = cmdpopen(arg4P);
1331      arg3P = arg4P = arg5P = NULL;
1332    }
1333    else if (arg4P && *arg4P == '|' && arg5P)
1334    {
1335      outfp = cmdpopen(arg5P);
1336      arg4P = arg5P = NULL;
1337    }
1338
1339    if (strcmp(cmdP, "?") == 0)
1340      DoHelp();
1341
1342    else if (strcmp(cmdP, "q") == 0)
1343      break;
1344
1345    else if (strcmp(cmdP, "quit") == 0)
1346      break;
1347
1348    else if (strcmp(cmdP, "address_space") == 0)
1349    {
1350      if (arg1P == NULL)
1351      {
1352        DoHelp();
1353        continue;
1354      }
1355
1356      addr = strtoul(arg1P, NULL, 16);
1357      x = GetAddressSpace(addr);
1358      PrintAddressSpace(x, addr);
1359      CondFree(x);
1360    }
1361    else if (strcmp(cmdP, "cxiNode_t") == 0)
1362    {
1363      if (arg1P == NULL)
1364      {
1365        DoHelp();
1366        continue;
1367      }
1368
1369      addr = strtoul(arg1P, NULL, 16);
1370      x = GenericGet(addr, sizeof(cxiNode_t), 0);
1371      PrintCxiNode_t(x, addr);
1372      CondFree(x);
1373    }
1374    else if (strcmp(cmdP, "dentry") == 0)
1375    {
1376      if (arg1P == NULL)
1377      {
1378        DoHelp();
1379        continue;
1380      }
1381
1382      addr = strtoul(arg1P, NULL, 16);
1383      x = GetDentry(addr);
1384      PrintDentry(x, addr);
1385      FreeDentry(x);
1386    }
1387    else if (strcmp(cmdP, "dentry_tree") == 0)
1388    {
1389      if (arg1P == NULL)
1390      {
1391        DoHelp();
1392        continue;
1393      }
1394
1395      addr = strtoul(arg1P, NULL, 16);
1396      x = GetDentry(addr);
1397      PrintDentryTree(x, addr);
1398      FreeDentry(x);
1399    }
1400    else if (strcmp(cmdP, "inode") == 0)
1401    {
1402      if (arg1P == NULL)
1403      {
1404        DoHelp();
1405        continue;
1406      }
1407
1408      addr = strtoul(arg1P, NULL, 16);
1409      x = GetInode(addr);
1410      PrintInode(x, addr);
1411      CondFree(x);
1412    }
1413    else if (strcmp(cmdP, "vfsmount") == 0)
1414    {
1415      if (arg1P == NULL)
1416      {
1417        DoHelp();
1418        continue;
1419      }
1420
1421      addr = strtoul(arg1P, NULL, 16);
1422      x = GetVFSMount(addr);
1423      PrintVFSMount(x, addr);
1424      CondFree(x);
1425    }
1426    else if (strcmp(cmdP, "vfsmount_list") == 0)
1427    {
1428      if (arg1P == NULL)
1429      {
1430        DoHelp();
1431        continue;
1432      }
1433
1434      addr = strtoul(arg1P, NULL, 16);
1435      x = GetVFSMount(addr);
1436      PrintVFSMountList(x, addr);
1437      CondFree(x);
1438    }
1439    else if (strcmp(cmdP, "fs") == 0)
1440    {
1441      if (arg1P == NULL)
1442      {
1443        DoHelp();
1444        continue;
1445      }
1446
1447      addr = strtoul(arg1P, NULL, 16);
1448      x = GetFSStruct(addr);
1449      PrintFSStruct(x, addr);
1450      CondFree(x);
1451    }
1452    else if (strcmp(cmdP, "mem") == 0)
1453    {
1454      int fMap = 0;
1455      if (arg1P == NULL || arg2P == NULL)
1456      {
1457        DoHelp();
1458        continue;
1459      }
1460
1461      sP = LookupSymbolByName(arg1P);
1462      if (sP != NULL)
1463      {
1464        addr = sP->addr;
1465        fMap = 1;
1466      }
1467      else
1468      {
1469        addr = GetHex(arg1P, &rc);
1470        if (rc != 0)
1471        {
1472          fprintf(stderr, "Bad address %s\n", arg1P);
1473          continue;
1474        }
1475      }
1476
1477      if (isalpha(arg2P[0]))
1478        DumpMemoryCast(addr, arg2P);
1479      else
1480      {
1481        len = strtol(arg2P, NULL, 0);
1482        x = malloc(len);
1483        if (x != NULL)
1484        {
1485          rc = ReadKernel(addr, x, len, fMap);
1486          if (rc != 0)
1487            fprintf(stderr, "Error reading from 0x%lX for %d bytes\n", 
1488                    addr, len);
1489          else
1490            DumpMemory((char*)x, len, addr, DUMPMEM_I4);
1491          free(x);
1492        }
1493      }
1494    }
1495    else if (strcmp(cmdP, "mm_struct") == 0)
1496    {
1497      if (arg1P == NULL)
1498      {
1499        DoHelp();
1500        continue;
1501      }
1502
1503      addr = strtoul(arg1P, NULL, 16);
1504      x = GetMMStruct(addr);
1505      PrintMMStruct(x, addr);
1506      CondFree(x);
1507    }
1508    else if (strcmp(cmdP, "page") == 0)
1509    {
1510      if (arg1P == NULL)
1511      {
1512        DoHelp();
1513        continue;
1514      }
1515
1516      addr = strtoul(arg1P, NULL, 16);
1517      x = GetPage(addr);
1518      PrintPage(x, addr);
1519      CondFree(x);
1520    }
1521    else if (strcmp(cmdP, "pgd") == 0)
1522    {
1523      if (arg1P == NULL || arg2P == NULL)
1524      {
1525        DoHelp();
1526        continue;
1527      }
1528
1529      addr = strtoul(arg1P, NULL, 16);
1530      vaddr = strtoul(arg2P, NULL, 16);
1531      VirtToReal(addr, vaddr);
1532    }
1533    else if (strcmp(cmdP, "task") == 0)
1534    {
1535      if (arg1P == NULL)
1536      {
1537        DoHelp();
1538        continue;
1539      }
1540
1541      pid = strtoul(arg1P, NULL, 10);
1542      x = GetTaskStructByPID(pid, &addr);
1543      if (x != NULL)
1544      {
1545        PrintTaskStruct(x, addr);
1546        CondFree(x);
1547      }
1548    }
1549    else if (strcmp(cmdP, "task_struct") == 0)
1550    {
1551      addr = strtoul(arg1P, NULL, 16);
1552      x = GetTaskStruct(addr);
1553      PrintTaskStruct(x, addr);
1554      CondFree(x);
1555    }
1556    else if (strcmp(cmdP, "super_block") == 0)
1557    {
1558      if (arg1P != NULL)
1559      {
1560        addr = strtoul(arg1P, NULL, 16);
1561        x = GetSuperBlock(addr);
1562      }
1563      else
1564        x = GetRootSuperBlock(&addr);
1565      PrintSuperBlock(x, addr);
1566      CondFree(x);
1567    }
1568    else if (strcmp(cmdP, "vm_area_struct") == 0)
1569    {
1570      if (arg1P == NULL)
1571      {
1572        DoHelp();
1573        continue;
1574      }
1575
1576      addr = strtoul(arg1P, NULL, 16);
1577      x = GetVMAreaStruct(addr);
1578      PrintVMAreaStruct(x, addr);
1579      CondFree(x);
1580    }
1581    else if (strcmp(cmdP, "ps") == 0)
1582    {
1583      DoPs();
1584    }
1585    else if (strcmp(cmdP, "btp") == 0)
1586    {
1587      if (arg1P == NULL)
1588      {
1589        DoHelp();
1590        continue;
1591      }
1592
1593      pid = atoi(arg1P);
1594      BacktracePid(pid);
1595    }
1596    else if (strcmp(cmdP, "bta") == 0)
1597    {
1598      BacktraceAll();
1599    }
1600    else
1601      fprintf(stderr, "Bad command '%s'\n", cmdP);
1602  }
1603}
Note: See TracBrowser for help on using the repository browser.