Hi Dave! anderson@xxxxxxxxxx wrote on 08/14/2006 04:58:11 PM: > This looks fine to me. Do me one favor, though, and run the build > through "make Warn"? There will be a couple minor items to clean > up in s390dbf.c. No problem, thanks for the hint! Here comes the updated version without warings. BTW: There are a couple of warnings in other files, which should probably be fixed, too. I use gcc 4.1.0 for our build on s390(x). I hope that I find time to fix the other warnings later. Thanks Michael --- Makefile | 7 defs.h | 6 global_data.c | 3 s390dbf.c | 1339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1353 insertions(+), 2 deletions(-) diff -Naur crash-4.0-3.1/Makefile crash-4.0-3.1-s390dbf/Makefile --- crash-4.0-3.1/Makefile 2006-08-04 17:24:00.000000000 +0200 +++ crash-4.0-3.1-s390dbf/Makefile 2006-08-14 17:17:23.000000000 +0200 @@ -73,7 +73,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \ kernel.c test.c gdb_interface.c configure.c net.c dev.c \ - alpha.c x86.c ppc.c ia64.c s390.c s390x.c ppc64.c x86_64.c \ + alpha.c x86.c ppc.c ia64.c s390.c s390x.c s390dbf.c ppc64.c x86_64.c \ extensions.c remote.c va_server.c va_server_v1.c symbols.c cmdline.c \ lkcd_common.c lkcd_v1.c lkcd_v2_v3.c lkcd_v5.c lkcd_v7.c lkcd_v8.c\ lkcd_fix_mem.c s390_dump.c lkcd_x86_trace.c \ @@ -85,7 +85,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \ build_data.o kernel.o test.o gdb_interface.o net.o dev.o \ - alpha.o x86.o ppc.o ia64.o s390.o s390x.o ppc64.o x86_64.o \ + alpha.o x86.o ppc.o ia64.o s390.o s390x.o s390dbf.o ppc64.o x86_64.o \ extensions.o remote.o va_server.o va_server_v1.o symbols.o cmdline.o \ lkcd_common.o lkcd_v1.o lkcd_v2_v3.o lkcd_v5.o lkcd_v7.o lkcd_v8.o \ lkcd_fix_mem.o s390_dump.o netdump.o diskdump.o xendump.o \ @@ -364,6 +364,9 @@ s390x.o: ${GENERIC_HFILES} ${IBM_HFILES} s390x.c cc -c ${CFLAGS} s390x.c ${WARNING_OPTIONS} ${WARNING_ERROR} +s390dbf.o: ${GENERIC_HFILES} ${IBM_HFILES} s390dbf.c + cc -c ${CFLAGS} s390dbf.c ${WARNING_OPTIONS} ${WARNING_ERROR} + s390_dump.o: ${GENERIC_HFILES} ${IBM_HFILES} s390_dump.c cc -c ${CFLAGS} s390_dump.c ${WARNING_OPTIONS} ${WARNING_ERROR} diff -Naur crash-4.0-3.1/defs.h crash-4.0-3.1-s390dbf/defs.h --- crash-4.0-3.1/defs.h 2006-08-04 17:24:00.000000000 +0200 +++ crash-4.0-3.1-s390dbf/defs.h 2006-08-14 17:17:27.000000000 +0200 @@ -2822,6 +2822,9 @@ void cmd_gdb(void); /* gdb_interface.c */ void cmd_net(void); /* net.c */ void cmd_extend(void); /* extensions.c */ +#if defined(S390) || defined(S390X) +void cmd_s390dbf(void); +#endif /* * main.c @@ -3239,6 +3242,9 @@ extern char *help_waitq[]; extern char *help_whatis[]; extern char *help_wr[]; +#if defined(S390) || defined(S390X) +extern char *help_s390dbf[]; +#endif /* * task.c diff -Naur crash-4.0-3.1/global_data.c crash-4.0-3.1-s390dbf/global_data.c --- crash-4.0-3.1/global_data.c 2006-08-04 17:24:00.000000000 +0200 +++ crash-4.0-3.1-s390dbf/global_data.c 2006-08-14 17:17:32.000000000 +0200 @@ -117,6 +117,9 @@ {"waitq", cmd_waitq, help_waitq, REFRESH_TASK_TABLE}, {"whatis", cmd_whatis, help_whatis, 0}, {"wr", cmd_wr, help_wr, 0}, +#if defined(S390) || defined(S390X) + {"s390dbf", cmd_s390dbf, help_s390dbf, 0}, +#endif {(char *)NULL} }; diff -Naur crash-4.0-3.1/s390dbf.c crash-4.0-3.1-s390dbf/s390dbf.c --- crash-4.0-3.1/s390dbf.c 1970-01-01 01:00:00.000000000 +0100 +++ crash-4.0-3.1-s390dbf/s390dbf.c 2006-08-14 17:17:40.000000000 +0200 @@ -0,0 +1,1339 @@ +/* + * s390 debug feature command for crash + * + * Copyright (C) IBM Corp. 2006 + * Author(s): Michael Holzheu <holzheu@xxxxxxxxxx> + */ + +#if defined(S390) || defined(S390X) + +#include "defs.h" +#include <iconv.h> +#include <ctype.h> + +/* + * Compat layer to integrate lcrash commands into crash + * Maps lcrash API to crash functions + */ + +#define KL_NBPW sizeof(long) +#define KL_ERRORFP stderr +#define MAX_ARGS 128 +#define MAX_CMDLINE 256 + +#define C_FALSE 0x00000001 /* Command takes no arguments */ +#define C_TRUE 0x00000002 /* Command requires arguments */ +#define C_ALL 0x00000004 /* All elements */ +#define C_PERM 0x00000008 /* Allocate perminant blocks */ +#define C_TEMP 0x00000000 /* For completeness */ +#define C_FULL 0x00000010 /* Full output */ +#define C_LIST 0x00000020 /* List items */ +#define C_NEXT 0x00000040 /* Follow links */ +#define C_WRITE 0x00000080 /* Write output to file */ +#define C_NO_OPCHECK 0x00000100 /* Don't reject bad cmd line options */ +#define C_ITER 0x00000200 /* set iteration threshold */ + +#define C_LFLG_SHFT 12 + +#define KL_ARCH_S390 0 +#define KL_ARCH_S390X 1 +#ifdef __s390x__ +#define KL_ARCH KL_ARCH_S390X +#define FMTPTR "l" +#define KL_PTRSZ 8 +#else +#define KL_ARCH KL_ARCH_S390 +#define FMTPTR "ll" +#define KL_PTRSZ 4 +#endif + +typedef unsigned long uaddr_t; +typedef unsigned long kaddr_t; + +typedef struct _syment { + char *s_name; + kaddr_t s_addr; +} syment_t; + +typedef struct option_s { + struct option_s *op_next; + char op_char; + char *op_arg; +} option_t; + +typedef struct command_s { + int flags; + char cmdstr[MAX_CMDLINE]; + char *command; + char *cmdline; + option_t *options; + int nargs; + char *args[MAX_ARGS]; + char *pipe_cmd; + FILE *ofp; + FILE *efp; +} command_t; + +static inline syment_t* kl_lkup_symaddr(kaddr_t addr) +{ + static syment_t sym; + struct syment *crash_sym; + + crash_sym = value_search(addr, &sym.s_addr); + if (!crash_sym) + return NULL; + sym.s_name = crash_sym->name; + return &sym; +} + +static inline syment_t* kl_lkup_symname(char* name) +{ + static syment_t sym; + sym.s_addr = symbol_value(name); + sym.s_name = NULL; + if(!sym.s_addr) + return NULL; + else + return &sym; +} + +static inline void GET_BLOCK(kaddr_t addr, int size, void* ptr) +{ + readmem(addr, KVADDR,ptr,size,"GET_BLOCK",FAULT_ON_ERROR); +} + +static inline kaddr_t KL_VREAD_PTR(kaddr_t addr) +{ + unsigned long ptr; + readmem(addr, KVADDR,&ptr,sizeof(ptr),"GET_BLOCK",FAULT_ON_ERROR); + return (kaddr_t)ptr; +} + +static inline uint32_t KL_GET_UINT32(void* ptr) +{ + return *((uint32_t*)ptr); +} + +static inline uint64_t KL_GET_UINT64(void* ptr) +{ + return *((uint64_t*)ptr); +} + +static inline kaddr_t KL_GET_PTR(void* ptr) +{ + return *((kaddr_t*)ptr); +} + +static inline void* K_PTR(void* addr, char* struct_name, char* member_name) +{ + return addr+MEMBER_OFFSET(struct_name,member_name); +} + +static inline uint32_t KL_UINT(void* ptr, char* struct_name, char* member_name) +{ + return (uint32_t) ULONG(ptr+MEMBER_OFFSET(struct_name,member_name)); +} + +static inline uint32_t KL_VREAD_UINT32(kaddr_t addr) +{ + uint32_t rc; + readmem(addr, KVADDR,&rc,sizeof(rc),"KL_VREAD_UINT32",FAULT_ON_ERROR); + return rc; +} + +static inline uint32_t KL_INT(void* ptr, char* struct_name, char* member_name) +{ + return UINT(ptr+MEMBER_OFFSET(struct_name,member_name)); +} + +static inline int set_cmd_flags(command_t *cmd, int flags, char *extraops) +{ + return 0; +} + +static inline void kl_s390tod_to_timeval(uint64_t todval, struct timeval *xtime) +{ + todval -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); + + todval >>= 12; + xtime->tv_sec = todval / 1000000; + xtime->tv_usec = todval % 1000000; +} + +static inline int kl_struct_len(char* struct_name) +{ + return STRUCT_SIZE(struct_name); +} + +static inline kaddr_t kl_funcaddr(kaddr_t addr) +{ + struct syment *crash_sym; + + crash_sym = value_search(addr, &addr); + if (!crash_sym) + return -1; + else + return crash_sym->value; +} + +#define CMD_USAGE(cmd, s) \ + fprintf(cmd->ofp, "Usage: %s %s\n", cmd->command, s); \ + fprintf(cmd->ofp, "Enter \"help %s\" for details.\n",cmd->command); + +/* + * s390 debug feature implementation + */ + +#ifdef DBF_DYNAMIC_VIEWS /* views defined in shared libs */ +#include <dlfcn.h> +#endif + +/* Local flags + */ + +#define LOAD_FLAG (1 << C_LFLG_SHFT) +#define VIEWS_FLAG (2 << C_LFLG_SHFT) + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +/* Stuff which has to match with include/asm-s390/debug.h */ + +#define DBF_VERSION_V1 1 +#define DBF_VERSION_V2 2 +#define PAGE_SIZE 4096 +#define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ +#define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */ +#define DEBUG_SPRINTF_MAX_ARGS 10 + +/* define debug-structures for lcrash */ +#define DEBUG_DATA(entry) (char*)(entry + 1) + +typedef struct debug_view_s debug_view_t; + +/* struct to hold contents of struct __debug_entry from dump + */ +typedef struct debug_entry_s{ + union { + struct { + unsigned long long clock:52; + unsigned long long exception:1; + unsigned long long level:3; + unsigned long long cpuid:8; + } fields; + + unsigned long long stck; + } id; + kaddr_t caller; /* changed from void* to kaddr_t */ +} __attribute__((packed)) debug_entry_t; +/* typedef struct __debug_entry debug_entry_t; */ + + +static unsigned int dbf_version; + +/* struct is used to manage contents of structs debug_info from dump + * in lcrash + */ +typedef struct debug_info_s { + struct debug_info_s *next; + struct debug_info_s *prev; + kaddr_t next_dbi; /* store next ptr of struct in dump */ + kaddr_t prev_dbi; /* store prev ptr of struct in dump */ + int level; + int nr_areas; + int page_order; + int buf_size; + int entry_size; + void **areas; /* contents of debug areas from dump */ + int active_area; + int *active_entry; /* change to uint32_t ? */ + debug_view_t *views[DEBUG_MAX_VIEWS]; + char name[DEBUG_MAX_PROCF_LEN]; + kaddr_t addr; + int pages_per_area_v2; + void ***areas_v2; +} debug_info_t; + + +/* functions to generate dbf output + */ +typedef int (debug_header_proc_t) (debug_info_t* id, debug_view_t* view, + int area, debug_entry_t* entry, + char* out_buf); +typedef int (debug_format_proc_t) (debug_info_t* id, debug_view_t* view, + char* out_buf, const char* in_buf); +typedef int (debug_prolog_proc_t) (debug_info_t* id, debug_view_t* view, + char* out_buf); + +struct debug_view_s { + char name[DEBUG_MAX_PROCF_LEN]; + debug_prolog_proc_t* prolog_proc; + debug_header_proc_t* header_proc; + debug_format_proc_t* format_proc; + void* private_data; +}; + +#define LCRASH_DB_VIEWS 1000 + +static debug_info_t *debug_area_first = NULL; +static debug_info_t *debug_area_last = NULL; +static debug_view_t *debug_views[LCRASH_DB_VIEWS]; +static int initialized = 0; +static iconv_t ebcdic_ascii_conv = 0; + +void s390dbf_usage(command_t * cmd); +static int add_lcrash_debug_view(debug_view_t *); +static int dbe_size = 0; + +static void +EBCASC(char *inout, size_t len) +{ + iconv(ebcdic_ascii_conv, &inout, &len, &inout, &len); +} + +/* + * prints header for debug entry + */ +static int +dflt_header_fn(debug_info_t * id, debug_view_t *view, + int area, debug_entry_t * entry, char *out_buf) +{ + struct timeval time_val; + unsigned long long time; + char *except_str; + kaddr_t caller; + int rc = 0; + char *caller_name; + int offset; + char caller_buf[30]; + unsigned int level; + syment_t *caller_sym; + debug_entry_t lentry; /* store byte swapped values of entry */ + + lentry.id.stck = KL_GET_UINT64(&entry->id); + lentry.caller = KL_GET_PTR(&entry->caller); + level = lentry.id.fields.level; + time = lentry.id.stck; + + kl_s390tod_to_timeval(time, &time_val); + + if (lentry.id.fields.exception) + except_str = "*"; + else + except_str = "-"; + caller = lentry.caller; + if(KL_ARCH == KL_ARCH_S390){ + caller &= 0x7fffffff; + } + caller_sym = kl_lkup_symaddr(caller); + if(caller_sym){ + caller_name = caller_sym->s_name; + offset = caller - kl_funcaddr(caller); + } + else { + sprintf(caller_buf, "%"FMTPTR"x", caller); + caller_name = caller_buf; + offset = 0; + } + + if(KL_ARCH == KL_ARCH_S390X){ + rc += sprintf(out_buf, + "%02i %011lu:%06lu %1u %1s %02i <%20s+%04i> ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller_name, + offset); + } else { + rc += sprintf(out_buf, + "%02i %011lu:%06lu %1u %1s %02i <%-20s+%04i> ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, lentry.id.fields.cpuid, caller_name, + offset); + } + return rc; +} + +/* + * prints debug header in raw format + */ +static int +raw_header_fn(debug_info_t * id, debug_view_t *view, + int area, debug_entry_t * entry, char *out_buf) +{ + int rc; + + rc = sizeof(debug_entry_t); + if (out_buf == NULL) + goto out; + memcpy(out_buf,entry,sizeof(debug_entry_t)); + out: + return rc; +} + +/* + * prints debug data in raw format + */ +static int +raw_format_fn(debug_info_t * id, debug_view_t *view, + char *out_buf, const char *in_buf) +{ + int rc; + + rc = id->buf_size; + if (out_buf == NULL || in_buf == NULL) + goto out; + memcpy(out_buf, in_buf, id->buf_size); + out: + return rc; +} + +/* + * prints debug data in hex/ascii format + */ +static int +hex_ascii_format_fn(debug_info_t * id, debug_view_t *view, + char *out_buf, const char *in_buf) +{ + int i, rc = 0; + + if (out_buf == NULL || in_buf == NULL) { + rc = id->buf_size * 4 + 3; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + rc += sprintf(out_buf + rc, "%02x ", + ((unsigned char *) in_buf)[i]); + } + rc += sprintf(out_buf + rc, "| "); + for (i = 0; i < id->buf_size; i++) { + unsigned char c = in_buf[i]; + if (!isprint(c)) + rc += sprintf(out_buf + rc, "."); + else + rc += sprintf(out_buf + rc, "%c", c); + } + rc += sprintf(out_buf + rc, "\n"); + out: + return rc; +} + +/* + * prints debug data in sprintf format + */ +static int +sprintf_format_fn(debug_info_t * id, debug_view_t *view, + char *out_buf, const char *in_buf) +{ +#define _BUFSIZE 1024 + char buf[_BUFSIZE]; + int i, k, rc = 0, num_longs = 0, num_used_args = 0, num_strings = 0; + /* use kaddr_t to store long values of 32bit and 64bit archs here */ + kaddr_t inbuf_cpy[DEBUG_SPRINTF_MAX_ARGS]; + /* store ptrs to strings to be deallocated at end of this function */ + uaddr_t to_dealloc[DEBUG_SPRINTF_MAX_ARGS]; + kaddr_t addr; + + memset(buf, 0, sizeof(buf)); + memset(inbuf_cpy, 0, sizeof(inbuf_cpy)); + memset(to_dealloc, 0, sizeof(to_dealloc)); + + if (out_buf == NULL || in_buf == NULL) { + rc = id->buf_size * 4 + 3; + goto out; + } + + /* get the format string into buf */ + addr = KL_GET_PTR((void*)in_buf); + GET_BLOCK(addr, _BUFSIZE, buf); + + k = 0; + for (i = 0; buf[i] && (buf[i] != '\n'); i++) { + if (buf[i] != '%') + continue; + if (k == DEBUG_SPRINTF_MAX_ARGS) { + fprintf(KL_ERRORFP, + "\nToo much parameters in sprinf view (%i)\n" + ,k + 1); + fprintf(KL_ERRORFP, "Format String: %s)\n", buf); + break; + } + /* for sprintf we have only unsigned long values ... */ + if (buf[i+1] != 's'){ + /* we use KL_GET_PTR here to read ulong value */ + addr = KL_GET_PTR((void*) in_buf + ((k + 1)* KL_NBPW)); + inbuf_cpy[k] = addr; + } else { /* ... or ptrs to strings in debug areas */ + inbuf_cpy[k] = (uaddr_t) malloc(_BUFSIZE); + to_dealloc[num_strings++] = inbuf_cpy[k]; + addr = KL_GET_PTR((void*) in_buf + ((k + 1)* KL_NBPW)); + GET_BLOCK(addr, _BUFSIZE, + (void*)(uaddr_t)(inbuf_cpy[k])); + } + k++; + } + + /* count of longs fit into one entry */ + num_longs = id->buf_size / KL_NBPW; /* sizeof(long); */ + if(num_longs < 1) /* bufsize of entry too small */ + goto out; + if(num_longs == 1) { /* no args, just print the format string */ + rc = sprintf(out_buf + rc, "%s", buf); + goto out; + } + + /* number of arguments used for sprintf (without the format string) */ + num_used_args = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); + + rc = sprintf(out_buf + rc, buf, (uaddr_t)(inbuf_cpy[0]), + (uaddr_t)(inbuf_cpy[1]), (uaddr_t)(inbuf_cpy[2]), + (uaddr_t)(inbuf_cpy[3]), (uaddr_t)(inbuf_cpy[4]), + (uaddr_t)(inbuf_cpy[5]), (uaddr_t)(inbuf_cpy[6]), + (uaddr_t)(inbuf_cpy[7]), (uaddr_t)(inbuf_cpy[8]), + (uaddr_t)(inbuf_cpy[9])); + out: + while (num_strings--){ + free((char*)(to_dealloc[num_strings])); + } + return rc; +} + + +/*********************************** + * functions for debug-views + ***********************************/ + +/* + * prints out actual debug level + */ +static int +prolog_level_fn(debug_info_t * id, + debug_view_t *view, char *out_buf) +{ + int rc = 0; + + if (out_buf == NULL) { + rc = 2; + goto out; + } + rc = sprintf(out_buf, "%i\n", id->level); + out: + return rc; +} + +/* + * prints out actual pages_per_area + */ +static int +prolog_pages_fn(debug_info_t * id, + debug_view_t *view, char *out_buf) +{ + int rc = 0; + + if (out_buf == NULL) { + rc = 2; + goto out; + } + rc = sprintf(out_buf, "%i\n", id->pages_per_area_v2); + out: + return rc; +} + +/* + * prints out prolog + */ +static int +prolog_fn(debug_info_t * id, + debug_view_t *view, char *out_buf) +{ + int rc = 0; + + rc = sprintf(out_buf, "AREA TIME LEVEL EXCEPTION CP CALLING FUNCTION" + " + OFFSET DATA\n===================================" + "=======================================\n"); + return rc; +} + +/* + * prints debug data in hex format + */ +static int +hex_format_fn(debug_info_t * id, debug_view_t *view, + char *out_buf, const char *in_buf) +{ + int i, rc = 0; + + for (i = 0; i < id->buf_size; i++) { + rc += sprintf(out_buf + rc, "%02x ", + ((unsigned char *) in_buf)[i]); + } + rc += sprintf(out_buf + rc, "\n"); + return rc; +} + +/* + * prints debug data in ascii format + */ +static int +ascii_format_fn(debug_info_t * id, debug_view_t *view, + char *out_buf, const char *in_buf) +{ + int i, rc = 0; + + if (out_buf == NULL || in_buf == NULL) { + rc = id->buf_size + 1; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + unsigned char c = in_buf[i]; + if (!isprint(c)) + rc += sprintf(out_buf + rc, "."); + else + rc += sprintf(out_buf + rc, "%c", c); + } + rc += sprintf(out_buf + rc, "\n"); + out: + return rc; +} + +/* + * prints debug data in ebcdic format + */ +static int +ebcdic_format_fn(debug_info_t * id, debug_view_t *view, + char *out_buf, const char *in_buf) +{ + int i, rc = 0; + + if (out_buf == NULL || in_buf == NULL) { + rc = id->buf_size + 1; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + char c = in_buf[i]; + EBCASC(&c, 1); + if (!isprint(c)) + rc += sprintf(out_buf + rc, "."); + else + rc += sprintf(out_buf + rc, "%c", c); + } + rc += sprintf(out_buf + rc, "\n"); + out: + return rc; +} + +debug_view_t ascii_view = { + "ascii", + &prolog_fn, + &dflt_header_fn, + &ascii_format_fn, +}; + +debug_view_t ebcdic_view = { + "ebcdic", + &prolog_fn, + &dflt_header_fn, + &ebcdic_format_fn, +}; + +debug_view_t hex_view = { + "hex", + &prolog_fn, + &dflt_header_fn, + &hex_format_fn, +}; + +debug_view_t level_view = { + "level", + &prolog_level_fn, + NULL, + NULL, +}; + +debug_view_t pages_view = { + "pages", + &prolog_pages_fn, + NULL, + NULL, +}; + +debug_view_t raw_view = { + "raw", + NULL, + &raw_header_fn, + &raw_format_fn, +}; + +debug_view_t hex_ascii_view = { + "hex_ascii", + &prolog_fn, + &dflt_header_fn, + &hex_ascii_format_fn, +}; + +debug_view_t sprintf_view = { + "sprintf", + &prolog_fn, + &dflt_header_fn, + &sprintf_format_fn, +}; + + +static debug_entry_t * +debug_find_oldest_entry(debug_entry_t *entries, int num, int entry_size) +{ + debug_entry_t *result, *current; + int i; + uint64_t clock1, clock2; + + result = entries; + current = entries; + for (i=0; i < num; i++) { + if (current->id.stck == 0) + break; + clock1 = current->id.fields.clock; + clock2 = result->id.fields.clock; + clock1 = KL_GET_UINT64(&clock1); + clock2 = KL_GET_UINT64(&clock2); + if (clock1 < clock2) + result = current; + current = (debug_entry_t *) ((char *) current + entry_size); + } + return result; +} + + +/* + * debug_format_output: + * - calls prolog, header and format functions of view to format output + */ +static int +debug_format_output_v1(debug_info_t * debug_area, debug_view_t *view, + FILE * ofp) +{ + int i, j, len; + int nr_of_entries; + debug_entry_t *act_entry, *last_entry; + char *act_entry_data; + char buf[2048]; + + /* print prolog */ + if (view->prolog_proc) { + len = view->prolog_proc(debug_area, view, buf); + fwrite(buf,len, 1, ofp); + memset(buf, 0, 2048); + } + /* print debug records */ + if (!(view->format_proc) && !(view->header_proc)) + goto out; + if(debug_area->entry_size <= 0){ + fprintf(ofp, "Invalid entry_size: %i\n",debug_area->entry_size); + goto out; + } + nr_of_entries = (PAGE_SIZE << debug_area->page_order) / debug_area->entry_size; + for (i = 0; i < debug_area->nr_areas; i++) { + act_entry = debug_find_oldest_entry(debug_area->areas[i], + nr_of_entries, + debug_area->entry_size); + last_entry = (debug_entry_t *) ((char *) debug_area->areas[i] + + (PAGE_SIZE << debug_area->page_order) - + debug_area->entry_size); + for (j = 0; j < nr_of_entries; j++) { + act_entry_data = (char*)act_entry + dbe_size; + if (act_entry->id.stck == 0) + break; /* empty entry */ + if (view->header_proc) { + len = view->header_proc(debug_area, view, i, + act_entry, buf); + fwrite(buf,len, 1, ofp); + memset(buf, 0, 2048); + } + if (view->format_proc) { + len = view->format_proc(debug_area, view, + buf, act_entry_data); + fwrite(buf,len, 1, ofp); + memset(buf, 0, 2048); + } + act_entry = + (debug_entry_t *) (((char *) act_entry) + + debug_area->entry_size); + if (act_entry > last_entry) + act_entry = debug_area->areas[i]; + } + } + out: + return 1; +} + +/* + * debug_format_output_v2: + * - calls prolog, header and format functions of view to format output + */ +static int +debug_format_output_v2(debug_info_t * debug_area, + debug_view_t *view, FILE * ofp) +{ + int i, j, k, len; + debug_entry_t *act_entry; + char *act_entry_data; + char buf[2048]; + + /* print prolog */ + if (view->prolog_proc) { + len = view->prolog_proc(debug_area, view, buf); + fwrite(buf,len, 1, ofp); + memset(buf, 0, 2048); + } + /* print debug records */ + if (!(view->format_proc) && !(view->header_proc)) + goto out; + if(debug_area->entry_size <= 0){ + fprintf(ofp, "Invalid entry_size: %i\n",debug_area->entry_size); + goto out; + } + for (i = 0; i < debug_area->nr_areas; i++) { + int nr_entries_per_page = PAGE_SIZE/debug_area->entry_size; + for (j = 0; j < debug_area->pages_per_area_v2; j++) { + act_entry = debug_area->areas_v2[i][j]; + for (k = 0; k < nr_entries_per_page; k++) { + act_entry_data = (char*)act_entry + dbe_size; + if (act_entry->id.stck == 0) + break; /* empty entry */ + if (view->header_proc) { + len = view->header_proc(debug_area, + view, i, act_entry, buf); + fwrite(buf,len, 1, ofp); + memset(buf, 0, 2048); + } + if (view->format_proc) { + len = view->format_proc(debug_area, + view, buf, act_entry_data); + fwrite(buf,len, 1, ofp); + memset(buf, 0, 2048); + } + act_entry = (debug_entry_t *) (((char *) + act_entry) + debug_area->entry_size); + } + } + } +out: + return 1; +} + +static debug_info_t * +find_debug_area(const char *area_name) +{ + debug_info_t* act_debug_info = debug_area_first; + while(act_debug_info != NULL){ + if (strcmp(act_debug_info->name, area_name) == 0) + return act_debug_info; + act_debug_info = act_debug_info->next; + } + return NULL; +} + +static void +dbf_init(void) +{ + if (!initialized) { + if(dbf_version >= DBF_VERSION_V2) + add_lcrash_debug_view(&pages_view); + add_lcrash_debug_view(&ascii_view); + add_lcrash_debug_view(&level_view); + add_lcrash_debug_view(&ebcdic_view); + add_lcrash_debug_view(&hex_view); + add_lcrash_debug_view(&hex_ascii_view); + add_lcrash_debug_view(&sprintf_view); + add_lcrash_debug_view(&raw_view); + ebcdic_ascii_conv = iconv_open("ISO-8859-1", "EBCDIC-US"); + initialized = 1; + } +} + +static debug_view_t* +get_debug_view(kaddr_t addr) +{ + void* k_debug_view; + int k_debug_view_size; + debug_view_t* rc; + + rc = (debug_view_t*)malloc(sizeof(debug_view_t)); + memset(rc, 0, sizeof(debug_view_t)); + + k_debug_view_size = kl_struct_len("debug_view"); + k_debug_view = malloc(k_debug_view_size); + GET_BLOCK(addr, k_debug_view_size, k_debug_view); + strncpy(rc->name,K_PTR(k_debug_view,"debug_view","name"), + DEBUG_MAX_PROCF_LEN); + + free(k_debug_view); + return rc; +} + +static void +free_debug_view(debug_view_t* view) +{ + if(view) + free(view); +} + +static void +debug_get_areas_v1(debug_info_t* db_info, void* k_dbi) +{ + kaddr_t mem_pos; + kaddr_t dbe_addr; + int area_size, i; + + /* get areas */ + /* place to hold ptrs to debug areas in lcrash */ + area_size = PAGE_SIZE << db_info->page_order; + db_info->areas = (void**)malloc(db_info->nr_areas * sizeof(void *)); + memset(db_info->areas, 0, db_info->nr_areas * sizeof(void *)); + mem_pos = (kaddr_t) KL_UINT(k_dbi,"debug_info","areas"); + for (i = 0; i < db_info->nr_areas; i++) { + dbe_addr = KL_VREAD_PTR(mem_pos); + db_info->areas[i] = (debug_entry_t *) malloc(area_size); + /* read raw data for debug area */ + GET_BLOCK(dbe_addr, area_size, db_info->areas[i]); + mem_pos += KL_NBPW; + } +} + +static void +debug_get_areas_v2(debug_info_t* db_info, void* k_dbi) +{ + kaddr_t area_ptr; + kaddr_t page_array_ptr; + kaddr_t page_ptr; + int i,j; + db_info->areas_v2=(void***)malloc(db_info->nr_areas * sizeof(void **)); + area_ptr = (kaddr_t) KL_UINT(k_dbi,"debug_info","areas"); + for (i = 0; i < db_info->nr_areas; i++) { + db_info->areas_v2[i] = (void**)malloc(db_info->pages_per_area_v2 + * sizeof(void*)); + page_array_ptr = KL_VREAD_PTR(area_ptr); + for(j=0; j < db_info->pages_per_area_v2; j++) { + page_ptr = KL_VREAD_PTR(page_array_ptr); + db_info->areas_v2[i][j] = (void*)malloc(PAGE_SIZE); + /* read raw data for debug area */ + GET_BLOCK(page_ptr, PAGE_SIZE, db_info->areas_v2[i][j]); + page_array_ptr += KL_NBPW; + } + area_ptr += KL_NBPW; + } +} + +static debug_info_t* +get_debug_info(kaddr_t addr,int get_areas) +{ + void *k_dbi; + kaddr_t mem_pos; + kaddr_t view_addr; + debug_info_t* db_info; + int i; + int dbi_size; + + /* get sizes of kernel structures */ + if(!(dbi_size = kl_struct_len("debug_info"))){ + fprintf (KL_ERRORFP, + "Could not determine sizeof(struct debug_info)\n"); + return(NULL); + } + if(!(dbe_size = kl_struct_len("__debug_entry"))){ + fprintf(KL_ERRORFP, + "Could not determine sizeof(struct __debug_entry)\n"); + return(NULL); + } + + /* get kernel debug_info structure */ + k_dbi = malloc(dbi_size); + GET_BLOCK(addr, dbi_size, k_dbi); + + db_info = (debug_info_t*)malloc(sizeof(debug_info_t)); + memset(db_info, 0, sizeof(debug_info_t)); + + /* copy members */ + db_info->level = KL_INT(k_dbi,"debug_info","level"); + db_info->nr_areas = KL_INT(k_dbi,"debug_info","nr_areas"); + db_info->pages_per_area_v2= KL_INT(k_dbi,"debug_info","pages_per_area"); + db_info->page_order = KL_INT(k_dbi,"debug_info","page_order"); + db_info->buf_size = KL_INT(k_dbi,"debug_info","buf_size"); + db_info->entry_size = KL_INT(k_dbi,"debug_info","entry_size"); + db_info->next_dbi = KL_UINT(k_dbi,"debug_info","next"); + db_info->prev_dbi = KL_UINT(k_dbi,"debug_info","prev"); + db_info->addr = addr; + strncpy(db_info->name,K_PTR(k_dbi,"debug_info","name"), + DEBUG_MAX_PROCF_LEN); + + + if(get_areas){ + if(dbf_version == DBF_VERSION_V1) + debug_get_areas_v1(db_info,k_dbi); + else + debug_get_areas_v2(db_info,k_dbi); + } else { + db_info->areas = NULL; + } + + /* get views */ + mem_pos = (uaddr_t) K_PTR(k_dbi,"debug_info","views"); + memset(&db_info->views, 0, DEBUG_MAX_VIEWS * sizeof(void*)); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + view_addr = KL_GET_PTR((void*)(uaddr_t)mem_pos); + if(view_addr == 0){ + break; + } else { + db_info->views[i] = get_debug_view(view_addr); + } + mem_pos += KL_NBPW; + } + free(k_dbi); + return db_info; +} + +static void +free_debug_info_v1(debug_info_t * db_info) +{ + int i; + if(db_info->areas){ + for (i = 0; i < db_info->nr_areas; i++) { + free(db_info->areas[i]); + } + } + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + free_debug_view(db_info->views[i]); + } + free(db_info->areas); + free(db_info); +} + +static void +free_debug_info_v2(debug_info_t * db_info) +{ + int i,j; + if(db_info->areas) { + for (i = 0; i < db_info->nr_areas; i++) { + for(j = 0; j < db_info->pages_per_area_v2; j++) { + free(db_info->areas_v2[i][j]); + } + free(db_info->areas[i]); + } + free(db_info->areas); + db_info->areas = NULL; + } + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + free_debug_view(db_info->views[i]); + } + free(db_info); +} + +static int +get_debug_areas(void) +{ + kaddr_t act_debug_area; + syment_t *debug_sym; + debug_info_t *act_debug_area_cpy; + + if(!(debug_sym = kl_lkup_symname("debug_area_first"))){ + printf("Did not find debug_areas"); + return -1; + } + act_debug_area = KL_VREAD_PTR(debug_sym->s_addr); + while(act_debug_area != 0){ + act_debug_area_cpy = get_debug_info(act_debug_area,0); + act_debug_area = act_debug_area_cpy->next_dbi; + if(debug_area_first == NULL){ + debug_area_first = act_debug_area_cpy; + } else { + debug_area_last->next = act_debug_area_cpy; + } + debug_area_last = act_debug_area_cpy; + } + return 0; +} + +static void +free_debug_areas(void) +{ + debug_info_t* next; + debug_info_t* act_debug_info = debug_area_first; + + while(act_debug_info != NULL){ + next = act_debug_info->next; + if(dbf_version == DBF_VERSION_V1) + free_debug_info_v1(act_debug_info); + else + free_debug_info_v2(act_debug_info); + act_debug_info = next; + } + + debug_area_first = NULL; + debug_area_last = NULL; +} + +static debug_view_t * +find_lcrash_debug_view(const char *name) +{ + int i; + for (i = 0; (i < LCRASH_DB_VIEWS) && (debug_views[i] != NULL); i++) { + if (strcmp(debug_views[i]->name, name) == 0) + return debug_views[i]; + } + return NULL; +} + +static void +print_lcrash_debug_views(FILE * ofp) +{ + int i; + fprintf(ofp, "REGISTERED VIEWS\n"); + fprintf(ofp, "=====================\n"); + for (i = 0; i < LCRASH_DB_VIEWS; i++) { + if (debug_views[i] == NULL) { + return; + } + fprintf(ofp, " - %s\n", debug_views[i]->name); + } +} + +static int +add_lcrash_debug_view(debug_view_t *view) +{ + int i; + for (i = 0; i < LCRASH_DB_VIEWS; i++) { + if (debug_views[i] == NULL) { + debug_views[i] = view; + return 0; + } + if (strcmp(debug_views[i]->name, view->name) == 0) + return -1; + } + return -1; +} + +static int +list_one_view(char *area_name, char *view_name, command_t * cmd) +{ + debug_info_t *db_info; + debug_view_t *db_view; + + if ((db_info = find_debug_area(area_name)) == NULL) { + fprintf(cmd->efp, "Debug log '%s' not found!\n", area_name); + return -1; + } + + db_info = get_debug_info(db_info->addr,1); + + if ((db_view = find_lcrash_debug_view(view_name)) == NULL) { + fprintf(cmd->efp, "View '%s' not registered!\n", view_name); + return -1; + } + if(dbf_version == DBF_VERSION_V1){ + debug_format_output_v1(db_info, db_view, cmd->ofp); + free_debug_info_v1(db_info); + } else { + debug_format_output_v2(db_info, db_view, cmd->ofp); + free_debug_info_v2(db_info); + } + return 0; +} + +static int +list_areas(FILE * ofp) +{ + debug_info_t* act_debug_info = debug_area_first; + fprintf(ofp, "Debug Logs:\n"); + fprintf(ofp, "==================\n"); + while(act_debug_info != NULL){ + fprintf(ofp, " - %s\n", act_debug_info->name); + act_debug_info = act_debug_info->next; + } + return 0; +} + +static int +list_one_area(const char *area_name, command_t * cmd) +{ + debug_info_t *db_info; + int i; + if ((db_info = find_debug_area(area_name)) == NULL) { + fprintf(cmd->efp, "Debug log '%s' not found!\n", area_name); + return -1; + } + fprintf(cmd->ofp, "INSTALLED VIEWS FOR '%s':\n", area_name); + fprintf(cmd->ofp, "================================================" + "==============================\n"); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (db_info->views[i] != NULL) { + fprintf(cmd->ofp, " - %s ", db_info->views[i]->name); + if (find_lcrash_debug_view(db_info->views[i]->name)) + fprintf(cmd->ofp, "(available)\n"); + else + fprintf(cmd->ofp, "(not available)\n"); + } + } + fprintf(cmd->ofp, "=================================================" + "=============================\n"); + return 0; +} + +#ifdef DBF_DYNAMIC_VIEWS +static int +load_debug_view(const char *path, command_t * cmd) +{ + void *library; + const char *error; + debug_view_t *(*view_init_func) (void); + + library = dlopen(path, RTLD_LAZY); + if (library == NULL) { + fprintf(cmd->efp, "Could not open %s: %s\n", path, dlerror()); + return (1); + } + + dlerror(); + + view_init_func = dlsym(library, "debug_view_init"); + error = dlerror(); + + if (error) { + fprintf(stderr, "could not find debug_view_init(): %s\n", + error); + exit(1); + } + + add_lcrash_debug_view((*view_init_func) ()); + + fprintf(cmd->ofp, "view %s loaded\n", path); + fflush(stdout); + return 0; +} +#endif + +/* + * s390dbf_cmd() -- Run the 's390dbf' command. + */ +static int +s390dbf_cmd(command_t * cmd) +{ + syment_t *dbf_version_sym; + int rc = 0; + + /* check version */ + + if(!(dbf_version_sym = kl_lkup_symname("debug_feature_version"))){ + fprintf(KL_ERRORFP, + "Could not determine debug_feature_version\n"); + return -1; + } + + dbf_version = KL_VREAD_UINT32(dbf_version_sym->s_addr); + + if ((dbf_version != DBF_VERSION_V1) && (dbf_version != DBF_VERSION_V2)){ + fprintf(cmd->efp,"lcrash does not support the" + " debug feature version of the dump kernel:\n"); + fprintf(cmd->efp,"DUMP: %i SUPPORTED: %i and %i\n", + dbf_version, DBF_VERSION_V1, DBF_VERSION_V2); + return -1; + } + + dbf_init(); + + if (cmd->flags & C_ALL) { + return (0); + } +#ifdef DBF_DYNAMIC_VIEWS + if (cmd->flags & LOAD_FLAG) { + printf("loading: %s\n", cmd->args[0]); + return (load_debug_view(cmd->args[0], cmd)); + } +#endif + if (cmd->flags & VIEWS_FLAG) { + print_lcrash_debug_views(cmd->ofp); + return (0); + } + if (cmd->nargs > 2) { + s390dbf_usage(cmd); + return (1); + } + + if(get_debug_areas() == -1) + return -1; + + switch (cmd->nargs) { + case 0: + rc = list_areas(cmd->ofp); + break; + case 1: + rc = list_one_area(cmd->args[0], cmd); + break; + case 2: + rc = list_one_view(cmd->args[0], cmd->args[1], cmd); + break; + } + + free_debug_areas(); + + return rc; +} + +#define _S390DBF_USAGE " [-v] [debug log] [debug view]" + +/* + * s390dbf_usage() -- Print the usage string for the 's390dbf' command. + */ +void +s390dbf_usage(command_t * cmd) +{ + CMD_USAGE(cmd, _S390DBF_USAGE); +} + +/* + * s390 debug feature command for crash + */ + +char *help_s390dbf[] = { + "s390dbf", + "s390dbf prints out debug feature logs", + "[-v] [debug_log] [debug_log view]", + "", + "Display Debug logs:", + " + If called without parameters, all active debug logs are listed.", + " + If called with '-v', all debug views which are available to", + " 'crash' are listed", + " + If called with the name of a debug log, all debug-views for which", + " the debug-log has registered are listed. It is possible thatsome", + " of the debug views are not available to 'crash'.", + " + If called with the name of a debug-log and an available viewname,", + " the specified view is printed.", + NULL +}; + +void cmd_s390dbf() +{ + int i,c; + + command_t cmd = { + .ofp = stdout, + .efp = stderr, + .cmdstr = "s390dbf", + .command = "s390dbf", + }; + + cmd.nargs=argcnt - 1; + for (i=1; i < argcnt; i++) + cmd.args[i-1] = args[i]; + + while ((c = getopt(argcnt, args, "v")) != EOF) { + switch(c) { + case 'v': + cmd.flags |= VIEWS_FLAG; + break; + default: + s390dbf_usage(&cmd); + return; + } + } + s390dbf_cmd(&cmd); +} + +#endif -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility