Logo Search packages:      
Sourcecode: lcrash version File versions  Download package

cmd_dbf_s390.c

/*
 * $Id: cmd_dbf_s390.c,v 1.1 2004/12/21 23:26:18 tjm Exp $
 *
 * This file is part of lcrash, an analysis tool for Linux memory dumps.
 *
 * Created by Silicon Graphics, Inc.
 * Contributions by IBM, and others
 *
 * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
 * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */

#include <lcrash.h>
#include <iconv.h>
#include <ctype.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)

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

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 */
} debug_entry_t __attribute__((packed));
/* __attribute__((packed));*/
/* typedef struct __debug_entry debug_entry_t; */


/* 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;
/*         debug_entry_t **areas; */
        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;
} 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;

/* function declarations
 */
void s390dbf_usage(command_t * cmd);
static int add_lcrash_debug_view(debug_view_t *);
static int dbe_size = 0;

/* function definitions
 */
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, lentry.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 = 1;
      for (i = 0; buf[i] != '\n'; i++) {
            if (buf[i] != '%')
                  continue;
            /* 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 * KL_NBPW));
                  inbuf_cpy[k] = addr;
                  /* For 32bit host with 64bit dump we get problems when
                   * printing longs (64bit) of dump exceeding 32-bit
                   * boundary. So, we issue a warning here.
                   */
                  if((KL_PTRSZ > KLP->host->ptrsz) &&
                     (addr >> 32)){
                        fprintf(KL_ERRORFP, "\nLong long arg "
                              "value too large for long "
                              "type: Possible loss of data.\n");
                  }
            } 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 * 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[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 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 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;

      result = entries;
      current = entries;
      for (i=0; i < num; i++) {
            if (current->id.stck == 0)
                  break;
            if (current->id.fields.clock < result->id.fields.clock)
                  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(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;
}

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;
      }
}

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 debug_info_t*
get_debug_info(kaddr_t addr,int get_areas)
{
      void *k_dbi;
      kaddr_t mem_pos;
      kaddr_t dbe_addr;
      kaddr_t view_addr;
      debug_info_t* db_info;
      int area_size, 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->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);

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

      if(get_areas){
            /* get areas */
            /* place to hold ptrs to debug areas in lcrash */
            db_info->areas = (void**)malloc(db_info->nr_areas * sizeof(void *));
            memset(db_info->areas, 0, db_info->nr_areas * sizeof(void *));
            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;
            }
        } 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(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 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;
            free_debug_info(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;
      }
      debug_format_output(db_info, db_view, cmd->ofp);
      free_debug_info(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;
        unsigned int dbf_version = 0;
      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) {
            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);
}

Generated by  Doxygen 1.6.0   Back to index