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

struct.c

/*
 * $Id: struct.c,v 1.2 2005/02/23 01:09:11 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>

typedef struct stype_s {
      char  *name;                       /* struct name                     */
      int    size;                     /* struct size                   */
      void  (*banner)(FILE *, int);      /* struct banner function          */
      void  (*print)(kaddr_t, void *, int, FILE *); /* print routine        */
} stype_t;

stype_t Struct[] = {
      /*--------------------------------------------------------------------*/
      /*  NAME          SIZE  BANNER()                PRINT()               */
      /*--------------------------------------------------------------------*/
      { "mm_struct",       0, mm_struct_banner,       print_mm_struct       },
      { "page",            0, page_banner,            print_page            },
      { "task_struct",     0, task_struct_banner,     print_task_struct     },
      { "vm_area_struct",  0, vm_area_struct_banner,  print_vm_area_struct  },
      { "module",          0, module_banner,          print_module          },
      { (char *)0,         0, 0,                      0                     }
};

/*
 * print_banner()
 */
void
print_banner(FILE *ofp, char *bline, int flags)
{
      int i, count = 0, maxline = 0;
      char *c, *s;

      s = bline;
      while (s && (c = strchr(s, '%'))) {
            while (s < c) {
                  if (flags & BANNER) {
                        fputc(*s, ofp);
                  }
                  count++;
                  s++;
            }
            c++;
            switch (*c) {
                  case '>':
                        if (PTRSZ64) {
                              if (flags & BANNER) {
                                    fprintf(ofp, "        ");
                              }
                              count += 8;
                        }
                        s = (c + 1);
                        break;
                  case '}':
                        if (*(c + 1)) {
                              maxline = atoi(c + 1);
                        }
                        s = 0;
                        break;
                  default:
                        s = c;
                        break;
            }
      }
      if (flags & BANNER) {
            if (s) {
                  while (*s) {
                        if (flags & BANNER) {
                              fputc(*s, ofp);
                        }
                        count++;
                        s++;
                  }
            }
            fprintf(ofp, "\n");
      }
      if (maxline && (maxline > count)) {
            count = maxline;
      }
      if (flags & SMAJOR) {
            for (i = 0; i < count; i++) {
                  fputc('=', ofp);
            }
            fputc('\n', ofp);
      }
      if (flags & SMINOR) {
            for (i = 0; i < count; i++) {
                  fputc('-', ofp);
            }
            fputc('\n', ofp);
      }
}

/*
 * print_value()
 */
void
print_value(FILE *ofp, char *ldstr, uint64_t value, int width, int flag)
{
      int w = 0;
      char fmtstr[12], f, s[2]="\000\000";

      if (ldstr) {
            fprintf(ofp, "%s", ldstr);
      }
      if (flag == ADDR_FLG) {
              s[0] = '#';
            f = 'x';
            if (width) {
                  if (PTRSZ64) {  
                        w = 18; /* due to leading "0x" */
                  } else {
                          w = 10; /* due to leading "0x" */
                  }
            }
      } else {
            switch (flag) {
                  case HEX_FLG:
                          s[0] = '#';
                        f = 'x';
                        break;
                  case OCTAL_FLG:
                        f = 'o';
                        break;
                  case UNSIGNED_FLG:
                        f = 'u';
                        break;
                  case CHAR_FLG:
                        f = 'c';
                        break;
                  case SIGNED_FLG:
                  default:
                        f = 'd';
                        break;
            }
            w = width;
      }
      if (w) {
            sprintf(fmtstr, "%%%s%d"FMT64"%c", s, w, f);
      } else {
            sprintf(fmtstr, "%%%s"FMT64"%c", s, f);
      }
      fprintf(ofp, fmtstr, value);
}

/*
 * list_head_banner()
 */
void
list_head_banner(FILE *ofp, int flags)
{
      if(flags & C_LISTHEAD_N){
            print_banner(ofp, "%>STRUCT ADDR%>       PREV%>   LISTHEAD"
                       "%>       NEXT%", flags);
      } else {
            print_banner(ofp, "%>STRUCT ADDR%>       NEXT%>   LISTHEAD"
                       "%>       PREV%", flags);

      }
}

/*
 * print_list_head()
 */
void
print_list_head(FILE *ofp, kaddr_t saddr, kaddr_t lhaddr, 
            kaddr_t prev, kaddr_t next, int flags)
{
      if (flags & C_TABLE){
            print_value(ofp, " ", ADDR64(saddr), 8, ADDR_FLG);
            if(flags & C_LISTHEAD_N){
                  print_value(ofp, " ", ADDR64(prev), 8, ADDR_FLG);
                  print_value(ofp, " ", ADDR64(lhaddr), 8, ADDR_FLG);
                  print_value(ofp, " ", ADDR64(next), 8, ADDR_FLG);
            } else {
                  print_value(ofp, " ", ADDR64(next), 8, ADDR_FLG);
                  print_value(ofp, " ", ADDR64(lhaddr), 8, ADDR_FLG);
                  print_value(ofp, " ", ADDR64(prev), 8, ADDR_FLG);
            }
            fprintf(ofp, "\n");
      } else if (flags & C_STRUCT) {
            print_value(ofp, "STRUCT ADDR: ", ADDR64(saddr), 8, ADDR_FLG);
            fprintf(ofp, "\n");
      } 
}

/*
 * check_prev_ptr()
 */
void
check_prev_ptr(FILE *ofp, kaddr_t ptr, kaddr_t prev)
{
      if(ptr != prev) {
            fprintf(ofp, "\nWARNING: Pointer broken. %#"FMTPTR"x,"
                  " SHOULD BE: %#"FMTPTR"x\n", prev, ptr);
      }
}

/*
 * mm_struct_banner()
 */
void
mm_struct_banner(FILE *ofp, int flags)
{
      print_banner(ofp, "%>      ADDR%  "
                        "MM_COUNT  MAP_COUNT  %>      MMAP%", flags);
}

/*
 * print_mm_struct()
 */
void
print_mm_struct(kaddr_t addr, void *p, int flags, FILE *ofp)
{
      kaddr_t vmap;
      void *vmapp;

      print_value(ofp, "", ADDR64(addr), 8, ADDR_FLG);
      if (LINUX_2_2_X(KL_LINUX_RELEASE)) {
            print_value(ofp, "  ", 
                  UINT64(KL_UINT(K_PTR(p, "mm_struct", "count"),
                  "atomic_t", "counter")), 8, UNSIGNED_FLG);
      } else {
            print_value(ofp, "  ", 
                  UINT64(KL_UINT(K_PTR(p, "mm_struct", "mm_count"),
                  "atomic_t", "counter")), 8, UNSIGNED_FLG);
      }
      print_value(ofp, "  ", 
            UINT64(KL_UINT(p, "mm_struct", "map_count")), 9, UNSIGNED_FLG);
      print_value(ofp, "  ", 
            ADDR64(kl_kaddr(p, "mm_struct", "mmap")), 8, ADDR_FLG);
      fprintf(ofp, "\n");

      if (flags & C_FULL) {
            fprintf(ofp, "\n");
            print_value(ofp, "  START_CODE:", 
                  ADDR64(kl_kaddr(p, "mm_struct", "start_code")), 
                  0, ADDR_FLG);
            print_value(ofp, ", END_CODE:", 
                  ADDR64(kl_kaddr(p, "mm_struct", "end_code")), 
                  0, ADDR_FLG);
            fprintf(ofp, "\n");

            print_value(ofp, "  START_DATA:", 
                  ADDR64(kl_kaddr(p, "mm_struct", "start_data")), 
                  0, ADDR_FLG);
            print_value(ofp, ", END_DATA:", 
                  ADDR64(kl_kaddr(p, "mm_struct", "end_data")), 
                  0, ADDR_FLG);
            fprintf(ofp, "\n");

            print_value(ofp, "  START_BRK:", 
                  ADDR64(kl_kaddr(p, "mm_struct", "start_brk")), 
                  0, ADDR_FLG);
            print_value(ofp, ", START_STACK:", 
                  ADDR64(kl_kaddr(p, "mm_struct", "start_stack")), 
                  0, ADDR_FLG);
            fprintf(ofp, "\n");

            print_value(ofp, "  ARG_START:", 
                  ADDR64(kl_kaddr(p, "mm_struct", "arg_start")), 
                  0, ADDR_FLG);
            print_value(ofp, ", ARG_END:", 
                  ADDR64(kl_kaddr(p, "mm_struct", "arg_end")), 
                  0, ADDR_FLG);
            fprintf(ofp, "\n");

            print_value(ofp, "  TOTAL_VM:", 
                  UINT64(KL_UINT(p, "mm_struct", "total_vm")),
                  0, HEX_FLG);
            fprintf(ofp, "\n\n");
      }
      if (flags & C_NEXT) {
            vmapp = kl_alloc_block(kl_struct_len("vm_area_struct"), K_TEMP);
            if (klib_error) {
                  fprintf(ofp, "could not allocate %d bytes for buffer "
                        "to hold vm_area_struct\n", 
                        kl_struct_len("vm_area_struct"));
                  return;
            }
            vmap = kl_kaddr(p, "mm_struct", "mmap");
            fprintf(ofp, "\n");
            vm_area_struct_banner(ofp, BANNER|SMINOR);
            while(vmap) {
                  GET_BLOCK(vmap, kl_struct_len("vm_area_struct"), vmapp);
                  if (klib_error) {
                        fprintf(ofp, "error reading vmap_struct at ");
                        print_value(ofp, "", UINT64(vmap), 
                              0, ADDR_FLG);
                        break;
                  }
                  print_vm_area_struct(vmap, vmapp, 0, ofp);
                  vmap = kl_kaddr(vmapp, "vm_area_struct", "vm_next");
            }
            vm_area_struct_banner(ofp, SMINOR);
            fprintf(ofp, "\n");
            kl_free_block(vmapp);
      }
}

/*
 * page_banner()
 */
void
page_banner(FILE *ofp, int flags)
{
      print_banner(ofp, "%>      ADDR%    PGNO  COUNT  "
            "%>     FLAGS%  %>   VIRTUAL%", flags);
}

void
print_page_struct(kaddr_t addr, void *pp, int flags, 
            unsigned long pgno, FILE *ofp)
{
      print_value(ofp, "", ADDR64(addr), 8, ADDR_FLG);
      print_value(ofp, "  ", UINT64(pgno), 6, UNSIGNED_FLG);
      print_value(ofp, "  ", UINT64(KL_UINT(K_PTR(pp, "page", "count"),
            "atomic_t", "counter")), 5, UNSIGNED_FLG);
      print_value(ofp, "  ", ADDR64(KL_UINT(pp, "page", "flags")),
            8, ADDR_FLG);
      print_value(ofp, "  ", ADDR64(KL_UINT(pp, "page", "virtual")),
            8, ADDR_FLG);
      fprintf(ofp, "\n");

      if (flags & C_FULL) {
            fprintf(ofp, "\n");
            if (LINUX_2_2_X(KL_LINUX_RELEASE)) {
                  print_value(ofp, "  NEXT:", 
                        ADDR64(KL_UINT(pp, "page", "next")),
                        0, ADDR_FLG);
                  print_value(ofp, ", PREV:", 
                        ADDR64(KL_UINT(pp, "page", "prev")),
                        0, ADDR_FLG);
                  fprintf(ofp, "\n");
            } else {
                  print_value(ofp, "  NEXT:", 
                        ADDR64(KL_UINT(K_PTR(pp, "page", "list"),
                        "list_head", "next")), 0, ADDR_FLG);
                  print_value(ofp, ", PREV:", 
                        ADDR64(KL_UINT(K_PTR(pp, "page", "list"),
                        "list_head", "prev")), 0, ADDR_FLG);
                  fprintf(ofp, "\n");
            }
            if (!LINUX_2_6_X(KL_LINUX_RELEASE)) {
                  print_value(ofp, "  NEXT_HASH:", 
                        ADDR64(KL_UINT(pp, "page", "next_hash")),
                        0, ADDR_FLG);
                  fprintf(ofp, "\n");
            }

            print_value(ofp, "  MAPPING:", 
                  ADDR64(KL_UINT(pp, "page", "mapping")),
                  0, ADDR_FLG);
            print_value(ofp, ", INDEX:", 
                  ADDR64(KL_UINT(pp, "page", "index")),
                  0, ADDR_FLG);
            fprintf(ofp, "\n\n");
      }
}

void
print_page(kaddr_t addr, void *pp, int flags, FILE *ofp)
{
        unsigned long pgno;

        pgno = (addr - MEM_MAP) / PAGE_SZ;
      print_page_struct(addr, pp, flags, pgno, ofp);
}

/*
 * task_struct_banner()
 */
void
task_struct_banner(FILE *ofp, int flags)
{
      print_banner(ofp, "%>      ADDR%    UID    PID   PPID  STATE  "
                        "   FLAGS CPU  NAME%}79", flags);
}

/*
 * print_task_struct()
 */
void
print_task_struct(kaddr_t addr, void *tsp, int flags, FILE *ofp)
{
      kaddr_t mmap_addr;
      void *mmp;

      print_value(ofp, "", ADDR64(addr), 8, ADDR_FLG);
      print_value(ofp, "  ", KL_UINT(tsp, "task_struct", "uid"), 
            5, UNSIGNED_FLG);
      print_value(ofp, "  ", KL_UINT(tsp, "task_struct", "pid"), 
            5, UNSIGNED_FLG);
      print_value(ofp, "  ", UINT64(kl_parent_pid(tsp)), 5, UNSIGNED_FLG);
      print_value(ofp, "  ", KL_UINT(tsp, "task_struct", "state"), 
            5, UNSIGNED_FLG);
      print_value(ofp, "  ", KL_UINT(tsp, "task_struct", "flags"), 
            8, HEX_FLG);

      if(task_has_cpu(addr,tsp)){
            print_value(ofp,"  ", task_cpu(tsp), 2, SIGNED_FLG);
      } else {
            fprintf(ofp,"   -");
      }

      fprintf(ofp, "  %s\n", (char *)K_PTR(tsp, "task_struct", "comm"));

      if (flags & C_FULL) {
            fprintf(ofp, "\n");

            print_value(ofp, "  MM:", 
                  KL_UINT(tsp, "task_struct", "mm"), 0, ADDR_FLG);
            fprintf(ofp, "\n\n");

            if (LINUX_2_2_X(KL_LINUX_RELEASE)) {
                  fprintf(ofp, "THREAD:\n");
                  print_value(ofp, "  ESP0:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "tss"),
                        "thread_struct", "esp0"), 0, ADDR_FLG);
                  print_value(ofp, ", ESP:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "tss"),
                        "thread_struct", "esp"), 0, ADDR_FLG);
                  print_value(ofp, ", EIP:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "tss"),
                        "thread_struct", "eip"), 0, ADDR_FLG);
                  fprintf(ofp, "\n");

                  print_value(ofp, "  FS:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "tss"),
                        "thread_struct", "fs"), 0, ADDR_FLG);
                  print_value(ofp, ", GS:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "tss"),
                        "thread_struct", "gs"), 0, ADDR_FLG);
                  fprintf(ofp, "\n");
            } else if (KL_ARCH == KL_ARCH_I386) {
                  fprintf(ofp, "THREAD:\n");
                  print_value(ofp, "  ESP0:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "thread"),
                        "thread_struct", "esp0"), 0, ADDR_FLG);
                  print_value(ofp, ", ESP:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "thread"),
                        "thread_struct", "esp"), 0, ADDR_FLG);
                  print_value(ofp, ", EIP:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "thread"),
                        "thread_struct", "eip"), 0, ADDR_FLG);
                  fprintf(ofp, "\n");

                  print_value(ofp, "  FS:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "thread"),
                        "thread_struct", "fs"), 0, ADDR_FLG);
                  print_value(ofp, ", GS:", 
                        KL_UINT(K_PTR(tsp, "task_struct", "thread"),
                        "thread_struct", "gs"), 0, ADDR_FLG);
                  fprintf(ofp, "\n");
            }
            fprintf(ofp, "\n");
      }
      if (flags & C_NEXT) {
            fprintf(ofp, "\n");
            if (!(mmp = kl_alloc_block(MM_STRUCT_SZ, K_TEMP))) {
                  return;
            }
            mmap_addr = kl_kaddr(tsp, "task_struct", "mm");
            GET_BLOCK(mmap_addr, MM_STRUCT_SZ, mmp);
            if (!mmap_addr || klib_error) {
                  kl_free_block(mmp);
                  return;     
            }
            mm_struct_banner(ofp, (BANNER|SMINOR));
            print_mm_struct(mmap_addr, mmp, flags&(~C_FULL), ofp);
            kl_free_block(mmp);
            fprintf(ofp, "\n");
      }
}

/*
 * print_active_tasks()
 */
int
print_active_tasks(int flags, FILE *ofp)
{
      int first_time = 1, task_cnt = 0;
      kaddr_t addr, first_task;
      void *tsp;

#if (ARCH == ia64) /*  XXX temporary HACK for snia64 */
      kaddr_t p1, p2;
#endif

      if(get_first_task(&first_task)) {
            /* XXX error message */
            return 0;
      }

      if (!(tsp = kl_alloc_block(TASK_STRUCT_SZ, K_TEMP))) {
            return(0);
      }
      addr = first_task;
      task_struct_banner(ofp, (BANNER|SMAJOR));
      do {
            unsigned int state;

            if (kl_get_task_struct(addr, 2, tsp)) {
                  break;
            }
            state = KL_UINT(tsp, "task_struct", "state");
            if (((flags & C_RUNABLE) && (state != 0)) ||
                ((flags & C_UNRUNABLE) && (state >= 0)) ||
                ((flags & C_STOPPED) && (state <= 0))) {
                  goto next;
            }
            if (first_time) {
                  first_time = 0;
            } else if (flags & (C_FULL|C_NEXT)) {
                  task_struct_banner(ofp, (BANNER|SMAJOR));
            }
            print_task_struct(addr, tsp, flags, ofp);
            task_cnt++;
next:
            addr = kl_next_task(tsp);
#if (ARCH == ia64) /* XXX temporary HACK for snia64 */
            if (KL_VIRTOP(addr, NULL, &p1)) {
                  break;
            }
            if (KL_VIRTOP(first_task, NULL, &p2)) {
                  break;
            }
      } while (p1 != p2);
#else 
        } while (addr != first_task);
#endif
        kl_free_block(tsp);
      return(task_cnt);
}

/*
 * vm_area_struct_banner()
 */
void
vm_area_struct_banner(FILE *ofp, int flags)
{
      print_banner(ofp, "%>      ADDR%  %>  VM_START%  "
                        "%>    VM_END%  VM_PGOFF %>  VM_FLAGS%", flags);
}

/*
 * print_vm_area_struct()
 */
void
print_vm_area_struct(kaddr_t addr, void *vmap, int flags, FILE *ofp)
{
      print_value(ofp, "", ADDR64(addr), 8, ADDR_FLG);
      print_value(ofp, "  ", 
            ADDR64(KL_UINT(vmap, "vm_area_struct", "vm_start")), 
            8, ADDR_FLG);
      print_value(ofp, "  ", 
            ADDR64(KL_UINT(vmap, "vm_area_struct", "vm_end")), 
            8, ADDR_FLG);
      if (LINUX_2_2_X(KL_LINUX_RELEASE)) {
            print_value(ofp, "  ", 
                  INT64(KL_INT(vmap, "vm_area_struct", "vm_offset")), 
                  8, SIGNED_FLG);
      } else {
            print_value(ofp, "  ", 
                  INT64(KL_INT(vmap, "vm_area_struct", "vm_pgoff")), 
                  8, SIGNED_FLG);
      }
      print_value(ofp, " ", 
            ADDR64(KL_UINT(vmap, "vm_area_struct", "vm_flags")), 
            8, ADDR_FLG);
      fprintf(ofp, "\n");

      if (flags & C_FULL) {
            fprintf(ofp, "\n");
            print_value(ofp, "  VM_MM:", 
                  ADDR64(KL_UINT(vmap, "vm_area_struct", "vm_mm")), 
                  8, ADDR_FLG);
            print_value(ofp, ", VM_NEXT:", 
                  ADDR64(KL_UINT(vmap, "vm_area_struct", "vm_next")), 
                  0, ADDR_FLG);
            fprintf(ofp, "\n");
            print_value(ofp, "  VM_FILE:", 
                  ADDR64(KL_UINT(vmap, "vm_area_struct", "vm_file")), 
                  0, ADDR_FLG);
            print_value(ofp, ", VM_PDATA:", 
                  ADDR64(KL_UINT(vmap, "vm_area_struct", 
                  "vm_private_data")), 0, ADDR_FLG);
            fprintf(ofp, "\n\n");
      }
}

/*
 * struct_index()
 */
int
struct_index(char *s)
{
      int i = 0;

      while(Struct[i].name) {
            if (!strcmp(s, Struct[i].name)) {
                  return(i);
            }
            i++;
      }
      return(-1);
}

/*
 * structlist_banner()
 */
void
structlist_banner(FILE *ofp, int flags)
{
      if (flags & BANNER) {
            fprintf(ofp, "NUM  NAME                      SIZE\n");
      }

      if (flags & SMAJOR) {
            fprintf(ofp, "===================================\n");
      }
}

/*
 * structlist()
 */
void
structlist(FILE *ofp)
{
      int i = 0;

      structlist_banner(ofp, BANNER|SMAJOR);
      while(Struct[i].name) {
            if (Struct[i].size == 0) {
                  Struct[i].size = kl_struct_len(Struct[i].name);
            }
            fprintf(ofp, "%3d  %-16s         %5d\n", 
                  i, Struct[i].name, Struct[i].size);
            i++;
      }
      structlist_banner(ofp, SMAJOR);
}

/*
 * Get page structure address and page number.
 */
kaddr_t
get_pg_struct_addr(uint64_t value, void *pgdat, int mode, unsigned long *pfn)
{
        kaddr_t mmap, p, pgdat_list;
        unsigned long start_pfn, spanned_pages;
        unsigned long pgdat_size;

        pgdat_size = kl_struct_len("pg_data_t");
        pgdat_list = KL_PGDAT_LIST;
        if (LINUX_2_6_X(KL_LINUX_RELEASE) && !MEM_MAP) {
            /*
             * For NUMA machines, mem_map symbol will not be used.
             * Each pgdata structure contains array of page structures 
             * for the corresponding node.
             */
                while (pgdat_list) {
                        GET_BLOCK(pgdat_list, pgdat_size, pgdat);
                        if (KL_ERROR) {
                                return 0;
                        }
                        start_pfn = KL_UINT(pgdat,"pg_data_t","node_start_pfn");
                        spanned_pages = KL_UINT(pgdat,"pg_data_t",
                                "node_spanned_pages");
                        mmap = kl_kaddr(pgdat,"pg_data_t","node_mem_map");
                        if ((mode == 1) && (value >= start_pfn) &&
                                (value - start_pfn < spanned_pages)) {
                                *pfn = value - start_pfn;
                                return (mmap + (*pfn * PAGE_SZ));
                        } else if ((mode == 2) && ((kaddr_t)value > mmap)
                                && ((((kaddr_t)value - mmap)/PAGE_SZ) < spanned_pages)) {
                                *pfn = ((kaddr_t)value - mmap)/PAGE_SZ;
                                return (kaddr_t)value;
                        }
                        pgdat_list = kl_kaddr(pgdat, "pg_data_t", "pgdat_next");
                }
        } else {
                if (mode == 1) {
                        /* Get the page by page number
                         */
                        p = MEM_MAP + (value * PAGE_SZ);
                } else if (mode == 2) {
                        p = (kaddr_t)value;
                } else return 0;
                if (((p - MEM_MAP)/PAGE_SZ) < NUM_PHYSPAGES) {
                        *pfn = ((kaddr_t)p - MEM_MAP)/PAGE_SZ;
                        return p;
                }
        }
        return 0;
}

/*
 * walk_structs() -- walk linked lists of kernel data structures
 */
int
walk_structs(char *s, char *f, int offset, kaddr_t addr, int flags, FILE *ofp)
{
      int sid, size, firsttime = 1;
      kaddr_t last = 0, next;
      void *ptr = NULL;
      kltype_t *klt = (kltype_t *)NULL;

      void *lhead_ptr = NULL;
      int lhead_size, counter = 0;
      kaddr_t head, head_next, head_prev, entry, entry_next, entry_prev;

      /* Make sure we have the right number of paramaters.
       */
      if (!s || (!f && (offset == -1)) || !addr) {
            KL_ERROR = KLE_BAD_STRUCT;
            return(1);
      }

      /* Check for mutual exclusive flags: */
      /* C_STRUCT NOR C_TABLE, C_LISTHEAD_N NOR C_LISTHEAD_P. */
      /* If C_TABLE is set, C_LISTHEAD must also be set. */
      if (((flags & C_STRUCT) && (flags & C_TABLE)) ||
          ((flags & C_LISTHEAD_P) && (flags & C_LISTHEAD_N))||
          ((flags & C_TABLE) && !(flags & C_LISTHEAD))) {
            fprintf(KL_ERRORFP, "ERROR: Internal error. Wrong flags "
                  "specified in function %s().\n", __FUNCTION__);
            return(1);
      }

      /* Get the index for struct name, set flag for "predefined" struct
       */
      if ((sid = struct_index(s)) > -1){
            flags |= C_PDSTRUCT;
      }

      /* One of C_STRUCT, C_PDSTRUCT or C_TABLE has to be set. */
      if (!(flags & (C_STRUCT | C_PDSTRUCT | C_TABLE))) {
            fprintf(KL_ERRORFP, "Neither a \"predefined\""
                  "structure, nor options '-s' or '-t' "
                  "specified. Can't print structure.\n");
            return(1);
      }

      /* If field name was passed, determine its offset in the struct.
       */
      if (offset == -1) {
            if ((offset = kl_member_offset(s, f)) == -1) {
                  fprintf(KL_ERRORFP, "Could not determine "
                        "offset for member %s of %s.\n", f, s);
                  KL_ERROR = KLE_BAD_FIELD;
                  return(1);
            }
      }

      /* Get the type */
      if (!(klt = kl_find_type(s, (KLT_STRUCT|KLT_UNION)))) {
            KL_ERROR = KLE_BAD_STRUCT;
            return(1);
      }
      /* Get the struct size */
      if (flags & C_PDSTRUCT) {
            if ((size = Struct[sid].size) == 0) {
                  if ((size = kl_struct_len(s)) == 0) {
                        KL_ERROR = KLE_BAD_STRUCT;
                        return(1);
                  }
                  /* Set the size value for future reference. */
                  Struct[sid].size = size;
            }
      } else {
            if ((size = kl_struct_len(s)) == 0) {
                  KL_ERROR = KLE_BAD_STRUCT;
                  return(1);
            }
      }

      if ((next = addr)) {
            /* get head of list (anchor) when struct list_head is used */
            if(flags & C_LISTHEAD) {
                  if ((lhead_size = kl_struct_len("list_head")) == 0){
                        KL_ERROR = KLE_BAD_STRUCT;
                        return(1);
                  }
                  head = next;
                  lhead_ptr = kl_alloc_block(lhead_size, K_TEMP);
                  kl_get_struct(head, lhead_size, lhead_ptr, 0);
                  /* get next field of anchor */
                  head_next = kl_kaddr(lhead_ptr, "list_head", "next");
                  /* get prev field of anchor */
                  head_prev = kl_kaddr(lhead_ptr, "list_head", "prev");
                  entry = 0;
            }

            if (!(flags & C_STRUCT)) {
                  /* print headline for output */
                  if (flags & C_TABLE) {
                        list_head_banner(ofp, BANNER|SMAJOR|flags);
                  } else { /* if (flags & C_PDSTRUCT) */
                        (*Struct[sid].banner)(ofp, BANNER|SMAJOR|flags);
                  }
            }
      }

      while(next && CHECK_ITER_THRESHOLD(counter++)) {
            if(flags & C_LISTHEAD) {
                  if(!(entry)){
                        if(flags & C_TABLE) {
                              print_list_head(ofp, 0, head, head_prev,
                                          head_next, flags);
                        }
                        if(flags & C_LISTHEAD_N){
                              entry = head_next;
                        } else {
                              entry = head_prev;
                        }
                        last = head;
                  }

                  if(head == entry) {
                        if(flags & C_LISTHEAD_N){
                              check_prev_ptr(ofp, last, head_prev);
                        } else {
                              check_prev_ptr(ofp, last, head_next);
                        }
                        if(flags & C_TABLE) {
                              list_head_banner(ofp, SMAJOR|flags);
                        }
                        break;
                  }

                  next = entry - offset;
                  kl_get_struct(entry, lhead_size, lhead_ptr, 0);
                  entry_next = kl_kaddr(lhead_ptr, "list_head", "next");
                  entry_prev = kl_kaddr(lhead_ptr, "list_head", "prev");
                  if(flags & C_LISTHEAD_N){
                        check_prev_ptr(ofp, last, entry_prev);
                  } else {
                        check_prev_ptr(ofp, last, entry_next);
                  }
                  print_list_head(ofp, next, entry, entry_prev,
                              entry_next, flags);
                  last = entry;
                  if(flags & C_LISTHEAD_N){
                        entry = entry_next;
                  } else {
                        entry = entry_prev;
                  }
            }
            
            if (!(flags & C_TABLE)) {
                  ptr = kl_alloc_block(size, K_TEMP);
                  kl_get_struct(next, size, ptr, s);
                  if (KL_ERROR) {
                        KL_ERROR |= KLE_BAD_STRUCT;
                        kl_free_block(ptr);
                        return(1);
                  }
                  if (flags & C_STRUCT) {
                        /* If C_STRUCT flag is set, print structure
                         *  in C-like struct format.
                         */
                        if (flags & C_OCTAL) {
                              kl_print_type(ptr, klt, 0, 
                                          K_OCTAL, ofp);
                        } else if (flags & C_HEX) {
                              kl_print_type(ptr, klt, 0, K_HEX, ofp);
                        } else {
                              kl_print_type(ptr, klt, 0, 0, ofp);
                        }
                  } else { /* if (flags & C_PDSTRUCT) */
                        if (flags & C_FULL) {
                              if (!firsttime) {
                                    (*Struct[sid].banner)
                                          (ofp, BANNER|
                                           SMAJOR|flags);
                              } else {
                                    firsttime = 0;
                              }
                        }
                        if (Struct[sid].print) {
                              (*Struct[sid].print)(next, ptr, 
                                               flags, ofp);
                        } else {
                              fprintf(ofp, 
                                    "%s: can't print struct\n", 
                                    Struct[sid].name);
                        }
                  }
                  kl_free_block(ptr);
                  if(!(flags & C_LISTHEAD)) {
                        last = next;
                        next = KL_VREAD_PTR(next + offset);
                        if (KL_ERROR || (next == addr) || 
                            (next == last)) {
                              break;
                        }
                  }
            }
      }
      ITER_THRESHOLD_MSG(ofp, counter-1);

      if (!(flags & (C_TABLE | C_STRUCT))) { /* && (flags & C_PDSTRUCT) */

            (*Struct[sid].banner)(ofp, SMAJOR|flags);
      }                       

      kl_free_block(lhead_ptr);
      return(0);
}

Generated by  Doxygen 1.6.0   Back to index