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