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