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

kl_symbol.c

/*
 * $Id: kl_symbol.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) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
 * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
 * Copyright 2000 Junichi Nomura, NEC Solutions <j-nomura@ce.jp.nec.com>
 *
 * 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>

/* static function declarations
 */
static int kl_print_syminfo(maplist_t*,int);
static void kl_free_syment(syment_t*);

/* macros
 */
#define DUMMY_MACRO_STRINGIFY(s) # s
#define STRINGIFY(s) DUMMY_MACRO_STRINGIFY(s)
/* #define _DBG_COMPONENT KL_DBGCOMP_SYMBOL */

/*
 * syment_cmp()
 *
 * comparison function for quick sort of syment_t array
 */
static int
syment_cmp(const void *sp_a, const void *sp_b)
{
      syment_t *const a = *(syment_t **) sp_a;
      syment_t *const b = *(syment_t **) sp_b;

      return ((a->s_addr > b->s_addr) - (a->s_addr < b->s_addr));
}

/*
 * kl_alloc_syment()
 */
syment_t *
kl_alloc_syment(kaddr_t addr, int type, const char *name)
{
      syment_t *sp;
      
      if ((sp = (syment_t *)malloc(sizeof(syment_t)))) {
            memset(sp, 0, sizeof(syment_t));
            sp->s_addr = addr;
            sp->s_type = type;
            sp->s_name = (char *)strdup(name);
      }
      return(sp);
}

/* XXX - error handling/return value
 * kl_insert_symbols()
 *
 * Insert symbols from from list of syment_t into symtab_t, and sorting symbols
 */
void
kl_insert_symbols(symtab_t * stp, syment_t *syment_list)
{
      int i, ret;
      syment_t *sp;

      if (stp->symcnt) {
            stp->symaddrs=(syment_t**)calloc(stp->symcnt,
                                     sizeof(syment_t*));
            sp = syment_list;
            for (i = 0; i < stp->symcnt; i++) {
                  stp->symaddrs[i] = sp;
                  ret = kl_insert_btnode((btnode_t **)&stp->symnames, 
                        (btnode_t *)sp, DUPLICATES_OK);
                  if (ret == -1) {
                        fprintf(KL_ERRORFP,
                              "i=%d sp=0x%lx\n", i, (uaddr_t)sp);
                        break;
                  }
                  sp = sp->s_next;
            }
            qsort(stp->symaddrs, stp->symcnt, sizeof(syment_t*),
                  syment_cmp );

            /* finally correct next/prev pointers, to
               point to next/prev entry in the sorted array */
            for(i=0; i<stp->symcnt - 1; i++){
                  stp->symaddrs[i]->s_next = stp->symaddrs[i+1];
            }
            for(i=1; i<stp->symcnt; i++){
                  stp->symaddrs[i]->s_prev = stp->symaddrs[i-1];
            }

            stp->symaddrs[0]->s_prev = NULL;
            stp->symaddrs[stp->symcnt-1]->s_next = NULL;

            /* Finally, walk through and search for an "_end"
             * symbol. If we find on, then make that the last
             * record to check for address matches. If there 
             * is no "_end" symbol, then make symaddrcnt equal
             * to symcnt.
             */ 
            for (i = 0; i < stp->symcnt; i++) {
                  if (!strcmp(stp->symaddrs[i]->s_name, "_end")) {
                        break;
                  }
            }
            stp->symaddrcnt = i;
      }
}

/*
 * Insert artificial section symbols to mark sections of modules.
 * This part is currently only exploitet by lcrash's symtab command.
 */
