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