Index: crash-4.0-8.9-build/defs.h
===================================================================
--- crash-4.0-8.9-build.orig/defs.h 2009-05-24 19:25:20.000000000 +0530
+++ crash-4.0-8.9-build/defs.h 2009-05-24 19:26:37.000000000 +0530
@@ -4133,6 +4133,8 @@
ulong xen_phys_start(void);
int xen_major_version(void);
int xen_minor_version(void);
+int get_netdump_arch(void);
+void* get_regs_from_elf_notes(struct task_context *tc);
/*
* diskdump.c
Index: crash-4.0-8.9-build/extensions/local.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ crash-4.0-8.9-build/extensions/local.c 2009-05-25 02:23:57.000000000 +0530
@@ -0,0 +1,796 @@
+/* local.c - this implements command to display local variables and arguments
+ * for current stack frame.
+ *
+ * Copyright (c) International Business Machines Corp., 2001
+ *
+ * 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 "local/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);
+static int display_registers_x86(void);
+
+/* ppc64 arch specific code */
+static ulong fetch_register_ppc64(int reg);
+static int assign_register_ppc64(int reg, ulong value);
+static int display_registers_ppc64(void);
+
+/* x86_64 arch specific code */
+static ulong fetch_register_x86_64(int reg);
+static int assign_register_x86_64(int reg, ulong value);
+static int display_registers_x86_64(void);
+
+/* 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
+#define DISPLAY_REGS 0x00000010
+
+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;
+ local->display_registers = display_registers_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;
+ local->display_registers = display_registers_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;
+ local->display_registers = display_registers_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;
+
+ 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;
+ case DISPLAY_REGS:
+ local->flags = DISPLAY_REGS;
+ local->display_registers();
+ 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 if(STREQ(str,"display"))
+ return DISPLAY_REGS;
+ else
+ return 0;
+}
+
+static int display_registers_x86(void)
+{
+ struct pt_regs_x86 *pt_regs;
+ pt_regs = (struct pt_regs_x86 *)local->regs;
+ fprintf(fp, "\n IP: \t%lx ", local->pc);
+ fprintf(fp, "\n ax: \t%lx ", pt_regs->ax);
+ fprintf(fp, "\n bx: \t%lx ", pt_regs->bx);
+ fprintf(fp, "\n cx: \t%lx ", pt_regs->cx);
+ fprintf(fp, "\n dx: \t%lx ", pt_regs->dx);
+ fprintf(fp, "\n sp: \t%lx ", pt_regs->sp);
+ fprintf(fp, "\n bp: \t%lx ", pt_regs->bp);
+ fprintf(fp, "\n si: \t%lx ", pt_regs->si);
+ fprintf(fp, "\n di: \t%lx ", pt_regs->di);
+ fprintf(fp, "\n cs: \t%lx ", pt_regs->cs);
+ fprintf(fp, "\n oirg_ax: \t%lx ", pt_regs->orig_ax);
+ fprintf(fp, "\n flags: \t%lx ", pt_regs->flags);
+ fprintf(fp, "\n ip: \t%lx ", pt_regs->ip);
+ fprintf(fp, "\n");
+ return 0;
+}
+
+static int display_registers_x86_64(void)
+{
+ struct pt_regs_x86_64 *pt_regs;
+ pt_regs = (struct pt_regs_x86_64 *)local->regs;
+ fprintf(fp, "\n IP: \t%lx ", local->pc);
+ fprintf(fp, "\n ax: \t%lx ", pt_regs->ax);
+ fprintf(fp, "\n bx: \t%lx ", pt_regs->bx);
+ fprintf(fp, "\n cx: \t%lx ", pt_regs->cx);
+ fprintf(fp, "\n dx: \t%lx ", pt_regs->dx);
+ fprintf(fp, "\n sp: \t%lx ", pt_regs->sp);
+ fprintf(fp, "\n bp: \t%lx ", pt_regs->bp);
+ fprintf(fp, "\n si: \t%lx ", pt_regs->si);
+ fprintf(fp, "\n di: \t%lx ", pt_regs->di);
+ fprintf(fp, "\n cs: \t%lx ", pt_regs->cs);
+ fprintf(fp, "\n oirg_ax: \t%lx ", pt_regs->orig_ax);
+ fprintf(fp, "\n flags: \t%lx ", pt_regs->flags);
+ fprintf(fp, "\n ip: \t%lx ", pt_regs->ip);
+ fprintf(fp, "\n r8: \t%lx ", pt_regs->r8);
+ fprintf(fp, "\n r9: \t%lx ", pt_regs->r9);
+ fprintf(fp, "\n r10: \t%lx ", pt_regs->r10);
+ fprintf(fp, "\n r11: \t%lx ", pt_regs->r11);
+ fprintf(fp, "\n r12: \t%lx ", pt_regs->r12);
+ fprintf(fp, "\n r13: \t%lx ", pt_regs->r13);
+ fprintf(fp, "\n");
+ return 0;
+}
+
+static int display_registers_ppc64(void)
+{
+ int i;
+ struct pt_regs_ppc64 *reg;
+ reg = local->regs;
+ for(i=0;i<32;i++)
+ fprintf(fp, "\n reg[%d]\t %lx", i+1,reg->gpr[i]);
+ 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,
+ "\nunable to get the compiler Unit for the address: %p", addr);
+ *nscopes = dwarf_getscopes(cu_die, addr, scopes);
+ if((*nscopes) < 0)
+ error(FATAL,
+ "\nunable 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 = 0;
+ 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 = false;
+ Dwarf_Attribute fb_attr, loc_attr;
+ Dwarf_Addr addr = local->pc;
+ ulong var_addr = 0;
+ 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:
+ 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
+};
Index: crash-4.0-8.9-build/extensions/local.mk
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ crash-4.0-8.9-build/extensions/local.mk 2009-05-25 02:23:57.000000000 +0530
@@ -0,0 +1,14 @@
+all: local.so
+
+CFLAGS += -O3 -g -fPIC -Wall
+ifeq ($(TARGET), PPC64)
+ CFLAGS += -m64
+endif
+
+all: local.so
+
+local.so: defs.h local.c local/local.h
+ gcc -nostartfiles -shared $(CFLAGS) -rdynamic -o $@ local.c -ldw -D$(TARGET)
+
+clean:
+ rm -rf local.o local.so
Index: crash-4.0-8.9-build/netdump.c
===================================================================
--- crash-4.0-8.9-build.orig/netdump.c 2009-05-24 19:25:20.000000000 +0530
+++ crash-4.0-8.9-build/netdump.c 2009-05-25 02:24:50.000000000 +0530
@@ -31,6 +31,10 @@
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_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 +571,18 @@
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 +2266,116 @@
machdep->get_stack_frame(bt, eip, esp);
}
+void* get_regs_from_elf_notes(struct task_context *tc)
+{
+ switch(get_netdump_arch())
+ {
+ case EM_386:
+ return get_x86_regs_from_elf_notes(tc);
+ 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_regs_from_elf_notes(struct task_context *tc)
+{
+ Elf32_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 = (Elf32_Nhdr *)
+ nd->nt_prstatus_percpu[tc->processor];
+ else
+ note = (Elf64_Nhdr *)nd->nt_prstatus;
+
+ len = sizeof(Elf32_Nhdr);
+ len = roundup(len + note->n_namesz, 4);
+ pt_regs = (void *)((char *)note + len +
+ MEMBER_OFFSET("elf_prstatus", "pr_reg"));
+ /* NEED TO BE FIXED: Hack to get the proper alignment */
+ pt_regs +=4;
+ }
+ else
+ error(FATAL, "\n cannot determine register set for the task %s"
+ "bailing out\n ", tc->comm);
+ return pt_regs;
+
+}
+
+
+
+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);
+ 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;
+
+}
+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)
{
Index: crash-4.0-8.9-build/extensions/local/local.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ crash-4.0-8.9-build/extensions/local/local.h 2009-05-25 02:23:57.000000000 +0530
@@ -0,0 +1,89 @@
+/* local.h - this has primary declaration as used by local
+ *
+ * Copyright (c) International Business Machines Corp., 2001
+ *
+ * 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;
+ unsigned long pc;
+ ulong flags;
+ ulong (*fetch_register)(int n);
+ int (*assign_register)(int n, ulong value);
+ int (*display_registers)(void);
+};
+
+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;
+};
--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility