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

util.c

/*
 * $Id: util.c,v 1.4 2005/02/25 22:04:04 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 - 2005 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 <string.h>
#include <lc_license.h>

#define BYTES_PER_LINE 16

#ifdef ALLOC_DEBUG
extern int alloc_debug;
#endif
extern int klib_trap_msg;
extern int cmp_debug;
extern int bfd_debug;

/*
 * function declarations
 */
static void* kl_block_alloc_func(int, int, void*);
static void* kl_block_realloc_func(void*, int, int, void*);
static void* kl_block_dup_func(void*, int, void*);
static void* kl_str_to_block_func(char*, int, void*);
static void  kl_block_free_func(void*);
static int   is_smp(void);

/*
 * function definitions
 */

/*
 * print_log_buf()
 */
void
print_log_buf(FILE *ofp)    
{
      int i, j, spacer = 1;
      char *np, *lbuf;
      kaddr_t symaddr = 0;
      syment_t *sp;
      int log_buf_size = 0;

      if (LINUX_2_6_X(KL_LINUX_RELEASE) || SN2_24X) {
            if ((sp = kl_lkup_symname("log_buf_len"))){
                  log_buf_size = KL_VREAD_UINT32(sp->s_addr);
                  if ((sp = kl_lkup_symname("log_buf"))) {
                        symaddr = KL_VREAD_PTR(sp->s_addr);
                  }
            }
      } else if ((sp = kl_lkup_symname("LOG_BUF_LEN")) &&
               (kl_lkup_symname("__log_buf"))) {
            /* support for Andrea Arcangeli's "log-buf-len dynamic" patch */
                log_buf_size = KL_VREAD_UINT32(sp->s_addr);
            if ((sp = kl_lkup_symname("log_buf"))) {
                  symaddr = KL_VREAD_PTR(sp->s_addr);
            }
      } 
      if (!symaddr) {                                       
            if ((sp = kl_lkup_symname("log_buf"))) {      
                  symaddr = sp->s_addr;                 
                  log_buf_size = kl_symsize(sp);        
            }                                             
      }                                                     

      if (!symaddr) {
            fprintf(KL_ERRORFP, "Could not find the symbol \"log_buf\"\n");
            return;
      }

      if (log_buf_size <= 0) {
            fprintf(KL_ERRORFP, "Could not determine \"log_buf_size\"\n");
            return;
      }


      if (!(lbuf = (char *)malloc(log_buf_size))) {
            return;
      }
      if (!(np = (char *)malloc(256))) {
            free(lbuf);
            return;
      }

      GET_BLOCK(symaddr, log_buf_size, lbuf);
      i = 0;
      j = 0;
      while (i < log_buf_size) {
            if (lbuf[i] == '\0') {
                  /* We're at the end of valid data...
                   */
                  break;
            }
            if (lbuf[i] == '\n') {
                  np[j] = '\0';
                  if (spacer) {
                        fprintf(ofp, "    ");
                  } else {
                        spacer = 1;
                  }
                  fprintf(ofp, "%s\n", np);
                  j = 0;
            } else {
                  np[j] = lbuf[i];
                  if (j == 255) {
                        np[j] = '\0';
                        if (spacer) {
                              fprintf(ofp, "    ");
                              spacer = 0;
                        } else {
                              spacer = 1;
                        }
                        fprintf(ofp, "%s", np);
                        j = 0;
                  } else {
                        j++;
                  }
            }
            i++;
      }
      if (j) {
            np[j] = '\0';
            if (spacer) {
                  fprintf(ofp, "    ");
                  spacer = 0;
            } else {
                  spacer = 1;
            }
            fprintf(ofp, "%s\n", np);
      }
      free(np);
      free(lbuf);
}

static int
is_smp(void)
{
      if(kl_lkup_symname("smp_count_cpus") || kl_lkup_symname("smp_init")
                  || kl_lkup_symname("smp_send_stop"))
            return 1;
      else
            return 0;
}

/*
 *  symaddr_per_cpu_2_6(symname, cpu)
 *  return address of symbol if defined as 'per_cpu' according to 
 *  asm-generic/per_cpu.h in linux 2.6
 *  FIXME: Think about integrating per_cpu() functions in libklib!
 */
kaddr_t 
symaddr_per_cpu_2_6(const char * symname, int cpu)
{
      syment_t* sp;
      kaddr_t rc = 0;
      kaddr_t cpu_offset;
      char symname_full[1024];

      sprintf(symname_full,"per_cpu__%s",symname);
      sp = kl_lkup_symname(symname_full);
      if(!sp)
            goto out;
      else
            rc += sp->s_addr;
      if(!(sp = kl_lkup_symname("__per_cpu_offset"))){
            rc = 0;
            goto out;
      }

      cpu_offset = KL_VREAD_PTR(sp->s_addr +  cpu * KL_NBPW);
      if(KL_ERROR){
            rc = 0;
            goto out;
      }

      rc += cpu_offset;
out:
      return rc;
}

/*
 * task_has_cpu(tsp_addr,tsp): Return 1 if task 'tsp' is running on a cpu 
 * else return 0
 */
int
task_has_cpu(uint64_t tsp_addr, void *tsp)
{
      int rc = 0;
      syment_t *sp;

      if(!is_smp()){
            rc = 0;
            /* FIXME: How can we find out if task is currently running? */
      } else if(kl_is_member("task_struct","has_cpu")){

            /* Linux 2.2 */

            if(KL_INT(tsp,"task_struct","has_cpu")) {
                  rc = 1;
            } else {
                  rc = 0;
            }
      } else if(kl_is_member("task_struct","cpus_runnable")){

            /* Linux 2.4 */

            uint64_t cpus_runnable;
            cpus_runnable = KL_UINT(tsp,"task_struct",
                              "cpus_runnable");
            if(((KL_NBPW == 4) && (cpus_runnable != ~0U)) ||
               ((KL_NBPW == 8) && (cpus_runnable != ~0ULL))){
                  rc = 1;
            } else {
                  rc = 0;
            }
      } else if(kl_is_member("task_struct","cpu")) {

            /* SN2_24X */

            if(KL_INT(tsp,"task_struct","cpu")) {
                  rc = 1;
            } else {
                  rc = 0;
            }
      } else if((sp = kl_lkup_symname("runqueues"))) {

            /* Linux 2.5 Scheduler + UL */

            int cpu, rq_size;
            char* runqueue;

            rq_size =  kl_struct_len("runqueue");
            if(KL_ERROR || (rq_size == 0)){
                  fprintf(KL_ERRORFP,"type >struct runqueue< not in Kerntypes\n");  
                  rc = 0;
                  goto out;
            }
            cpu = task_cpu(tsp);
            runqueue = (char *)kl_alloc_block(rq_size, K_TEMP);
            GET_BLOCK(sp->s_addr + rq_size * cpu ,rq_size,runqueue);
                if(KL_ERROR){
                        rc = 0;
                        goto out;
                }
            if(kl_kaddr(runqueue,"runqueue","curr") == tsp_addr){
                        rc = 1;
            } else {
                        rc = 0;
            }
      } else if((sp = kl_lkup_symname("per_cpu__runqueues"))){

            /* Linux 2.6 Scheduler  */

            int cpu, rq_size;
            char* runqueue;
            kaddr_t rq_addr;
                  
            cpu = task_cpu(tsp);

            rq_addr = symaddr_per_cpu_2_6("runqueues",cpu);
            if(!rq_addr){
                  fprintf(KL_ERRORFP,"cannot find per cpu symbol 'runqueues'\n");
                  rc = 0;
                  goto out;
            }
            rq_size =  kl_struct_len("runqueue");
            if(KL_ERROR || (rq_size == 0)){
                  fprintf(KL_ERRORFP,"type >struct runqueue< not in Kerntypes\n");  
                  rc = 0;
                  goto out;
            }
            runqueue = (char *)kl_alloc_block(rq_size, K_TEMP);
            GET_BLOCK(rq_addr, rq_size,runqueue);
                if(KL_ERROR){
                        rc = 0;
                        goto out;
                }
            if(kl_kaddr(runqueue,"runqueue","curr") == tsp_addr){
                        rc = 1;
            } else {
                        rc = 0;
            }
      } else {
            fprintf(KL_ERRORFP,"Unknown kernel - cannot find out if task is running\n");
            rc = 0;
      }
out:
      return rc;
}

/*
 * task_cpu(tsp): Return cpu number of task
 */
int task_cpu(void* tsp){
      int rc;
      if(kl_is_member("task_struct","processor")){
            rc = KL_INT(tsp,"task_struct","processor");
      } else if(kl_is_member("task_struct","cpu")){
            rc = KL_INT(tsp,"task_struct","cpu");
      } else if(kl_is_member("thread_info", "cpu")){
            /* 2.5 */
            void* thread_info=malloc(kl_struct_len("thread_info"));
            uint64_t addr;
            addr = KL_UINT(tsp,"task_struct", "thread_info");     
            GET_BLOCK(addr, kl_struct_len("thread_info"), thread_info);
            rc = KL_INT(thread_info, "thread_info", "cpu");
            free(thread_info);
            if(KL_ERROR)
                  rc=-1;
      } else {
            rc = -1;
      }
      return rc;
}

/*
 * get_utsname()
 */
char *
get_utsname(void)
{
      char *utsname;
      syment_t *sp;

      if (!(sp = kl_lkup_symname("system_utsname"))) {
            return(0);
      }
      utsname = (char *)kl_alloc_block(NEW_UTSNAME_SZ, K_TEMP);
        if (KL_ERROR) {
                return(0);
        }
      GET_BLOCK(sp->s_addr, NEW_UTSNAME_SZ, utsname);
        if (KL_ERROR) {
                kl_free_block(utsname);
                return(0);
        }

      return(utsname);
}

/*
 * dump_string()
 */
kaddr_t
dump_string(kaddr_t addr, int flags, FILE *ofp)
{
      int i, col = 0, line = 0;
      char buf[256];
      kaddr_t cur_addr = addr;

next_buf:
      if (flags & C_PADDR) {
            kl_readmem(cur_addr, 256, (void *)buf);
      } else {
            GET_BLOCK(cur_addr, 256, (void *)buf);
      }
      if (KL_ERROR) {
            fprintf(KL_ERRORFP, "dump_string: ");
            switch (KL_ERROR) {
                  case KLE_INVALID_PADDR:
                        fprintf(KL_ERRORFP, "Invalid memory "
                              "address (0x%"FMT64"x)\n",
                              cur_addr);
                        break;

                  default:
                        fprintf(KL_ERRORFP,
                              "error=0x%"FMT64"x\n",
                              klib_error);
            }
      }
      i = 0;
next_line:
      if (col == 0) {
            if (line) {
                  fputc(' ', ofp);
            } else {
                  fputc('\"', ofp);
                  line++;
            }
            col++;
      }
      while(buf[i]) {
            if (buf[i] == '\n') {
                  /* Print our own return char so that we can get
                   * the double quote in. 
                   */
                  fputc('\n', ofp);
                  i++;
                  if (i == 256) {
                        cur_addr += 256;
                        goto next_buf;
                  }
                  col = 0;
                  goto next_line;
            }
            fputc(buf[i++], ofp);
            if (col == 77) {
                  fputc('\n', ofp);
                  col = 0;
                  if (i == 256) {
                        cur_addr += 256;
                        goto next_buf;
                  } else {
                        goto next_line;
                  }
            } else {
                  col++;
            }
            if (i == 256) {
                  cur_addr += 256;
                  goto next_buf;
            }
      }
      i++;
      fprintf(ofp, "\"\n");
      return(cur_addr + i);
}

