Whamcloud - gitweb
a4376fda403fb0fd5b6c2bf24e080564a92108d0
[fs/lustre-release.git] / lnet / utils / debug.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lnet/utils/debug.c
37  * Some day I'll split all of this functionality into a cfs_debug module
38  * of its own. That day is not today.
39  */
40
41 #define __USE_FILE_OFFSET64
42 #ifndef _GNU_SOURCE
43 #define  _GNU_SOURCE
44 #endif
45
46 #include <stdio.h>
47 #ifdef HAVE_NETDB_H
48 #include <netdb.h>
49 #endif
50 #include <stdlib.h>
51 #include <string.h>
52 #ifdef HAVE_SYS_IOCTL_H
53 #include <sys/ioctl.h>
54 #endif
55 #ifndef _IOWR
56 #include "ioctl.h"
57 #endif
58 #include <fcntl.h>
59 #include <errno.h>
60 #include <unistd.h>
61 #include <assert.h>
62
63 #include <sys/types.h>
64 #include <sys/socket.h>
65 #include <sys/stat.h>
66 #include <sys/mman.h>
67 #include <sys/utsname.h>
68
69 #include <libcfs/libcfsutil.h>
70 #include <lnet/lnetctl.h>
71 #include <libcfs/portals_utils.h>
72
73 #include <time.h>
74
75 static char rawbuf[8192];
76 static char *buf = rawbuf;
77 static int max = 8192;
78 /*static int g_pfd = -1;*/
79 static int subsystem_mask = ~0;
80 static int debug_mask = ~0;
81
82 #define MAX_MARK_SIZE 256
83
84 static const char *libcfs_debug_subsystems[] =
85         {"undefined", "mdc", "mds", "osc",
86          "ost", "class", "log", "llite",
87          "rpc", "mgmt", "lnet", "lnd",
88          "pinger", "filter", "", "echo",
89          "ldlm", "lov", "", "",
90          "", "", "", "lmv",
91          "", "sec", "gss", "", 
92          "mgc", "mgs", "fid", "fld", NULL};
93 static const char *libcfs_debug_masks[] =
94         {"trace", "inode", "super", "ext2",
95          "malloc", "cache", "info", "ioctl",
96          "neterror", "net", "warning", "buffs",
97          "other", "dentry", "nettrace", "page",
98          "dlmtrace", "error", "emerg", "ha",
99          "rpctrace", "vfstrace", "reada", "mmap",
100          "config", "console", "quota", "sec", NULL};
101
102 #ifdef __linux__
103
104 #define DAEMON_CTL_NAME         "/proc/sys/lnet/daemon_file"
105 #define SUBSYS_DEBUG_CTL_NAME   "/proc/sys/lnet/subsystem_debug"
106 #define DEBUG_CTL_NAME          "/proc/sys/lnet/debug"
107 #define DUMP_KERNEL_CTL_NAME    "/proc/sys/lnet/dump_kernel"
108
109 static int
110 dbg_open_ctlhandle(const char *str)
111 {
112         int fd;
113         fd = open(str, O_WRONLY);
114         if (fd < 0) {
115                 fprintf(stderr, "open %s failed: %s\n", str,
116                         strerror(errno));
117                 return -1;
118         }
119         return fd;
120 }
121
122 static void
123 dbg_close_ctlhandle(int fd)
124 {
125         close(fd);
126 }
127
128 static int
129 dbg_write_cmd(int fd, char *str, int len)
130 {
131         int    rc  = write(fd, str, len);
132
133         return (rc == len ? 0 : 1);
134 }
135
136 #elif defined(__DARWIN__)
137
138 #define DAEMON_CTL_NAME         "lnet.trace_daemon"
139 #define SUBSYS_DEBUG_CTL_NAME   "lnet.subsystem_debug"
140 #define DEBUG_CTL_NAME          "lnet.debug"
141 #define DUMP_KERNEL_CTL_NAME    "lnet.trace_dumpkernel"
142
143 static char     sysctl_name[128];
144 static int
145 dbg_open_ctlhandle(const char *str)
146 {
147
148         if (strlen(str)+1 > 128) {
149                 fprintf(stderr, "sysctl name is too long: %s.\n", str);
150                 return -1;
151         }
152         strcpy(sysctl_name, str);
153
154         return 0;
155 }
156
157 static void
158 dbg_close_ctlhandle(int fd)
159 {
160         sysctl_name[0] = '\0';
161         return;
162 }
163
164 static int
165 dbg_write_cmd(int fd, char *str, int len)
166 {
167         int     rc;
168
169         rc = sysctlbyname(sysctl_name, NULL, NULL, str, len+1);
170         if (rc != 0) {
171                 fprintf(stderr, "sysctl %s with cmd (%s) error: %d\n",
172                         sysctl_name, str, errno);
173         }
174         return (rc == 0 ? 0: 1);
175 }
176
177 #else
178 #error - Unknown sysctl convention.
179 #endif
180
181 static int do_debug_mask(char *name, int enable)
182 {
183         int found = 0, i;
184
185         for (i = 0; libcfs_debug_subsystems[i] != NULL; i++) {
186                 if (strcasecmp(name, libcfs_debug_subsystems[i]) == 0 ||
187                     strcasecmp(name, "all_subs") == 0) {
188                         printf("%s output from subsystem \"%s\"\n",
189                                 enable ? "Enabling" : "Disabling",
190                                 libcfs_debug_subsystems[i]);
191                         if (enable)
192                                 subsystem_mask |= (1 << i);
193                         else
194                                 subsystem_mask &= ~(1 << i);
195                         found = 1;
196                 }
197         }
198         for (i = 0; libcfs_debug_masks[i] != NULL; i++) {
199                 if (strcasecmp(name, libcfs_debug_masks[i]) == 0 ||
200                     strcasecmp(name, "all_types") == 0) {
201                         printf("%s output of type \"%s\"\n",
202                                 enable ? "Enabling" : "Disabling",
203                                 libcfs_debug_masks[i]);
204                         if (enable)
205                                 debug_mask |= (1 << i);
206                         else
207                                 debug_mask &= ~(1 << i);
208                         found = 1;
209                 }
210         }
211
212         return found;
213 }
214
215 int dbg_initialize(int argc, char **argv)
216 {
217         return 0;
218 }
219
220 int jt_dbg_filter(int argc, char **argv)
221 {
222         int   i;
223
224         if (argc < 2) {
225                 fprintf(stderr, "usage: %s <subsystem ID or debug mask>\n",
226                         argv[0]);
227                 return 0;
228         }
229
230         for (i = 1; i < argc; i++)
231                 if (!do_debug_mask(argv[i], 0))
232                         fprintf(stderr, "Unknown subsystem or debug type: %s\n",
233                                 argv[i]);
234         return 0;
235 }
236
237 int jt_dbg_show(int argc, char **argv)
238 {
239         int    i;
240
241         if (argc < 2) {
242                 fprintf(stderr, "usage: %s <subsystem ID or debug mask>\n",
243                         argv[0]);
244                 return 0;
245         }
246
247         for (i = 1; i < argc; i++)
248                 if (!do_debug_mask(argv[i], 1))
249                         fprintf(stderr, "Unknown subsystem or debug type: %s\n",
250                                 argv[i]);
251
252         return 0;
253 }
254
255 static int applymask(char* procpath, int value)
256 {
257         int rc;
258         char buf[64];
259         int len = snprintf(buf, 64, "%d", value);
260
261         int fd = dbg_open_ctlhandle(procpath);
262         if (fd == -1) {
263                 fprintf(stderr, "Unable to open %s: %s\n",
264                         procpath, strerror(errno));
265                 return fd;
266         }
267         rc = dbg_write_cmd(fd, buf, len+1);
268         if (rc != 0) {
269                 fprintf(stderr, "Write to %s failed: %s\n",
270                         procpath, strerror(errno));
271                 return rc;
272         }
273         dbg_close_ctlhandle(fd);
274         return 0;
275 }
276
277 static void applymask_all(unsigned int subs_mask, unsigned int debug_mask)
278 {
279         if (!dump_filename) {
280                 applymask(SUBSYS_DEBUG_CTL_NAME, subs_mask);
281                 applymask(DEBUG_CTL_NAME, debug_mask);
282         } else {
283                 struct libcfs_debug_ioctl_data data;
284
285                 data.hdr.ioc_len = sizeof(data);
286                 data.hdr.ioc_version = 0;
287                 data.subs = subs_mask;
288                 data.debug = debug_mask;
289
290                 dump(OBD_DEV_ID, LIBCFS_IOC_DEBUG_MASK, &data);
291         }
292         printf("Applied subsystem_debug=%d, debug=%d to /proc/sys/lnet\n",
293                subs_mask, debug_mask);
294 }
295
296 int jt_dbg_list(int argc, char **argv)
297 {
298         int i;
299
300         if (argc != 2) {
301                 fprintf(stderr, "usage: %s <subs || types>\n", argv[0]);
302                 return 0;
303         }
304
305         if (strcasecmp(argv[1], "subs") == 0) {
306                 printf("Subsystems: all_subs");
307                 for (i = 0; libcfs_debug_subsystems[i] != NULL; i++)
308                         if (libcfs_debug_subsystems[i][0])
309                                 printf(", %s", libcfs_debug_subsystems[i]);
310                 printf("\n");
311         } else if (strcasecmp(argv[1], "types") == 0) {
312                 printf("Types: all_types");
313                 for (i = 0; libcfs_debug_masks[i] != NULL; i++)
314                         printf(", %s", libcfs_debug_masks[i]);
315                 printf("\n");
316         } else if (strcasecmp(argv[1], "applymasks") == 0) {
317                 applymask_all(subsystem_mask, debug_mask);
318         }
319         return 0;
320 }
321
322 /* all strings nul-terminated; only the struct and hdr need to be freed */
323 struct dbg_line {
324         struct ptldebug_header *hdr;
325         char *file;
326         char *fn;
327         char *text;
328 };
329
330 static int cmp_rec(const void *p1, const void *p2)
331 {
332         struct dbg_line *d1 = *(struct dbg_line **)p1;
333         struct dbg_line *d2 = *(struct dbg_line **)p2;
334
335         if (d1->hdr->ph_sec < d2->hdr->ph_sec)
336                 return -1;
337         if (d1->hdr->ph_sec == d2->hdr->ph_sec &&
338             d1->hdr->ph_usec < d2->hdr->ph_usec)
339                 return -1;
340         if (d1->hdr->ph_sec == d2->hdr->ph_sec &&
341             d1->hdr->ph_usec == d2->hdr->ph_usec)
342                 return 0;
343         return 1;
344 }
345
346 static void print_rec(struct dbg_line **linev, int used, FILE *out)
347 {
348         int i;
349
350         for (i = 0; i < used; i++) {
351                 struct dbg_line *line = linev[i];
352                 struct ptldebug_header *hdr = line->hdr;
353
354                 fprintf(out, "%08x:%08x:%u:%u.%06llu:%u:%u:%u:(%s:%u:%s()) %s",
355                         hdr->ph_subsys, hdr->ph_mask, hdr->ph_cpu_id,
356                         hdr->ph_sec, (unsigned long long)hdr->ph_usec,
357                         hdr->ph_stack, hdr->ph_pid, hdr->ph_extern_pid,
358                         line->file, hdr->ph_line_num, line->fn, line->text);
359                 free(line->hdr);
360                 free(line);
361         }
362         free(linev);
363 }
364
365 static int add_rec(struct dbg_line *line, struct dbg_line ***linevp, int *lenp,
366                    int used)
367 {
368         struct dbg_line **linev = *linevp;
369
370         if (used == *lenp) {
371                 int nlen = *lenp + 512;
372                 int nsize = nlen * sizeof(struct dbg_line *);
373
374                 linev = *linevp ? realloc(*linevp, nsize) : malloc(nsize);
375                 if (!linev)
376                         return 0;
377                 *linevp = linev;
378                 *lenp = nlen;
379         }
380         linev[used] = line; 
381         return 1;
382 }
383
384 static int parse_buffer(FILE *in, FILE *out)
385 {
386         struct dbg_line *line;
387         struct ptldebug_header *hdr;
388         char buf[4097], *p;
389         int rc;
390         unsigned long dropped = 0, kept = 0;
391         struct dbg_line **linev = NULL;
392         int linev_len = 0;
393
394         while (1) {
395                 rc = fread(buf, sizeof(hdr->ph_len) + sizeof(hdr->ph_flags), 1, in);
396                 if (rc <= 0)
397                         break;
398
399                 hdr = (void *)buf;
400                 if (hdr->ph_len == 0)
401                         break;
402                 if (hdr->ph_len > 4094) {
403                         fprintf(stderr, "unexpected large record: %d bytes.  "
404                                 "aborting.\n",
405                                 hdr->ph_len);
406                         break;
407                 }
408
409                 rc = fread(buf + sizeof(hdr->ph_len) + sizeof(hdr->ph_flags), 1,
410                            hdr->ph_len - sizeof(hdr->ph_len) - sizeof(hdr->ph_flags), in);
411                 if (rc <= 0)
412                         break;
413
414                 if ((hdr->ph_subsys && !(subsystem_mask & hdr->ph_subsys)) ||
415                     (hdr->ph_mask   && !(debug_mask & hdr->ph_mask))) {
416                         dropped++;
417                         continue;
418                 }
419
420                 line = malloc(sizeof(*line));
421                 if (line == NULL) {
422                         fprintf(stderr, "malloc failed; printing accumulated "
423                                 "records and exiting.\n");
424                         break;
425                 }
426
427                 line->hdr = malloc(hdr->ph_len + 1);
428                 if (line->hdr == NULL) {
429                         free(line);
430                         fprintf(stderr, "malloc failed; printing accumulated "
431                                 "records and exiting.\n");
432                         break;
433                 }
434
435                 p = (void *)line->hdr;
436                 memcpy(line->hdr, buf, hdr->ph_len);
437                 p[hdr->ph_len] = '\0';
438
439                 p += sizeof(*hdr);
440                 line->file = p;
441                 p += strlen(line->file) + 1;
442                 line->fn = p;
443                 p += strlen(line->fn) + 1;
444                 line->text = p;
445
446                 if (!add_rec(line, &linev, &linev_len, kept)) {
447                         fprintf(stderr, "malloc failed; printing accumulated " 
448                                 "records and exiting.\n");
449                         break;
450                 }        
451                 kept++;
452         }
453
454         if (linev) {
455                 qsort(linev, kept, sizeof(struct dbg_line *), cmp_rec);
456                 print_rec(linev, kept, out);
457         }
458
459         printf("Debug log: %lu lines, %lu kept, %lu dropped.\n",
460                 dropped + kept, kept, dropped);
461         return 0;
462 }
463
464 int jt_dbg_debug_kernel(int argc, char **argv)
465 {
466         char filename[4096];
467         struct stat st;
468         int rc, raw = 0, fd;
469         FILE *in, *out = stdout;
470
471         if (argc > 3) {
472                 fprintf(stderr, "usage: %s [file] [raw]\n", argv[0]);
473                 return 0;
474         }
475
476         if (argc > 2) {
477                 raw = atoi(argv[2]);
478         } else if (argc > 1 && (argv[1][0] == '0' || argv[1][0] == '1')) {
479                 raw = atoi(argv[1]);
480                 argc--;
481         }
482
483         /* If we are dumping raw (which means no conversion step to ASCII)
484          * then dump directly to any supplied filename, otherwise this is
485          * just a temp file and we dump to the real file at convert time. */
486         if (argc > 1 && raw)
487                 strcpy(filename, argv[1]);
488         else
489                 sprintf(filename, "/tmp/lustre-log."CFS_TIME_T".%u",
490                         time(NULL),getpid());
491
492         if (stat(filename, &st) == 0 && S_ISREG(st.st_mode))
493                 unlink(filename);
494
495         fd = dbg_open_ctlhandle(DUMP_KERNEL_CTL_NAME);
496         if (fd < 0) {
497                 fprintf(stderr, "open(dump_kernel) failed: %s\n",
498                         strerror(errno));
499                 return 1;
500         }
501
502         rc = dbg_write_cmd(fd, filename, strlen(filename));
503         if (rc != 0) {
504                 fprintf(stderr, "write(%s) failed: %s\n", filename,
505                         strerror(errno));
506                 close(fd);
507                 return 1;
508         }
509         dbg_close_ctlhandle(fd);
510
511         if (raw)
512                 return 0;
513
514         in = fopen(filename, "r");
515         if (in == NULL) {
516                 if (errno == ENOENT) /* no dump file created */
517                         return 0;
518
519                 fprintf(stderr, "fopen(%s) failed: %s\n", filename,
520                         strerror(errno));
521                 return 1;
522         }
523         if (argc > 1) {
524                 out = fopen(argv[1], "w");
525                 if (out == NULL) {
526                         fprintf(stderr, "fopen(%s) failed: %s\n", argv[1],
527                                 strerror(errno));
528                         fclose(in);
529                         return 1;
530                 }
531         }
532
533         rc = parse_buffer(in, out);
534         fclose(in);
535         if (argc > 1)
536                 fclose(out);
537         if (rc) {
538                 fprintf(stderr, "parse_buffer failed; leaving tmp file %s "
539                         "behind.\n", filename);
540         } else {
541                 rc = unlink(filename);
542                 if (rc)
543                         fprintf(stderr, "dumped successfully, but couldn't "
544                                 "unlink tmp file %s: %s\n", filename,
545                                 strerror(errno));
546         }
547         return rc;
548 }
549
550 int jt_dbg_debug_file(int argc, char **argv)
551 {
552         int    fdin;
553         int    fdout;
554         FILE  *in;
555         FILE  *out = stdout;
556         int    rc;
557
558         if (argc > 3 || argc < 2) {
559                 fprintf(stderr, "usage: %s <input> [output]\n", argv[0]);
560                 return 0;
561         }
562
563         fdin = open(argv[1], O_RDONLY | O_LARGEFILE);
564         if (fdin == -1) {
565                 fprintf(stderr, "open(%s) failed: %s\n", argv[1],
566                         strerror(errno));
567                 return 1;
568         }
569         in = fdopen(fdin, "r");
570         if (in == NULL) {
571                 fprintf(stderr, "fopen(%s) failed: %s\n", argv[1],
572                         strerror(errno));
573                 close(fdin);
574                 return 1;
575         }
576         if (argc > 2) {
577                 fdout = open(argv[2],
578                              O_CREAT | O_TRUNC | O_WRONLY | O_LARGEFILE,
579                              0600);
580                 if (fdout == -1) {
581                         fprintf(stderr, "open(%s) failed: %s\n", argv[2],
582                                 strerror(errno));
583                         fclose(in);
584                         return 1;
585                 }
586                 out = fdopen(fdout, "w");
587                 if (out == NULL) {
588                         fprintf(stderr, "fopen(%s) failed: %s\n", argv[2],
589                                 strerror(errno));
590                         fclose(in);
591                         close(fdout);
592                         return 1;
593                 }
594         }
595
596         rc = parse_buffer(in, out);
597
598         fclose(in);
599         if (out != stdout)
600                 fclose(out);
601
602         return rc;
603 }
604
605 const char debug_daemon_usage[] = "usage: %s {start file [MB]|stop}\n";
606
607 int jt_dbg_debug_daemon(int argc, char **argv)
608 {
609         int  rc;
610         int  fd;
611
612         if (argc <= 1) {
613                 fprintf(stderr, debug_daemon_usage, argv[0]);
614                 return 1;
615         }
616
617         fd = dbg_open_ctlhandle(DAEMON_CTL_NAME);
618         if (fd < 0)
619                 return -1;
620
621         rc = -1;
622         if (strcasecmp(argv[1], "start") == 0) {
623              if (argc < 3 || argc > 4 ||
624                     (argc == 4 && strlen(argv[3]) > 5)) {
625                         fprintf(stderr, debug_daemon_usage, argv[0]);
626                         goto out;
627                 }
628                 if (argc == 4) {
629                         char       buf[12];
630                         const long min_size = 10;
631                         const long max_size = 20480;
632                         long       size;
633                         char      *end;
634
635                         size = strtoul(argv[3], &end, 0);
636                         if (size < min_size ||
637                             size > max_size ||
638                             *end != 0) {
639                                 fprintf(stderr, "size %s invalid, must be in "
640                                         "the range %ld-%ld MB\n", argv[3],
641                                         min_size, max_size);
642                                 goto out;
643                         }
644                         snprintf(buf, sizeof(buf), "size=%ld", size);
645                         rc = dbg_write_cmd(fd, buf, strlen(buf));
646
647                         if (rc != 0) {
648                                 fprintf(stderr, "set %s failed: %s\n",
649                                         buf, strerror(errno));
650                                 goto out;
651                         }
652                 }
653
654                 rc = dbg_write_cmd(fd, argv[2], strlen(argv[2]));
655                 if (rc != 0) {
656                         fprintf(stderr, "start debug_daemon on %s failed: %s\n",
657                                 argv[2], strerror(errno));
658                         goto out;
659                 }
660                 rc = 0;
661                 goto out;
662         }
663         if (strcasecmp(argv[1], "stop") == 0) {
664                 rc = dbg_write_cmd(fd, "stop", 4);
665                 if (rc != 0) {
666                         fprintf(stderr, "stopping debug_daemon failed: %s\n",
667                                 strerror(errno));
668                         goto out;
669                 }
670
671                 rc = 0;
672                 goto out;
673         }
674
675         fprintf(stderr, debug_daemon_usage, argv[0]);
676         rc = -1;
677 out:
678         dbg_close_ctlhandle(fd);
679         return rc;
680 }
681
682 int jt_dbg_clear_debug_buf(int argc, char **argv)
683 {
684         int rc;
685         struct libcfs_ioctl_data data;
686
687         if (argc != 1) {
688                 fprintf(stderr, "usage: %s\n", argv[0]);
689                 return 0;
690         }
691
692         memset(&data, 0, sizeof(data));
693         if (libcfs_ioctl_pack(&data, &buf, max) != 0) {
694                 fprintf(stderr, "libcfs_ioctl_pack failed.\n");
695                 return -1;
696         }
697
698         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_CLEAR_DEBUG, buf);
699         if (rc) {
700                 fprintf(stderr, "IOC_LIBCFS_CLEAR_DEBUG failed: %s\n",
701                         strerror(errno));
702                 return -1;
703         }
704         return 0;
705 }
706
707 int jt_dbg_mark_debug_buf(int argc, char **argv)
708 {
709         static char scratch[MAX_MARK_SIZE] = { '\0' };
710         int rc, max_size = MAX_MARK_SIZE-1;
711         struct libcfs_ioctl_data data = { 0 };
712         char *text;
713         time_t now = time(NULL);
714
715         if (argc > 1) {
716                 int count;
717                 text = scratch;
718                 strncpy(text, argv[1], max_size);
719                 max_size-=strlen(argv[1]);
720                 for (count = 2; (count < argc) && (max_size > 0); count++){
721                         strncat(text, " ", max_size);
722                         max_size -= 1;
723                         strncat(text, argv[count], max_size);
724                         max_size -= strlen(argv[count]);
725                 }
726         } else {
727                 text = ctime(&now);
728         }
729
730         data.ioc_inllen1 = strlen(text) + 1;
731         data.ioc_inlbuf1 = text;
732         if (libcfs_ioctl_pack(&data, &buf, max) != 0) {
733                 fprintf(stderr, "libcfs_ioctl_pack failed.\n");
734                 return -1;
735         }
736
737         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_MARK_DEBUG, buf);
738         if (rc) {
739                 fprintf(stderr, "IOC_LIBCFS_MARK_DEBUG failed: %s\n",
740                         strerror(errno));
741                 return -1;
742         }
743         return 0;
744 }
745
746 static struct mod_paths {
747         char *name, *path;
748 } mod_paths[] = {
749         {"libcfs", "libcfs/libcfs"},
750         {"lnet", "lnet/lnet"},
751         {"kciblnd", "lnet/klnds/ciblnd"},
752         {"kgmlnd", "lnet/klnds/gmlnd"},
753         {"kmxlnd", "lnet/klnds/mxlnd"},
754         {"kiiblnd", "lnet/klnds/iiblnd"},
755         {"ko2iblnd", "lnet/klnds/o2iblnd"},
756         {"kopeniblnd", "lnet/klnds/openiblnd"},
757         {"kptllnd", "lnet/klnds/ptllnd"},
758         {"kqswlnd", "lnet/klnds/qswlnd"},
759         {"kralnd", "lnet/klnds/ralnd"},
760         {"ksocklnd", "lnet/klnds/socklnd"},
761         {"ktdilnd", "lnet/klnds/tdilnd"},
762         {"kviblnd", "lnet/klnds/viblnd"},
763         {"lvfs", "lustre/lvfs"},
764         {"obdclass", "lustre/obdclass"},
765         {"llog_test", "lustre/obdclass"},
766         {"ptlrpc_gss", "lustre/ptlrpc/gss"},
767         {"ptlrpc", "lustre/ptlrpc"},
768         {"gks", "lustre/sec/gks"},
769         {"gkc", "lustre/sec/gks"},
770         {"ost", "lustre/ost"},
771         {"osc", "lustre/osc"},
772         {"mds", "lustre/mds"},
773         {"mdc", "lustre/mdc"},
774         {"llite", "lustre/llite"},
775         {"lustre", "lustre/llite"},
776         {"llite_lloop", "lustre/llite"},
777         {"ldiskfs", "ldiskfs/ldiskfs"},
778         {"smfs", "lustre/smfs"},
779         {"obdecho", "lustre/obdecho"},
780         {"ldlm", "lustre/ldlm"},
781         {"obdfilter", "lustre/obdfilter"},
782         {"lov", "lustre/lov"},
783         {"lmv", "lustre/lmv"},
784         {"fsfilt_ext3", "lustre/lvfs"},
785         {"fsfilt_reiserfs", "lustre/lvfs"},
786         {"fsfilt_smfs", "lustre/lvfs"},
787         {"fsfilt_ldiskfs", "lustre/lvfs"},
788         {"mds_ext3", "lustre/mds"},
789         {"cobd", "lustre/cobd"},
790         {"cmobd", "lustre/cmobd"},
791         {"lquota", "lustre/quota"},
792         {"mgs", "lustre/mgs"},
793         {"mgc", "lustre/mgc"},
794         {"mdt", "lustre/mdt"},
795         {"mdd", "lustre/mdd"},
796         {"osd", "lustre/osd"},
797         {"cmm", "lustre/cmm"},
798         {"fid", "lustre/fid"},
799         {"fld", "lustre/fld"},
800         {NULL, NULL}
801 };
802
803 static int jt_dbg_modules_2_4(int argc, char **argv)
804 {
805 #ifdef HAVE_LINUX_VERSION_H
806 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
807         struct mod_paths *mp;
808         char *path = "";
809         char *kernel = "linux";
810
811         if (argc >= 2)
812                 path = argv[1];
813         if (argc == 3)
814                 kernel = argv[2];
815         if (argc > 3) {
816                 printf("%s [path] [kernel]\n", argv[0]);
817                 return 0;
818         }
819
820         for (mp = mod_paths; mp->name != NULL; mp++) {
821                 struct module_info info;
822                 int rc;
823                 size_t crap;
824                 int query_module(const char *name, int which, void *buf,
825                                  size_t bufsize, size_t *ret);
826
827                 rc = query_module(mp->name, QM_INFO, &info, sizeof(info),
828                                   &crap);
829                 if (rc < 0) {
830                         if (errno != ENOENT)
831                                 printf("query_module(%s) failed: %s\n",
832                                        mp->name, strerror(errno));
833                 } else {
834                         printf("add-symbol-file %s%s%s/%s.o 0x%0lx\n", path,
835                                path[0] ? "/" : "", mp->path, mp->name,
836                                info.addr + sizeof(struct module));
837                 }
838         }
839
840         return 0;
841 #endif // Headers are 2.6-only
842 #endif // !HAVE_LINUX_VERSION_H
843         return -EINVAL;
844 }
845
846 static int jt_dbg_modules_2_5(int argc, char **argv)
847 {
848         struct mod_paths *mp;
849         char *path = "";
850         char *kernel = "linux";
851         const char *proc = "/proc/modules";
852         char modname[128], others[4096];
853         long modaddr;
854         int rc;
855         FILE *file;
856
857         if (argc >= 2)
858                 path = argv[1];
859         if (argc == 3)
860                 kernel = argv[2];
861         if (argc > 3) {
862                 printf("%s [path] [kernel]\n", argv[0]);
863                 return 0;
864         }
865
866         file = fopen(proc, "r");
867         if (!file) {
868                 printf("failed open %s: %s\n", proc, strerror(errno));
869                 return 0;
870         }
871
872         while ((rc = fscanf(file, "%s %s %s %s %s %lx\n",
873                 modname, others, others, others, others, &modaddr)) == 6) {
874                 for (mp = mod_paths; mp->name != NULL; mp++) {
875                         if (!strcmp(mp->name, modname))
876                                 break;
877                 }
878                 if (mp->name) {
879                         printf("add-symbol-file %s%s%s/%s.o 0x%0lx\n", path,
880                                path[0] ? "/" : "", mp->path, mp->name, modaddr);
881                 }
882         }
883
884         fclose(file);
885         return 0;
886 }
887
888 int jt_dbg_modules(int argc, char **argv)
889 {
890         int rc = 0;
891         struct utsname sysinfo;
892
893         rc = uname(&sysinfo);
894         if (rc) {
895                 printf("uname() failed: %s\n", strerror(errno));
896                 return 0;
897         }
898
899         if (sysinfo.release[2] > '4') {
900                 return jt_dbg_modules_2_5(argc, argv);
901         } else {
902                 return jt_dbg_modules_2_4(argc, argv);
903         }
904
905         return 0;
906 }
907
908 int jt_dbg_panic(int argc, char **argv)
909 {
910         int rc;
911         struct libcfs_ioctl_data data;
912
913         if (argc != 1) {
914                 fprintf(stderr, "usage: %s\n", argv[0]);
915                 return 0;
916         }
917
918         memset(&data, 0, sizeof(data));
919         if (libcfs_ioctl_pack(&data, &buf, max) != 0) {
920                 fprintf(stderr, "libcfs_ioctl_pack failed.\n");
921                 return -1;
922         }
923
924         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_PANIC, buf);
925         if (rc) {
926                 fprintf(stderr, "IOC_LIBCFS_PANIC failed: %s\n",
927                         strerror(errno));
928                 return -1;
929         }
930         return 0;
931 }