Branch data Line data Source code
1 : : #include <stdio.h>
2 : : #include <stdlib.h>
3 : : #include <signal.h>
4 : : #include <limits.h>
5 : : #include <unistd.h>
6 : : #include <errno.h>
7 : : #include <string.h>
8 : : #include <ctype.h>
9 : :
10 : : #include <fcntl.h>
11 : :
12 : : #include <sys/types.h>
13 : : #include <sys/stat.h>
14 : :
15 : : #include "asm/types.h"
16 : : #include "list.h"
17 : : #include "fdset.h"
18 : : #include "namespaces.h"
19 : : #include "compiler.h"
20 : : #include "cr_options.h"
21 : : #include "util.h"
22 : : #include "sockets.h"
23 : : #include "image.h"
24 : : #include "uts_ns.h"
25 : : #include "ipc_ns.h"
26 : : #include "pstree.h"
27 : : #include "cr-show.h"
28 : : #include "crtools.h"
29 : :
30 : : #include "protobuf.h"
31 : : #include "protobuf/pstree.pb-c.h"
32 : : #include "protobuf/pipe-data.pb-c.h"
33 : : #include "protobuf/siginfo.pb-c.h"
34 : :
35 : : #define DEF_PAGES_PER_LINE 6
36 : :
37 : :
38 : : static LIST_HEAD(pstree_list);
39 : :
40 : 0 : static void pipe_data_handler(int fd, void *obj)
41 : : {
42 : : PipeDataEntry *e = obj;
43 : 0 : print_image_data(fd, e->bytes, opts.show_pages_content);
44 : 0 : }
45 : :
46 : : static int nice_width_for(unsigned long addr)
47 : : {
48 : : int ret = 3;
49 : :
50 [ # # ]: 0 : while (addr) {
51 : 0 : addr >>= 4;
52 : 0 : ret++;
53 : : }
54 : :
55 : : return ret;
56 : : }
57 : :
58 : 0 : static inline void pr_xdigi(unsigned char *data, size_t len, int pos)
59 : : {
60 [ # # ]: 0 : if (pos < len)
61 : 0 : pr_msg("%02x ", data[pos]);
62 : : else
63 : 0 : pr_msg(" ");
64 : 0 : }
65 : :
66 : 0 : static inline void pr_xsym(unsigned char *data, size_t len, int pos)
67 : : {
68 : : char sym;
69 : :
70 [ # # ]: 0 : if (pos < len)
71 : 0 : sym = data[pos];
72 : : else
73 : : sym = ' ';
74 : :
75 [ # # ]: 0 : pr_msg("%c", isprint(sym) ? sym : '.');
76 : 0 : }
77 : :
78 : 0 : void print_data(unsigned long addr, unsigned char *data, size_t size)
79 : : {
80 : : int i, j, addr_len;
81 : : unsigned zero_line = 0;
82 : :
83 : 0 : addr_len = nice_width_for(addr + size);
84 : :
85 [ # # ]: 0 : for (i = 0; i < size; i += 16) {
86 [ # # ][ # # ]: 0 : if (*(u64 *)(data + i) == 0 && *(u64 *)(data + i + 8) == 0) {
87 [ # # ]: 0 : if (zero_line == 0)
88 : : zero_line = 1;
89 : : else {
90 [ # # ]: 0 : if (zero_line == 1) {
91 : 0 : pr_msg("*\n");
92 : : zero_line = 2;
93 : : }
94 : :
95 : 0 : continue;
96 : : }
97 : : } else
98 : : zero_line = 0;
99 : :
100 : 0 : pr_msg("%#0*lx: ", addr_len, addr + i);
101 [ # # ]: 0 : for (j = 0; j < 8; j++)
102 : 0 : pr_xdigi(data, size, i + j);
103 : 0 : pr_msg(" ");
104 [ # # ]: 0 : for (j = 8; j < 16; j++)
105 : 0 : pr_xdigi(data, size, i + j);
106 : :
107 : 0 : pr_msg(" |");
108 [ # # ]: 0 : for (j = 0; j < 8; j++)
109 : 0 : pr_xsym(data, size, i + j);
110 : 0 : pr_msg(" ");
111 [ # # ]: 0 : for (j = 8; j < 16; j++)
112 : 0 : pr_xsym(data, size, i + j);
113 : :
114 : 0 : pr_msg("|\n");
115 : : }
116 : 0 : }
117 : :
118 : 0 : void print_image_data(int fd, unsigned int length, int show)
119 : : {
120 : : void *data;
121 : : int ret;
122 : :
123 [ # # ]: 0 : if (!show) {
124 : 0 : lseek(fd, length, SEEK_CUR);
125 : 0 : return;
126 : : }
127 : :
128 : 0 : pr_msg("\n");
129 : :
130 [ # # ]: 0 : data = xmalloc(length);
131 [ # # ]: 0 : if (!data)
132 : : return;
133 : 0 : ret = read_img_buf(fd, (unsigned char *)data, length);
134 [ # # ]: 0 : if (ret < 0) {
135 [ # # ]: 0 : xfree(data);
136 : : return;
137 : : }
138 : 0 : print_data(0, (unsigned char *)data, length);
139 [ # # ]: 0 : xfree(data);
140 : : }
141 : :
142 : 0 : static void show_pagemaps(int fd, void *obj)
143 : : {
144 : 0 : pb_show_plain_pretty(fd, PB_PAGEMAP, "nr_pages:%u");
145 : 0 : }
146 : :
147 : 0 : void show_siginfo(int fd)
148 : : {
149 : : int ret;
150 : :
151 : 0 : pr_img_head(CR_FD_SIGNAL);
152 : : while (1) {
153 : : SiginfoEntry *sie;
154 : : siginfo_t *info;
155 : :
156 : 0 : ret = pb_read_one_eof(fd, &sie, PB_SIGINFO);
157 [ # # ]: 0 : if (ret <= 0)
158 : : break;
159 : :
160 : 0 : info = (siginfo_t *) sie->siginfo.data;
161 : 0 : pr_msg("signal: si_signo=%d si_code=%x\n",
162 : : info->si_signo, info->si_code);
163 : 0 : siginfo_entry__free_unpacked(sie, NULL);
164 : :
165 : 0 : }
166 : 0 : pr_img_tail(CR_FD_SIGNAL);
167 : 0 : }
168 : :
169 : 0 : static int pstree_item_from_pb(PstreeEntry *e, struct pstree_item *item)
170 : : {
171 : : int i;
172 : :
173 : 0 : item->pid.virt = e->pid;
174 : 0 : item->nr_threads = e->n_threads;
175 [ # # ]: 0 : item->threads = xzalloc(sizeof(struct pid) * e->n_threads);
176 [ # # ]: 0 : if (!item->threads)
177 : : return -1;
178 : :
179 [ # # ]: 0 : for (i = 0; i < item->nr_threads; i++)
180 : 0 : item->threads[i].virt = e->threads[i];
181 : :
182 : : return 0;
183 : : }
184 : :
185 : 0 : static void pstree_handler(int fd, void *obj)
186 : : {
187 : : PstreeEntry *e = obj;
188 : : struct pstree_item *item = NULL;
189 : :
190 [ # # ]: 0 : item = xzalloc(sizeof(struct pstree_item));
191 [ # # ]: 0 : if (!item)
192 : : return;
193 : :
194 [ # # ]: 0 : if (pstree_item_from_pb(e, item)) {
195 [ # # ]: 0 : xfree(item);
196 : : return;
197 : : }
198 : :
199 : 0 : list_add_tail(&item->sibling, &pstree_list);
200 : : }
201 : :
202 : 0 : void show_collect_pstree(int fd, int collect)
203 : : {
204 [ # # ]: 0 : pb_show_plain_payload_pretty(fd, PB_PSTREE,
205 : : collect ? pstree_handler : NULL, "*:%d");
206 : 0 : }
207 : :
208 : : static inline char *task_state_str(int state)
209 : : {
210 : : switch (state) {
211 : : case TASK_ALIVE:
212 : : return "running/sleeping";
213 : : case TASK_DEAD:
214 : : return "zombie";
215 : : default:
216 : : return "UNKNOWN";
217 : : }
218 : : }
219 : :
220 : 0 : static void show_core_regs(UserX86RegsEntry *regs)
221 : : {
222 : : #define pr_regs4(s, n1, n2, n3, n4) \
223 : : pr_msg("\t%8s: 0x%-16"PRIx64" " \
224 : : "%8s: 0x%-16"PRIx64" " \
225 : : "%8s: 0x%-16"PRIx64" " \
226 : : "%8s: 0x%-16"PRIx64"\n", \
227 : : #n1, s->n1, \
228 : : #n2, s->n2, \
229 : : #n3, s->n3, \
230 : : #n4, s->n4)
231 : :
232 : : #define pr_regs3(s, n1, n2, n3) \
233 : : pr_msg("\t%8s: 0x%-16"PRIx64" " \
234 : : "%8s: 0x%-16"PRIx64" " \
235 : : "%8s: 0x%-16"PRIx64"\n", \
236 : : #n1, s->n1, \
237 : : #n2, s->n2, \
238 : : #n3, s->n3)
239 : :
240 : 0 : pr_msg("\t---[ GP registers set ]---\n");
241 : :
242 : 0 : pr_regs4(regs, cs, ip, ds, es);
243 : 0 : pr_regs4(regs, ss, sp, fs, gs);
244 : 0 : pr_regs4(regs, di, si, dx, cx);
245 : 0 : pr_regs4(regs, ax, r8, r9, r10);
246 : 0 : pr_regs4(regs, r11, r12, r13, r14);
247 : 0 : pr_regs3(regs, r15, bp, bx);
248 : 0 : pr_regs4(regs, orig_ax, flags, fs_base, gs_base);
249 : 0 : pr_msg("\n");
250 : 0 : }
251 : :
252 : 0 : void show_thread_info(ThreadInfoX86 *thread_info)
253 : : {
254 [ # # ]: 0 : if (!thread_info)
255 : 0 : return;
256 : :
257 : 0 : pr_msg("\t---[ Thread info ]---\n");
258 : 0 : pr_msg("\tclear_tid_addr: 0x%"PRIx64"\n", thread_info->clear_tid_addr);
259 : 0 : pr_msg("\n");
260 : :
261 : 0 : show_core_regs(thread_info->gpregs);
262 : : }
263 : :
264 : : static struct {
265 : : u32 magic;
266 : : u32 mask;
267 : : char *hint;
268 : : } magic_hints[] = {
269 : : { .magic = 0x45311224, .mask = 0xffffffff, .hint = "ip route dump", },
270 : : { .magic = 0x47361222, .mask = 0xffffffff, .hint = "ip ifaddr dump", },
271 : : { .magic = 0x00008b1f, .mask = 0x0000ffff, .hint = "gzip file", },
272 : : { },
273 : : };
274 : :
275 : 0 : static void try_hint_magic(u32 magic)
276 : : {
277 : : int i;
278 : :
279 [ # # ]: 0 : for (i = 0; magic_hints[i].hint != 0; i++)
280 [ # # ]: 0 : if ((magic & magic_hints[i].mask) == magic_hints[i].magic)
281 : 0 : pr_msg("This can be %s\n", magic_hints[i].hint);
282 : 0 : }
283 : :
284 : : #define SHOW_PLAIN(name) { name##_MAGIC, PB_##name, false, NULL, NULL, }
285 : : /* nothing special behind this -S, just to avoid heavy patching */
286 : : #define SHOW_PLAINS(name) { name##S_MAGIC, PB_##name, false, NULL, NULL, }
287 : : #define SHOW_VERT(name) { name##_MAGIC, PB_##name, true, NULL, NULL, }
288 : :
289 : : static struct show_image_info show_infos[] = {
290 : : SHOW_VERT(INVENTORY),
291 : : SHOW_VERT(CORE),
292 : : SHOW_VERT(IDS),
293 : : SHOW_VERT(CREDS),
294 : : SHOW_VERT(UTSNS),
295 : : SHOW_VERT(IPC_VAR),
296 : : SHOW_VERT(FS),
297 : : SHOW_VERT(GHOST_FILE),
298 : : SHOW_VERT(MM),
299 : :
300 : : SHOW_PLAINS(REG_FILE),
301 : : SHOW_PLAINS(NS_FILE),
302 : : SHOW_PLAIN(EVENTFD_FILE),
303 : : SHOW_PLAIN(EVENTPOLL_FILE),
304 : : SHOW_PLAIN(EVENTPOLL_TFD),
305 : : SHOW_PLAIN(SIGNALFD),
306 : : SHOW_PLAIN(INOTIFY_FILE),
307 : : SHOW_PLAIN(INOTIFY_WD),
308 : : SHOW_PLAIN(FANOTIFY_FILE),
309 : : SHOW_PLAIN(FANOTIFY_MARK),
310 : : SHOW_PLAINS(VMA),
311 : : SHOW_PLAINS(PIPE),
312 : : SHOW_PLAIN(FIFO),
313 : : SHOW_PLAIN(SIGACT),
314 : : SHOW_PLAIN(NETLINK_SK),
315 : : SHOW_PLAIN(REMAP_FPATH),
316 : : SHOW_PLAINS(MNT),
317 : : SHOW_PLAINS(TTY_FILE),
318 : : SHOW_PLAIN(TTY_INFO),
319 : : SHOW_PLAINS(FILE_LOCK),
320 : : SHOW_PLAIN(RLIMIT),
321 : : SHOW_PLAIN(TUNFILE),
322 : : SHOW_PLAINS(EXT_FILE),
323 : : SHOW_PLAIN(IRMAP_CACHE),
324 : :
325 : : { TCP_STREAM_MAGIC, PB_TCP_STREAM, true, show_tcp_stream, "1:%u 2:%u 3:%u 4:%u 12:%u", },
326 : : { STATS_MAGIC, PB_STATS, true, NULL, "1.1:%u 1.2:%u 1.3:%u 1.4:%u 1.5:%Lu 1.6:%Lu 1.7:%Lu 1.8:%u", },
327 : : { FDINFO_MAGIC, PB_FDINFO, false, NULL, "flags:%#o fd:%d", },
328 : : { UNIXSK_MAGIC, PB_UNIX_SK, false, NULL, "1:%#x 2:%#x 3:%d 4:%d 5:%d 6:%d 7:%d 8:%#x 11:S", },
329 : : { INETSK_MAGIC, PB_INET_SK, false, NULL, "1:%#x 2:%#x 3:%d 4:%d 5:%d 6:%d 7:%d 8:%d 9:%2x 11:A 12:A", },
330 : : { PACKETSK_MAGIC, PB_PACKET_SOCK, false, NULL, "5:%d", },
331 : : { ITIMERS_MAGIC, PB_ITIMER, false, NULL, "*:%Lu", },
332 : : { POSIX_TIMERS_MAGIC, PB_POSIX_TIMER, false, NULL, "*:%d 5:%Lu 7:%Lu 8:%lu 9:%Lu 10:%Lu", },
333 : : { NETDEV_MAGIC, PB_NETDEV, false, NULL, "2:%d", },
334 : :
335 : : { PAGEMAP_MAGIC, PB_PAGEMAP_HEAD, true, show_pagemaps, NULL, },
336 : : { PIPES_DATA_MAGIC, PB_PIPE_DATA, false, pipe_data_handler, NULL, },
337 : : { FIFO_DATA_MAGIC, PB_PIPE_DATA, false, pipe_data_handler, NULL, },
338 : : { SK_QUEUES_MAGIC, PB_SK_QUEUES, false, sk_queue_data_handler, NULL, },
339 : : { IPCNS_SHM_MAGIC, PB_IPC_SHM, false, ipc_shm_handler, NULL, },
340 : : { IPCNS_SEM_MAGIC, PB_IPC_SEM, false, ipc_sem_handler, NULL, },
341 : : { IPCNS_MSG_MAGIC, PB_IPCNS_MSG_ENT, false, ipc_msg_handler, NULL, },
342 : :
343 : : { }
344 : : };
345 : :
346 : 0 : static int cr_parse_file(void)
347 : : {
348 : : u32 magic;
349 : : int ret = -1, fd;
350 : :
351 : 0 : fd = open(opts.show_dump_file, O_RDONLY);
352 [ # # ]: 0 : if (fd < 0) {
353 : 0 : pr_perror("Can't open %s", opts.show_dump_file);
354 : 0 : goto out;
355 : : }
356 : :
357 [ # # ]: 0 : if (read_img(fd, &magic) < 0)
358 : : goto out;
359 : :
360 : 0 : ret = cr_parse_fd(fd, magic);
361 : : out:
362 : 0 : close_safe(&fd);
363 : 0 : return ret;
364 : : }
365 : :
366 : 0 : int cr_parse_fd(int fd, u32 magic)
367 : : {
368 : : int ret = 0, i;
369 : :
370 [ # # ]: 0 : if (magic == PSTREE_MAGIC) {
371 : : show_collect_pstree(fd, 0);
372 : : goto out;
373 : : }
374 : :
375 [ # # ]: 0 : if (magic == SIGNAL_MAGIC || magic == PSIGNAL_MAGIC) {
376 : 0 : show_siginfo(fd);
377 : 0 : goto out;
378 : : }
379 : :
380 [ # # ]: 0 : for (i = 0; show_infos[i].magic; i++) {
381 : : struct show_image_info *si;
382 : :
383 : 0 : si = &show_infos[i];
384 [ # # ]: 0 : if (si->magic != magic)
385 : 0 : continue;
386 : :
387 : 0 : do_pb_show_plain(fd, si->pb_type, si->single,
388 : 0 : si->payload, si->fmt);
389 : 0 : goto out;
390 : : }
391 : :
392 : : ret = -1;
393 : 0 : pr_err("Unknown magic %#x in %s\n",
394 : : magic, opts.show_dump_file);
395 : 0 : try_hint_magic(magic);
396 : :
397 : : out:
398 : 0 : return ret;
399 : : }
400 : :
401 : 0 : static int cr_show_pstree_item(struct pstree_item *item)
402 : : {
403 : : int ret = -1, i;
404 : 0 : struct cr_fdset *cr_fdset = NULL;
405 : : TaskKobjIdsEntry *ids;
406 : :
407 : 0 : cr_fdset = cr_task_fdset_open(item->pid.virt, O_SHOW);
408 [ # # ]: 0 : if (!cr_fdset)
409 : : goto out;
410 : :
411 : 0 : pr_msg("Task %d:\n", item->pid.virt);
412 : 0 : pr_msg("----------------------------------------\n");
413 : :
414 : 0 : cr_parse_fd(fdset_fd(cr_fdset, CR_FD_CORE), CORE_MAGIC);
415 : :
416 [ # # ]: 0 : if (item->nr_threads > 1) {
417 : : int fd_th;
418 : :
419 [ # # ]: 0 : for (i = 0; i < item->nr_threads; i++) {
420 : :
421 [ # # ]: 0 : if (item->threads[i].virt == item->pid.virt)
422 : 0 : continue;
423 : :
424 : 0 : fd_th = open_image(CR_FD_CORE, O_SHOW, item->threads[i].virt);
425 [ # # ]: 0 : if (fd_th < 0)
426 : : goto outc;
427 : :
428 : 0 : pr_msg("Thread %d.%d:\n", item->pid.virt, item->threads[i].virt);
429 : 0 : pr_msg("----------------------------------------\n");
430 : :
431 : 0 : cr_parse_fd(fd_th, CORE_MAGIC);
432 : 0 : close_safe(&fd_th);
433 : : }
434 : : }
435 : :
436 : 0 : pr_msg("Resources for %d:\n", item->pid.virt);
437 : 0 : pr_msg("----------------------------------------\n");
438 [ # # ]: 0 : for (i = _CR_FD_TASK_FROM + 1; i < _CR_FD_TASK_TO; i++)
439 [ # # ]: 0 : if ((i != CR_FD_CORE) && (i != CR_FD_IDS)) {
440 : 0 : pr_msg("* ");
441 : 0 : pr_msg(fdset_template[i].fmt, item->pid.virt);
442 : 0 : pr_msg(":\n");
443 : 0 : cr_parse_fd(fdset_fd(cr_fdset, i), fdset_template[i].magic);
444 : : }
445 : :
446 : 0 : i = open_image(CR_FD_RLIMIT, O_SHOW | O_OPT, item->pid.virt);
447 [ # # ]: 0 : if (i >= 0) {
448 : 0 : pr_msg("* ");
449 : 0 : pr_msg(fdset_template[CR_FD_RLIMIT].fmt, item->pid.virt);
450 : 0 : pr_msg(":\n");
451 : :
452 : 0 : cr_parse_fd(i, RLIMIT_MAGIC);
453 : 0 : close(i);
454 : : }
455 : :
456 [ # # ]: 0 : if (pb_read_one(fdset_fd(cr_fdset, CR_FD_IDS), &ids, PB_IDS) > 0) {
457 : 0 : i = open_image(CR_FD_FDINFO, O_SHOW, ids->files_id);
458 [ # # ]: 0 : if (i >= 0) {
459 : 0 : pr_msg("* ");
460 : 0 : pr_msg(fdset_template[CR_FD_FDINFO].fmt, ids->files_id);
461 : 0 : pr_msg(":\n");
462 : :
463 : 0 : cr_parse_fd(i, FDINFO_MAGIC);
464 : 0 : close(i);
465 : : }
466 : :
467 : 0 : task_kobj_ids_entry__free_unpacked(ids, NULL);
468 : : }
469 : :
470 : 0 : pr_msg("---[ end of task %d ]---\n", item->pid.virt);
471 : :
472 : : ret = 0;
473 : : outc:
474 : 0 : close_cr_fdset(&cr_fdset);
475 : : out:
476 : 0 : return ret;
477 : : }
478 : :
479 : 0 : static int cr_show_pid(int pid)
480 : : {
481 : : int fd, ret;
482 : : struct pstree_item item;
483 : :
484 : 0 : fd = open_image(CR_FD_PSTREE, O_SHOW);
485 [ # # ]: 0 : if (fd < 0)
486 : : return -1;
487 : :
488 : : while (1) {
489 : : PstreeEntry *pe;
490 : :
491 : 0 : ret = pb_read_one_eof(fd, &pe, PB_PSTREE);
492 [ # # ]: 0 : if (ret <= 0) {
493 : 0 : close(fd);
494 : 0 : return ret;
495 : : }
496 : :
497 [ # # ]: 0 : if (pe->pid == pid) {
498 : 0 : pstree_item_from_pb(pe, &item);
499 : 0 : pstree_entry__free_unpacked(pe, NULL);
500 : 0 : break;
501 : : }
502 : :
503 : 0 : pstree_entry__free_unpacked(pe, NULL);
504 : 0 : }
505 : :
506 : 0 : close(fd);
507 : :
508 : 0 : return cr_show_pstree_item(&item);
509 : : }
510 : :
511 : 0 : static int cr_show_all(void)
512 : : {
513 : : struct pstree_item *item = NULL, *tmp;
514 : : int ret = -1, fd, pid;
515 : :
516 : 0 : fd = open_image(CR_FD_PSTREE, O_SHOW);
517 [ # # ]: 0 : if (fd < 0)
518 : : goto out;
519 : : show_collect_pstree(fd, 1);
520 : 0 : close(fd);
521 : :
522 : 0 : fd = open_image(CR_FD_SK_QUEUES, O_SHOW);
523 [ # # ]: 0 : if (fd < 0)
524 : : goto out;
525 : :
526 : 0 : close(fd);
527 : :
528 : 0 : pid = list_first_entry(&pstree_list, struct pstree_item, sibling)->pid.virt;
529 : 0 : ret = try_show_namespaces(pid);
530 [ # # ]: 0 : if (ret)
531 : : goto out;
532 : :
533 [ # # ]: 0 : list_for_each_entry(item, &pstree_list, sibling)
534 [ # # ]: 0 : if (cr_show_pstree_item(item))
535 : : break;
536 : :
537 : : out:
538 [ # # ]: 0 : list_for_each_entry_safe(item, tmp, &pstree_list, sibling) {
539 : : list_del(&item->sibling);
540 [ # # ]: 0 : xfree(item->threads);
541 [ # # ]: 0 : xfree(item);
542 : : }
543 : 0 : return ret;
544 : : }
545 : :
546 : 0 : int cr_show(int pid)
547 : : {
548 [ # # ]: 0 : if (opts.show_dump_file)
549 : 0 : return cr_parse_file();
550 : :
551 [ # # ]: 0 : if (pid)
552 : 0 : return cr_show_pid(pid);
553 : :
554 : 0 : return cr_show_all();
555 : : }
|