/*
 * dump_strings()
 */
void
dump_strings(kaddr_t addr, uint64_t count, int flags, FILE *ofp)
{
      int i;
      kaddr_t cur_addr;

      i = 0;
      cur_addr = addr;
      while (i < count) {
            cur_addr = dump_string(cur_addr, flags, ofp);
            i++;
      }
}

/*
 * dump_memory()
 */
void
dump_memory(kaddr_t addr, uint64_t count, int flags, FILE *ofp)
{
      int i, j, type = 0, base, nbytes, remaining = count;
      int nunits, unit_size; 
      int units_per_line, units_per_blk, lines_per_entry = 1;
      int capture_ascii = 0;
      kaddr_t cur_addr;
      void *blk, *ptr;
      char *cp, cstr[17];

      if (flags & C_STRING) {
            /* Dump out count number of a NULL terminated strings
             * of characters that starts at addr.
             */
            dump_strings(addr, count, flags, ofp);
            return;
      }

      if (flags & C_INSTR) {
            /* Dump out count instructions starting with addr. We
             * have to make a call to an architecture specific 
             * function to do this for us.
             */
            DUMP_INSTR(addr, count, flags, ofp);
            return;
      }

      /* Make sure there are no conflicts with the flags controlling
       * the base (octal, hex, decimal) and element size (byte, half
       * word, word and double word). Set base and ewidth to the highest
       * priority flag that is set.
       */
      if (flags & C_HEX) {
            base = C_HEX;
      } else if (flags & C_DECIMAL) {
            base = C_DECIMAL;
      } else if (flags & C_OCTAL) {
            base = C_OCTAL;
      } else {
            base = C_HEX;
      }

      /* Check to see if we need to print a space between unit values
       * or compress them together. Note that the C_CONCAT option
       * only is valid with the C_HEX format. If we are displaying in
       * decimal or octal, then turn this flag off.
       */
      if ((flags & C_CONCAT) && (base != C_HEX)) {
            flags &= ~C_CONCAT;
      }

      /* If none of the width flags are set, use the pointer size to
       * determine what the width should be.
       */
      if (!(flags & C_DWORD) && !(flags & C_WORD) &&
            !(flags & C_HWORD) && !(flags & C_BYTE)) {
            if (PTRSZ64) {
                  flags |= C_DWORD;
            } else {
                  flags |= C_WORD;
            }
      }

      /* Make sure that addr is aligned properly (based on flag values).
       */
      if (flags & C_BYTE) {
            type = C_BYTE;
            units_per_blk = BLKSZ;
            units_per_line = 16;
            unit_size = 1;
            if ((base == C_DECIMAL) || (base == C_OCTAL)) {
                  lines_per_entry = 2; 
            }
      } else if (flags & C_HWORD) {
            type = C_HWORD;
            if (addr % 2) {
                  fprintf(KL_ERRORFP, "addr (0x%"FMTPTR"x) is not "
                        "half_word aligned!\n", addr);
                  return;
            }
            units_per_blk = BLKSZ / 2;
            units_per_line = 8;
            unit_size = 2;
      } else if (flags & C_WORD) {
            type = C_WORD;
            if (addr % 4) {
                  fprintf(KL_ERRORFP, "addr (0x%"FMTPTR"x) is not "
                        "word aligned!\n", addr);
                  return;
            }
            units_per_blk = BLKSZ / 4;
            units_per_line = 4;
            unit_size = 4;
            if (base == C_OCTAL) {
                  lines_per_entry = 2;
            }
      } else if (flags & C_DWORD) {
            type = C_DWORD;
            if (addr % 8) {
                  fprintf(KL_ERRORFP, "addr (0x%"FMTPTR"x) is not "
                        "double word aligned!\n", addr);
                  return;
            }
            units_per_blk = BLKSZ / 8;
            units_per_line = 2;
            unit_size = 8;
      } 

      /* Turn on ASCII dump only if outputtting in HEX 
       */
      if (base == C_HEX) {
            capture_ascii = 1;
      }

      if (!(blk = (void *)kl_alloc_block(BLKSZ, K_TEMP))) {
            return;
      }
      memset(blk, 0, BLKSZ);

      cur_addr = addr;
      while (remaining) {

            if (remaining >= units_per_blk) {
                  nbytes = BLKSZ;
                  nunits = units_per_blk;
                  remaining -= units_per_blk;
            } else {
                  nbytes = remaining * unit_size;
                  nunits = remaining;
                  remaining = 0;
            }

            if (flags & C_PADDR){
                  kl_readmem(cur_addr, nbytes, blk);
            } else {
                  GET_BLOCK(cur_addr, nbytes, blk);
            }

            if (KL_ERROR) {
                  switch (KL_ERROR) {
                        case KLE_INVALID_PADDR:
                              fprintf(KL_ERRORFP, "Invalid memory "
                                    "address (0x%"FMT64"x)\n",
                                    addr);
                              break;

                        default:
                              fprintf(KL_ERRORFP,
                                    "error=0x%"FMT64"x\n",
                                    klib_error);
                  }
                  break;
            }

            ptr = blk;
            i = 0;
            while (i < nunits) {
                  if ((i % units_per_line) == 0) {
                        print_kaddr(cur_addr, ofp, 2);
                        fprintf(ofp, ": ");
                        cp = ptr;
                        cur_addr += BYTES_PER_LINE;
                  }
                  if (type == C_BYTE) {
                        switch (base) {
                              case C_HEX:
                                    fprintf(ofp, "%02x", 
                                          KL_GET_UINT8(ptr));
                                    break;

                              case C_DECIMAL:
                                    fprintf(ofp, "%04d ", 
                                          KL_GET_UINT8(ptr));
                                    break;

                              case C_OCTAL:
                                    fprintf(ofp, "%04o ", 
                                          KL_GET_UINT8(ptr));
                                    break;
                        }
                        ptr++;
                  } else if (type == C_HWORD) {
                        switch (base) {
                              case C_HEX:
                                    fprintf(ofp, "%04x",
                                          KL_GET_UINT16(ptr));
                                    break;

                              case C_DECIMAL:
                                    fprintf(ofp, "%06d ", 
                                          KL_GET_UINT16(ptr));
                                    break;

                              case C_OCTAL:
                                    fprintf(ofp, "%07o ", 
                                          KL_GET_UINT16(ptr));
                                    break;
                        }
                        ptr += 2;
                  } else if (type == C_WORD) {
                        switch (base) {
                              case C_HEX:
                                    fprintf(ofp, "%08x",
                                          KL_GET_UINT32(ptr));
                                    break;

                              case C_DECIMAL:
                                    fprintf(ofp, "%011d ", 
                                          KL_GET_UINT32(ptr));
                                    break;

                              case C_OCTAL:
                                    fprintf(ofp, "%020o ", 
                                          KL_GET_UINT32(ptr));
                                    break;
                        }
                        ptr += 4;
                  } else if (type == C_DWORD) {
                        switch (base) {
                              case C_HEX:
                                    fprintf(ofp, "%016"FMT64"x",
                                          KL_GET_UINT64(ptr));
                                    break;

                              case C_DECIMAL:
                                    fprintf(ofp, "%020"FMT64"ud ", 
                                          KL_GET_UINT64(ptr));
                                    break;

                              case C_OCTAL:
                                    fprintf(ofp, "%023"FMT64"o ", 
                                          KL_GET_UINT64(ptr));
                                    break;
                        }
                        ptr += 8;
                  }
                  i++;
                  if ((i < nunits) && (lines_per_entry == 2) && 
                      ((i % units_per_line) == (units_per_line/2))) {
                        if (PTRSZ32) {
                              fprintf(ofp, "\n            ");
                        } else {
                              fprintf(ofp, "\n                    ");
                        }
                  } else if (!(flags & C_CONCAT)) {
                        fprintf(ofp, " ");
                  }
                  if (capture_ascii &&
                        ((i && ((i % units_per_line) == 0)) ||
                                    (i == nunits))) {

                        int extra = 0;

                        if ((i == nunits) && (i % units_per_line)) {
                              /* Our last line is not a full one. 
                               * We have to padd it with blanks.
                               */
                              extra = units_per_line -
                                    (i % units_per_line);
                              for (j = 0; j < extra; j++) {
                                    if (type == C_BYTE) {
                                          fprintf(ofp, "   ");    
                                    } else if (type == C_HWORD) {
                                          fprintf(ofp, "     ");  
                                    } else if (type == C_WORD) {
                                          fprintf(ofp, 
                                                "         ");     
                                    } else {
                                          fprintf(ofp, "      "
                                                "           ");
                                    }
                              }
                        }
                        
                        /* Get an ASCII representation of 
                         * the bytes being dumpped
                         */
                        for(j = 0; j < 16 - (extra * unit_size); j++) {
                              if (*cp >= 32 && *cp <= 126) {
                                    cstr[j] = (char)*cp;
                              } else {
                                    cstr[j] = '.';
                              }
                              cp++;
                        }
                        cstr[j] = 0;
                        fprintf(ofp, ": %s\n", cstr);
                  } else if (i && (((i % units_per_line) == 0) ||
                              (i == nunits))) {
                        fprintf(ofp, "\n");
                  }
            }
      }
      kl_free_block(blk);
}

int
i_fprintf(FILE *ofp, const char *fmt, char *buffer) 
{
      return(fprintf((FILE *)ofp, fmt, buffer));
}


/*
 * kl_block_alloc_func()
 */
void *
kl_block_alloc_func(int size, int flag, void *ra)
{
      void *b;

      b = (void *)alloc_block(size, flag, ra);
      return(b);
}

/*
 * kl_block_realloc_func()
 */
void *
kl_block_realloc_func(void *blk, int size, int flag, void *ra)
{
      void *b;

      b = (void *)realloc_block(blk, size, flag, ra);
      return(b);
}

/*
 * kl_block_dup_func()
 */
void *
kl_block_dup_func(void *blk, int flag, void *ra)
{
      void *b;

      b = (void *)dup_block(blk, flag, ra);
      return(b);
}

/*
 * kl_str_to_block_func()
 */
void *
kl_str_to_block_func(char * s, int flag, void *ra)
{
      void *b;

      b = (void *)str_to_block(s, flag, ra);
      return(b);
}

/*
 * kl_block_free_func()
 */
void
kl_block_free_func(void *blk)
{
      free_block(blk);
}

/*
 * init_liballoc()
 */
void
init_liballoc(int pghdr_cnt, int blkhdr_cnt, int page_cnt)
{
      KL_BLOCK_ALLOC() = kl_block_alloc_func;
      KL_BLOCK_REALLOC() = kl_block_realloc_func;
      KL_BLOCK_DUP() = kl_block_dup_func;
      KL_STR_TO_BLOCK() = kl_str_to_block_func;
      KL_BLOCK_FREE() = kl_block_free_func;
}

/*
 * get_string()
 */
int
get_string(char *str, int size)
{
      char c;
      int count = 0;

      if (!str || (size == 0)) {
            return(0);  
      }
      while ((c = getchar())) {
            /* If we're at the end of the line, return without updating
             * the string.
             */
            if (c == '\n') {
                  break;
            }

            str[count] = c;
            count++;
            /* See if we have a full string. Make sure we leave 
             * room for the terminating NULL
             */
            if (count == (size - 1)) {
                  break;
            }
      }
      str[count] = 0;
      return(count);
}

/*
 * symbol_banner()
 */
void
symbol_banner(FILE *ofp, int flags)
{
      if(flags & C_WOFFSET){
            print_banner(ofp, "%      ADDR%>  OFFSET"
                       " SECTION     NAME                 TYPE%}78",
                       flags);
      } else {
            print_banner(ofp, "%      ADDR%> SECTION    "
                       " NAME                 TYPE%}78",
                       flags);
      }
}

/* Architecture specific print routines. This allows commands to print out
 * arch dependant values such as kernel addresses, from within the arch
 * independant section of lcrash. 
 */

/*
 * print_kaddr()
 *
 * Print out a kernel address. Note that there leading "0x".
 */
void
print_kaddr(kaddr_t kaddr, FILE *ofp, int flag)
{
      if(KL_NBPW==8){
            if (flag == 1) {
                  fprintf(ofp, "%#18"FMTPTR"x", kaddr);
            } else if (flag == 2) {
                  fprintf(ofp, "%#018"FMTPTR"x", kaddr);
            } else {
                  fprintf(ofp, "%#"FMTPTR"x", kaddr);
            }
      } else {
            if (flag == 1) {
                  fprintf(ofp, "%#10"FMTPTR"x", kaddr);
            } else if (flag == 2) {
                  fprintf(ofp, "%#010"FMTPTR"x", kaddr);
            } else {
                  fprintf(ofp, "%#"FMTPTR"x", kaddr);
            }
      }
}

