mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-08-19 11:56:28 +00:00
kvm tools: Lookup symbol based on RIP for 'kill -3'
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.hejun@gmail.com> Cc: Avi Kivity <avi@redhat.com> Cc: Cyrill Gorcunov <gorcunov@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Prasad Joshi <prasadjoshi124@gmail.com> Cc: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
3780b3d5e7
commit
b0b42ba014
@@ -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/ \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user