[Crash-utility] s390dbf support for crash

Michael Holzheu holzheu at de.ibm.com
Mon Aug 14 14:25:09 UTC 2006


Hi Dave,

For lcrash we have a command, to print out kernel traces from
the s390 debug feature (s390dbf). The debug feature is an s390 kernel
trace API which uses wraparound buffers to store trace records in memory.
Many of the s390 device drivers use this feature. Since more and more
service and support people use crash instead of lcrash for dump
analysis, it would be very useful to have this command in the crash
dumpanalysis tool, too. There is some documentation of the s390dbf in
the kernel sources under /Documentation/s390/s390dbf.txt

Here are some examples, how the command works:

1. Display all registerd debug features:
----------------------------------------
crash> s390dbf

Debug Logs:
==================
 - cio_msg
 - cio_crw
 - qdio_setup
...

2. Show content of a debug feature:
-----------------------------------
crash> s390dbf cio_msg sprintf

00 01155560919:434118 2 - 02 <ccw_device_sense_id_irq+0320>  
SenseID : UC on dev 0.0.e89e, lpum 80, cnt 00, sns : 10000000 9EFF003FF ...

00 01155560919:434273 2 - 02 <ccw_device_recog_done+0956> 
SenseID : device 0.0.eee2 reports: CU  Type/Mod = 3990/E9, Dev Type/Mod = 3390/0A

00 01155560919:434291 2 - 02 <ccw_device_recog_done+0956>
SenseID : device 0.0.e919 reports: CU  Type/Mod = 3990/E9, Dev Type/Mod = 3390/0C


Would you please consider integrating the command into crash?
Here the patch against "crash-4.0-3.1":

---

 Makefile      |   11
 defs.h        |    6
 global_data.c |    3
 s390dbf.c     | 1340 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1356 insertions(+), 4 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 15:57:29.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 15:57:24.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 15:57:34.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 15:57:17.000000000 +0200
@@ -0,0 +1,1340 @@
+/*
+ *    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;
+	kaddr_t addr;
+	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
+ */
+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++) {
+		unsigned 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.
+ */
+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 1;
+		}
+	}
+	s390dbf_cmd(&cmd);
+}
+
+#endif




More information about the Crash-utility mailing list