/*
 * print_version_info() -- Print version(licensing info of lcrash
 */
void
print_version_info(FILE* ofp)
{
      fprintf(ofp, LCRASH_LICENSE);
}

/*
 * get first task
 */
int
get_first_task(kaddr_t *addr)
{
      syment_t *sp;
      if ((sp = kl_lkup_symname("init_task_union"))){
            /* linux 2.2 and UL */
            *addr = sp->s_addr;
      } else if ((sp = kl_lkup_symname("init_tasks"))){
            /* linux 2.4 */
            *addr = KL_VREAD_PTR(sp->s_addr);   
      } else if ((sp =  kl_lkup_symname("init_task"))){
            /* linux 2.5 */
            *addr = sp->s_addr;
      } else {
            /* XXX error message */
            *addr = 0;
            return 1;
      }

      return 0;
}

/*
 * return debug components as string
 */
#define _DBGCOMP_ALLOC    "alloc"
#define _DBGCOMP_BFD      "bfd"
#define _DBGCOMP_BTREE    "btree"
#define _DBGCOMP_COMPRESS "compress"
#define _DBGCOMP_INIT     "init"
#define _DBGCOMP_NONE     "none"
#define _DBGCOMP_MEMMAP   "memmap"
#define _DBGCOMP_MODULE   "module"
#define _DBGCOMP_SIGNAL   "signal"
#define _DBGCOMP_STABS    "stabs"
#define _DBGCOMP_SYMBOL   "symbol"
#define _DBGCOMP_TYPE     "type"
#define _DBGCOMP_ALL      "all"

