To make debugging easier, look up symbol from guest kernel image based on RIP when user does 'kill -3' to the hypervisor.
Example output looks as follows: Code: ----- rip: [<ffffffff812cb3a0>] delay_loop+30 (/home/penberg/linux/arch/x86/lib/delay.c:32) Cc: Asias He <asias.he...@gmail.com> Cc: Avi Kivity <a...@redhat.com> Cc: Cyrill Gorcunov <gorcu...@gmail.com> Cc: Ingo Molnar <mi...@elte.hu> Cc: Prasad Joshi <prasadjoshi...@gmail.com> Cc: Sasha Levin <levinsasha...@gmail.com> Signed-off-by: Pekka Enberg <penb...@kernel.org> --- tools/kvm/Makefile | 2 + tools/kvm/include/kvm/kvm.h | 2 + tools/kvm/include/kvm/symbol.h | 12 +++++ tools/kvm/kvm-cpu.c | 9 ++++ tools/kvm/kvm-run.c | 43 +++++++++++++++-- tools/kvm/symbol.c | 98 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 tools/kvm/include/kvm/symbol.h create mode 100644 tools/kvm/symbol.c diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index fb839fc..1aaed24 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -24,6 +24,7 @@ OBJS += main.o OBJS += mmio.o OBJS += pci.o OBJS += rtc.o +OBJS += symbol.o OBJS += term.o OBJS += util.o OBJS += virtio/blk.o @@ -50,6 +51,7 @@ OBJS += bios/bios.o LIBS += -lrt LIBS += -lpthread +LIBS += -lbfd # Additional ARCH settings for x86 ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h index 501c74c..b310d50 100644 --- a/tools/kvm/include/kvm/kvm.h +++ b/tools/kvm/include/kvm/kvm.h @@ -28,6 +28,8 @@ struct kvm { u16 boot_sp; struct interrupt_table interrupt_table; + + const char *vmlinux; }; struct kvm *kvm__init(const char *kvm_dev, unsigned long ram_size); diff --git a/tools/kvm/include/kvm/symbol.h b/tools/kvm/include/kvm/symbol.h new file mode 100644 index 0000000..eaa84ea --- /dev/null +++ b/tools/kvm/include/kvm/symbol.h @@ -0,0 +1,12 @@ +#ifndef KVM__SYMBOL_H +#define KVM__SYMBOL_H + +#include <stddef.h> + +struct kvm; + +void symbol__init(const char *vmlinux); + +char *symbol__lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size); + +#endif /* KVM__SYMBOL_H */ diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c index 8a27e02..a507fa4 100644 --- a/tools/kvm/kvm-cpu.c +++ b/tools/kvm/kvm-cpu.c @@ -1,5 +1,6 @@ #include "kvm/kvm-cpu.h" +#include "kvm/symbol.h" #include "kvm/util.h" #include "kvm/kvm.h" @@ -9,6 +10,7 @@ #include <sys/mman.h> #include <signal.h> #include <stdlib.h> +#include <string.h> #include <errno.h> #include <stdio.h> @@ -282,11 +284,14 @@ void kvm_cpu__show_registers(struct kvm_cpu *vcpu) printf("\n"); } +#define MAX_SYM_LEN 128 + void kvm_cpu__show_code(struct kvm_cpu *vcpu) { unsigned int code_bytes = 64; unsigned int code_prologue = code_bytes * 43 / 64; unsigned int code_len = code_bytes; + char sym[MAX_SYM_LEN]; unsigned char c; unsigned int i; u8 *ip; @@ -302,6 +307,10 @@ void kvm_cpu__show_code(struct kvm_cpu *vcpu) printf("\n Code:\n"); printf( " -----\n"); + symbol__lookup(vcpu->kvm, vcpu->regs.rip, sym, MAX_SYM_LEN); + + printf(" rip: [<%016lx>] %s\n\n", (unsigned long) vcpu->regs.rip, sym); + for (i = 0; i < code_len; i++, ip++) { if (!host_ptr_in_ram(vcpu->kvm, ip)) break; diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c index 84f05cb..91a194e 100644 --- a/tools/kvm/kvm-run.c +++ b/tools/kvm/kvm-run.c @@ -26,6 +26,7 @@ #include <kvm/ioport.h> #include <kvm/threadpool.h> #include <kvm/barrier.h> +#include <kvm/symbol.h> /* header files for gitish interface */ #include <kvm/kvm-run.h> @@ -52,6 +53,7 @@ static u64 ram_size; static u8 image_count; static const char *kernel_cmdline; static const char *kernel_filename; +static const char *vmlinux_filename; static const char *initrd_filename; static const char *image_filename[MAX_DISK_IMAGES]; static const char *console; @@ -214,17 +216,25 @@ panic_kvm: } static char kernel[PATH_MAX]; -const char *host_kernels[] = { + +static const char *host_kernels[] = { "/boot/vmlinuz", "/boot/bzImage", NULL }; -const char *default_kernels[] = { + +static const char *default_kernels[] = { "./bzImage", "../../arch/x86/boot/bzImage", NULL }; +static const char *default_vmlinux[] = { + "../../../vmlinux", + "../../vmlinux", + NULL +}; + static void kernel_usage_with_options(void) { const char **k; @@ -317,6 +327,23 @@ static const char *find_kernel(void) return NULL; } +static const char *find_vmlinux(void) +{ + const char **vmlinux; + + vmlinux = &default_vmlinux[0]; + while (*vmlinux) { + struct stat st; + + if (stat(*vmlinux, &st) < 0 || !S_ISREG(st.st_mode)) { + vmlinux++; + continue; + } + return *vmlinux; + } + return NULL; +} + static int root_device(char *dev, long *part) { struct stat st; @@ -359,13 +386,13 @@ static char *host_image(char *cmd_line, size_t size) int kvm_cmd_run(int argc, const char **argv, const char *prefix) { + struct virtio_net_parameters net_params; static char real_cmdline[2048]; unsigned int nr_online_cpus; - int max_cpus; int exit_code = 0; - int i; - struct virtio_net_parameters net_params; + int max_cpus; char *hi; + int i; signal(SIGALRM, handle_sigalrm); signal(SIGQUIT, handle_sigquit); @@ -399,6 +426,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) return EINVAL; } + vmlinux_filename = find_vmlinux(); + if (nrcpus < 1 || nrcpus > KVM_NR_CPUS) die("Number of CPUs %d is out of [1;%d] range", nrcpus, KVM_NR_CPUS); @@ -433,6 +462,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) if (!script) script = DEFAULT_SCRIPT; + symbol__init(vmlinux_filename); + term_init(); kvm = kvm__init(kvm_dev, ram_size); @@ -482,6 +513,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) real_cmdline)) die("unable to load kernel %s", kernel_filename); + kvm->vmlinux = vmlinux_filename; + ioport__setup_legacy(); rtc__init(); diff --git a/tools/kvm/symbol.c b/tools/kvm/symbol.c new file mode 100644 index 0000000..56dd346 --- /dev/null +++ b/tools/kvm/symbol.c @@ -0,0 +1,98 @@ +#include "kvm/symbol.h" + +#include "kvm/kvm.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <bfd.h> + +static bfd *abfd; + +void symbol__init(const char *vmlinux) +{ + if (!vmlinux) + return; + + bfd_init(); + + abfd = bfd_openr(vmlinux, NULL); +} + +static asymbol *lookup(asymbol **symbols, int nr_symbols, const char *symbol_name) +{ + int i; + + for (i = 0; i < nr_symbols; i++) { + asymbol *symbol = symbols[i]; + + if (!strcmp(bfd_asymbol_name(symbol), symbol_name)) + return symbol; + } + + return NULL; +} + +char *symbol__lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size) +{ + const char *filename; + bfd_vma sym_offset; + bfd_vma sym_start; + asection *section; + unsigned int line; + const char *func; + long symtab_size; + asymbol *symbol; + asymbol **syms; + int nr_syms; + char *s; + + if (!abfd) + goto not_found; + + if (!bfd_check_format(abfd, bfd_object)) + goto not_found; + + symtab_size = bfd_get_symtab_upper_bound(abfd); + if (!symtab_size) + goto not_found; + + syms = malloc(symtab_size); + if (!syms) + goto not_found; + + nr_syms = bfd_canonicalize_symtab(abfd, syms); + + section = bfd_get_section_by_name(abfd, ".debug_aranges"); + if (!section) + goto not_found; + + if (!bfd_find_nearest_line(abfd, section, NULL, addr, &filename, &func, &line)) + goto not_found; + + if (!func) + goto not_found; + + symbol = lookup(syms, nr_syms, func); + if (!symbol) + goto not_found; + + sym_start = bfd_asymbol_value(symbol); + + sym_offset = addr - sym_start; + + snprintf(sym, size, "%s+%llx (%s:%i)", func, (long long) sym_offset, filename, line); + + sym[size - 1] = '\0'; + + free(syms); + + return sym; + +not_found: + s = strncpy(sym, "<unknown>", size); + + sym[size - 1] = '\0'; + + return s; +} -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html