int
kl_insert_artificial_symbols(symtab_t *stp, syment_t **cur,
                       kl_modinfo_t *modinfo)
{
      if(*cur && modinfo) {
            if(modinfo->text_sec){
                  (*cur)->s_next = 
                        kl_alloc_syment(modinfo->text_sec, SYM_ABS,
                                    KL_S_TEXT);
                  (*cur) = (*cur)->s_next;
                  stp->symcnt++;
                  if(modinfo->text_len) {
                        (*cur)->s_next = 
                              kl_alloc_syment(modinfo->text_sec +
                                          modinfo->text_len,
                                          SYM_ABS, KL_E_TEXT);
                        (*cur) = (*cur)->s_next;
                        stp->symcnt++;
                  }
            }
            if(modinfo->data_sec){
                  (*cur)->s_next = 
                        kl_alloc_syment(modinfo->data_sec, SYM_ABS,
                                    KL_S_DATA);
                  (*cur) = (*cur)->s_next;
                  stp->symcnt++;
                  if(modinfo->data_len) {
                        (*cur)->s_next = 
                              kl_alloc_syment(modinfo->data_sec +
                                          modinfo->data_len,
                                          SYM_ABS, KL_E_DATA);
                        (*cur) = (*cur)->s_next;
                        stp->symcnt++;
                  }
            } 
            if(modinfo->rodata_sec){
                  (*cur)->s_next = 
                        kl_alloc_syment(modinfo->rodata_sec,
                                    SYM_ABS, KL_S_RODATA);
                  (*cur) = (*cur)->s_next;
                  stp->symcnt++;
                  if(modinfo->rodata_len) {
                        (*cur)->s_next = 
                              kl_alloc_syment(modinfo->rodata_sec+
                                          modinfo->rodata_len,
                                          SYM_ABS, KL_E_RODATA);
                        (*cur) = (*cur)->s_next;
                        stp->symcnt++;
                  }
            } 
            if(modinfo->bss_sec){
                  (*cur)->s_next = 
                        kl_alloc_syment(modinfo->bss_sec, SYM_ABS,
                                    KL_S_BSS);
                  (*cur) = (*cur)->s_next;
                  stp->symcnt++;
                  if(modinfo->bss_len) {
                        (*cur)->s_next = 
                              kl_alloc_syment(modinfo->bss_sec +
                                          modinfo->bss_len,
                                          SYM_ABS, KL_E_BSS);
                        (*cur) = (*cur)->s_next;
                        stp->symcnt++;
                  }
            }
      }
      return(0);
}

/*
 * convert symbol table entries into internal format
 */
int
kl_convert_symbol(kaddr_t *addr, int *type, char symtype,
              kl_modinfo_t *modinfo)
{
      switch (symtype) {
      case 'r': /* local read only data */
            if(modinfo){
                  *addr += modinfo->rodata_sec;
            }
            *type = SYM_LOCAL_DATA;
            break;

      case 'b': /* local uninitialized data */
      case 's':
            if(modinfo){
                  *addr += modinfo->bss_sec;
            }
            *type = SYM_LOCAL_DATA;
            break;
      case 'g': /* local initialized data */
      case 'd': /* XXX need this on s390 for s390dbf */
            if(modinfo){
                  *addr += modinfo->data_sec;
            }
            *type = SYM_LOCAL_DATA;
            break;
      case 'R': /* global read only data */
            if(modinfo){
                  *addr += modinfo->rodata_sec;
            }
            *type = SYM_GLOBAL_DATA;
            break;
      case 'B': /* global uninitialized data */
      case 'S':
            if(modinfo){
                  *addr += modinfo->bss_sec;
            }
            *type = SYM_GLOBAL_DATA;
            break;
      case 'G': /* global initialized data */
      case 'D':
            if(modinfo){
                  *addr += modinfo->data_sec;
            }
            *type = SYM_GLOBAL_DATA;
            break;
      case 't': /* code section (local symbol) */
            if(modinfo){
                  *addr += modinfo->text_sec;
            }
            *type = SYM_LOCAL_TEXT;
            break;
      case 'T': /* code section (global symbol) */
            if(modinfo){
                  *addr += modinfo->text_sec;
            }
            *type = SYM_GLOBAL_TEXT;
            break;
      case 'A': /* absolut symbol */
            *type = SYM_ABS;
            break;
            /* FALLTHROUGH */
      case 'a':
      case 'i':
      case 'I':
      case 'n':
      case 'N':
      case 'u':
      case 'U':
      case 'v':
      case 'V':
      case 'w':
      case 'W':
      case '-':
      case '?': 
            /* Special Stuff: __ksymtab_* and __kstrtab_* */
            return(1);    /* Ignore */
      default:
            DUMP_BP();
            if(isprint((unsigned char)symtype)){
                  fprintf(KL_ERRORFP, "unknown symbol type '%c'\n",
                        symtype);
            } else {
                  fprintf(KL_ERRORFP, "unknown symboltype '\\%03hho'\n",
                        (unsigned char) symtype);
            }
            return(2);

      }
      return(0);
}

/*
 * load "absolute" symbol table from file
 */
int
kl_load_sym(char *filename)
{
      maplist_t *ml, *last_ml;
      
      /* check whether this symbol table already exists */
      for(ml=STP; ml!=NULL; ml=ml->next){
            if(ml->maplist_type == SYM_MAP_FILE && ml->mapfile
               && !strcmp(ml->mapfile, filename)){
                  KL_ERROR = KLE_MAP_FILE_PRESENT;
            return(1);
      }
            last_ml = ml;
      }

      if(!(ml = (maplist_t*) calloc(1, sizeof(maplist_t)))){
            KL_ERROR = KLE_NO_MEMORY;
                  return(1);
            }
      ml->mapfile = strdup(filename);
      ml->maplist_type=SYM_MAP_FILE;

      /* first treat file as an elf object file */
      if(kl_read_bfd_syminfo(ml)){
            /* now treat as ascii map file */
            if((KL_ERROR == KLE_ARCHIVE_FILE) ||
               (kl_read_syminfo(ml))){
                  kl_free_maplist(ml);
                        return(1);
                  }
                  }

      if(STP){
            last_ml->next=ml;
                  } else {
            STP=ml;
                  }
      return(0);
}

/*
 * print one maplist
 */
static int
kl_print_syminfo(maplist_t *ml, int flags)
{
      int i;
      if(ml->maplist_type == SYM_MAP_KSYM){
            fprintf(kl_stdout, "\nKernel symbol table:\n");
      } else {
            fprintf(kl_stdout, "\n%s:\n", ml->mapfile);
            if(ml->maplist_type == SYM_MAP_MODULE){
                  assert(ml->modname);
                  fprintf(kl_stdout, "\tmodule: %s\n",
                        ml->modname);
            }
      }
      fprintf(kl_stdout, "\tnumber of symbols: %8d\n",
            ml->syminfo->symcnt);

      if(flags & KL_SYMFULL){
            fprintf(kl_stdout, "\n");
            if(flags & KL_SYMBYNAME){
                  syment_t *s;
                  for(s=(syment_t*)kl_first_btnode(ml->syminfo->symnames);
                      s!=NULL;
                      s=(syment_t*)kl_next_btnode((btnode_t*)s)){
                        kl_print_symbol(0, s, 0);
                  }
            } else {
                  for(i=0; i<ml->syminfo->symcnt; i++){
                        kl_print_symbol(0, ml->syminfo->symaddrs[i], 0);
            }
            }
      }
      return(0);
}

/*
 * print all or certain symbol table
 * rc: 0 - success, 1 - failed
 */
int
kl_print_symtables(char *modname, char *filename, int maplist_type, int flags)
{
      maplist_t *ml;
      int rc = 1;


      /* lookup this symbol table */
      for(ml=STP; ml!=NULL; ml=ml->next){
            if(maplist_type && (maplist_type != ml->maplist_type)){
                  continue;
            }
            if(filename &&  ml->mapfile &&
               !strcmp(ml->mapfile, filename)){
                  if(modname) {
                        if((ml->maplist_type == SYM_MAP_MODULE) &&
                           !strcmp(ml->modname, modname)){
                              /* symbol table is unique */
                              kl_print_syminfo(ml, flags);
                              rc = 0;
                              break;
                        } else {
                              continue;
                        }
                  } else {
                        kl_print_syminfo(ml, flags);
                        rc = 0;
                        continue;
                  }
            } else if(modname) {
                  if((ml->maplist_type == SYM_MAP_MODULE) &&
                     !strcmp(ml->modname, modname)){
                        /* symbol table is unique */
                        kl_print_syminfo(ml, flags);
                        rc = 0;
                        break;
                  } else {
                        continue;
                  }
            } else if(!modname && !filename) {
                  kl_print_syminfo(ml, flags);
                  rc = 0;
                  continue;
            }
      }
      return(rc);
}

