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

kl_debug.c

/*
 * $Id: kl_debug.c,v 1.1 2004/12/21 23:26:20 tjm Exp $
 *
 * This file is part of libklib.
 * A library which provides access to Linux system kernel dumps.
 *
 * Created by Silicon Graphics, Inc.
 * Contributions by IBM, NEC, and others
 *
 * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved.
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */

#include <klib.h>
#include <bfd.h>

/* "roots" for binary search trees containing various types of symbol
 * data. There are multiple trees for performance reasons (quicker tree
 * building and searching) and to allow records of different types to
 * have the same name (e.g., when a typedef is the same name as a type).
 * We COULD have allowed duplicate entries in a single tree, but this
 * approach is faster and cleaner. Note that these trees are global and
 * may contain information from multiple namelists.
 */
dbg_sym_t *type_tree = (dbg_sym_t *)NULL;
dbg_sym_t *typedef_tree = (dbg_sym_t *)NULL;
dbg_sym_t *func_tree = (dbg_sym_t *)NULL;
dbg_sym_t *srcfile_tree = (dbg_sym_t *)NULL;
dbg_sym_t *var_tree = (dbg_sym_t *)NULL;
dbg_sym_t *xtype_tree = (dbg_sym_t *)NULL;

/* Hash table for hashing sym records via typenum. If the typenum is
 * for a duplicate definition, then the hash record will point to the
 * one that was already captured.
 */
dbg_hashrec_t *dbg_hash[TYPE_NUM_SLOTS];

int debug_format;

/*
 * dbg_alloc_sym()
 */
dbg_sym_t *
dbg_alloc_sym(int dbgtyp)
{
      dbg_sym_t *stp;

      stp = (dbg_sym_t *)malloc(sizeof(dbg_sym_t));
      memset(stp, 0, sizeof(dbg_sym_t));
      stp->sym_dbgtyp = dbgtyp;
      return (stp);
}

/*
 * dbg_free_sym()
 */
void
dbg_free_sym(dbg_sym_t *stp)
{
      if (!stp) {
            return;
      }
      if (stp->sym_name) {
            free(stp->sym_name);
      }
      free(stp);
}

/*
 * dbg_hash_sym()
 */
void
dbg_hash_sym(uint64_t typenum, dbg_sym_t *stp)
{
      dbg_hashrec_t *shp, *hshp;

      if ((typenum == 0) || (!stp)) {
            return;
      }
      shp = (dbg_hashrec_t *)malloc(sizeof(dbg_hashrec_t));
      shp->h_typenum = typenum; 
      shp->h_ptr = stp;
      shp->h_next = (dbg_hashrec_t *)NULL;
      if ((hshp = dbg_hash[TYPE_NUM_HASH(typenum)])) {
            while (hshp->h_next) {
                  hshp = hshp->h_next;
            }
            hshp->h_next = shp;
      } else {
            dbg_hash[TYPE_NUM_HASH(typenum)] = shp;
      }
}

/*
 * dbg_insert_sym() 
 *
 *   Return values:
 *
 *     -1 == error
 *      0 == success
 *      1 == duplicate symbol
 */
int
dbg_insert_sym(dbg_sym_t *stp)
{
      short type;
      int ret = 0;
      dbg_sym_t *match_stp;
      dbg_sym_t **tmp_tree;

      if (!stp) {
            return(-1);
      }

      /* Check to see if this is a cross reference type. If it is, 
       * and we find a type already on the type tree, then we can just
       * link it to the one already there.
       */
      if ((type = stp->sym_type) == DBG_XTYPE) {
            type = DBG_TYPE;
      } 
      if ((match_stp = dbg_find_sym(stp->sym_name, type, 0))) {
            /* This is an instance of the same symbol definition,
             * from a different location in the symbol table. If 
             * the symbol includes a type definition, then we
             * need to create a cross mapping to allow other 
             * types that might reference this type definition
             * to use the one already captured. Otherwise, just
             * drop the duplicate type.
             */
            if (stp->sym_typenum) {
                  dbg_hash_sym(stp->sym_typenum, match_stp);
            }
            return(1);
      }

      /* We can't place the sym on one of the sym trees if there is no
       * type name. If there is a type number, we can put it on the
       * hash table. Otherwise, we'll return an error (it's up to the
       * calling funciton to determine what to do with it).
       */
      if (!stp->sym_name) {
            if (stp->sym_typenum) {
                  dbg_hash_sym(stp->sym_typenum, stp);
            } else {
                  return(-1);
            }
            return(0);
      }
      switch (stp->sym_type) {
            case DBG_SRCFILE:
                  tmp_tree = &srcfile_tree;
                  break;
            case DBG_TYPE:
                  tmp_tree = &type_tree;
                  break;
            case DBG_TYPEDEF:
                  tmp_tree = &typedef_tree;
                  break;
            case DBG_FUNC:
                  tmp_tree = &func_tree;
                  break;
            case DBG_VAR:
                  tmp_tree = &var_tree;
                  break;
            case DBG_XTYPE:
                  tmp_tree = &xtype_tree;
                  break;
            default:
                  return(-1);
      }
      ret = kl_insert_btnode((btnode_t **)tmp_tree, (btnode_t *)stp, 0);
      if (ret) {
            return(-1);
      }

      /* If this is a type and there is a type number, then add this 
       * record to the hash table (so that we can do quick lookups via 
       * type number).
       */
      if (stp->sym_typenum && ((stp->sym_type == DBG_TYPE) || 
                   (stp->sym_type == DBG_TYPEDEF) || 
                   (stp->sym_type == DBG_XTYPE))) {
            dbg_hash_sym(stp->sym_typenum, stp);
      }
      return(0);
}

/*
 * dbg_walk_hash() -- Walk all the records in the dbg hash table.
 *                    First time in, *index==0 and *tag==NULL.
 */
dbg_type_t *
dbg_walk_hash(int *index, void **tag)
{
      dbg_hashrec_t *dbghp;
      dbg_hashrec_t *next_dbghp;

      /* We have to have both pointers or we can't go on...
       */
      if (!index || !tag) {
            return((dbg_type_t *)NULL);
      }
      /* We we are at the end, just return
       */
      if (*index == TYPE_NUM_SLOTS) {
            return((dbg_type_t *)NULL);
      }
      dbghp = (dbg_hashrec_t *)*tag;

      /* Check to see if this is the first time through
       */
      if ((*index == 0) && (dbghp == NULL)) {
            while (dbg_hash[*index] == (dbg_hashrec_t *)NULL) {
                  (*index)++;
                  if (*index == TYPE_NUM_SLOTS) {
                        return((dbg_type_t *)NULL);
                    }       
            }
            next_dbghp = dbg_hash[*index];
      } else if (dbghp) {
            /* We've been through before. See if there is another
             * hash record on this chain. If not, go to the next
             * non-NULL chain.
             */
            if (!(next_dbghp = dbghp->h_next)) {
                  (*index)++;
                  if (*index == TYPE_NUM_SLOTS) {
                        return((dbg_type_t *)NULL);
                  }
                  while (dbg_hash[*index] == (dbg_hashrec_t *)NULL) {
                        (*index)++;
                        if (*index == TYPE_NUM_SLOTS) {
                              return((dbg_type_t *)NULL);
                        }       
                  }
                  next_dbghp = dbg_hash[*index];
            }
      }
      /* Our index pointer should be current. Make sure that tag
       * points to our our current hash record (or NULL if we are at
       * end of the hash records).
       */
      *tag = (void*)next_dbghp;

      if (next_dbghp) {
            return((dbg_type_t *)next_dbghp->h_ptr->sym_kltype);
      }
      return((dbg_type_t *)NULL);
}

/*
 * dbg_find_sym()
 */
dbg_sym_t *
dbg_find_sym(char *name, int type, uint64_t typenum)
{
      dbg_sym_t *stp = (dbg_sym_t *)NULL;

      if (name && strlen(name)) {
            /* Cycle through the type flags and see if any records are
             * present. Note that if multiple type flags or DBG_ALL is 
             * passed in, only the first occurance of 'name' will be 
             * found and returned. If name exists in multiple trees, 
             * then multiple searches are necessary to find them.
             */
            if (type & DBG_TYPE) {
                  if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *)
                              type_tree, name, (int *)NULL))) {
                        goto found_sym;
                  }
            } 
            if (type & DBG_TYPEDEF) {
                  if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *)
                              typedef_tree, name, (int *)NULL))) {
                        goto found_sym;
                  }
            } 
            if (type & DBG_FUNC) {
                  if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *)
                              func_tree, name, (int *)NULL))) {
                        goto found_sym;
                  }
            } 
            if (type & DBG_VAR) {
                  if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *)
                              var_tree, name, (int *)NULL))) {
                        goto found_sym;
                  }
            }
            if (type & DBG_XTYPE) {
                  if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *)
                              xtype_tree, name, (int *)NULL))) {
                        goto found_sym;
                  }
            }
            if (type & DBG_SRCFILE) {
                  if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *)
                              srcfile_tree, name, (int *)NULL))) {
                        goto found_sym;
                  }
            } 
            if (!stp) {
                  return((dbg_sym_t*)NULL);
            }
      }
found_sym:
      if (typenum) {
            dbg_hashrec_t *hshp;

            if (stp) {
                  if (stp->sym_typenum == typenum) {
                        return(stp);
                  }
            } else if ((hshp = dbg_hash[TYPE_NUM_HASH(typenum)])) {
                  while (hshp) {
                        if (hshp->h_typenum == typenum) {
                              return(hshp->h_ptr);
                        }
                        hshp = hshp->h_next;
                  }
            }
      }
      return(stp);
}

/*
 * dbg_first_sym()
 */
dbg_sym_t *
dbg_first_sym(int type) 
{
      dbg_sym_t *stp = (dbg_sym_t *)NULL;

      switch(type) {
            case DBG_TYPE:
                  stp = (dbg_sym_t *)
                        kl_first_btnode((btnode_t *)type_tree);
                  break;
            case DBG_TYPEDEF:
                  stp = (dbg_sym_t *)
                        kl_first_btnode((btnode_t *)typedef_tree);
                  break;
            case DBG_FUNC:
                  stp = (dbg_sym_t *)
                        kl_first_btnode((btnode_t *)func_tree);
                  break;
            case DBG_VAR:
                  stp = (dbg_sym_t *)
                        kl_first_btnode((btnode_t *)var_tree);
                  break;
            case DBG_XTYPE:
                  stp = (dbg_sym_t *)
                        kl_first_btnode((btnode_t *)xtype_tree);
                  break;
            case DBG_SRCFILE:
                  stp = (dbg_sym_t *)
                        kl_first_btnode((btnode_t *)srcfile_tree);
                  break;
      }
      return(stp);
}

/*
 * dbg_next_sym()
 */
dbg_sym_t *
dbg_next_sym(dbg_sym_t *stp)
{
      dbg_sym_t *next_stp;

      next_stp = (dbg_sym_t *)kl_next_btnode((btnode_t *)stp);
      return(next_stp);
}

/*
 * dbg_prev_sym()
 */
dbg_sym_t *
dbg_prev_sym(dbg_sym_t *stp)
{
      dbg_sym_t *prev_stp;

      prev_stp = (dbg_sym_t *)kl_prev_btnode((btnode_t *)stp);
      return(prev_stp);
}

/*
 * dbg_find_typenum()
 */
dbg_type_t *
dbg_find_typenum(uint64_t typenum)
{
        dbg_sym_t *stp;
        dbg_type_t *sp = (dbg_type_t *)NULL;
                                                                                           
        if ((stp = dbg_find_sym(0, DBG_TYPE, typenum))) {
                sp = (dbg_type_t *)stp->sym_kltype;
        }
        return(sp);
}

Generated by  Doxygen 1.6.0   Back to index