From 52245517821bbbdad16aac3786b23609f81585bd Mon Sep 17 00:00:00 2001 From: Balazs Gerofi Date: Fri, 6 Mar 2020 18:34:26 +0900 Subject: [PATCH] mcinspect: vtop (in progress) Change-Id: I09f487e96edc7c4f59c97e6fb6dde28baf84c1e5 --- executer/user/CMakeLists.txt | 1 + executer/user/mcinspect.c | 318 +++++++++++++++++++++++++++++------ 2 files changed, 271 insertions(+), 48 deletions(-) diff --git a/executer/user/CMakeLists.txt b/executer/user/CMakeLists.txt index 0d5ce1b7..2abe4bfd 100644 --- a/executer/user/CMakeLists.txt +++ b/executer/user/CMakeLists.txt @@ -29,6 +29,7 @@ if (NOT LIBDWARF) else() target_link_libraries(mcinspect ${LIBDWARF}) endif() +target_link_libraries(mcinspect ${LIBBFD}) add_executable(eclair eclair.c arch/${ARCH}/arch-eclair.c) target_link_libraries(eclair ${LIBBFD}) diff --git a/executer/user/mcinspect.c b/executer/user/mcinspect.c index f368af60..af4f924f 100644 --- a/executer/user/mcinspect.c +++ b/executer/user/mcinspect.c @@ -22,6 +22,7 @@ #include #include #include +#include void usage(char **argv) { @@ -32,22 +33,88 @@ void usage(char **argv) printf(" --help Display this help message.\n"); printf(" --kernel PATH Path to kernel image.\n"); printf(" --ps List processes running on LWK.\n"); - printf(" -v, --vtop [ADDR] Display page table corresponding to ADDR\n"); - printf(" or dump all page tables.\n"); + printf(" --vtop Dump page tables.\n"); + printf(" -v, --va ADDR Dump page tables for ADDR only.\n"); + printf(" -p, --pid PID Use process PID for vtop.\n"); printf(" --debug Enable debug mode.\n"); printf("\n"); - printf("Example: \n"); + printf("Examples: \n"); printf(" %s --kernel=smp-x86/kernel/mckernel.img --ps\n", basename(argv[0])); + printf(" %s --kernel=smp-x86/kernel/mckernel.img --vtop --pid 100 --va 0x3fffff800000\n", + basename(argv[0])); } - int debug; int mcfd; +/* + * BFD based symbol table + */ +bfd *symbfd = NULL; +asymbol **symtab = NULL; +ssize_t nsyms; +#define NOSYMBOL (-1UL) + +unsigned long int lookup_bfd_symbol(char *name) +{ + int i; + + for (i = 0; i < nsyms; ++i) { + if (!strcmp(symtab[i]->name, name)) { + return (symtab[i]->section->vma + symtab[i]->value); + } + } + + return NOSYMBOL; +} + +int init_bfd_symbols(char *fname) { + ssize_t needs; + bfd_boolean ok; + + symbfd = bfd_openr(fname, NULL); + + if (!symbfd) { + bfd_perror("bfd_openr"); + return -1; + } + + ok = bfd_check_format(symbfd, bfd_object); + if (!ok) { + bfd_perror("bfd_check_format"); + return -1; + } + + needs = bfd_get_symtab_upper_bound(symbfd); + if (needs < 0) { + bfd_perror("bfd_get_symtab_upper_bound"); + return -1; + } + + if (!needs) { + printf("no symbols\n"); + return -1; + } + + symtab = malloc(needs); + if (!symtab) { + perror("malloc"); + return -1; + } + + nsyms = bfd_canonicalize_symtab(symbfd, symtab); + if (nsyms < 0) { + bfd_perror("bfd_canonicalize_symtab"); + return -1; + } + + return 0; +} + /* * Walk DWARF tree and call func with arg for each Die */ -static int dwarf_walk_tree(Dwarf_Debug dbg, +int dwarf_walk_tree(Dwarf_Debug dbg, int (*func)(Dwarf_Debug dbg, Dwarf_Die die, void *arg), void *arg) { Dwarf_Bool is_info; @@ -191,7 +258,7 @@ static int dwarf_walk_tree(Dwarf_Debug dbg, return -1; } -static int dwarf_get_size(Dwarf_Debug dbg, +int dwarf_get_size(Dwarf_Debug dbg, Dwarf_Die die, unsigned long *psize, Dwarf_Error *perr) @@ -345,7 +412,7 @@ out: }) -static int dwarf_get_offset(Dwarf_Debug dbg, +int dwarf_get_offset(Dwarf_Debug dbg, Dwarf_Die die, unsigned long *poffset, Dwarf_Error *perr) @@ -560,7 +627,7 @@ out: /* * Find the address of a global variable. */ -static int dwarf_get_address(Dwarf_Debug dbg, +int dwarf_get_address(Dwarf_Debug dbg, Dwarf_Die die, unsigned long *paddr, Dwarf_Error *perr) @@ -611,6 +678,7 @@ static int dwarf_get_address(Dwarf_Debug dbg, if (attr_i != DW_AT_location) { continue; } + printf("%s: DW_AT_location\n", __func__); rc = dwarf_whatform(attr, &form, perr); if (rc != DW_DLV_OK) { @@ -779,8 +847,11 @@ int dwarf_global_var_addr(Dwarf_Debug dbg, Dwarf_Die die, void *arg) goto out; } + printf("%s: inspecting %s\n", __func__, name); + rc = dwarf_get_address(dbg, die, &addr, &err); if (rc == DW_DLV_NO_ENTRY) { + printf("%s: inspecting %s -> DW_DLV_NO_ENTRY for addr?\n", __func__, name); goto out; } else if (rc != DW_DLV_OK) { @@ -812,11 +883,14 @@ out: .variable = #__variable__, \ .addrp = &addr, \ }; \ - rc = dwarf_walk_tree(dbg, dwarf_global_var_addr, &gva); \ - if (rc != DW_DLV_OK) { \ - fprintf(stderr, "%s: error: finding addr of %s\n", \ - __func__, gva.variable); \ - exit(1); \ + addr = lookup_bfd_symbol(gva.variable); \ + if (addr == NOSYMBOL) { \ + rc = dwarf_walk_tree(dbg, dwarf_global_var_addr, &gva); \ + if (rc != DW_DLV_OK) { \ + fprintf(stderr, "%s: error: finding addr of %s\n", \ + __func__, gva.variable); \ + exit(1); \ + } \ } \ addr; \ }) @@ -831,7 +905,7 @@ struct ihk_os_read_kaddr_desc { void *ubuf; }; -static void ihk_read_kernel(unsigned long addr, +void ihk_read_kernel(unsigned long addr, unsigned long len, void *buf) { struct ihk_os_read_kaddr_desc desc; @@ -850,6 +924,14 @@ static void ihk_read_kernel(unsigned long addr, #define ihk_read_val(addr, pval) \ ihk_read_kernel(addr, sizeof(*pval), (void *)pval) +#define get_pointer_symbol_val(__variable__, pval) \ +({ \ + unsigned long addr; \ + addr = DWARF_GET_VARIABLE_ADDRESS(__variable__); \ + ihk_read_kernel(addr, sizeof(*pval), (void *)pval); \ +}) + + #define PS_RUNNING 0x1 #define PS_INTERRUPTIBLE 0x2 #define PS_UNINTERRUPTIBLE 0x4 @@ -857,6 +939,9 @@ static void ihk_read_kernel(unsigned long addr, #define PS_EXITED 0x10 #define PS_STOPPED 0x20 +/* + * Globals + */ int nr_cpus; unsigned long clv; unsigned long clv_size; @@ -868,10 +953,44 @@ unsigned long thread_sched_list_offset; unsigned long thread_proc_offset; unsigned long thread_status_offset; unsigned long process_pid_offset; +unsigned long process_vm_offset; unsigned long process_saved_cmdline_offset; unsigned long process_saved_cmdline_len_offset; +unsigned long vm_address_space_offset; +unsigned long address_space_page_table_offset; -static void print_thread(int cpu, +void init_globals(Dwarf_Debug dbg) +{ + unsigned long num_processors_addr; + + num_processors_addr = DWARF_GET_VARIABLE_ADDRESS(mck_num_processors); + ihk_read_val(num_processors_addr, &num_processors_addr); + ihk_read_val(num_processors_addr, &nr_cpus); + ihk_read_val(DWARF_GET_VARIABLE_ADDRESS(clv), &clv); + clv_size = DWARF_GET_SIZE(cpu_local_var); + + clv_runq_offset = DWARF_GET_OFFSET_IN_STRUCT(cpu_local_var, runq); + clv_idle_offset = DWARF_GET_OFFSET_IN_STRUCT(cpu_local_var, idle); + clv_current_offset = DWARF_GET_OFFSET_IN_STRUCT(cpu_local_var, current); + thread_tid_offset = DWARF_GET_OFFSET_IN_STRUCT(thread, tid); + thread_proc_offset = DWARF_GET_OFFSET_IN_STRUCT(thread, proc); + thread_status_offset = DWARF_GET_OFFSET_IN_STRUCT(thread, status); + thread_sched_list_offset = + DWARF_GET_OFFSET_IN_STRUCT(thread, sched_list); + process_pid_offset = DWARF_GET_OFFSET_IN_STRUCT(process, pid); + process_saved_cmdline_offset = + DWARF_GET_OFFSET_IN_STRUCT(process, saved_cmdline); + process_saved_cmdline_len_offset = + DWARF_GET_OFFSET_IN_STRUCT(process, saved_cmdline_len); + process_vm_offset = + DWARF_GET_OFFSET_IN_STRUCT(process, vm); + vm_address_space_offset = + DWARF_GET_OFFSET_IN_STRUCT(process_vm, address_space); + address_space_page_table_offset = + DWARF_GET_OFFSET_IN_STRUCT(address_space, page_table); +} + +void print_thread(int cpu, unsigned long thread, unsigned long idle, int active) @@ -925,31 +1044,9 @@ static void print_thread(int cpu, free(cmd_line); } - -static int mcps(Dwarf_Debug dbg) +int mcps(Dwarf_Debug dbg) { int cpu; - unsigned long num_processors_addr; - - num_processors_addr = DWARF_GET_VARIABLE_ADDRESS(mck_num_processors); - ihk_read_val(num_processors_addr, &num_processors_addr); - ihk_read_val(num_processors_addr, &nr_cpus); - ihk_read_val(DWARF_GET_VARIABLE_ADDRESS(clv), &clv); - clv_size = DWARF_GET_SIZE(cpu_local_var); - - clv_runq_offset = DWARF_GET_OFFSET_IN_STRUCT(cpu_local_var, runq); - clv_idle_offset = DWARF_GET_OFFSET_IN_STRUCT(cpu_local_var, idle); - clv_current_offset = DWARF_GET_OFFSET_IN_STRUCT(cpu_local_var, current); - thread_tid_offset = DWARF_GET_OFFSET_IN_STRUCT(thread, tid); - thread_proc_offset = DWARF_GET_OFFSET_IN_STRUCT(thread, proc); - thread_status_offset = DWARF_GET_OFFSET_IN_STRUCT(thread, status); - thread_sched_list_offset = - DWARF_GET_OFFSET_IN_STRUCT(thread, sched_list); - process_pid_offset = DWARF_GET_OFFSET_IN_STRUCT(process, pid); - process_saved_cmdline_offset = - DWARF_GET_OFFSET_IN_STRUCT(process, saved_cmdline); - process_saved_cmdline_len_offset = - DWARF_GET_OFFSET_IN_STRUCT(process, saved_cmdline_len); printf("%3s %s%6s %6s %18s %2s %s\n", "CPU", " ", "TID", "PID", "Thread", "ST", "exe"); @@ -991,12 +1088,107 @@ static int mcps(Dwarf_Debug dbg) return 0; } +int find_proc(Dwarf_Debug dbg, int pid, unsigned long *rproc) +{ + int cpu; + + /* Iterate CPUs */ + for (cpu = 0; cpu < nr_cpus; ++cpu) { + unsigned long per_cpu; + unsigned long runq; + unsigned long thread; + unsigned long thread_sched_list; + int ipid; + + per_cpu = clv + (clv_size * cpu); + runq = per_cpu + clv_runq_offset; + ihk_read_val(per_cpu + clv_runq_offset, &thread_sched_list); + + /* Iterate threads */ + for (; thread_sched_list != runq; + ihk_read_val(thread_sched_list, &thread_sched_list)) { + unsigned long proc; + + thread = thread_sched_list - thread_sched_list_offset; + + ihk_read_val(thread + thread_proc_offset, &proc); + ihk_read_val(proc + process_pid_offset, &ipid); + + if (pid == ipid) { + *rproc = proc; + return 0; + } + } + } + + return -1; +} + + +#if 0 +void do_pte_walk_single(Dwarf_Debug dbg, + unsigned long pt, int level, unsigned long va) +{ + unsigned long pte; + int idx = va >> ptl_shift(level); + + ihk_read_val(pt + idx * sizeof(pte), &pte); + if (pte_is_type_page(pte, level)) { + + } + + if (level > 1) { + pt = + do_pte_walk_single(); + } +} + + +int print_pte_single(Dwarf_Debug dbg, + unsigned long pt, unsigned long va) +{ + int level = PGTABLE_LEVELS; + printf("VA: 0x%lx -> \n", va); + do_pte_walk_single(dbg, pt, PGTABLE_LEVELS, va); +} + +#endif + + +int mcvtop(Dwarf_Debug dbg, int pid, unsigned long vtop_addr) +{ + unsigned long proc = 0; + unsigned long init_pt; + unsigned long vm, ap, pt = 0; + + if (pid != 0) { + if (find_proc(dbg, pid, &proc) < 0) { + fprintf(stderr, "%s: error: finding PID %d\n", + __func__, pid); + return -1; + } + } + + get_pointer_symbol_val(swapper_page_table, &init_pt); + printf("%s: init_pt: 0x%lx\n", __func__, init_pt); + + if (proc) { + ihk_read_val(proc + process_vm_offset, &vm); + ihk_read_val(vm + vm_address_space_offset, &ap); + ihk_read_val(ap + address_space_page_table_offset, &pt); + } + + return 0; +} + + int help; int ps; int vtop; +int pid; unsigned long vtop_addr; -static struct option mcinspect_options[] = { +struct option mcinspect_options[] = { { .name = "kernel", .has_arg = required_argument, @@ -1015,17 +1207,29 @@ static struct option mcinspect_options[] = { .flag = &help, .val = 1, }, + { + .name = "debug", + .has_arg = no_argument, + .flag = &debug, + .val = 1, + }, { .name = "vtop", + .has_arg = no_argument, + .flag = &vtop, + .val = 1, + }, + { + .name = "va", .has_arg = required_argument, .flag = NULL, .val = 'v', }, { - .name = "debug", - .has_arg = no_argument, - .flag = &debug, - .val = 1, + .name = "pid", + .has_arg = required_argument, + .flag = NULL, + .val = 'p', }, /* end */ { NULL, 0, NULL, 0, }, @@ -1048,9 +1252,10 @@ int main(int argc, char **argv) help = 0; ps = 0; vtop = 0; - vtop_addr = -1; + vtop_addr = -1UL; + pid = 0; - while ((opt = getopt_long(argc, argv, "+k:v:", + while ((opt = getopt_long(argc, argv, "+k:v:p:", mcinspect_options, NULL)) != -1) { switch (opt) { case 'k': @@ -1058,7 +1263,17 @@ int main(int argc, char **argv) break; case 'v': - vtop_addr = strtoul(optarg, 0, 0); + vtop_addr = strtoul(optarg, 0, 16); + if (vtop_addr == 0 || + errno == EINVAL || errno == ERANGE) { + fprintf(stderr, "error: invalid VA? (expected format: 0xXXXX)\n\n"); + usage(argv); + exit(1); + } + break; + + case 'p': + pid = atoi(optarg); break; } } @@ -1075,10 +1290,16 @@ int main(int argc, char **argv) } if (!ps && !vtop) { + printf("PID: %d\n", pid); usage(argv); exit(1); } + if (init_bfd_symbols(kernel_path) < 0) { + fprintf(stderr, "error: accessing ELF image %s\n", kernel_path); + exit(1); + } + mcfd = open("/dev/mcos0", O_RDONLY); if (mcfd < 0) { fprintf(stderr, "error: opening IHK OS device file\n"); @@ -1097,12 +1318,13 @@ int main(int argc, char **argv) exit(1); } + init_globals(dbg); + if (ps) mcps(dbg); if (vtop) { - fprintf(stderr, "error: not implemented\n"); - exit(1); + mcvtop(dbg, pid, vtop_addr); } dwarf_finish(dbg, &error);