/*
 * read symbol table information
 */
int
kl_read_syminfo(maplist_t *ml)
{
      int type, ret;
      FILE *fp;
      syment_t *cur_syment = (syment_t *)NULL;
      syment_t *syment_list = (syment_t *)NULL;
      kaddr_t addr;
      symtab_t *stp;
      char symtype, name[KL_SYMBOL_NAME_LEN+1];
      kl_modinfo_t *modinfo = NULL;

      if(ml->modname){
            modinfo = kl_lkup_modinfo(ml->modname);
      }

      name[KL_SYMBOL_NAME_LEN] = '\0';
      if (!(fp = fopen(ml->mapfile, "r"))) {
            ml->syminfo=NULL;
            fprintf(KL_ERRORFP, "Could not open file: %s\n", ml->mapfile);
            return(1);
      }
      stp = (symtab_t *)calloc(1, sizeof(symtab_t));
      addr = 0;
      symtype = 0;
      name[0] = 0;
      for ( ;; ) {
            /* we scan address as long long because kaddr_t 
             * is large enough to hold 64 bit pointers
             */
            ret = fscanf(fp, "%"FMTPTR"x %c %"
                       STRINGIFY(KL_SYMBOL_NAME_LEN)"s",
                       &addr, &symtype, name);
            if (ret == EOF) {
                  break;
            }
            if (ret == 0) {
                  addr=0;
                  ret = fscanf(fp, "%c %"
                             STRINGIFY(KL_SYMBOL_NAME_LEN)"s",
                             &symtype, name);
                  if (ret != 2){
                        /* was: break;
                         * but we decide that this is no proper map file
                         * XXX - think about real check for valid map
                         * files
                         */
                        /* XXX Error code: not a system map file */
                        kl_free_syment_list(syment_list);
                        kl_free_symtab(stp);
                        return(1);
                        
                  }
            }
            ret = kl_convert_symbol(&addr, &type, symtype, modinfo);
            if(ret == 1){
                  addr = 0;
                  symtype = 0;
                  name[0] = 0;
                  continue;
            } else if(ret == 2){
                  /* XXX error code: not a system map file */
                  kl_free_symtab(stp);
                  return(1);
            }

            stp->symcnt++;
            if (cur_syment) {
                  cur_syment->s_next = kl_alloc_syment(addr, type, name);
                  cur_syment = cur_syment->s_next;
            } else {
                  syment_list = kl_alloc_syment(addr, type, name);
                  cur_syment = syment_list;
            }
            addr = 0;
            symtype = 0;
            name[0] = 0;
      }

      if(kl_insert_artificial_symbols(stp, &cur_syment, modinfo)){
            /* XXX - error code/error message */
            kl_free_syment_list(syment_list);
            kl_free_symtab(stp);
            return(1);
      }
      kl_insert_symbols(stp, syment_list);

      ml->syminfo=stp;
      fclose(fp);
      return(0);
}

/*
 * free syment_t
 */
static void
kl_free_syment(syment_t *sp)
{
      if(sp && sp->s_name) {
                                    free(sp->s_name);
                              }
                              free(sp);
}

/*
 * free list of syment_t
 */
void
kl_free_syment_list(syment_t *sp)
{
      syment_t *next;

      for( ; sp!=NULL; sp=next){
            next = sp->s_next;
            kl_free_syment(sp);
                        }
}

/*
 * free symtab_t
 */
void
kl_free_symtab(symtab_t *stp)
{
      int i;

      if(stp && stp->symaddrs){
            for (i = 0; i < stp->symcnt; i++) {
                  kl_free_syment(stp->symaddrs[i]);
                  }
                        free(stp->symaddrs);
                  }
                  free(stp);
}
/*
 * free maplist_t
 */
void
kl_free_maplist(maplist_t *ml)
{
      free(ml->mapfile);
      free(ml->modname);
      kl_free_symtab(ml->syminfo);
      free(ml);
}

/*
 * if mapfile == NULL delete all maplist_t structs  otherwise delete
 * all maplist_t structs matching mapfile
 * rc: 0 - success, 1 - no such symbol table loaded
 */
int
kl_free_syminfo(char *mapfile)
{
      maplist_t *ml, *prev_ml;
      int rc = 1;

      for (prev_ml = NULL, ml = STP; ml != NULL; prev_ml = ml, ml = ml->next){
            if(mapfile){
                  /* free only specified maplist */
                  if(ml->maplist_type == SYM_MAP_KSYM){
                        continue;
                  } else if(strcmp(mapfile, ml->mapfile)){
                        continue;
                  }
            }
            rc = 0;
            if(prev_ml){
                  prev_ml->next=ml->next;
                  kl_free_maplist(ml);
                  ml=prev_ml;
            } else {
                  STP=ml->next;
                  kl_free_maplist(ml);
                  ml=STP;
                  if(!ml) {
                        break;
                  }
            }
      }
      return(rc);
}

syment_t *
kl_lkup_symname(char *name)
{
      syment_t *ret;

      if( (ret = _kl_lkup_symname(name, SYM_MAP_FILE, 0)) ) {
            return(ret);
      } else if( (ret = _kl_lkup_symname(name, SYM_MAP_MODULE, 0)) ) {
            return(ret);
      } else {
            return (_kl_lkup_symname(name, SYM_MAP_KSYM, 0));
      }
}

/*
 * _kl_lkup_symname()
 */
syment_t *
_kl_lkup_symname(char *name, int maplist_type, size_t len)
{
      int max_depth;
      syment_t *sp = NULL;
      maplist_t *ml;

      /* Search for name in the types list
       */
      kl_reset_error();
      KL_ERROR = KLE_BAD_SYMNAME;
      for(ml=STP; ml!=NULL; ml=ml->next){
            if(maplist_type && (maplist_type != ml->maplist_type)) {
                  continue;
            }
            
            if(ml->maplist_type == SYM_MAP_KSYM){
                  if((sp = (syment_t *)
                     _kl_find_btnode(ml->syminfo->symnames, name,
                                 &max_depth, len))) {
                        kl_reset_error();
                        break;
                  }
            } else {
                  if((sp = (syment_t *)
                     _kl_find_btnode(ml->syminfo->symnames,
                                 name, &max_depth, len))) {
                        kl_reset_error();
                        break;
                  }
            }
      }
                 
      return(sp);
}

syment_t *
kl_lkup_symaddr(kaddr_t addr)
{
      syment_t *ret;
      if ( (ret = _kl_lkup_symaddr(addr, SYM_MAP_FILE)) ) {
            return(ret);
      } else if ( (ret = _kl_lkup_symaddr(addr, SYM_MAP_MODULE)) ) {
            return(ret);
      } else {
            return(_kl_lkup_symaddr(addr, SYM_MAP_KSYM));
      }
}

syment_t *
kl_lkup_symaddr_text(kaddr_t addr)
{
      static int types[] = { SYM_MAP_FILE, SYM_MAP_MODULE, SYM_MAP_KSYM };
      int i;
      syment_t *ret;
      for ( i = 0 ; i < sizeof(types) ; i++) {
            ret = _kl_lkup_symaddr(addr, types[i]);
            if (ret && (ret->s_type == SYM_GLOBAL_TEXT || 
                ret->s_type == SYM_LOCAL_TEXT || 
                ret->s_type == SYM_LOCORE_TEXT ||
                ret->s_type == SYM_KSYM_TEXT)) {
                  return ret;
            }
      }
      return NULL;
}

/*
 * return syment_t* of first symbol in list having addr as its address
 */
syment_t *
_kl_lkup_symaddr(kaddr_t addr, int maplist_type)
{
      int idx, first, last;
      symtab_t *stp;
      maplist_t *ml;

      for(ml=STP; ml!=NULL; ml=ml->next){
            if(maplist_type && (maplist_type != ml->maplist_type)) {
                  continue;
            }

            kl_reset_error();

            stp = ml->syminfo;

            if (!stp ||  (stp->symcnt == 0)) {
                  continue;
            }

            first = 0;
            last = stp->symaddrcnt - 1;
            idx = last / 2;

            /* Make sure the address is within the valid range
             * for this symtab.
             */
            if (addr < stp->symaddrs[first]->s_addr) {
                  return((syment_t *)NULL);
            } 
            if (addr > stp->symaddrs[last]->s_addr) {
#ifdef NOTYET
                  if ((stp->symaddrs[last]->s_end == 0) ||
                        (addr > stp->symaddrs[last]->s_end)) {
                        return((syment_t *)NULL);

                  }
#else
                  return((syment_t *)NULL);
#endif
            }        

            while (idx != first) {
                  if (stp->symaddrs[idx]->s_addr == addr) {
                        /* Exact match...
                         */
                        return(stp->symaddrs[idx]);
                  } else if (addr >= stp->symaddrs[idx]->s_addr) {
                        /* If there is a symbol end address, then
                         * check to see if addr falls between the
                         * start and end address.
                         */
#ifdef NOTYET
                        if (stp->symaddrs[idx]->s_end &&
                              (addr < stp->symaddrs[idx]->s_end)) {
                              return(stp->symaddrs[idx]);
                        }
#endif
                        first = idx;
                        idx = first + ((last - first) / 2);
                  } else {
                        last = idx;
                        idx = first + ((last - first) / 2);
                  }
            }

            if (addr == stp->symaddrs[first]->s_addr) {
                  return(stp->symaddrs[first]);
            } else if (addr == stp->symaddrs[last]->s_addr) {
                  return(stp->symaddrs[last]);
            } else if (addr < stp->symaddrs[last]->s_addr) {
                  return(stp->symaddrs[first]);
            } else {
#ifdef NOTYET
                  /* If there is an end address for the
                   * symbol, we can consider a match. Otherwise,
                   * only exact matches allowed on the last
                   * symbol found (not necessarily the last 
                   * symbol in the list
                   */
                  return(stp->symaddrs[last]);
#endif
            }
      }
      KL_ERROR = KLE_BAD_SYMADDR;
      return((syment_t *)NULL);
}

/*
 * kl_lkup_funcaddr() -- Get the symbol entry from a specific address.
 */
syment_t *
kl_lkup_funcaddr(kaddr_t pc)
{
      syment_t *sp;
      kaddr_t addr;

      if (!(sp = kl_lkup_symaddr_text(pc))) {
            return (0);
      }

      addr = sp->s_addr;
      /* rewind */
      while (sp->s_prev && sp->s_prev->s_addr == addr) {
                  sp = sp->s_prev;
      };

      do {
            if ((sp->s_type == SYM_LOCAL_TEXT) ||
                  (sp->s_type == SYM_GLOBAL_TEXT) ||
                  (sp->s_type == SYM_KSYM_TEXT) ||
                  (sp->s_type == SYM_KSYM)) {
                  return(sp);
            } else {
                  sp = sp->s_next;
            }
      } while (sp && (sp->s_addr == addr));

      return (0);
}

/*
 *  Return name of function (first function name if more symbols are located at
 *  the same address) where pc is from.
 *  Note that the function name returned does NOT need to be freed
 *  up by the caller.
 */
char *
kl_funcname(kaddr_t pc)
{
      syment_t *sp;

      if ((sp = kl_lkup_funcaddr(pc))) {
            return(sp->s_name);
      }
      return((char *)NULL);
}

/*
 * return address of function where pc is from
 */
kaddr_t
kl_funcaddr(kaddr_t pc)
{
      syment_t *sp;

      if ((sp = kl_lkup_funcaddr(pc))) {
            return(sp->s_addr);
      }
      return((kaddr_t)NULL);
}

/*
 * return the size of a function in bytes
 */
int
kl_funcsize(kaddr_t pc)
{
      syment_t *sp;

      if ((sp = kl_lkup_funcaddr(pc))) {
            return(kl_symsize(sp));
      }
      return(0);
}

/*
 * kl_symsize() -- Get the size of a labeled symbol in bytes by looking
 * for the next symbol
 */
int
kl_symsize(syment_t *sp)
{
      int size=0;

      if(sp){
            syment_t *t = sp;
/*          kl_trace3(0, "  sp: %#llx %s\n", t->s_addr, */
/*                  t->s_name); */
            while(t->s_next && (t->s_addr == t->s_next->s_addr)) {
                  t = t->s_next;
/*                kl_trace3(0, "next: %#llx %s\n", t->s_addr, */
/*                        t->s_name); */
            }
            if(t->s_next){
                  size = t->s_next->s_addr - sp->s_addr;
/*                kl_trace3(0, "next: %#llx %s\n", t->s_next->s_addr, */
/*                        t->s_next->s_name); */
      }
      }
            
      return(size);
}

/*
 * kl_get_similar_name() -- This function gets the queue of symbol names which
 *                          match 'name' for symbol name completion. 
 *                          It saves the number of candidates to 'sym_cnt'. 
 *                          It saves the maximum length of the candidates to 
 *                          'maxlen'.
 *                          It saves a string for completion to 'retstr'.
 *                          Return the head of queue.
 */
syment_t *
kl_get_similar_name(char *name, char *retstr, int *sym_cnt, int *maxlen) 
{
      syment_t *sq_cur, *sq_head = NULL, *sq_tail = NULL;
      int   namelen;
      int found = 0;
      maplist_t *ml;
      int i;

      /* Search for name in the types list
       */
      kl_reset_error();
      KL_ERROR = KLE_BAD_SYMNAME;
      namelen = strlen(name);
      for(ml=STP; ml!=NULL; ml=ml->next){
            if ((ml->maplist_type == SYM_MAP_KSYM) || 
                (ml->maplist_type == SYM_MAP_FILE) ||
                (ml->maplist_type == SYM_MAP_MODULE)) {
                  /* get the queue of candidates for symbol name */
                  if(namelen){
                        sq_cur = (syment_t *)
                              _kl_find_btnode(ml->syminfo->symnames,
                                          name, NULL, namelen);
                  } else {
                        sq_cur = (syment_t *)
                              kl_first_btnode(ml->syminfo->symnames);
                  }
                  if(!sq_cur){
                        continue;
                  }
                  do {
                        if (!namelen ||
                            !strncmp(name, sq_cur->s_name, namelen)) {
                              if (!found)
                                    found = 1;
                              if (!*sym_cnt) {
                                    strcpy(retstr, sq_cur->s_name +
                                           namelen);
                                    *maxlen =
                                          strlen(sq_cur->s_name);
                                    sq_head = sq_tail = sq_cur;
                              } else {
                                    sq_tail->s_forward = sq_cur;
                                    sq_tail = sq_cur;
                                    if (retstr[0] != '\0') {
                                          /* get the identical part of string of 
                                             candidates and save to 'retstr' */
                                          for (i = 0; retstr[i] != '\0' &&
                                                retstr[i] == *(sq_cur->s_name+namelen+i);
                                                i++); 
                                          retstr[i] = '\0';
                                    }
                                    /* get the maximum length of candidates and save to 'maxlen' */
                                    if (*maxlen < strlen(sq_cur->s_name)) {
                                          *maxlen = strlen(sq_cur->s_name);
                                    }
                              }
                              sq_tail->s_forward = (syment_t *)0;
                              (*sym_cnt)++;
                        } else {
                              if (found)
                                    break;
                        }
                  } while ((sq_cur = (syment_t *)kl_next_btnode((btnode_t *)sq_cur)) != NULL);
            } else {
                  continue;
            }
      }
      return(sq_head); /* return the head of queue */
}

