>From 2074f09c27354d46b94d2e191b4bf4e43c25f5db Mon Sep 17 00:00:00 2001 From: root <root@xxxxxxxxxxxxxxxx> Date: Mon, 4 May 2009 23:06:58 +0530 Subject: [PATCH] Display local variables and function parameters Introduce the command 'local' in crash utility which allows one to display local variables and argumement in the current active stack frame. It uses interfaces provided by libdw library. Signed-off-by: Sharyathi Nagesh <sharyath@xxxxxxxxxxxxxxxxxx> Signed-off-by: M. Mohan Kumar <mohan@xxxxxxxxxx> Signed-off-by: Sachin P Sant <sachinp@xxxxxxxxxx> --- extensions/local.c | 731 +++++++++++++++++++++++++++++++++++++++++++++++++++ extensions/local.h | 88 ++++++ extensions/local.mk | 14 + netdump.c | 99 +++++++ netdump.h | 3 + 5 files changed, 935 insertions(+), 0 deletions(-) create mode 100644 extensions/local.c create mode 100644 extensions/local.h create mode 100644 extensions/local.mk diff --git a/extensions/local.c b/extensions/local.c new file mode 100644 index 0000000..e6559cd --- /dev/null +++ b/extensions/local.c @@ -0,0 +1,731 @@ +/* local.c - this implements command to display local variables and arguments + * for current stack frame. + * + * Copyright (c) International Business Machines Corp., 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <dwarf.h> +#include <elfutils/libdw.h> +#include "defs.h" /* From the crash source top-level directory */ +#include "../netdump.h" +#include "local.h" + +/* Main Function */ +void cmd_local(); + +/* Initializations functions */ +static int initial_setup(void); /* Does the initial Dwarf setup */ +static int open_file(void); /* Returns the file descriptor for the Executable */ +static int initialize_local(); +static int initialize_register(); + +/* x86 arch specific code */ +static ulong fetch_register_x86(int reg); +static int assign_register_x86(int reg, ulong value); + +/* ppc64 arch specific code */ +static ulong fetch_register_ppc64(int reg); +static int assign_register_ppc64(int reg, ulong value); + +/* x86_64 arch specific code */ +static ulong fetch_register_x86_64(int reg); +static int assign_register_x86_64(int reg, ulong value); + +/* Dwarf routines */ +static void print_function_variables(); +static void print_variables(Dwarf_Die *); +static void print_variable(Dwarf_Die *, Dwarf_Die *); +static void get_function_dies(Dwarf_Die **, int *); +static ulong translate(Dwarf_Op *, size_t , ulong *,bool *); +static Dwarf_Op * get_location(Dwarf_Attribute *, Dwarf_Addr , size_t *); +static ulong variable_address(Dwarf_Die *, Dwarf_Die *, ulong *); + +/* generic functions */ +static int str_to_option(char *str); +static void read_vmcore(ulong , size_t, void *); + +static Elf *elf_descriptor; +static Dwarf *dbg; +static int fd; +char *help_local[]; + +#define DISPLAY_ARGS 0x00000001 +#define DISPLAY_LOCALS 0x00000002 +#define STACK_UNWIND_UP 0x00000004 +#define STACK_UNWIND_DOWN 0x00000008 + +struct local_context *local = NULL; +static struct command_table_entry command_table[] = { + { "local", cmd_local, help_local, 0 }, /* One or more commands, */ + { NULL } /* terminated by NULL, */ +}; + +/* + * The _init() function is called if the shared object is loaded. + * If desired, performs initialization here. + */ +int +_init() /* Register the command set. */ +{ + register_extension(command_table); + if (initial_setup() && initialize_local()) + return 1; + else + return -1; +} + +static int +initialize_local() +{ + if(local){ + free(local->regs); + local->regs = NULL; + free(local); + local = NULL; + } + local = calloc(1, sizeof(struct local_context)); + local->tc = CURRENT_CONTEXT(); + if(KDUMP_DUMPFILE() || NETDUMP_DUMPFILE()){ + if(!initialize_register()) + return 0; + } + else{ + error(FATAL, + "Support for only KDUMP/NETDUMPs is available"); + return 0; + } + return 1; +} + +static int initialize_register() +{ + void *pt_regs; + pt_regs = get_regs_from_elf_notes(local->tc); + switch(get_netdump_arch()) + { + case EM_386: + local->regs = calloc(1, sizeof(struct pt_regs_x86)); + if(!local->regs){ + fprintf(fp, "\n Memory allocation failed"); + return 0; + } + memcpy(local->regs, pt_regs, sizeof(struct pt_regs_x86)); + local->pc = ((struct pt_regs_x86 *)local->regs)->ip; + local->fetch_register = fetch_register_x86; + local->assign_register = assign_register_x86; + break; + case EM_PPC64: + local->regs = calloc(1, sizeof(struct pt_regs_ppc64)); + if(!local->regs){ + fprintf(fp, "\n Memory allocation failed"); + return 0; + } + memcpy(local->regs, pt_regs, sizeof(struct pt_regs_ppc64)); + local->pc = ((struct pt_regs_ppc64 *)local->regs)->nip; + local->fetch_register = fetch_register_ppc64; + local->assign_register = assign_register_ppc64; + break; + case EM_X86_64: + local->regs = calloc(1, sizeof(struct pt_regs_x86_64)); + if(!local->regs){ + fprintf(fp, "\n Memory allocation failed"); + return 0; + } + memcpy(local->regs, pt_regs, sizeof(struct pt_regs_x86_64)); + local->pc = ((struct pt_regs_x86_64 *)local->regs)->ip; + local->fetch_register = fetch_register_x86_64; + local->assign_register = assign_register_x86_64; + break; + default: + error(FATAL, + "Support for ELF machine type %d not available", + get_netdump_arch()); + return 0; + } + return 1; +} + +int +static initial_setup(void) +{ + + Elf_Cmd elf_cmd = ELF_C_READ; + Dwarf_Cmd dwarf_cmd = DWARF_C_READ; + int fd; + + if (elf_version(EV_CURRENT) == EV_NONE) { + error(FATAL, + "libelf.a out of date \n"); + return 0; + } + + fd = open_file(); + if (fd < 0) + return 0; + + elf_descriptor = elf_begin(fd, elf_cmd, (Elf *) 0); + + dbg = dwarf_begin_elf(elf_descriptor, dwarf_cmd, NULL); + if (!dbg) { + error(FATAL, + "Failed to get dwarf header error %s", + dwarf_errmsg(dwarf_errno())); + return 0; + } + return 1; +} + +/* + * Reads the vmlinux exe file and returns a file descriptor to calling function + */ +static int +open_file() +{ + extern struct program_context *pc; + + if (pc->namelist_debug) + fd = open(pc->namelist_debug, O_RDONLY); + else + fd = open(pc->namelist, O_RDONLY); + return fd; +} + +/* + * The _fini() function is called if the shared object is unloaded. + * If desired, performs cleanups here. + */ +int +_fini() +{ + if(local){ + if (local->regs){ + free(local->regs); + local->regs = NULL; + } + free(local); + local = NULL; + } + elf_end(elf_descriptor); + close(fd); + return 1; +} + +/* + * This function displays the local variables and argument information + * It takes input like 1. params, locals, up and down + */ +void +cmd_local() +{ + int c; + extern struct program_context *pc; + if (local->tc != CURRENT_CONTEXT()) + initialize_local(); + while ((c = getopt(argcnt, args, "")) != EOF) { + switch(c) + { + default: + argerrs++; + break; + } + } + if(argerrs) + cmd_usage(pc->curcmd,SYNOPSIS); + + while(args[optind]){ + switch(str_to_option(args[optind])) + { + case STACK_UNWIND_UP: + local->flags = STACK_UNWIND_UP; + /* Not implemented */ + break; + case STACK_UNWIND_DOWN: + local->flags = STACK_UNWIND_DOWN; + /* Not implemented */ + break; + case DISPLAY_LOCALS: + fprintf(fp, "display locals"); + local->flags = DISPLAY_LOCALS; + print_function_variables(); + break; + case DISPLAY_ARGS: + fprintf(fp, "display args"); + local->flags = DISPLAY_ARGS; + print_function_variables(); + break; + default: + cmd_usage(pc->curcmd,SYNOPSIS); + } + ++optind; + } +} + +static int +str_to_option(char *str) +{ + if(STREQ(str,"params")) + return DISPLAY_ARGS; + else if(STREQ(str, "locals")) + return DISPLAY_LOCALS; + else if(STREQ(str, "up")) + return STACK_UNWIND_UP; + else if(STREQ(str,"down")) + return STACK_UNWIND_DOWN; + else + return 0; +} + +static void +print_function_variables() +{ + Dwarf_Die *scopes; + int nscopes; + int index; + + scopes = NULL; + get_function_dies(&scopes,&nscopes); + for(index = 0; index < nscopes; index++){ + switch(dwarf_tag(&scopes[index])){ + case DW_TAG_subprogram: + case DW_TAG_entry_point: + case DW_TAG_inlined_subroutine: + print_variables(&scopes[index]); + break; + default: + break; + } + } +} + +static void +get_function_dies(Dwarf_Die **scopes, int *nscopes) +{ + Dwarf_Die result_cu; + Dwarf_Die *cu_die; + Dwarf_Addr addr = local->pc; + + cu_die = dwarf_addrdie(dbg, addr, &result_cu); + if (!cu_die) + error(FATAL, + "unabled to get the compiler Unit for the address: %p", addr); + *nscopes = dwarf_getscopes(cu_die, addr, scopes); + if((*nscopes) < 0) + error(FATAL, + "unable to get the function die at address %p", addr); +} + +static void +print_variables(Dwarf_Die *fun_die) +{ + Dwarf_Die result; + if (dwarf_child (fun_die, &result) == 0) + do{ + switch (dwarf_tag (&result)) + { + case DW_TAG_variable: + if(local->flags & DISPLAY_LOCALS) + print_variable(fun_die, &result); + break; + case DW_TAG_formal_parameter: + if(local->flags & DISPLAY_ARGS) + print_variable(fun_die, &result); + break; + default: + break; + } + }while(dwarf_siblingof(&result,&result) == 0); +} + +int var_type (Dwarf_Die *typedie, char space) +{ + int tag; + Dwarf_Attribute attr_mem; + Dwarf_Die die_mem; + Dwarf_Die *die; + const char *name; + int size = 0; + + if (typedie == NULL) + fprintf (fp,"%c<no type>", space); + else + { + name = dwarf_diename (typedie); + if (name != NULL) + fprintf (fp, "%c%c%s", space, space, name); + + die = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem), &die_mem); + + tag = dwarf_tag (typedie); + name = dwarf_diename (die); + + if (name) + fprintf(fp, "\t%c%c%s\t", space, space, dwarf_diename (die)); + + switch (tag) + { + case DW_TAG_pointer_type: + size = dwarf_bytesize(die); + fputc('*', fp); + break; + case DW_TAG_array_type: + fprintf (fp, "[]"); + break; + case DW_TAG_const_type: + fprintf (fp, " const"); + break; + case DW_TAG_volatile_type: + fprintf (fp, " volatile"); + size = dwarf_bytesize(die); + break; + case DW_TAG_base_type: + break; + default: + fprintf (fp, "%c<unknown %#x>", space, tag); + break; + } + } + return size; +} + +static void +print_variable(Dwarf_Die *fun_die, Dwarf_Die *var_die) +{ + size_t size; + ulong var_addr; + ulong value = 0; + int pointer_desize; + Dwarf_Attribute attr_mem; + Dwarf_Die typedie_mem; + + fprintf(fp,"\n %s\t", dwarf_diename(var_die)); + + Dwarf_Die *typedie = dwarf_formref_die (dwarf_attr_integrate (var_die, DW_AT_type, &attr_mem), &typedie_mem); + + pointer_desize = var_type (typedie, '\t'); + size = dwarf_bytesize(typedie); + + var_addr = variable_address (fun_die,var_die, &value); + if (!var_addr && !value) { + fprintf(fp, "\t Dwarf information not available"); + return; + } + + if(!value && var_addr) { + if (size != ULONG_MAX) + read_vmcore(var_addr,size, &value); + else + read_vmcore(var_addr,pointer_desize, &value); + + if (pointer_desize && size != ULONG_MAX) { + char ch; + char *p = (char *)value; + short int s; + int i; + ulong l; + + fprintf(fp, "0x%lx: ", value); + switch (pointer_desize) { + case 1: /* char * */ + do { + read_vmcore((ulong)p++, 1, &ch); + fputc(ch, fp); + } while(ch!='\0'); + break; + case 2: /* short int * */ + read_vmcore(value, 2, &s); + fprintf(fp, "%d\n", s); + break; + case 8: /* long * */ + read_vmcore(value, 2, &l); + fprintf(fp, "%ld\n", l); + break; + case 4: /* int * */ + read_vmcore(value, 4, &i); + fprintf(fp, "%d\n", i); + break; + } + } else + fprintf(fp,"\tvalue:%ld",value); + + } else + fprintf(fp,"\tvalue:%ld",value); + +} + +static void +read_vmcore(ulong addr, size_t size, void *value) +{ + if (readmem(addr, KVADDR, value, size, "read_vmcore", RETURN_ON_ERROR) == FALSE) + fprintf(fp, "read_vmcore error\n"); + +} + +static ulong +variable_address(Dwarf_Die *fun_die, Dwarf_Die *var_die, ulong *value) +{ + size_t len; + Dwarf_Op *locexpr; + bool need_fb; + Dwarf_Attribute fb_attr, loc_attr; + Dwarf_Addr addr = local->pc; + ulong var_addr = 0x0; + if(!dwarf_attr_integrate(var_die, DW_AT_location, &loc_attr)) + goto out; + + locexpr = get_location(&loc_attr, addr, &len); + if (!locexpr) + goto out; + + var_addr = translate(locexpr, len, value, &need_fb); + if (need_fb) { + if(!dwarf_attr_integrate(fun_die, DW_AT_frame_base, &fb_attr)) + goto out; + + locexpr = get_location(&fb_attr, addr, &len); + if (!locexpr) + goto out; + + var_addr += translate(locexpr, len, value, 0); + } + return var_addr; + out: + return 0; +} + +static ulong +translate(Dwarf_Op *locexpr, size_t len, ulong *value ,bool *need_fb) +{ + int i; + unsigned int reg; + unsigned long loc = 0; + unsigned long offset = 0; + for (i=0; i<len; i++) { + switch (locexpr[i].atom) { + case DW_OP_reg0 ... DW_OP_reg31: + reg = locexpr[i].atom - DW_OP_reg0; + goto op_reg; + case DW_OP_regx: + reg = locexpr[i].number; + op_reg: + *value = local->fetch_register(reg); + break; + case DW_OP_fbreg: + *need_fb = true; + loc = locexpr[i].number; + break; + case DW_OP_addr: + loc = locexpr[i].number; + break; + case DW_OP_breg0 ... DW_OP_breg31: + reg = locexpr[i].atom - DW_OP_breg0; + offset = locexpr[i].number; + loc = local->fetch_register(reg) + offset; + break; + case DW_OP_bregx: + reg = locexpr[i].number; + offset = locexpr[i].number2; + loc = local->fetch_register(reg) + offset; + break; + default: + error(FATAL, + "unprocessed OpCode in translate()"); + break; + } + } + return loc; +} + +static ulong +fetch_register_x86(int reg) +{ + struct pt_regs_x86 *pt_regs; + pt_regs = (struct pt_regs_x86 *)local->regs; + + switch(reg){ + case 0: return pt_regs->ax; + case 1: return pt_regs->cx; + case 2: return pt_regs->dx; + case 3: return pt_regs->bx; + case 4: return pt_regs->sp; + case 5: return pt_regs->bp; + case 6: return pt_regs->si; + case 7: return pt_regs->di; + default: + error(FATAL, + "unhandled x86 register %d", reg); + } + return 0; +} + + +static int +assign_register_x86(int reg, ulong value) +{ + struct pt_regs_x86 *pt_regs; + pt_regs = (struct pt_regs_x86 *)local->regs; + + switch(reg){ + case 0: pt_regs->ax = value;break; + case 1: pt_regs->cx = value;break; + case 2: pt_regs->dx = value;break; + case 3: pt_regs->bx = value;break; + case 4: pt_regs->sp = value;break; + case 5: pt_regs->bp = value;break; + case 6: pt_regs->si = value;break; + case 7: pt_regs->di = value;break; + default: + error(FATAL, + "unhandled x86 register %d", reg); + return 0; + } + return 1; +} + +static ulong +fetch_register_x86_64(int reg) +{ + struct pt_regs_x86_64 *pt_regs; + pt_regs = (struct pt_regs_x86_64 *)local->regs; + + switch(reg){ + case 0: return pt_regs->ax; + case 1: return pt_regs->dx; + case 2: return pt_regs->cx; + case 3: return pt_regs->bx; + case 4: return pt_regs->si; + case 5: return pt_regs->di; + case 6: return pt_regs->bp; + case 7: return pt_regs->sp; + case 8: return pt_regs->r8; + case 9: return pt_regs->r9; + case 10: return pt_regs->r10; + case 11: return pt_regs->r11; + case 12: return pt_regs->r12; + case 13: return pt_regs->r13; + case 14: return pt_regs->r14; + case 15: return pt_regs->r15; + default: + error(FATAL, + "fetch_register_x86_64: unhandled x86_64 register %d", reg); + } + return 0; +} + +static int +assign_register_x86_64(int reg, ulong value) +{ + struct pt_regs_x86_64 *pt_regs; + pt_regs = (struct pt_regs_x86_64 *)local->regs; + + switch(reg){ + case 0: pt_regs->ax = value;break; + case 1: pt_regs->dx = value;break; + case 2: pt_regs->cx = value;break; + case 3: pt_regs->bx = value;break; + case 4: pt_regs->si = value;break; + case 5: pt_regs->di = value;break; + case 6: pt_regs->bp = value;break; + case 7: pt_regs->sp = value;break; + case 8: pt_regs->r8 = value;break; + case 9: pt_regs->r9 = value;break; + case 10: pt_regs->r10 = value;break; + case 11: pt_regs->r11 = value;break; + case 12: pt_regs->r12 = value;break; + case 13: pt_regs->r13 = value;break; + case 14: pt_regs->r14 = value;break; + case 15: pt_regs->r15 = value;break; + default: + error(FATAL, + "assign_register_x86_64: unhandled x86_64 register %d", reg); + return 0; + } + return 1; +} + +static ulong +fetch_register_ppc64(int reg) +{ + struct pt_regs_ppc64 *regs; + regs = (struct pt_regs_ppc64 *)local->regs; + if (reg >= 32) + error(FATAL, "fetch_register_ppc64 unknown reg %d\n", reg); + return (ulong)regs->gpr[reg]; +} + +static int +assign_register_ppc64(int reg, ulong value ) +{ + struct pt_regs_ppc64 *regs; + regs = (struct pt_regs_ppc64 *)local->regs; + if (reg >= 32){ + error(FATAL, "assign_register_ppc64 unknown reg %d\n", reg); + return 0; + } + regs->gpr[reg] = value; + return 1; +} + +static Dwarf_Op * +get_location(Dwarf_Attribute *location, Dwarf_Addr addr, size_t *len) +{ + Dwarf_Op *expr; + switch(dwarf_getlocation_addr(location, addr, &expr,len,1)) + { + case 1: + if( len > 0) + break; + case 0: + return NULL; + break; + default: + return NULL; + } + return expr; +} + + +/* + * NAME + * local - Displays local variables + * + * SYNOPSIS + * local params locals ... + * + * DESCRIPTION + * This command displays local variables for a functions. + * + * EXAMPLE + * + * crash> local <locals|params> + * + */ + +char *help_local[] = { + "local", /* command name */ + "displays local variables in current context", /* short description */ + " This command displays local variables as well as parameters.", + "\nEXAMPLE", + " crash> local <locals|params>", + NULL +}; diff --git a/extensions/local.h b/extensions/local.h new file mode 100644 index 0000000..320592b --- /dev/null +++ b/extensions/local.h @@ -0,0 +1,88 @@ +/* local.h - this has primary declaration as used by local + * + * Copyright (c) International Business Machines Corp., 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +struct local_context { + struct task_context *tc; + void *regs; + Dwarf_Addr pc; + ulong flags; + ulong (*fetch_register)(int n); + int (*assign_register)(int n, ulong value); +}; + +struct pt_regs_ppc64 { + long gpr[32]; + long nip; + long msr; + long orig_gpr3; /* Used for restarting system calls */ + long ctr; + long link; + long xer; + long ccr; + long mq; /* 601 only (not used at present) */ + /* Used on APUS to hold IPL value. */ + long trap; /* Reason for being here */ + long dar; /* Fault registers */ + long dsisr; + long result; /* Result of a system call */ +}; + +struct pt_regs_x86 { + unsigned long bx; + unsigned long cx; + unsigned long dx; + unsigned long si; + unsigned long di; + unsigned long bp; + unsigned long ax; + unsigned long ds; + unsigned long es; + unsigned long fs; + unsigned long orig_ax; + unsigned long ip; + unsigned long cs; + unsigned long flags; + unsigned long sp; + unsigned long ss; +}; + +struct pt_regs_x86_64 { + unsigned long r15; + unsigned long r14; + unsigned long r13; + unsigned long r12; + unsigned long bp; + unsigned long bx; + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long ax; + unsigned long cx; + unsigned long dx; + unsigned long si; + unsigned long di; + unsigned long orig_ax; + unsigned long ip; + unsigned long cs; + unsigned long flags; + unsigned long sp; + unsigned long ss; +}; diff --git a/extensions/local.mk b/extensions/local.mk new file mode 100644 index 0000000..3ba385a --- /dev/null +++ b/extensions/local.mk @@ -0,0 +1,14 @@ +# +ifeq ($(TARGET), PPC64) + TARGET_FLAGS = -D$(TARGET) -m64 +else + TARGET_FLAGS = -D$(TARGET) +endif + +all: local.so + +local.so: ../defs.h local.c local.h + gcc -nostartfiles -shared -rdynamic -o $@ local.c -fPIC -ldw -L ../../elfutils-0.137/libdw -I ../../elfutils-0.137/libdw -I ../../elfutils-0.137/libelf/ -D$(TARGET) $(TARGET_CFLAGS) $(ADD_CFLAGS) -Wall; + +clean: + rm -rf local.o local.so diff --git a/netdump.c b/netdump.c index c4a6656..2639cb7 100644 --- a/netdump.c +++ b/netdump.c @@ -31,6 +31,8 @@ static size_t dump_Elf64_Nhdr(Elf64_Off offset, int); static void get_netdump_regs_ppc64(struct bt_info *, ulong *, ulong *); static physaddr_t xen_kdump_p2m(physaddr_t); static void check_dumpfile_size(char *); +static void* get_ppc64_regs_from_elf_notes(struct task_context *tc); +static void* get_x86_64_regs_from_elf_notes(struct task_context *tc); #define ELFSTORE 1 #define ELFREAD 0 @@ -567,6 +569,18 @@ int netdump_memory_used(void) return (VMCORE_VALID() ? 0 : 0); } +int get_netdump_arch(void) +{ + int e_machine; + if (nd->elf32) + e_machine = nd->elf32->e_machine; + else if(nd->elf64) + e_machine = nd->elf64->e_machine; + else + e_machine = EM_NONE; + + return e_machine; +} /* * The netdump server will eventually use the NT_TASKSTRUCT section * to pass the task address. Until such time, look at the ebp of the @@ -2250,6 +2264,91 @@ get_netdump_regs_ppc64(struct bt_info *bt, ulong *eip, ulong *esp) machdep->get_stack_frame(bt, eip, esp); } +void* get_regs_from_elf_notes(struct task_context *tc) +{ + switch(get_netdump_arch()) + { + case EM_386: + error(FATAL, + "Support for EM_386 machine type not available"); + return NULL; + case EM_PPC64: + return get_ppc64_regs_from_elf_notes(tc); + case EM_X86_64: + return get_x86_64_regs_from_elf_notes(tc); + default: + error(FATAL, + "Support for ELF machine type %d not available", + get_netdump_arch()); + return NULL; + } +} + +static void* get_x86_64_regs_from_elf_notes(struct task_context *tc) +{ + Elf64_Nhdr *note; + size_t len; + char *pt_regs; + ulong regs_size; + + if((tc->task == tt->panic_task) || + (is_task_active(tc->task))){ + if (nd->num_prstatus_notes > 1) + note = (Elf64_Nhdr *) + nd->nt_prstatus_percpu[tc->processor]; + else + note = (Elf64_Nhdr *)nd->nt_prstatus; + + len = sizeof(Elf64_Nhdr); + len = roundup(len + note->n_namesz, 4); + len = roundup(len + note->n_descsz, 4); + + regs_size = VALID_STRUCT(user_regs_struct) ? + SIZE(user_regs_struct) : + sizeof(struct x86_64_user_regs_struct); + pt_regs = ((char *)note + len) - regs_size - sizeof(long); + } + else + error(FATAL, "\n cannot determine register set for the task %s" + "bailing out\n ", tc->comm); + return pt_regs; + +} +static void* get_ppc64_regs_from_elf_notes(struct task_context *tc) +{ + Elf64_Nhdr *note; + size_t len; + void* pt_regs = NULL; + extern struct vmcore_data *nd; + if ((tc->task == tt->panic_task) || + (is_task_active(tc->task) && nd->num_prstatus_notes > 1)) { + /* + * Registers are saved during the dump process for the + * panic task. Whereas in kdump, regs are captured for all + * CPUs if they responded to an IPI. + */ + if (nd->num_prstatus_notes > 1) { + if (tc->processor >= nd->num_prstatus_notes) + error(FATAL, "cannot determine NT_PRSTATUS ELF note " + "for %s task: %lx\n", (tc->task == tt->panic_task) ? + "panic" : "active", tc->task); + note = (Elf64_Nhdr *) + nd->nt_prstatus_percpu[tc->processor]; + } else + note = (Elf64_Nhdr *)nd->nt_prstatus; + + len = sizeof(Elf64_Nhdr); + len = roundup(len + note->n_namesz, 4); + pt_regs = (void *)((char *)note + len + + MEMBER_OFFSET("elf_prstatus", "pr_reg")); + } + else + error(FATAL, "\n cannot determine register set for the task %s" + "bailing out\n ", tc->comm); + return pt_regs; +} + + int is_partial_netdump(void) { diff --git a/netdump.h b/netdump.h index 2417d9d..bbba15a 100644 --- a/netdump.h +++ b/netdump.h @@ -121,3 +121,6 @@ struct xen_kdump_data { #define KDUMP_MFN_LIST (0x4) #define P2M_FAILURE ((physaddr_t)(0xffffffffffffffffLL)) + +extern int get_netdump_arch(void); +extern void* get_regs_from_elf_notes(struct task_context *tc); -- 1.6.0.2
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility