[Crash-utility] Re: s390dbf support for crash

Michael Holzheu holzheu at de.ibm.com
Mon Aug 14 15:44:32 UTC 2006


Hi Dave!

anderson at redhat.com 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 at de.ibm.com>
+ */
+
+#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




More information about the Crash-utility mailing list