#define _APPEND_DBGCOMP(COMP) \
do{ \
      if(dbg_components & KL_##COMP){ \
            if(firsttime){ \
                  firsttime=0; \
            } else { \
                  strcat(strp++, ","); \
            } \
            strcat(strp, _##COMP); \
            strp += strlen(_##COMP); \
      } \
} while (0)

const char*
get_klib_dbg_components(void)
{
      static char components[256];
      uint64_t dbg_components;
      char *strp = components;
      int firsttime=1;

      *strp = 0;
      dbg_components = kl_get_dbg_component();
      if(dbg_components == KL_DBGCOMP_ALL){
            strcat(strp, _DBGCOMP_ALL);
            strp += strlen(_DBGCOMP_ALL);
      } else {
            _APPEND_DBGCOMP(DBGCOMP_ALLOC);
            _APPEND_DBGCOMP(DBGCOMP_BFD);
            _APPEND_DBGCOMP(DBGCOMP_BTREE);
            _APPEND_DBGCOMP(DBGCOMP_COMPRESS);
            _APPEND_DBGCOMP(DBGCOMP_INIT);
            _APPEND_DBGCOMP(DBGCOMP_MEMMAP);
            _APPEND_DBGCOMP(DBGCOMP_MODULE);
            _APPEND_DBGCOMP(DBGCOMP_SIGNAL);
            _APPEND_DBGCOMP(DBGCOMP_STABS);
            _APPEND_DBGCOMP(DBGCOMP_SYMBOL);
            _APPEND_DBGCOMP(DBGCOMP_TYPE);
      }
      if(*components == 0){
            strcat(components, _DBGCOMP_NONE);
      }
      return((const char*)components);
}

/*
 * set debug components of libklib
 */
int
set_klib_dbg_components(const char *components)
{
      char *s;
      char *tok;
      char invert = 0;


      if(!(s=strdup(components))){
            /* out of mem */
            return(-1);
      }

      lcrash_debug = 0;
      tok = strtok(s, ",");
      while(tok){
            if(!strcmp(tok, _DBGCOMP_NONE)){
                  lcrash_debug = 0;
                  invert = 0;
                  break;
            } else if(!strcmp(tok, _DBGCOMP_ALL)){
                  invert = 1;
            } else if(!strcmp(tok, _DBGCOMP_ALLOC)){
                  lcrash_debug |= KL_DBGCOMP_ALLOC;
            } else if(!strcmp(tok, _DBGCOMP_BFD)){
                  lcrash_debug |= KL_DBGCOMP_BFD;
            } else if(!strcmp(tok, _DBGCOMP_BTREE)){
                  lcrash_debug |= KL_DBGCOMP_BTREE;
            } else if(!strcmp(tok, _DBGCOMP_COMPRESS)){
                  lcrash_debug |= KL_DBGCOMP_COMPRESS;
            } else if(!strcmp(tok, _DBGCOMP_INIT)){
                  lcrash_debug |= KL_DBGCOMP_INIT;
            } else if(!strcmp(tok, _DBGCOMP_MEMMAP)){
                  lcrash_debug |= KL_DBGCOMP_MEMMAP;
            } else if(!strcmp(tok, _DBGCOMP_MODULE)){
                  lcrash_debug |= KL_DBGCOMP_MODULE;
            } else if(!strcmp(tok, _DBGCOMP_SIGNAL)){
                  lcrash_debug |= KL_DBGCOMP_SIGNAL;
            } else if(!strcmp(tok, _DBGCOMP_STABS)){
                  lcrash_debug |= KL_DBGCOMP_STABS;
            } else if(!strcmp(tok, _DBGCOMP_SYMBOL)){
                  lcrash_debug |= KL_DBGCOMP_SYMBOL;
            } else if(!strcmp(tok, _DBGCOMP_TYPE)){
                  lcrash_debug |= KL_DBGCOMP_TYPE;
            } else {
                  kl_error("Invalid debug component \"%s\"\n", tok);
            }
            tok = strtok(NULL, ",");
      }
      if(invert){
            lcrash_debug = ~lcrash_debug;
      }

#ifdef ALLOC_DEBUG
      alloc_debug = lcrash_debug & KL_DBGCOMP_ALLOC;
#endif
      bfd_debug = lcrash_debug & KL_DBGCOMP_BFD;
      cmp_debug = lcrash_debug & KL_DBGCOMP_COMPRESS;

      kl_set_dbg_component(lcrash_debug);
      free(s);
      return(0);
}

Generated by  Doxygen 1.6.0   Back to index