/* 
 * kl_print_symbol()
 */
void
kl_print_symbol(kaddr_t pc, syment_t *sp, int flags)
{
      int offset;
      kaddr_t addr;
      dbg_sym_t *stp;
      kltype_t *kltp;

      if (!sp) {
            /* XXX -- Set error */
            return;
      }

      if (pc) {
            addr = pc;  
      } else {
            addr = sp->s_addr;
      }

      if(KL_NBPW == 8){
            fprintf(kl_stdout, "%#18"FMTPTR"x", addr);
      } else {
            fprintf(kl_stdout, "%#10"FMTPTR"x", addr);
      }
      if(flags & KL_SYMWOFFSET){
            offset = (addr - sp->s_addr);
            fprintf(kl_stdout, " %6d", offset);
      }
      switch(sp->s_type) {
            case SYM_GLOBAL_TEXT:
                  fprintf(kl_stdout, " GLOBAL_TEXT  ");
                  break;
            case SYM_LOCAL_TEXT:
                  fprintf(kl_stdout, " LOCAL_TEXT   ");
                  break;
            case SYM_LOCORE_TEXT:
                  fprintf(kl_stdout, " LOCORE_TEXT  ");
                  break;
            case SYM_GLOBAL_DATA:
                  fprintf(kl_stdout, " GLOBAL_DATA  ");
                  break;
            case SYM_LOCAL_DATA:
                  fprintf(kl_stdout, " LOCAL_DATA   ");
                  break;
            case SYM_ABS:
                  fprintf(kl_stdout, " ABS          ");
                  break;
            case SYM_KSYM:
                  fprintf(kl_stdout, " EXP_KSYM     ");
                  break;
            case SYM_KSYM_TEXT:
                  fprintf(kl_stdout, " EXP_KSYM_TEXT ");
                  break;
            case SYM_UNK:
            default:
                  fprintf(kl_stdout, " UNKNOWN      ");
                  break;
      }
      fprintf(kl_stdout, "%-20s", sp->s_name);
      if(((stp = dbg_find_sym(sp->s_name, DBG_VAR, (uint64_t)0)) != NULL)){
            if((kltp = kl_find_typenum(stp->sym_typenum)) != NULL){
                  fprintf(kl_stdout, " %s", kltp->kl_typestr);
                  if(kltp->kl_type == KLT_ARRAY){
                        int a = kltp->kl_high_bounds -
                              kltp->kl_low_bounds + 1;
                        if(a>0){
                              fprintf(kl_stdout, " [%d]\n", a);
                        } else {
                              fprintf(kl_stdout, " []\n");
                        }
                  } else if((strcmp(kltp->kl_typestr,
                               KL_TYPESTR_STRUCT) == 0) ||
                          (strcmp(kltp->kl_typestr,
                               KL_TYPESTR_STRUCT" ") == 0) ||
                          (strcmp(kltp->kl_typestr,
                               KL_TYPESTR_UNION) == 0)){
                        /* anonymous struct or union */
                        fprintf(kl_stdout, " {...}\n");
                  } else {
                        fprintf(kl_stdout, "\n");
                  }
            } else {
                  fprintf(kl_stdout, " (unknown)\n");
            }
      } else if((stp = dbg_find_sym(sp->s_name, DBG_FUNC,
                             (uint64_t)0)) != NULL){
            if((kltp = kl_find_typenum(stp->sym_typenum)) != NULL){
                  fprintf(kl_stdout, " %s (...)\n", kltp->kl_typestr);

            } else {
                  fprintf(kl_stdout, " (unknown)\n");
            }

      } else {
            fprintf(kl_stdout, " (unknown)\n");
      }
}

Generated by  Doxygen 1.6.0   Back to index