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 "types.h"
16 : : #include "list.h"
17 : : #include "namespaces.h"
18 : : #include "compiler.h"
19 : : #include "crtools.h"
20 : : #include "util.h"
21 : : #include "sockets.h"
22 : : #include "image.h"
23 : : #include "uts_ns.h"
24 : : #include "ipc_ns.h"
25 : : #include "pstree.h"
26 : :
27 : : #include "protobuf.h"
28 : : #include "protobuf/fdinfo.pb-c.h"
29 : : #include "protobuf/regfile.pb-c.h"
30 : : #include "protobuf/ghost-file.pb-c.h"
31 : : #include "protobuf/fifo.pb-c.h"
32 : : #include "protobuf/remap-file-path.pb-c.h"
33 : : #include "protobuf/fown.pb-c.h"
34 : : #include "protobuf/fs.pb-c.h"
35 : : #include "protobuf/pstree.pb-c.h"
36 : : #include "protobuf/pipe.pb-c.h"
37 : : #include "protobuf/pipe-data.pb-c.h"
38 : : #include "protobuf/sa.pb-c.h"
39 : : #include "protobuf/itimer.pb-c.h"
40 : : #include "protobuf/mm.pb-c.h"
41 : : #include "protobuf/vma.pb-c.h"
42 : : #include "protobuf/creds.pb-c.h"
43 : : #include "protobuf/core.pb-c.h"
44 : : #include "protobuf/tty.pb-c.h"
45 : :
46 : : #define DEF_PAGES_PER_LINE 6
47 : :
48 : : #ifndef CONFIG_X86_64
49 : : # error No x86-32 support yet
50 : : #endif
51 : :
52 : :
53 : : #define PR_SYMBOL(sym) \
54 : : (isprint(sym) ? sym : '.')
55 : :
56 : : static LIST_HEAD(pstree_list);
57 : :
58 : 0 : void show_files(int fd_files, struct cr_options *o)
59 : : {
60 : 0 : pb_show_plain_pretty(fd_files, PB_FDINFO, "2:%#o 4:%d");
61 : 0 : }
62 : :
63 : 0 : void show_fown_cont(void *p)
64 : : {
65 : 0 : FownEntry *fown = p;
66 : 0 : pr_msg("fown: uid: %#x euid: %#x signum: %#x pid_type: %#x pid: %u",
67 : : fown->uid, fown->euid, fown->signum, fown->pid_type, fown->pid);
68 : 0 : }
69 : :
70 : 0 : void show_reg_files(int fd_reg_files, struct cr_options *o)
71 : : {
72 : 0 : pb_show_plain(fd_reg_files, PB_REG_FILES);
73 : 0 : }
74 : :
75 : 0 : void show_remap_files(int fd, struct cr_options *o)
76 : : {
77 : 0 : pb_show_plain(fd, PB_REMAP_FPATH);
78 : 0 : }
79 : :
80 : 0 : void show_ghost_file(int fd, struct cr_options *o)
81 : : {
82 : 0 : pb_show_vertical(fd, PB_GHOST_FILE);
83 : 0 : }
84 : :
85 : 0 : static void pipe_data_handler(int fd, void *obj, int show_pages_content)
86 : : {
87 : 0 : PipeDataEntry *e = obj;
88 : 0 : print_image_data(fd, e->bytes, show_pages_content);
89 : 0 : }
90 : :
91 : 0 : void show_pipes_data(int fd, struct cr_options *o)
92 : : {
93 : 0 : pb_show_plain_payload(fd, PB_PIPES_DATA,
94 : : pipe_data_handler, o->show_pages_content);
95 : 0 : }
96 : :
97 : 0 : void show_pipes(int fd_pipes, struct cr_options *o)
98 : : {
99 : 0 : pb_show_plain(fd_pipes, PB_PIPES);
100 : 0 : }
101 : :
102 : 0 : void show_fifo_data(int fd, struct cr_options *o)
103 : : {
104 : 0 : show_pipes_data(fd, o);
105 : 0 : }
106 : :
107 : 0 : void show_fifo(int fd, struct cr_options *o)
108 : : {
109 : 0 : pb_show_plain(fd, PB_FIFO);
110 : 0 : }
111 : :
112 : 0 : void show_tty(int fd, struct cr_options *o)
113 : : {
114 : 0 : pb_show_plain(fd, PB_TTY);
115 : 0 : }
116 : :
117 : 0 : void show_tty_info(int fd, struct cr_options *o)
118 : : {
119 : 0 : pb_show_plain(fd, PB_TTY_INFO);
120 : 0 : }
121 : :
122 : 0 : void show_fs(int fd_fs, struct cr_options *o)
123 : : {
124 : 0 : pb_show_vertical(fd_fs, PB_FS);
125 : 0 : }
126 : :
127 : 0 : void show_vmas(int fd_vma, struct cr_options *o)
128 : : {
129 : 0 : pb_show_plain(fd_vma, PB_VMAS);
130 : 0 : }
131 : :
132 : : static int nice_width_for(unsigned long addr)
133 : : {
134 : 0 : int ret = 3;
135 : :
136 [ # # ]: 0 : while (addr) {
137 : 0 : addr >>= 4;
138 : 0 : ret++;
139 : : }
140 : :
141 : : return ret;
142 : : }
143 : :
144 : 0 : void print_data(unsigned long addr, unsigned char *data, size_t size)
145 : : {
146 : : int i, j, addr_len;
147 : 0 : unsigned zero_line = 0;
148 : :
149 : 0 : addr_len = nice_width_for(addr + size);
150 : :
151 [ # # ]: 0 : for (i = 0; i < size; i += 16) {
152 [ # # ][ # # ]: 0 : if (*(u64 *)(data + i) == 0 && *(u64 *)(data + i + 8) == 0) {
153 [ # # ]: 0 : if (zero_line == 0)
154 : : zero_line = 1;
155 : : else {
156 [ # # ]: 0 : if (zero_line == 1) {
157 : 0 : pr_msg("*\n");
158 : 0 : zero_line = 2;
159 : : }
160 : :
161 : 0 : continue;
162 : : }
163 : : } else
164 : : zero_line = 0;
165 : :
166 : 0 : pr_msg("%#0*lx: ", addr_len, addr + i);
167 [ # # ]: 0 : for (j = 0; j < 8; j++)
168 : 0 : pr_msg("%02x ", data[i + j]);
169 : 0 : pr_msg(" ");
170 [ # # ]: 0 : for (j = 8; j < 16; j++)
171 : 0 : pr_msg("%02x ", data[i + j]);
172 : :
173 : 0 : pr_msg(" |");
174 [ # # ]: 0 : for (j = 0; j < 8; j++)
175 [ # # ]: 0 : pr_msg("%c", PR_SYMBOL(data[i + j]));
176 : 0 : pr_msg(" ");
177 [ # # ]: 0 : for (j = 8; j < 16; j++)
178 [ # # ]: 0 : pr_msg("%c", PR_SYMBOL(data[i + j]));
179 : :
180 : 0 : pr_msg("|\n");
181 : : }
182 : 0 : }
183 : :
184 : 0 : void print_image_data(int fd, unsigned int length, int show)
185 : : {
186 : : void *data;
187 : : int ret;
188 : :
189 [ # # ]: 0 : if (!show) {
190 : 0 : lseek(fd, length, SEEK_CUR);
191 : 0 : return;
192 : : }
193 : :
194 : 0 : pr_msg("\n");
195 : :
196 [ # # ]: 0 : data = xmalloc(length);
197 [ # # ]: 0 : if (!data)
198 : : return;
199 : 0 : ret = read_img_buf(fd, (unsigned char *)data, length);
200 [ # # ]: 0 : if (ret < 0) {
201 [ # # ]: 0 : xfree(data);
202 : : return;
203 : : }
204 : 0 : print_data(0, (unsigned char *)data, length);
205 [ # # ]: 0 : xfree(data);
206 : : }
207 : :
208 : 0 : void show_pages(int fd_pages, struct cr_options *o)
209 : : {
210 : 0 : pr_img_head(CR_FD_PAGES);
211 : :
212 [ # # ]: 0 : if (o->show_pages_content) {
213 : : while (1) {
214 : : struct page_entry e;
215 : :
216 [ # # ]: 0 : if (read_img_eof(fd_pages, &e) <= 0)
217 : : break;
218 : :
219 : 0 : print_data(e.va, e.data, PAGE_IMAGE_SIZE);
220 : 0 : pr_msg("\n --- End of page ---\n\n");
221 : 0 : }
222 : : } else {
223 : : while (1) {
224 : : struct page_entry e;
225 : : int i;
226 : :
227 : 0 : pr_msg("\t");
228 [ # # ]: 0 : for (i = 0; i < DEF_PAGES_PER_LINE; i++) {
229 [ # # ]: 0 : if (read_img_eof(fd_pages, &e) <= 0) {
230 : 0 : pr_msg("\n");
231 : : goto out;
232 : : }
233 : :
234 : 0 : pr_msg("0x%16lx ", e.va);
235 : : }
236 : 0 : pr_msg("\n");
237 : 0 : }
238 : : }
239 : :
240 : : out:
241 : 0 : pr_img_tail(CR_FD_PAGES);
242 : 0 : }
243 : :
244 : 0 : void show_sigacts(int fd_sigacts, struct cr_options *o)
245 : : {
246 : 0 : pb_show_plain(fd_sigacts, PB_SIGACT);
247 : 0 : }
248 : :
249 : 0 : void show_itimers(int fd, struct cr_options *o)
250 : : {
251 : 0 : pb_show_plain_pretty(fd, PB_ITIMERS, "1:%Lu 2:%Lu 3:%Lu 4:%Lu");
252 : 0 : }
253 : :
254 : 0 : void show_creds(int fd, struct cr_options *o)
255 : : {
256 : 0 : pb_show_vertical(fd, PB_CREDS);
257 : 0 : }
258 : :
259 : 0 : static void pstree_handler(int fd, void *obj, int collect)
260 : : {
261 : 0 : PstreeEntry *e = obj;
262 : 0 : struct pstree_item *item = NULL;
263 : :
264 [ # # ]: 0 : if (!collect)
265 : : return;
266 : :
267 [ # # ]: 0 : item = xzalloc(sizeof(struct pstree_item));
268 [ # # ]: 0 : if (!item)
269 : : return;
270 : :
271 : 0 : item->pid.virt = e->pid;
272 : 0 : item->nr_threads = e->n_threads;
273 [ # # ]: 0 : item->threads = xzalloc(sizeof(u32) * e->n_threads);
274 [ # # ]: 0 : if (!item->threads) {
275 [ # # ]: 0 : xfree(item);
276 : : return;
277 : : }
278 : :
279 : 0 : list_add_tail(&item->sibling, &pstree_list);
280 : : }
281 : :
282 : 0 : void show_collect_pstree(int fd, int collect)
283 : : {
284 : 0 : pb_show_plain_payload_pretty(fd, PB_PSTREE, pstree_handler,
285 : : collect, "1:%d 2:%d 3:%d 4:%d 5:%d");
286 : 0 : }
287 : :
288 : 0 : void show_pstree(int fd, struct cr_options *o)
289 : : {
290 : 0 : show_collect_pstree(fd, 0);
291 : 0 : }
292 : :
293 : : static inline char *task_state_str(int state)
294 : : {
295 : : switch (state) {
296 : : case TASK_ALIVE:
297 : : return "running/sleeping";
298 : : case TASK_DEAD:
299 : : return "zombie";
300 : : default:
301 : : return "UNKNOWN";
302 : : }
303 : : }
304 : :
305 : 0 : static void show_core_regs(UserX86RegsEntry *regs)
306 : : {
307 : : #define pr_regs4(s, n1, n2, n3, n4) \
308 : : pr_msg("\t%8s: 0x%-16lx " \
309 : : "%8s: 0x%-16lx " \
310 : : "%8s: 0x%-16lx " \
311 : : "%8s: 0x%-16lx\n", \
312 : : #n1, s->n1, \
313 : : #n2, s->n2, \
314 : : #n3, s->n3, \
315 : : #n4, s->n4)
316 : :
317 : : #define pr_regs3(s, n1, n2, n3) \
318 : : pr_msg("\t%8s: 0x%-16lx " \
319 : : "%8s: 0x%-16lx " \
320 : : "%8s: 0x%-16lx\n", \
321 : : #n1, s->n1, \
322 : : #n2, s->n2, \
323 : : #n3, s->n3)
324 : :
325 : 0 : pr_msg("\t---[ GP registers set ]---\n");
326 : :
327 : 0 : pr_regs4(regs, cs, ip, ds, es);
328 : 0 : pr_regs4(regs, ss, sp, fs, gs);
329 : 0 : pr_regs4(regs, di, si, dx, cx);
330 : 0 : pr_regs4(regs, ax, r8, r9, r10);
331 : 0 : pr_regs4(regs, r11, r12, r13, r14);
332 : 0 : pr_regs3(regs, r15, bp, bx);
333 : 0 : pr_regs4(regs, orig_ax, flags, fs_base, gs_base);
334 : 0 : pr_msg("\n");
335 : 0 : }
336 : :
337 : 0 : void show_thread_info(ThreadInfoX86 *thread_info)
338 : : {
339 [ # # ]: 0 : if (!thread_info)
340 : 0 : return;
341 : :
342 : 0 : pr_msg("\t---[ Thread info ]---\n");
343 : 0 : pr_msg("\tclear_tid_addr: 0x%lx\n", thread_info->clear_tid_addr);
344 : 0 : pr_msg("\n");
345 : :
346 : 0 : show_core_regs(thread_info->gpregs);
347 : : }
348 : :
349 : 0 : void show_core(int fd_core, struct cr_options *o)
350 : : {
351 : 0 : pb_show_vertical(fd_core, PB_CORE);
352 : 0 : }
353 : :
354 : 0 : void show_mm(int fd_mm, struct cr_options *o)
355 : : {
356 : 0 : pb_show_vertical(fd_mm, PB_MM);
357 : 0 : }
358 : :
359 : : static struct {
360 : : u32 magic;
361 : : u32 mask;
362 : : char *hint;
363 : : } magic_hints[] = {
364 : : { .magic = 0x45311224, .mask = 0xffffffff, .hint = "ip route dump", },
365 : : { .magic = 0x47361222, .mask = 0xffffffff, .hint = "ip ifaddr dump", },
366 : : { .magic = 0x00008b1f, .mask = 0x0000ffff, .hint = "gzip file", },
367 : : { },
368 : : };
369 : :
370 : 0 : static void try_hint_magic(u32 magic)
371 : : {
372 : : int i;
373 : :
374 [ # # ]: 0 : for (i = 0; magic_hints[i].hint != 0; i++)
375 [ # # ]: 0 : if ((magic & magic_hints[i].mask) == magic_hints[i].magic)
376 : 0 : pr_msg("This can be %s\n", magic_hints[i].hint);
377 : 0 : }
378 : :
379 : 0 : static int cr_parse_file(struct cr_options *opts)
380 : : {
381 : : u32 magic;
382 : 0 : int fd = -1, ret = -1, i;
383 : :
384 : 0 : fd = open(opts->show_dump_file, O_RDONLY);
385 [ # # ]: 0 : if (fd < 0) {
386 : 0 : pr_perror("Can't open %s", opts->show_dump_file);
387 : 0 : goto err;
388 : : }
389 : :
390 [ # # ]: 0 : if (read_img(fd, &magic) < 0)
391 : : goto err;
392 : :
393 [ # # ]: 0 : for (i = 0; i < CR_FD_MAX; i++)
394 [ # # ]: 0 : if (fdset_template[i].magic == magic)
395 : : break;
396 : :
397 [ # # ]: 0 : if (i == CR_FD_MAX) {
398 : 0 : pr_err("Unknown magic %#x in %s\n",
399 : : magic, opts->show_dump_file);
400 : 0 : try_hint_magic(magic);
401 : 0 : goto err;
402 : : }
403 : :
404 [ # # ]: 0 : if (!fdset_template[i].show) {
405 : 0 : pr_err("No handler for %#x/%s\n",
406 : : magic, opts->show_dump_file);
407 : 0 : goto err;
408 : : }
409 : :
410 : 0 : fdset_template[i].show(fd, opts);
411 : 0 : ret = 0;
412 : : err:
413 : 0 : close_safe(&fd);
414 : 0 : return ret;
415 : : }
416 : :
417 : 0 : static int cr_show_all(struct cr_options *opts)
418 : : {
419 : 0 : struct pstree_item *item = NULL, *tmp;
420 : 0 : int i, ret = -1, fd, pid;
421 : :
422 : 0 : fd = open_image_ro(CR_FD_PSTREE);
423 [ # # ]: 0 : if (fd < 0)
424 : : goto out;
425 : 0 : show_collect_pstree(fd, 1);
426 : 0 : close(fd);
427 : :
428 : 0 : fd = open_image_ro(CR_FD_SK_QUEUES);
429 [ # # ]: 0 : if (fd < 0)
430 : : goto out;
431 : :
432 : 0 : show_sk_queues(fd, opts);
433 : 0 : close(fd);
434 : :
435 : 0 : pid = list_first_entry(&pstree_list, struct pstree_item, sibling)->pid.virt;
436 : 0 : ret = try_show_namespaces(pid, opts);
437 [ # # ]: 0 : if (ret)
438 : : goto out;
439 : :
440 [ # # ]: 0 : list_for_each_entry(item, &pstree_list, sibling) {
441 : 0 : struct cr_fdset *cr_fdset = NULL;
442 : :
443 : 0 : cr_fdset = cr_task_fdset_open(item->pid.virt, O_SHOW);
444 [ # # ]: 0 : if (!cr_fdset)
445 : : goto out;
446 : :
447 : 0 : show_core(fdset_fd(cr_fdset, CR_FD_CORE), opts);
448 : :
449 [ # # ]: 0 : if (item->nr_threads > 1) {
450 : : int fd_th;
451 : :
452 [ # # ]: 0 : for (i = 0; i < item->nr_threads; i++) {
453 : :
454 [ # # ]: 0 : if (item->threads[i].virt == item->pid.virt)
455 : 0 : continue;
456 : :
457 : 0 : fd_th = open_image_ro(CR_FD_CORE, item->threads[i]);
458 [ # # ]: 0 : if (fd_th < 0)
459 : : goto out;
460 : :
461 : 0 : pr_msg("\n");
462 : 0 : pr_msg("Thread: %d\n", item->threads[i].virt);
463 : 0 : pr_msg("----------------------------------------\n");
464 : :
465 : 0 : show_core(fd_th, opts);
466 : 0 : close_safe(&fd_th);
467 : :
468 : 0 : pr_msg("----------------------------------------\n");
469 : :
470 : : }
471 : : }
472 : :
473 [ # # ]: 0 : for (i = _CR_FD_TASK_FROM + 1; i < _CR_FD_TASK_TO; i++)
474 [ # # ][ # # ]: 0 : if (i != CR_FD_CORE && fdset_template[i].show)
475 : 0 : fdset_template[i].show(fdset_fd(cr_fdset, i), opts);
476 : :
477 : 0 : close_cr_fdset(&cr_fdset);
478 : : }
479 : :
480 : : out:
481 [ # # ]: 0 : list_for_each_entry_safe(item, tmp, &pstree_list, sibling) {
482 : 0 : list_del(&item->sibling);
483 [ # # ]: 0 : xfree(item->threads);
484 [ # # ]: 0 : xfree(item);
485 : : }
486 : 0 : return ret;
487 : : }
488 : :
489 : 0 : int cr_show(struct cr_options *opts)
490 : : {
491 [ # # ]: 0 : if (opts->show_dump_file)
492 : 0 : return cr_parse_file(opts);
493 : :
494 : 0 : return cr_show_all(opts);
495 : : }
|