/*
 *  lcrash/arch/s390/cmds/s390dbf.c
 *    S/390 debug facility:
 *
 *    Provides the functionality of displaying debug areas which have been
 *    allocated by the l/390 debug feature.
 *
 *    Copyright (C) 2000,2001 IBM Deutschland Entwicklung GmbH,
 *                            IBM Corporation
 *    Author(s): Michael Holzheu (holzheu@de.ibm.com),
 *
 *    Bugreports to: <Linux390@de.ibm.com>
 */

#include <lcrash.h>
#include <iconv.h>
#include <ctype.h>
#include <asm/kl_s390_util.h>

#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)

#define MIN(a,b) (((a)<(b))?(a):(b))

/* Stuff which has to match with include/asm-s390/debug.h */

#define DBF_VERSION 1
#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)
struct debug_view;

struct __debug_entry{
        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;
        void* caller;
} __attribute__((packed));

typedef struct __debug_entry debug_entry_t;
typedef struct debug_info {
        struct debug_info* next;
        struct debug_info* prev;
        int level;
        int nr_areas;
        int page_order;
        int buf_size;
        int entry_size;
        struct __debug_entry** areas;
        int active_area;
        int *active_entry;
        struct debug_view* views[DEBUG_MAX_VIEWS];
        char name[DEBUG_MAX_PROCF_LEN];
} debug_info_t;

typedef int (debug_header_proc_t) (debug_info_t* id,
                                   struct debug_view* view,
                                   int area,
                                   debug_entry_t* entry,
                                   char* out_buf);

typedef int (debug_format_proc_t) (debug_info_t* id,
                                   struct debug_view* view, char* out_buf,
                                   const char* in_buf);
typedef int (debug_prolog_proc_t) (debug_info_t* id,
                                   struct debug_view* view,
                                   char* out_buf);

struct debug_view {
        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 struct debug_view *debug_views[LCRASH_DB_VIEWS];
static int initialized = 0;
static iconv_t ebcdic_ascii_conv = 0;


static int add_lcrash_debug_view(struct debug_view *view);

static void EBCASC(char *inout, size_t len)
{
        char *in = inout;
        iconv(ebcdic_ascii_conv, (char **) &in, &len, &inout, &len);
}

/*
 * prints header for debug entry
 */

static int dflt_header_fn(debug_info_t * id, struct debug_view *view,
			 int area, struct __debug_entry * entry, char *out_buf)
{
	struct timeval time_val;
	unsigned long long time;
	char *except_str;
	unsigned long caller;
	int rc = 0;
	char *caller_name;
	int offset;
	char caller_buf[30];
	unsigned int level;
	syment_t *caller_sym;

	level = entry->id.fields.level;
	time = entry->id.stck;

	s390_tod_to_timeval(time, &time_val);

	if (entry->id.fields.exception)
		except_str = "*";
	else
		except_str = "-";
	caller = (unsigned long) entry->caller;
#if defined(_ARCH_S390)
	caller &= 0x7fffffff;
#endif
	caller_sym = kl_lkup_symaddr(caller);
	if(caller_sym){
		caller_name = caller_sym->s_name;
		offset = caller - kl_funcaddr(caller);
	}
	else {
		sprintf(caller_buf, "%lx", caller);
		caller_name = caller_buf;
		offset = 0;
	}

#if defined(_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,
		    entry->id.fields.cpuid, caller_name, offset);
#endif
	return rc;
}

/*
 * prints debug header in raw format
 */

int raw_header_fn(debug_info_t * id, struct debug_view *view,
                         int area, struct __debug_entry * entry, char *out_buf)
{
        int rc;

        rc = sizeof(struct __debug_entry);
        if (out_buf == NULL)
                goto out;
        memcpy(out_buf,entry,sizeof(struct __debug_entry));
      out:
        return rc;
}

/*
 * prints debug data in raw format
 */

static int raw_format_fn(debug_info_t * id, struct debug_view *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, struct debug_view *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, struct debug_view *view,
                                  char *out_buf, const char *in_buf)
{
        char buf[1024];
	int i, k, rc = 0, num_longs = 0, num_used_args = 0, num_strings = 0;
	int index[DEBUG_SPRINTF_MAX_ARGS];
	unsigned long inbuf_cpy[DEBUG_SPRINTF_MAX_ARGS];
	unsigned long to_dealloc[DEBUG_SPRINTF_MAX_ARGS];

	if (out_buf == NULL || in_buf == NULL) {
	      rc = id->buf_size * 4 + 3;
	      goto out;
	}

	/* get the format string into buf */
	GET_BLOCK(((kaddr_t*)in_buf)[0], 1024, buf);

	k = 1;
	for (i = 0; buf[i] != '\n'; i++) {
	  if (buf[i] != '%')
	    continue;
	  if (buf[i+1] != 's')
	    inbuf_cpy[k] = ((unsigned long*)in_buf)[k];
	  else {
	    inbuf_cpy[k] = (unsigned long)malloc(1024);
	    to_dealloc[num_strings++] = inbuf_cpy[k];
	    GET_BLOCK(((kaddr_t*)in_buf)[k], 1024, (char*)inbuf_cpy[k]);
	  }
	  k++;
	}

	/* count of longs fit into one entry */
	num_longs = id->buf_size /  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));
	memset(index, 0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int));

	for (i = 1; i <= num_used_args; i++)
	  index[i] = i;

	rc = sprintf(out_buf + rc, buf, ((kaddr_t*)inbuf_cpy)[index[1]],
		     ((kaddr_t*)inbuf_cpy)[index[2]], ((kaddr_t*)inbuf_cpy)[index[3]], ((kaddr_t*)inbuf_cpy)[index[4]],
		     ((kaddr_t*)inbuf_cpy)[index[5]], ((kaddr_t*)inbuf_cpy)[index[6]], ((kaddr_t*)inbuf_cpy)[index[7]],
		     ((kaddr_t*)inbuf_cpy)[index[8]], ((kaddr_t*)inbuf_cpy)[index[9]]);

 out:
	while (num_strings--)
		free((unsigned long*)to_dealloc[num_strings]);			
	return rc;
}


