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 | */ |
---|
84 | char* StringAreaP = NULL; |
---|
85 | #define STRING_AREA_SIZE (4*1024*1024) |
---|
86 | int 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 | */ |
---|
93 | int NSymbols = 0; |
---|
94 | int SymbolTableSorted = 0; |
---|
95 | |
---|
96 | #define MAX_SYMBOLS (128*1024) |
---|
97 | struct Symbol* SymbolAreaP = NULL; |
---|
98 | struct Symbol** SymsByAddrPP = NULL; |
---|
99 | |
---|
100 | #define SYM_HASH_BUCKETS 4093 |
---|
101 | struct Symbol* SymbolHashAnchor[SYM_HASH_BUCKETS]; |
---|
102 | |
---|
103 | /* Stab area. Structure sizes and member offset for |
---|
104 | * dump data formatting. |
---|
105 | */ |
---|
106 | int NStabs = 0; |
---|
107 | #define MAX_STABS (128*1024) |
---|
108 | struct Stab *StabAreaP = NULL; |
---|
109 | |
---|
110 | #define STAB_HASH_BUCKETS 4093 |
---|
111 | struct Stab* StabHashAnchor[STAB_HASH_BUCKETS]; |
---|
112 | |
---|
113 | /* Handle of /dev/kmem */ |
---|
114 | int 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. */ |
---|
119 | unsigned long LowKernelAddr = 4096; |
---|
120 | unsigned long HighKernelAddr = -1L; |
---|
121 | |
---|
122 | unsigned 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. */ |
---|
127 | struct vmStruct* vmListHeadP = NULL; |
---|
128 | |
---|
129 | /* Are we reading a core file or /dev/kmem ? */ |
---|
130 | int isCore = 0; |
---|
131 | |
---|
132 | /* core file descriptor */ |
---|
133 | int coreFD = -1; |
---|
134 | |
---|
135 | int savefdout = -1; |
---|
136 | int 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 | |
---|
145 | void |
---|
146 | cmdpclose(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 | |
---|
174 | FILE * |
---|
175 | cmdpopen(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 */ |
---|
206 | void 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 | */ |
---|
256 | static char * |
---|
257 | CopyString(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 */ |
---|
271 | static int |
---|
272 | SymbolHash(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 | */ |
---|
287 | struct Symbol * |
---|
288 | LookupSymbolByName(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 | */ |
---|
310 | struct Symbol * |
---|
311 | AddUniqueSymbol(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 | */ |
---|
348 | struct Symbol * |
---|
349 | AddSymbol(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 | */ |
---|
377 | static int |
---|
378 | StabHash(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 */ |
---|
391 | struct Stab * |
---|
392 | LookupStabByName(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 | |
---|
410 | struct Stab * |
---|
411 | AllocStab(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 | |
---|
428 | struct Stab * |
---|
429 | AddStab(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>" */ |
---|
454 | void |
---|
455 | ParseStabString(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 | */ |
---|
534 | int |
---|
535 | GenerateStabs(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 | */ |
---|
617 | static int |
---|
618 | SymbolAddrCompare(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 */ |
---|
634 | static 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. */ |
---|
659 | struct 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. */ |
---|
685 | const 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 */ |
---|
701 | static 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. */ |
---|
790 | int 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 | |
---|
823 | addrOK: |
---|
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. */ |
---|
862 | int 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 */ |
---|
879 | void* 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 */ |
---|
887 | void kFree(void* p) |
---|
888 | { |
---|
889 | free(p); |
---|
890 | } |
---|
891 | |
---|
892 | |
---|
893 | /* Conditional free. Free storage if p is not NULL. */ |
---|
894 | void CondFree(void* p) |
---|
895 | { |
---|
896 | if (p != NULL) |
---|
897 | free(p); |
---|
898 | } |
---|
899 | |
---|
900 | |
---|
901 | /* Dump a block of memory. Duplicate lines are supressed. */ |
---|
902 | void |
---|
903 | DumpMemory(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 | |
---|
1024 | int |
---|
1025 | DumpMemoryCast(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 | |
---|
1123 | xerror: |
---|
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 */ |
---|
1130 | static 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. */ |
---|
1147 | void |
---|
1148 | PrintCxiNode_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 | |
---|
1185 | void 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 | |
---|
1196 | void 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 | |
---|
1212 | void 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 | |
---|
1230 | static void Usage() |
---|
1231 | { |
---|
1232 | fprintf(stderr, "Usage: kdump map-file [corefile]\n"); |
---|
1233 | exit(1); |
---|
1234 | } |
---|
1235 | |
---|
1236 | static 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 | |
---|
1263 | main(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 | } |
---|