/*
 * functions for debug-views
 ***********************************
*/

/*
 * prints out actual debug level
 */

static int prolog_level_fn(debug_info_t * id,
	  	  	   struct debug_view *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 prolog
 */

static int prolog_fn(debug_info_t * id,
			   struct debug_view *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, struct debug_view *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,
				 struct debug_view *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,
				  struct debug_view *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;
}


struct debug_view ascii_view = {
	"ascii",
	&prolog_fn,
	&dflt_header_fn,
	&ascii_format_fn,
};

struct debug_view ebcdic_view = {
	"ebcdic",
	&prolog_fn,
	&dflt_header_fn,
	&ebcdic_format_fn,
};

struct debug_view hex_view = {
	"hex",
	&prolog_fn,
	&dflt_header_fn,
	&hex_format_fn,
};

struct debug_view level_view = {
	"level",
	&prolog_level_fn,
	NULL,
	NULL,
};

struct debug_view raw_view = {
        "raw",
        NULL,
        &raw_header_fn,
        &raw_format_fn,
};

struct debug_view hex_ascii_view = {
        "hex_ascii",
        &prolog_fn,
        &dflt_header_fn,
        &hex_ascii_format_fn,
};

struct debug_view sprintf_view = {
        "sprintf",
        &prolog_fn,
        &dflt_header_fn,
        &sprintf_format_fn,
};

/*
 * debug_format_output:
 * - calls prolog, header and format functions of view to format output
 */

static int debug_format_output(debug_info_t * debug_area,
			       struct debug_view *view, FILE * ofp)
{
	int i, j, len;
	int nr_of_entries;
	struct __debug_entry *act_entry;
	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->entry_size
	    << debug_area->page_order;
	for (i = 0; i < debug_area->nr_areas; i++) {
		act_entry = debug_area->areas[i];
		for (j = 0; j < nr_of_entries; j++) {
			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, DEBUG_DATA(act_entry));
				fwrite(buf,len, 1, ofp);
				memset(buf, 0, 2048); 
			}
			act_entry =
			    (struct __debug_entry *) (((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) {
		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;
	}
}

void s390dbf_usage(command_t * cmd);

static struct debug_view* get_debug_view(kaddr_t addr)
{
	void* k_debug_view;
	int   k_debug_view_size;
	struct debug_view* rc;

	rc = (struct debug_view*)malloc(sizeof(struct debug_view));

	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(struct debug_view* view)
{
	if(view) 
		free(view);
}

static debug_info_t* get_debug_info(kaddr_t addr)
{
	void* k_debug_info;
	int k_debug_info_size;
	kaddr_t mem_pos;
	debug_info_t* db_info;
	int area_size,i;

	db_info = (debug_info_t*)malloc(sizeof(debug_info_t));

	k_debug_info_size = kl_struct_len("debug_info");

	/* get kernel debug_info structure */

	k_debug_info = malloc(k_debug_info_size);
	GET_BLOCK(addr, k_debug_info_size, k_debug_info);

	/* copy members */

	db_info->level      = KL_INT(k_debug_info,"debug_info","level");
	db_info->nr_areas   = KL_INT(k_debug_info,"debug_info","nr_areas");
	db_info->page_order = KL_INT(k_debug_info,"debug_info","page_order");
	db_info->buf_size   = KL_INT(k_debug_info,"debug_info","buf_size");
	db_info->entry_size = KL_INT(k_debug_info,"debug_info","entry_size");
	db_info->next       = (void*)(kaddr_t)KL_UINT(k_debug_info,"debug_info","next");
	db_info->prev       = (void*)(kaddr_t)KL_UINT(k_debug_info,"debug_info","prev");
	strncpy(db_info->name,K_PTR(k_debug_info,"debug_info","name"),DEBUG_MAX_PROCF_LEN);

        area_size = PAGE_SIZE << db_info->page_order;
        mem_pos = (kaddr_t) KL_UINT(k_debug_info,"debug_info","areas");

        /* get areas */

        db_info->areas =
            (struct __debug_entry **) malloc(db_info->nr_areas *
                                      sizeof(struct __debug_entry *));
        GET_BLOCK(mem_pos, db_info->nr_areas * sizeof(struct __debug_entry *), db_info->areas);

        for (i = 0; i < db_info->nr_areas; i++) {
                mem_pos = (kaddr_t) db_info->areas[i];

                db_info->areas[i] = (struct __debug_entry *) malloc(area_size);
                GET_BLOCK(mem_pos, area_size, db_info->areas[i]);
        }

        /* get views */

	mem_pos = (kaddr_t) K_PTR(k_debug_info,"debug_info","views");
	memcpy(db_info->views, (void*)mem_pos, DEBUG_MAX_VIEWS * sizeof(void*));

	for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
                mem_pos = (kaddr_t) db_info->views[i];
		if(mem_pos == 0){
			db_info->views[i] = NULL;
			break;
		}
		else {
                	db_info->views[i] = get_debug_view(mem_pos);
		}
        }

	return db_info;
}

static void free_debug_info(debug_info_t * db_info)
{
        int i;
        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 int get_debug_areas(void)
{
	kaddr_t mem_pos;
	syment_t *debug_sym;
	void* act_debug_area;
	debug_info_t* act_debug_area_cpy;

	debug_sym = kl_lkup_symname("debug_area_first");
	if (debug_sym == NULL) {
		printf("Did not find debug_areas");
		return -1;
	}
	mem_pos = debug_sym->s_addr;
	GET_BLOCK(mem_pos, sizeof(void*), &act_debug_area);
	while(act_debug_area != NULL){
		act_debug_area_cpy = get_debug_info((kaddr_t)act_debug_area);
		act_debug_area     = act_debug_area_cpy->next;
	 	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* act_debug_info = debug_area_first;
        while(act_debug_info != NULL){
		debug_info_t* next;
                next = act_debug_info->next;
		free_debug_info(act_debug_info);
		act_debug_info = next;
        }
	debug_area_first = NULL;
	debug_area_last  = NULL;
}

static struct debug_view *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(struct debug_view *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;
	struct debug_view *db_view;

	if ((db_info = find_debug_area(area_name)) == NULL) {
		fprintf(cmd->efp, "Debug log '%s' not found!\n", area_name);
		return -1;
	}

	if ((db_view = find_lcrash_debug_view(view_name)) == NULL) {
		fprintf(cmd->efp, "View '%s' not registered!\n", view_name);
		return -1;
	}
	debug_format_output(db_info, db_view, cmd->ofp);
	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;
	struct debug_view *(*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;
        unsigned int dbf_version = 0;
	int rc = 0;

	/* check version */
 
	dbf_version_sym = kl_lkup_symname("debug_feature_version");
	if(dbf_version_sym)
        	GET_BLOCK(dbf_version_sym->s_addr, sizeof(unsigned int), 
				&dbf_version);

	if (dbf_version_sym == NULL || dbf_version != DBF_VERSION) {
		fprintf(cmd->efp,"Actual kernel does not have the correct debug_feature version:\n");
		fprintf(cmd->efp,"ACTUAL: %i NEEDED: %i\n",dbf_version, DBF_VERSION);
        	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->ofp));
	}
#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 "[-w outfile] [-v] [debug_log] [debug_log view]"

/*
 * s390dbf_usage() -- Print the usage string for the 's390dbf' command.
 */
void s390dbf_usage(command_t * cmd)
{
	CMD_USAGE(cmd, _S390DBF_USAGE);
}

/*
 * s390dbf_help() -- Print the help information for the 's390dbf' command.
 */
void s390dbf_help(command_t * cmd)
{
	CMD_HELP(
	cmd, _S390DBF_USAGE, 
	"Display Debug logs:\n\n"
	"+ If called without parameters, all active debug logs are listed.\n\n"
	"+ If called with '-v', all debug views which are available to"
        "'lcrash' are listed.\n\n"
	"+ If called with the name of a debug log, all debug-views for which"
	"the debug-log has registered are listed. It is possible that"
	"some of the debug views are not available to 'lcrash' (see '-v'"
	"option).\n\n"
	"+ If called with the name of a debug-log and an available viewname,"
	"the specified view is printed." 
	);
}


/*
 * s390dbf_parse() -- Parse the command line arguments for the 's390dbf' 
 * command.
 */
int s390dbf_parse(command_t * cmd)
{
	option_t *op;
	if (set_cmd_flags(cmd, (C_WRITE | C_ALL), "lv")) {
		return (1);
	}
	op = cmd->options;
	while (op) {
		switch (op->op_char) {
#ifdef DBF_DYNAMIC_VIEWS
		case 'l':
			cmd->flags |= LOAD_FLAG;
			break;
#endif
		case 'v':
			cmd->flags |= VIEWS_FLAG;
			break;
		}
		op = op->op_next;
	}
	return (0);
}
