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

kl_stabs.c

/*
 * $Id: kl_stabs.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 - 2004 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>
#include <bfd.h>
#include <stab.h>
#include <kl_debug.h>

/* Global error stabs 'errno' value
 */
static int stab_err;

st_global_t G_values;

/* Structure used to track start and end of include file scope.
 * Note that include files can include other include files -- between 
 * start_off and end_off. 
 */
typedef struct incfile_s {
      struct incfile_s  *next;            /* on list */
      struct incfile_s  *prev;            /* on list/stack */
      int                srcfile;
      int                incfile;
      int                stroff;
      unsigned int             value;
      int                staboff;
      int                start_num;
      int                end_num;
} incfile_t;

/* Top of the include file stack
 */
static incfile_t *incp_top = (incfile_t *)NULL;
static int next_incp = 1;

/* Structure that contains all 'private' data for a namelist (archive
 * or object file).
 */
typedef struct st_namelist_s {
        bfd             *abfd;
        incfile_t       *incp_list;
} st_namelist_t;

/* Global flag that indicates if we are in the process of opening a
 * namelist.
 */
static int opening_st_namelist = 0;

/* Linked lists of dbg_sym_t records for various processing
 * passes.
 */
static dbg_sym_t *initsyms = (dbg_sym_t *)NULL;
static dbg_sym_t *initsyms_end = (dbg_sym_t *)NULL;
static dbg_sym_t *allsyms = (dbg_sym_t *)NULL;
static dbg_sym_t *allsyms_end = (dbg_sym_t *)NULL;

#define ADD_INITSYM(S) \
      if (initsyms_end) { \
            initsyms_end->sym_link = (S); \
      } else { \
            initsyms = (S); \
      } \
      initsyms_end = (S);
#define NEXT_INITSYM(S) (S)->sym_link

#define ADD_ALLSYM(S) \
      if (allsyms_end) { \
            allsyms_end->sym_next = (S); \
      } else { \
            allsyms = (S); \
      } \
      allsyms_end = (S);
#define NEXT_ALLSYM(S) (S)->sym_next

#define ST_PRIVATE      ((st_namelist_t *)nmlist[curnmlist].private)
#define ABFD            ST_PRIVATE->abfd
#define INCP_LIST       ST_PRIVATE->incp_list

#define INC_FILE(X)     (((uint64_t)(X) >> 32) & 0xffff)
#define NMLIST(X)       (((uint64_t)(X) >> 60) & 0xf)

/* Local static variables (stabs memory)
 */
static bfd_byte *debug = (bfd_byte *)NULL;
static bfd_size_type debug_size = (bfd_size_type)0;
static char *strtab = (char *)NULL;
static bfd_size_type debugstr_size = (bfd_size_type)0;;

/* Function prototypes
 */
static dbg_sym_t *get_next_stab_entry(void);
static int read_debug_data(bfd *abfd);
static int set_srcfile(bfd *, int);
static int get_next_str(void);
static dbg_sym_t *get_sym_info(void);
static char *get_symdesc(char *);
static char *bump_str_ptr(int);
static char *get_range(uint64_t *, int *, int *);
static char *get_typenum(uint64_t *);
static char *get_typenum_type(uint64_t *, int);
static char *get_byte_size(int *);
static char *get_name(char **);
static char *get_members(dbg_type_t *);
static char *get_enumlist(dbg_type_t *);
static char *get_array(uint64_t *, uint64_t *, int *, int *);
static char *get_embedded_type(uint64_t );
static int setup_stabs_typeinfo(dbg_sym_t *);

/* 
 * save_global_values()
 */
static void
save_global_values(st_global_t *G)
{
      G->abfd = G_abfd;
      G->type = G_type;
      G->flags = G_flags;
      G->flag = G_flag;
      G->nmlist = G_nmlist;
      G->srcfile = G_srcfile;
      G->incfile = G_incfile;
      G->symnum = G_symnum;
      G->stabp = G_stabp;
      G->stabs_end = G_stabs_end;
      G->value = G_value;
      G->stroffset = G_stroffset;
      G->desc = G_desc;
      G->stab_str = G_stab_str;
      G->stab_str.ptr = CUR_CHAR;
}

/* 
 * restore_global_values()
 */
static void
restore_global_values(st_global_t *G)
{
      G_abfd = G->abfd;
      G_type = G->type;
      G_flags = G->flags;
      G_flag = G->flag;
      G_nmlist = G->nmlist;
      G_srcfile = G->srcfile;
      G_incfile = G->incfile;
      G_symnum = G->symnum;
      G_stabp = G->stabp;
      G_stabs_end = G->stabs_end;
      G_value = G->value;
      G_stroffset = G->stroffset;
      G_desc = G->desc;
      G_stab_str = G->stab_str;
      CUR_CHAR = G->stab_str.ptr;
}

/*
 * alloc_incp()
 */
static incfile_t *
alloc_incp(void)
{
      incfile_t *incp;

      incp = calloc(1, sizeof(incfile_t));
      return(incp);
}

#ifdef NOTUSED
/*
 * free_incp()
 */
static void
free_incp(incfile_t *incp)
{
      free(incp);
}
#endif

/* 
 * push_incp()
 */
static void
push_incp(incfile_t *incp)
{
      if (incp_top) {
            incp->prev = incp_top;
      } 
      incp_top = incp;
}

/*
 * pop_incp()
 */
static incfile_t *
pop_incp(void)
{
      incfile_t *incp = (incfile_t *)NULL;

      if ((incp = incp_top)) {
            incp_top = incp->prev;
      }
      return(incp);
}

/*
 * queue_incp()
 */
static void
queue_incp(incfile_t *incp)
{
      incfile_t *p, *last = (incfile_t *)NULL;

      incp->prev = incp->next = (incfile_t *)NULL;
      if ((p = INCP_LIST)) {
            if (incp->srcfile < p->srcfile) {
                  p->prev = incp;
                  incp->next = p;
                  INCP_LIST = incp;
                  return;
            }
            while(p) {
                  if (incp->srcfile > p->srcfile) {
                        last = p;
                        p = p->next;
                  } else if (incp->srcfile == p->srcfile) {
                        while(incp->incfile > p->incfile) {
                              last = p;
                              if (!(p = p->next)) {
                                    last->next = incp;
                                    incp->prev = last;
                                    return;
                              }
                              if (p->srcfile != incp->srcfile) {
                                    break;
                              } 
                        }
                        if (!p->prev) {
                              /* Our new record goes first on the
                               * list
                               */
                              p->prev = incp;
                              incp->next = p;
                              INCP_LIST = incp;
                              return;
                        }
                        p->prev->next = incp;
                        incp->prev = p->prev;
                        p->prev = incp;
                        incp->next = p;
                        return;
                  } else {
                        break;
                  }
            }
            if (last->next) {
                  last->next->prev = incp;
                  incp->next = last->next;
            }
            last->next = incp;
            incp->prev = last;
      } else {
            INCP_LIST = incp;
      }
}

#ifdef NOTUSED
/*
 * find_incp()
 */
static incfile_t *
find_incp(int srcfile, int incfile)
{
      incfile_t *incp = INCP_LIST;

      while (incp) {
            if (incp->srcfile < srcfile) {
                  incp = incp->next;
                  continue;
            } else if (incp->srcfile == srcfile) {
                  while (incp->incfile < incfile) {
                        if (!(incp = incp->next)) {
                              return((incfile_t *)NULL);
                        }
                        if (incp->srcfile != srcfile) {
                              return((incfile_t *)NULL);
                        }
                  }
                  if (incp->incfile == incfile) {
                        return(incp);
                  } else {
                        return((incfile_t *)NULL);
                  }
            } else {
                  return((incfile_t *)NULL);
            }
      }
      return((incfile_t *)NULL);
}
#endif

/* 
 * get_debug_entries() -- return 1 on error, 0 otherwise
 */
static int
get_debug_entries(void)
{
      int ret;
      dbg_sym_t *stp;   

      /* Read in the stab/dwarf2 section data.
       */
      if (!read_debug_data(G_abfd)) {
            /* XXX - print error msg */
            return(1);
      }

      /* Now loop through all the stab type entries 
       */
      while (1) {

            if (!(stp = get_next_stab_entry())) {
                  break;
            }
            if (!(G_symnum % 1000)) {
                  fprintf(KL_ERRORFP, ".");
            }
            /* We only log records for source files, types, typedefs,
             * functions and variables...
             */
            if (stp->sym_type & 
                  (DBG_SRCFILE|DBG_TYPE|DBG_TYPEDEF|DBG_FUNC|DBG_VAR)) {

                  ret = dbg_insert_sym(stp);
                  if (ret < 0) {
                        fprintf(KL_ERRORFP, "get_debug_entries: "
                              "dbg_insert_sym() returned ERROR!\n");
                        dbg_free_sym(stp);
                        continue;
                  } else if (ret == 1) {
                        /* Duplicate symbol...
                         */
                        dbg_free_sym(stp);           
                        continue;
                  }

                  /* Put on list of found symbols. Also put on list
                   * of primary symbols (this list does not include
                   * embedded symbols). Note that each list is linked
                   * on a separate chain (sym_link and sym_next 
                   * respectively).
                   */
                  ADD_ALLSYM(stp);
                  ADD_INITSYM(stp);
            } else {
                  dbg_free_sym(stp);
            }
      }
      return(0);
}

static asection *last_debugsect = 0, *last_debugstrsect = 0; 

/*
 * free_debug_memory()
 */
static void
free_debug_memory(void)
{
      last_debugsect = 0;
      last_debugstrsect = 0;
      if (debug) {
            free(debug);
            debug = (bfd_byte *)NULL;
            debug_size = (bfd_size_type)0;
      }
      if (strtab) {
            free(strtab);
            strtab = (char *)NULL;
            debugstr_size = (bfd_size_type)0;;
      }
}

/*
 * read_debug_data()
 */
static int
read_debug_data(bfd *abfd)
{
      asection *debugsect, *debugstrsect;
      char *debugsect_name = ".stab";
      char *strsect_name = ".stabstr";

      /* Make sure we have stabs debug data 
       */
      if ((debugsect = bfd_get_section_by_name(abfd, debugsect_name))) {
            debugstrsect = bfd_get_section_by_name(abfd, strsect_name);
            if (!debugstrsect) {
                  return(FALSE);
            }
      }

      /* Check to see if the last one we loaded is the same one
       * we are trying to load now.
       */
      if ((debugsect == last_debugsect) && 
                  (debugstrsect == last_debugstrsect)) {
            return(TRUE);
      }
      free_debug_memory();

      debug_size = bfd_section_size(abfd, debugsect);
      debugstr_size = bfd_section_size(abfd, debugstrsect);

      debug  = (bfd_byte *)malloc(debug_size);
      strtab = (char *)malloc(debugstr_size);

      if (!bfd_get_section_contents(abfd, debugsect, 
                        (PTR)debug, 0, debug_size)) {
            free_debug_memory();
            return(FALSE);
      }
      if (!bfd_get_section_contents(abfd, debugstrsect, 
                        (PTR)strtab, 0, debugstr_size)) {
            free_debug_memory();
            return(FALSE);
      }
      last_debugsect = debugsect;
      last_debugstrsect = debugstrsect;
      return(TRUE);
}

/*
 * want_sym()
 */
static int
want_sym(unsigned char type, int flags)
{
      switch (type) {
            case N_UNDF:
                  if (flags & ST_UNDF) {
                        return(1);
                  }
                  break;
            case N_LSYM:
                  if (flags & ST_LSYM) {
                        return(1);
                  }
                  break;
            case N_GSYM:
                  if (flags & ST_GSYM) {
                        return(1);
                  }
                  break;
            case N_PSYM:
                  if (flags & ST_PSYM) {
                        return(1);
                  }
                  break;
            case N_RSYM:
                  if (flags & ST_RSYM) {
                        return(1);
                  }
                  break;
            case N_STSYM:
                  if (flags & ST_STSYM) {
                        return(1);
                  }
                  break;
            case N_LCSYM:
                  if (flags & ST_LCSYM) {
                        return(1);
                  }
                  break;
            case N_BINCL:
                  if (flags & ST_BINCL) {
                        return(1);
                  }
                  break;
            case N_EINCL:
                  if (flags & ST_EINCL) {
                        return(1);
                  }
                  break;
            case N_EXCL:
                  if (flags & ST_EXCL) {
                        return(1);
                  }
                  break;
            case N_FUN:
                  if (flags & ST_FUN) {
                        return(1);
                  }
                  break;
            case N_SLINE:
                  if (flags & ST_SLINE) {
                        return(1);
                  }
                  break;
            case N_SO:
                  if (flags & ST_SO) {
                        return(1);
                  }
                  break;
      }
      return(0);
}

/***
 *** Functions for accessing STABS data
 ***/

/* Stabs entries use a 12 byte format:
 *    4 byte string table index
 *    1 byte stab type
 *    1 byte stab other field
 *    2 byte stab desc field
 *    4 byte stab value
 *    FIXME: This will have to change for a 64 bit object format.  
 */
#define STRDXOFF (0)
#define TYPEOFF (4)
#define OTHEROFF (5)
#define DESCOFF (6)
#define VALOFF (8)
#define STABSIZE (12)

/* 
 * set_sym_globals()
 */
static void
set_sym_globals(bfd *abfd, dbg_sym_t *stp)
{
      G_type = stp->sym_pvttype;
      G_flags = stp->sym_flag;
      G_symnum = stp->sym_num;
      G_stabp = (bfd_byte *)((uaddr_t)debug + stp->sym_off);
      G_stabs_end = debug + debug_size;
      G_value = bfd_h_get_32(abfd, G_stabp + VALOFF);
      G_desc = bfd_h_get_16(abfd, G_stabp + DESCOFF);
      G_srcfile = stp->sym_srcfile;
      G_incfile = stp->sym_incfile;
      G_nmlist = stp->sym_nmlist;
      G_stab_str.str = &strtab[stp->sym_stroff];
      CUR_CHAR = G_stab_str.str;
}

/*
 * get_next_sym_str()
 */
static char *
get_next_sym_str(bfd *abfd, int flags)
{
      char *str;
      incfile_t *incp;
      static int gcc_EINCL_bug;

      if (G_stabp == (bfd_byte *)NULL) {
            G_stabp = debug;
            G_stabs_end = G_stabp + debug_size;
      }

      /* Loop through all STABS symbol entries. 
       */
again:
      if (G_stabp < G_stabs_end) {
            unsigned long stroff;
            unsigned char type;
            unsigned char other;
            unsigned short desc;
            bfd_vma value;

            G_symnum++;

            /* Get the symbol information
             */
            type = bfd_h_get_8(abfd, G_stabp + TYPEOFF);
            stroff = bfd_h_get_32(abfd, G_stabp + STRDXOFF);
            desc = bfd_h_get_16(abfd, G_stabp + DESCOFF);
            other = bfd_h_get_8(abfd, G_stabp + OTHEROFF);
            value = bfd_h_get_32(abfd, G_stabp + VALOFF);

            /* Using the string table offset, locate the start
             * of the definition string for this symbol.
             */
            if (stroff < debugstr_size) {
                  str = &strtab[stroff];
            } else {
                  str = (char *)NULL;
            }

            G_staboff = ((uaddr_t)G_stabp - (uaddr_t)debug);

            /* Check to see if the symbol type is N_SO (source
             * file).  If it is, we need to bump the G_srcfile 
             * number. This allows us to destinguish between 
             * the same symbol name being used in more than one 
             * source module (possibly as a local variable/type 
             * definition in one file and a global in another). 
             */
            if (type == N_SO) {
                  if (str && str[0]) {
                        if (strstr(&str[strlen(str) - 2], ".c")) {
                              G_srcfile++;
                              if (opening_st_namelist) {
                                    incp = alloc_incp();
                                    incp->incfile = 0;
                                    incp->srcfile = G_srcfile; 
                                    incp->stroff = stroff; 
                                    incp->value = value; 
                                    incp->staboff = G_staboff;
                                    incp->start_num = G_symnum; 
                                    G_incfile = incp->incfile;
                                    push_incp(incp);
                              }
                              next_incp = 1;
                              G_incfile = 0;
                        }
                  } else {
                        if(gcc_EINCL_bug) {
                              /* workaround for gcc 3.x bug
                               * (missing NO_EINCL)
                               */
                              if (opening_st_namelist) {
                                    if ((incp = pop_incp())) {
                                          incp->end_num = G_symnum; 
                                          queue_incp(incp);
                                    }
                                    if (incp_top) {
                                          G_incfile = incp_top->incfile;
                                    } else {
                                          G_incfile = 0;
                                    }
                              } else {
                                    G_incfile--;
                              }
                        }
                        if (opening_st_namelist) {
                              if ((incp = pop_incp())) {
                                    incp->end_num = G_symnum; 
                                    queue_incp(incp);
                              }
                              if (incp_top) {
                                    G_incfile = incp_top->incfile;
                              } else {
                                    G_incfile = 0;
                              }
                        } else {
                              G_incfile--;
                        }
                  }
            } else if (type == N_BINCL) {
                  /* workaround for gcc 3.x bug
                   * (missing NO_EINCL)
                   */
                  if((str && str[0]) &&
                     (strstr(&str[strlen(str) - 2], ".c"))) {
                        gcc_EINCL_bug = 1;
                  }

                  /* If we are cycling through the symbol entries 
                   * during a namelist open, we need to capture the 
                   * begin and end points for each include file. In 
                   * all cases, we need to track the current include 
                   * file number.
                   */
                  if (opening_st_namelist) {
                        incp = alloc_incp();
                        incp->incfile = next_incp++;
                        incp->srcfile = G_srcfile; 
                        incp->stroff = stroff; 
                        incp->value = value; 
                        incp->staboff = G_staboff;
                        incp->start_num = G_symnum; 
                        G_incfile = incp->incfile;
                        push_incp(incp);
                  } else {
                        G_incfile++;
                  }
            } else if (type == N_EINCL) {
                  if (opening_st_namelist) {
                        if ((incp = pop_incp())) {
                              incp->end_num = G_symnum; 
                              queue_incp(incp);
                        }
                        if (incp_top) {
                              G_incfile = incp_top->incfile;
                        } else {
                              G_incfile = 0;
                        }
                  } else {
                        G_incfile--;
                  }
            } else if (opening_st_namelist && (type == N_EXCL)) {
                  next_incp++;
            }

            /* See if this is a symbol entry type that we are
             * interested in.
             */
            if (!want_sym(type, flags)) {
                  G_stabp += STABSIZE;
                  goto again;
            }

            G_stroffset = stroff;
            G_value = value;
            G_desc = desc;
            G_type = (int)type;
      } else {
            str = (char *)NULL;
      }

      /* Get ready for the next read
       */
      G_stabp += STABSIZE;
      return(str);
}

/*
 * set_srcfile()
 */
static int
set_srcfile(bfd *abfd, int srcfile)
{
      if (bfd_check_format(abfd, bfd_archive) == TRUE) {
            int srcnum = 1;
            bfd *arbfd = (bfd *)NULL;

            for (;;) {
                  /* clear bfd_error, if we use more than one target
                   * bfd_error_wrong_format could be set
                   */
                  bfd_set_error(bfd_error_no_error);

                  arbfd = bfd_openr_next_archived_file(abfd, arbfd);
                  if (arbfd == NULL) {
                        return(1);
                  }
                  if (srcnum == srcfile) {
                        /* Read in the stab section data.
                         */
                        if (!read_debug_data(arbfd)) {
                              return(1);
                        }
                        break;
                  }
                  srcnum++;
            }
      } else {
            kl_check_bfd_error(bfd_error_file_not_recognized);
            if (!read_debug_data(abfd)) {
                  /* XXX - error msg */
                  return(1);
            }
      }
      return(0);
}

/* 
 * set_sym_entry()
 */
static int
set_sym_entry(bfd *abfd, dbg_sym_t *stp)
{
      if (set_srcfile(abfd, stp->sym_srcfile)) {
            return(1);
      }
      set_sym_globals(abfd, stp);
      /* This gets bumpped to the correct value in the get_next_str()
       * call.
       */
      G_symnum--;
      get_next_str();
      return(0);
}

/*
 * get_next_stab_entry()
 */
static dbg_sym_t *
get_next_stab_entry(void)
{
      int symnum, staboff, type, flag=0;
      dbg_sym_t *stp = (dbg_sym_t *)NULL;
      
again:
      if (get_next_str()) {
            return((dbg_sym_t *)NULL);
      }
      staboff = G_staboff;
      symnum = G_symnum;
      type = G_type;
      switch(G_type) {
            case N_LSYM:
                  if ((flag = (G_flags & ST_LSYM))) {
                        stp = get_sym_info();
                  }
                  break;
            case N_GSYM:
                  if ((flag = (G_flags & ST_GSYM))) {
                        if ((stp = get_sym_info())) {
                              stp->sym_type = DBG_VAR;
                        }
                  }
                  break;
            case N_PSYM:
                  if ((flag = (G_flags & ST_PSYM))) {
                        if ((stp = get_sym_info())) {
                              stp->sym_type = DBG_PARAM;
                        }
                  }
                  break;
            case N_RSYM:
                  if ((flag = (G_flags & ST_RSYM))) {
                        if ((stp = get_sym_info())) {
                              stp->sym_type = DBG_PARAM;
                        }
                  }
                  break;
            case N_SO:
                  if ((flag = (G_flags & ST_SO))) {
                        if (CUR_CHAR && CUR_CHAR[0]) {
                              if (!strstr(&CUR_CHAR[strlen(CUR_CHAR) 
                                          - 2], ".c")) {
                                    break;
                              }
                        } else {
                              break;
                        }
                        if (!(stp = dbg_alloc_sym(DBG_STABS))) {
                              break;
                        }
                        stp->sym_name = 
                              (char *)malloc(strlen(CUR_CHAR) +1);
                        strcpy(stp->sym_name, CUR_CHAR);
                        stp->sym_type = DBG_SRCFILE;
                        stp->sym_stroff = G_stroffset;
                  }
                  break;
            case N_FUN:
                  if ((flag = (G_flags & ST_FUN))) {
                        if ((stp = get_sym_info())) {
                              stp->sym_type = DBG_FUNC;
                        }
                  }
                  break;
            case N_SLINE:
                  if ((flag = (G_flags & ST_SLINE))) {
                        if ((stp = dbg_alloc_sym(DBG_STABS))) {
                              stp->sym_type = ST_SLINE;
                              stp->sym_stroff = G_stroffset;
                        }
                  }
                  break;
            default:    
                  break;
      }
      if (stp) {
            stp->sym_num = symnum;
            stp->sym_flag = flag;
            stp->sym_pvttype = type;
            stp->sym_off = staboff;
            stp->sym_nmlist = curnmlist;
            stp->sym_srcfile = G_srcfile;
            stp->sym_incfile = G_incfile;
      } else if (CUR_CHAR) {
            goto again;
      }
      return(stp);
}

#define CHK_STABERR() \
      if (stab_err) { \
            if (stp) { \
                  free(stp); \
            } \
            return((dbg_sym_t *)NULL); \
      }

/*
 * get_sym_info()
 */
static dbg_sym_t *
get_sym_info(void)
{
      uint64_t type_num;
      char *ptr, *name, symdesc;

      dbg_sym_t *stp = (dbg_sym_t *)NULL;

      ptr = get_name(&name);
      CHK_STABERR();
      ptr = get_symdesc(&symdesc);
      CHK_STABERR();
      if (symdesc == 0) {
            /* This is a parameter, not a type...
             */
            return((dbg_sym_t *)NULL);
      }
      ptr = get_typenum(&type_num);
      CHK_STABERR();

      if (!(stp = dbg_alloc_sym(DBG_STABS))) {
            return((dbg_sym_t*)NULL);
      }
      stp->sym_name = name;
      stp->sym_typenum = type_num;
      if (*ptr == '=') {
            ptr = bump_str_ptr(1);
      }
      if (*ptr == '(') {
            uint64_t real_type_num;

            ptr = get_typenum(&real_type_num);
            if (type_num == real_type_num) {
                  /* This is a void type
                   */
                  stp->sym_type = DBG_TYPE;
            } else {
                  /* This is a typedef
                   */
                  stp->sym_type = DBG_TYPEDEF;
            }
      } else {
            stp->sym_type = DBG_TYPE;
      }
      stp->sym_stroff = G_stroffset;

      while (strchr(G_stab_str.ptr, '\\')) {
            if (get_next_str()) {
                  free(stp);
                  return((dbg_sym_t *)NULL);
            }
      }
      return(stp);
}

/*
 * get_next_str()
 */
static int
get_next_str(void)
{
      if (!(G_stab_str.str = get_next_sym_str(G_abfd, G_flags))) {
            return(1);
      }
      CUR_CHAR = G_stab_str.str;
      return(0);
}

/*
 * alloc_stab_type()
 */
static dbg_type_t *
alloc_stab_type(void)
{
      dbg_type_t *stp;

      stp = (dbg_type_t *)calloc(1, sizeof(dbg_type_t));
      return (stp);
}

/*
 * free_stab_type()
 */
static void
free_stab_type(dbg_type_t *stp)
{
      dbg_type_t *mp, *mpnext;

      if (!stp) {
            return;
      }
      if ((mp = (dbg_type_t *)stp->st_member)) {
            while(mp) {
                  mpnext = (dbg_type_t *)mp->st_member;
                  free(mp);
                  mp = mpnext;
            }
      }
      free(stp);
}

/*
 * bump_str_ptr()
 */
static char *
bump_str_ptr(int count)
{
      if (!CUR_CHAR || !(*CUR_CHAR)) {
            return((char *)NULL);
      }
      if (strlen(CUR_CHAR) < count) {
            /* ERROR? */
            return((char *)NULL);
      } else {
            CUR_CHAR += count;
            if (*CUR_CHAR == '\\') {
                  if (get_next_str()) {
                        return((char *)NULL);
                  }
            }
      }
      return(CUR_CHAR);
}

/*
 * advance_ptr()
 */
static int
advance_ptr(char c)
{
      int i = 0;
      char *ptr;

      stab_err = 0;
      if (!CUR_CHAR) {
            stab_err = 1;
            return(0);
      }
      if (!(ptr = strchr(CUR_CHAR, c))) {
            CUR_CHAR = &CUR_CHAR[strlen(CUR_CHAR)];
            stab_err = 1;
            return(1);
      }
      i = (int)(ptr - CUR_CHAR);
      CUR_CHAR = ptr;
      return(i);
}

/*
 * get_name()
 */
static char *
get_name(char **namep)
{
      int i = 0, j;
      char name[256], *ptr = CUR_CHAR;

      stab_err = 0;
      i = advance_ptr(':');
      if (stab_err) {
            return(ptr);
      }
      strncpy(name, ptr, i);
      name[i] = 0;
      /* Make sure there IS a name...if there is nothing but 
       * spaces, return a NULL string.
       */
      for (j = 0; j < strlen(name); j++) {
            if (name[j] != ' ') {
                  break;
            }
      }
      if (j == i) {
            *namep = (char *)NULL; 
      } else {
            *namep = (char *)malloc(strlen(name) + 1);
            strcpy(*namep, name);
      }
      bump_str_ptr(1);
      return(CUR_CHAR);
}

/*
 * get_symdesc()
 */
static char *
get_symdesc(char *symdesc)
{
      stab_err = 0;
      if (*CUR_CHAR == '(') {
            *symdesc = 0;
      } else {
            *symdesc = *CUR_CHAR;
            bump_str_ptr(1);
      }
      return(CUR_CHAR);
}

/*
 * get_typenum()
 */
static char *
get_typenum(uint64_t *type_num)
{
      int i = 0;
      uint64_t tnum;
      char *p, num[25];
      char *ptr = CUR_CHAR;

      stab_err = 0;
      if (!ptr) {
            stab_err = 1;
            return(ptr);
      }
      /* Get the file number from the stabs entry
       */
      advance_ptr('(');
      if (stab_err) {
            return(ptr);
      }
      if (!(ptr = bump_str_ptr(1))) {
            stab_err = 1;
            return(ptr);
      }
      i = advance_ptr(',');
      if (stab_err) {
            return(ptr);
      }
      strncpy(num, ptr, i);
      num[i] = 0;
      tnum = ((uint64_t)atoi(num)) << 32;

      if (!(ptr = bump_str_ptr(1))) {
            stab_err = 1;
            return(ptr);
      }

      /* Get the type number from the stabs entry
       */
      i = advance_ptr(')');
      if (stab_err) {
            return(ptr);
      }
      strncpy(num, ptr, i);
      num[i] = 0;
      tnum |= atoi(num);

      /* Add the current source file number
       */
      tnum |= ((uint64_t)G_srcfile) << 48;

      /* Add the current namelist number
       */
      tnum |= ((uint64_t)curnmlist) << 60;

      p = bump_str_ptr(1);

      *type_num = tnum;

      /* 'type_num' should now contain a unique value that will 
       * allow us to distinguish this type definition from ones 
       * defined in other namelists having the same file number, type
       * number and source file number (however unlikely that may be).
       * This scheme will also allow use to use a single hash table
       * for types even if multiple namelists are in use.
       */
      return(p);
}

/*
 * get_embedded_type()
 */
static char *
get_embedded_type(uint64_t type_num)
{
      int ret;
      dbg_type_t *sp = ((dbg_type_t *)NULL);
      char *p,*ptr;
      dbg_sym_t *stp;
      
      p = ptr = CUR_CHAR;
      if (!p) {
            stab_err = 1;
            return(ptr);
      }
      if (*p == 'f') {
            /* This is a function
             */
            sp = alloc_stab_type();
            sp->st_type = KLT_FUNCTION;
            sp->st_type_num = type_num; 
            p = bump_str_ptr(1);
            p = get_typenum_type(&sp->st_real_type, 1);
      } else if (*p == 'x') {
            /* This is a cross-reference type. We need to check
             * and see if we have sucked in this type during
             * initialization. If we did, then we need to set up
             * the cross-reference link here.
             */
            p = bump_str_ptr(1);
            sp = alloc_stab_type();
            switch (*p) {
                  case 's':
                        sp->st_type = STAB_XSTRUCT;
                        break;
                  case 'u':
                        sp->st_type = STAB_XUNION;
                        break;
                  case 'e':
                        sp->st_type = STAB_XENUM;
                        break;
                  default:
                        free_stab_type(sp);
                        stab_err = 1;
                        return(ptr);
            }
            p = bump_str_ptr(1);
            p = get_name(&sp->st_name);
            sp->st_type_num = type_num; 
      } else if ((*p == 's') || (*p == 'u')) {
            sp = alloc_stab_type();
            if (*p == 's') {
                  sp->st_type = KLT_STRUCT;
            } else if (*p == 'u') {
                  sp->st_type = KLT_UNION;
            }
            p = bump_str_ptr(1);
            sp->st_type_num = type_num; 
            p = get_byte_size(&sp->st_size);
            if (stab_err) {
                  free_stab_type(sp);
                  return(ptr);
            }
            /* Check to see if this struct/union has
             * a byte_size equal to zero. If it does,
             * it's OK...we just have to make sure we
             * don't try to get the members...
             */
            if (sp->st_size) {
                  p = get_members(sp);
                  if (stab_err) {
                        free_stab_type(sp);
                        return(ptr);
                  }
            }
      } else if (*p == 'e') {
            sp = alloc_stab_type();
            sp->st_type = KLT_ENUMERATION;
            p = bump_str_ptr(1);
            sp->st_type_num = type_num;
            p = get_enumlist(sp);
            if (stab_err) {
                  free_stab_type(sp);
                  return(ptr);
            }
      } else if (*p == 'a') {
            sp = alloc_stab_type();
            sp->st_type = KLT_ARRAY;
            p = get_array(&sp->st_index_type, 
                  &sp->st_element_type, 
                  &sp->st_low_bounds, 
                  &sp->st_high_bounds);
            if (stab_err) {
                  free_stab_type(sp);
                  return(ptr);
            }
      } else if (*p == '*') {
            sp = alloc_stab_type();
            sp->st_type = KLT_POINTER;
            p = get_typenum_type(&sp->st_real_type, 1);
            if (stab_err) {
                  free_stab_type(sp);
                  return(ptr);
            }
      } else if (*p == 'r') {
            sp = alloc_stab_type();
            sp->st_type = KLT_BASE;
            ptr = get_range(&sp->st_index_type, 
                  &sp->st_low_bounds, &sp->st_high_bounds);
      } else if (*p == '(') {
            /* This is a hack, but there are known cases where there
             * is no 'void' entry in the stab data. We need to find
             * the embedded type definition and make sure that it
             * is named appropriately.
             */
            sp = alloc_stab_type();
            p = get_typenum_type(&sp->st_real_type, 1);
            if ((type_num == sp->st_real_type)){
                  /* Treat this as the actual 'void' case.
                   */
                  sp->st_type = KLT_BASE;
                  sp->st_name = (char *)malloc(5);
                  strcpy(sp->st_name, KL_TYPESTR_VOID);
            } else {
                  /* XXX - If it's not void, toss it out?
                   */
                  fprintf(KL_ERRORFP, "Stab type references itself!\n");
                  free_stab_type(sp);
                  sp = (dbg_type_t *)NULL;
                  stab_err = 1;
            }
      }
      if (sp) {
            stp = dbg_alloc_sym(DBG_STABS);
            if ((sp->st_type == STAB_XSTRUCT) 
                        || (sp->st_type == STAB_XUNION) 
                        || (sp->st_type == STAB_XENUM)) {
                  stp->sym_type = DBG_XTYPE;
            } else {
                  stp->sym_type = DBG_TYPE;
            }
            if (sp->st_name) {
                  stp->sym_name = (char *)malloc(strlen(sp->st_name) +1);
                  strcpy(stp->sym_name, sp->st_name);
            }
            stp->sym_typenum = type_num;
            stp->sym_pvttype = G_type;
            stp->sym_flag = G_flag;
            stp->sym_num = G_symnum;
            stp->sym_off = G_stabp - debug;
            stp->sym_srcfile = G_srcfile;
            stp->sym_nmlist = G_nmlist;
            stp->sym_stroff = G_stroffset;
            stp->sym_kltype = (kltype_t*)sp;
            sp->st_ptr = stp;
            ret = dbg_insert_sym(stp);
            if (ret  < 0) {
                  fprintf(KL_ERRORFP, "get_embedded_type: "
                        "dbg_insert_sym() returned ERROR!\n");
                  dbg_free_sym(stp);
            } else if (ret == 1) { 
                  /* Duplicate symbol...
                   */
                  dbg_free_sym(stp);
            } else {
                  /* Add to the list of all known syms
                   */
                  ADD_ALLSYM(stp);
            }
      }
      return(p);
}

/*
 * get_typenum_type()
 */
static char *
get_typenum_type(uint64_t *type_num, int follow)
{
      char *p, *ptr = CUR_CHAR;
      
      p = get_typenum(type_num);
      if (stab_err) {
            return(p);
      }
      if (p && *p && (*p == '=')) {
            /* This is a new type. If the follow flag is set, we 
             * need to capture the type information and create a 
             * new stab_type record.
             */
            p = bump_str_ptr(1);
            if (follow) {
                  p = get_embedded_type(*type_num);
                  if (!p) {
                        stab_err = 1;
                        return(ptr);
                  }
            }
      }
      return(p);
}

/*
 * get_byte_size()
 */
static char *
get_byte_size(int *byte_size)
{
      int i = 0;
      char *ptr = CUR_CHAR, num[25];

      stab_err = 0;
      while(CUR_CHAR && *CUR_CHAR 
                  && (*CUR_CHAR >= '0') && (*CUR_CHAR <= '9')) {
            bump_str_ptr(1);
            i++;
      }
      if (CUR_CHAR && !(*CUR_CHAR)) {
            stab_err = 1;
            return(ptr);
      }
      strncpy(num, ptr, i);
      num[i] = 0;
      *byte_size = atoi(num);
      return(CUR_CHAR);
}

/*
 * get_range()
 */
static char *
get_range(uint64_t *index_type, int *low_bounds, int *high_bounds) 
{
      int i;
      char *p, num[25];
      char *ptr = CUR_CHAR;

      stab_err = 0;
      p = get_typenum_type(index_type, 1);
      p = bump_str_ptr(1);
      i = advance_ptr(';');
      if (stab_err) {
            return(ptr);
      }
      strncpy(num, p, i);
      num[i] = 0;
      *low_bounds = atoi(num);
      p = bump_str_ptr(1);
      i = advance_ptr(';');
      if (stab_err) {
            return(ptr);
      }
      strncpy(num, p, i);
      num[i] = 0;
      *high_bounds = atoi(num);
      p = bump_str_ptr(1);
      return(p);
}

/*
 * get_array()
 */
static char *
get_array(
      uint64_t *index_type, 
      uint64_t *element_type, 
      int *low_bounds, 
      int *high_bounds)
{
      char *p;
      char *ptr = CUR_CHAR;

      p = bump_str_ptr(1);
      if (*p == 'r') {
            p = get_range(index_type, low_bounds, high_bounds);
            if (stab_err) {
                  return(ptr);
            }

      }
      p = get_typenum_type(element_type, 1);
      if (stab_err) {
            return(ptr);
      }
      return(p);
}

/* 
 * get_enum()
 */
static char *
get_enum(dbg_type_t **stpp)
{
      int i, value;
      char *ptr = CUR_CHAR, *p, *name, num[25];
      dbg_type_t *stp;

      p = get_name(&name);
      if (stab_err) {
            return(ptr);
      }
      i = advance_ptr(',');
      if (stab_err) {
            return(ptr);
      }
      strncpy(num, p, i);
      num[i] = 0;
      value = atoi(num);
      p = bump_str_ptr(1);
      stp = alloc_stab_type();
      if (stab_err) {
            return(ptr);
      }
      stp->st_type = KLT_MEMBER;
      stp->st_name = name;
      stp->st_value = value;
      *stpp = stp;
      return(p);
}

/*
 * get_enumlist()
 */
static char *
get_enumlist(dbg_type_t *stp)
{
      dbg_type_t *member, *mp = (dbg_type_t *)NULL;
      char *ptr = CUR_CHAR, *p = ptr;
      
      while (1) {
            p = get_enum(&member);
            if (stab_err) {
                  return(ptr);
            }
            if (mp) {
                  mp->st_member = (kltype_t *)member;
                  mp = member;
            } else {
                  stp->st_member = (kltype_t *)member;
                  mp = member;
            }
            if (*p == ';') {
                  p = bump_str_ptr(1);
                  break;
            }
      }
      return(p);
}

/* 
 * get_member()
 */
static char *
get_member(dbg_type_t **spp)
{
      int i;
      int bit_offset, bit_size; 
      uint64_t real_type;
      char *ptr = CUR_CHAR, *name, *p, num[25];
      dbg_type_t *sp;

      p = get_name(&name);
      if (stab_err) {
            return(ptr);
      }
      p = get_typenum_type(&real_type, 1);
      p = bump_str_ptr(1);
      i = advance_ptr(',');
      if (stab_err) {
            return(ptr);
      }
      strncpy(num, p, i);
      num[i] = 0;
      bit_offset = atoi(num);
      p = bump_str_ptr(1);
      i = advance_ptr(';');
      strncpy(num, p, i);
      num[i] = 0;
      bit_size = atoi(num);
      p = bump_str_ptr(1);

      sp = alloc_stab_type();
      sp->st_type = KLT_MEMBER;
      sp->st_name = name;
      sp->st_real_type = real_type;
      sp->st_bit_offset = bit_offset;
      sp->st_bit_size = bit_size;
      *spp = sp;
      return(p);
}

/*
 * get_members()
 */
static char *
get_members(dbg_type_t *stp)
{
      dbg_type_t *member, *mp = (dbg_type_t *)NULL;
      char *ptr = CUR_CHAR, *p = ptr;
      
      while (1) {
            p = get_member(&member);
            if (stab_err) {
                  return(ptr);
            }
            if (mp) {
                  mp->st_member = (kltype_t *)member;
                  mp = member;
            } else {
                  stp->st_member = (kltype_t *)member;
                  mp = member;
            }
            if (*p == ';') {
                  p = bump_str_ptr(1);
                  break;
            }
      }
      return(p);
}

/*
 * setup_base_type()
 */
static void
setup_base_type(dbg_type_t *stp)
{
      if (!stp->st_name) {
            return;
      }
      if (!strcmp(stp->st_name, "int")) {
            stp->st_size = 4;
            stp->st_encoding = ENC_SIGNED;
      } else if (!strcmp(stp->st_name, "char")) {
            stp->st_size = 1;
            stp->st_encoding = ENC_CHAR;
      } else if (!strcmp(stp->st_name, "long int")) {
            stp->st_size = KL_NBPW;
            stp->st_encoding = ENC_SIGNED;
      } else if (!strcmp(stp->st_name, "unsigned int")) {
            stp->st_size = 4;
            stp->st_encoding = ENC_UNSIGNED;
      } else if (!strcmp(stp->st_name, "long unsigned int")) {
            stp->st_size = KL_NBPW;
            stp->st_encoding = ENC_UNSIGNED;
      } else if (!strcmp(stp->st_name, "long long int")) {
            stp->st_size = 8;
            stp->st_encoding = ENC_SIGNED;
      } else if (!strcmp(stp->st_name, "long long unsigned int")) {
            stp->st_size = 8;
            stp->st_encoding = ENC_UNSIGNED;
      } else if (!strcmp(stp->st_name, "short int")) {
            stp->st_size = 2;
            stp->st_encoding = ENC_SIGNED;
      } else if (!strcmp(stp->st_name, "short unsigned int")) {
            stp->st_size = 2;
            stp->st_encoding = ENC_UNSIGNED;
      } else if (!strcmp(stp->st_name, "signed char")) {
            stp->st_size = 1;
            stp->st_encoding = ENC_SIGNED;
      } else if (!strcmp(stp->st_name, "unsigned char")) {
            stp->st_size = 1;
            stp->st_encoding = ENC_UNSIGNED;
      } else if (!strcmp(stp->st_name, "float")) {
            stp->st_size = stp->st_low_bounds;
            stp->st_encoding = ENC_FLOAT;
      } else if (!strcmp(stp->st_name, "double")) {
            stp->st_size = stp->st_low_bounds;
            stp->st_encoding = ENC_FLOAT;
      } else if (!strcmp(stp->st_name, "long double")) {
            stp->st_size = stp->st_low_bounds;
            stp->st_encoding = ENC_FLOAT;
      } else if (!strcmp(stp->st_name, "complex float")) {
            stp->st_size = stp->st_low_bounds;
            stp->st_encoding = ENC_FLOAT;
      } else if (!strcmp(stp->st_name, "complex double")) {
            stp->st_size = stp->st_low_bounds;
            stp->st_encoding = ENC_FLOAT;
      } else if (!strcmp(stp->st_name, "complex long double")) {
            stp->st_size = stp->st_low_bounds;
            stp->st_encoding = ENC_FLOAT;
      } else if (!strcmp(stp->st_name, KL_TYPESTR_VOID)) {
            stp->st_size = -1;
            stp->st_encoding = ENC_UNDEFINED;
      }
}

#define CHK_STABERR_TYPE() \
      if (stab_err) { \
            if (sp) { \
                  free_stab_type(sp); \
            } \
            return(1); \
      }

/*
 * get_typeinfo()
 */
static int
get_typeinfo(dbg_sym_t *stp) 
{
      char *ptr, symdesc;
      dbg_type_t *sp = (dbg_type_t *)NULL;

      /* If we already have type info, just return.
       */
      if (stp->sym_kltype) {
            return(0);
      }
      /* Check to see if this is a cross-reference type. If it is,
       * we need to see if we can locate the real type this is a 
       * cross-reference to.
       */
      if (stp->sym_type == DBG_XTYPE) {
            dbg_sym_t *xstp;

            fprintf(kl_stdout, "%s: THIS IS AN XTYPE!\n", stp->sym_name);
            if ((xstp = dbg_find_sym(stp->sym_name, DBG_TYPE, 0))) {
                  fprintf(kl_stdout, "%s: FOUND REAL TYPE!\n", 
                        stp->sym_name);
            }
      }
      kl_set_curnmlist(stp->sym_nmlist);
      if (set_sym_entry(ABFD, stp)) {
            return(1);
      }
      if (!(sp = alloc_stab_type())) {
            return(1);
      }
      ptr = get_name(&sp->st_name);
      CHK_STABERR_TYPE();
      /* It's possible that this type does not have a name...
       */
      if (sp->st_name || stp->sym_name) {
            if (!sp->st_name || !stp->sym_name) { 
                  free_stab_type(sp);
                  return(1);
            }
            if (strcmp(sp->st_name, stp->sym_name)) {
                  free_stab_type(sp);
                  return(1);
            }
      }
      ptr = get_symdesc(&symdesc);
      CHK_STABERR_TYPE();
      ptr = get_typenum_type(&sp->st_type_num, 0);
      if (sp->st_type_num != stp->sym_typenum) {
            free_stab_type(sp);
            return(1);
      }
      CHK_STABERR_TYPE();
      if ((*ptr == 's' || (*ptr == 'u') || (*ptr == 'e'))) {
            switch (*ptr) {
                  case 's':
                        sp->st_type = KLT_STRUCT;
                        break;

                  case 'u':
                        sp->st_type = KLT_UNION;
                        break;

                  case 'e':
                        sp->st_type = KLT_ENUMERATION;
                        break;
            }
            ptr = bump_str_ptr(1);
            ptr = get_byte_size(&sp->st_size);
            CHK_STABERR_TYPE();
      } else if (*ptr == 'r') {
            sp->st_type = KLT_BASE;
            ptr = get_range(&sp->st_index_type, 
                        &sp->st_low_bounds, &sp->st_high_bounds);
            CHK_STABERR_TYPE();
      } else if (*ptr == '(') {
            ptr = get_typenum_type(&sp->st_real_type, 1);
            if (sp->st_type_num == sp->st_real_type) {
                  /* Make sure we catch the the 'void' case
                   */
                  sp->st_type = KLT_BASE;
            } else {
                  sp->st_type = KLT_TYPEDEF;
            }
            CHK_STABERR_TYPE();
      } else if (*ptr == '*') {
            sp->st_type = KLT_POINTER;
            ptr++;
            ptr = get_typenum_type(&sp->st_real_type, 1);
      }
      switch (sp->st_type) {
            case KLT_BASE:
                  setup_base_type(sp);
                  break;
            case KLT_STRUCT:
            case KLT_UNION:
                  if (sp->st_size) {
                        ptr = get_members(sp);
                        CHK_STABERR_TYPE();
                  }
                  break;
            case KLT_ENUMERATION:
                  ptr = get_enumlist(sp);
                  CHK_STABERR_TYPE();
                  break;
      }
      stp->sym_kltype = (kltype_t *)sp;
      sp->st_ptr = stp;
      return(0);
}

/*
 * strip_traling_blanks()
 */
void
strip_trailing_blanks(char *str)
{
      char *cp;

      if (!str || !(cp = &str[strlen(str) - 1])) {
            return;
      }
      while((cp >= str) && *cp == ' ') {
            *cp-- = 0;
      }
}

/*
 * get_typestring()
 */
static int
get_typestring(dbg_type_t *sp)
{
      int ptrcnt = 0;
      dbg_type_t *rsp, *itp;
      char typestr[256];
      dbg_sym_t *stp;

      /* check to see if we are already setting the typestring for
       * this type. This will stop an endless loop when we process
       * next, prev, etc. pointers.
       */
      if (sp->st_flags & TYP_TYPESTRING_FLG) {
            return(0);
      }
      sp->st_flags |= TYP_TYPESTRING_FLG;

      if ((sp->st_type == KLT_STRUCT) || (sp->st_type == KLT_UNION)) {
            dbg_type_t *mp;

            /* Capture the typestring now, in case one of the members
             * needs it.
             */
            typestr[0] = 0;
            switch (sp->st_type) {
                  case KLT_STRUCT:
                        strcpy(typestr, KL_TYPESTR_STRUCT); 
                        break;
                  case KLT_UNION:
                        strcpy(typestr, KL_TYPESTR_UNION);  
                        break;
            }
            if (sp->st_name) {
                  strcat(typestr, " ");   
                  strcat(typestr, sp->st_name); 
                  strcat(typestr, " ");   
            } 
            sp->st_typestr = kl_get_string(nmlist[curnmlist].stringtab, 
                              typestr, K_PERM);

            /* Now walk through the members
             */
            mp = (dbg_type_t *)sp->st_member;
            while (mp) {
                  (void)get_typestring(mp);
                  mp = (dbg_type_t *)mp->st_member;
            }
            return(0);
      } 
      
      if (sp->st_type == KLT_MEMBER) {
            if (!(rsp = (dbg_type_t *)sp->st_realtype)) {
                  rsp = (dbg_type_t *)dbg_find_typenum(sp->st_real_type);
            }
            if (!rsp) {
                  sprintf(typestr, "<ERROR_1>");
                  goto got_typedef;
            }
      } else if((sp->st_realtype == NULL) &&
              (sp->st_type == 0)){
            if((rsp = dbg_find_typenum(sp->st_type_num)) && 
                              (rsp->st_typestr)){
                  sprintf(typestr, "%s", rsp->st_typestr);
                  return(0);
            }
      } else {
            rsp = sp;
      }

      if (!rsp) { /* XXX this should not happen */
            return 0;
      }

        while (rsp->st_type == KLT_POINTER) {
            ptrcnt++;
            if (rsp->st_realtype) {
                  rsp = (dbg_type_t *)rsp->st_realtype;
            } else if (rsp->st_real_type) {
                  rsp = dbg_find_typenum(rsp->st_real_type);
            } else {
                  sprintf(typestr, "<ERROR_2>");
                  goto got_typedef;
            }
            if (!rsp) {
                  sprintf(typestr, "<ERROR_3>");
                  goto got_typedef;
            }
      }
      if ((rsp->st_type == STAB_XSTRUCT) || (rsp->st_type == STAB_XUNION) 
                  || (rsp->st_type == STAB_XENUM)) {

            if ((stp = dbg_find_sym(rsp->st_name, DBG_TYPE|DBG_XTYPE, 0))) {
                  setup_stabs_typeinfo(stp);
                  if (stp->sym_kltype) {
                        rsp = (dbg_type_t *)stp->sym_kltype;
                  }
            }
      }

      typestr[0] = 0;
      switch (rsp->st_type) {

            case STAB_XSTRUCT:
                  strcpy(typestr, KL_TYPESTR_STRUCT); 
                  break;

            case STAB_XUNION:
                  strcpy(typestr, KL_TYPESTR_UNION);
                  break;

            case KLT_STRUCT:
            case KLT_UNION:
                  if (!rsp->st_typestr) {
                        get_typestring(rsp);
                  }
                  if (rsp->st_typestr) {
                        strcpy(typestr, rsp->st_typestr);
                        strip_trailing_blanks(typestr);
                  } else {
                        if (rsp->st_name) {
                              sprintf(typestr, "<%s>", rsp->st_name);
                        }
                  }
                  goto got_typedef;

            case KLT_ENUMERATION:
            case STAB_XENUM:
                  strcpy(typestr, KL_TYPESTR_ENUM);
                  break;

            case KLT_ARRAY: {
                  if ((itp = (dbg_type_t *)rsp->st_elementtype)) {
                        while (itp->st_type == KLT_POINTER) {
                              ptrcnt++;
                              if (itp->st_realtype) {
                                    itp = (dbg_type_t *)
                                          itp->st_realtype;
                              } else if (itp->st_real_type) {
                                    itp = dbg_find_typenum(
                                          itp->st_real_type);
                              }
                              if (!itp) {
                                    sprintf(typestr, "<ARRAY>");
                                    goto got_typedef;
                              }
                        }
                        if (!itp->st_typestr) {
                              get_typestring(itp);
                        }
                        if (itp->st_type == KLT_TYPEDEF) {
                              if (itp->st_name) {
                                    strcpy(typestr, itp->st_name);
                              } else {
                                    strcpy(typestr, "<TYPEDEF>");
                              }
                        } else if (itp->st_typestr) {
                              strcpy(typestr, itp->st_typestr);
                              strip_trailing_blanks(typestr);
                        } else if (itp->st_name) {
                              sprintf(typestr, "<%s>", itp->st_name);
                        }
                        goto got_typedef;
                  } else {
                        sprintf(typestr, "<ARRAY>");
                        goto got_typedef;
                  }
                  break;
            }

            case KLT_FUNCTION:
                  if (!(itp = (dbg_type_t *)rsp->st_realtype) 
                              && rsp->st_real_type) {
                        itp = dbg_find_typenum(rsp->st_real_type);
                  }
                  ptrcnt = 0;
                  while (itp && (itp->st_type == KLT_POINTER)) {
                        ptrcnt++;
                        if (itp->st_realtype) {
                              itp = (dbg_type_t *)itp->st_realtype;
                        } else if (itp->st_real_type) {
                              itp = dbg_find_typenum(itp->st_real_type);
                        }
                  }
                  if (itp) {
                        if (!itp->st_typestr) {
                              get_typestring(itp);
                        }
                        if (itp->st_type == KLT_TYPEDEF) {
                              if (itp->st_name) {
                                    strcpy(typestr, itp->st_name);
                              } else {
                                    strcpy(typestr, "<TYPEDEF>");
                              }
                        } else if (itp->st_typestr) {
                              strcpy(typestr, itp->st_typestr);
                              strip_trailing_blanks(typestr);
                        } else if (itp->st_name) {
                              strcat(typestr, itp->st_name);
                        } else {
                              strcat(typestr, "<UNKNOWN>");
                        }
                        goto got_typedef;
                  } 
                  strcpy(typestr, "<FUNCTION>");
                  goto got_typedef;

            case KLT_TYPEDEF:
                  if (sp->st_type == KLT_MEMBER) {
                        strcpy(typestr, rsp->st_name);
                  } else {
                        itp = (dbg_type_t *)sp->st_realtype;
                        if (!itp && sp->st_real_type) {
                              itp = dbg_find_typenum(sp->st_real_type);
                        }
                        if (itp) {
                              if (!itp->st_typestr) {
                                    get_typestring(itp);
                              }
                              if (itp->st_typestr) {
                                    strcpy(typestr, 
                                          itp->st_typestr);
                                    strip_trailing_blanks(typestr);
                                    goto got_typedef;
                              } else if (itp->st_name) {
                                    strcpy(typestr, itp->st_name);
                                    goto got_typedef;
                              }
                        }
                        strcat(typestr, "<TYPEDEF>");
                        goto got_typedef;
                  }
                  goto got_typedef;

            case KLT_BASE:
                  if (rsp->st_name) {
                        strcpy(typestr, rsp->st_name);
                  }
                  goto got_typedef;

            default: 
                  sprintf(typestr, "<type=%d>", rsp->st_type);
                  break;
      }
      if (rsp->st_name) {
            strcat(typestr, " ");
            strcat(typestr, rsp->st_name);      
      }
got_typedef:
      if (ptrcnt) {
            strcat(typestr, " ");
            while(ptrcnt--) {
                  strcat(typestr, "*");
            }
      } 
      if (!strchr(typestr, '*')) {
            strcat(typestr, " ");
      }
      sp->st_typestr = 
            kl_get_string(nmlist[curnmlist].stringtab, typestr, K_PERM);
      return(0);
}

/*
 * setup_stabs_typeinfo()
 */
static int
setup_stabs_typeinfo(dbg_sym_t *stp)
{
      st_global_t G;

      /* If we have already completed this type or stp->kltype has
       * been filled in on the first pass as it is with Dwarf2, then 
       * just return.
       */
      if (stp->sym_state == DBG_SETUP_DONE) {
            return (0);
      }

      /* If we are in the process of setting this type up, then just 
       * return without doing anyting (and with no error).
       */
      if (stp->sym_state == DBG_SETUP) {
            return(0);
      }
      stp->sym_state = DBG_SETUP;

      save_global_values(&G);
      if (get_typeinfo(stp)) {
            stp->sym_state = DBG_SETUP_FAILED;
            restore_global_values(&G);
            return(1);
      }
      restore_global_values(&G);
      return(0);
}

/*
 * set_pointers()
 */
static void
set_pointers(dbg_type_t *sp)
{
      if (sp->st_real_type && !sp->st_realtype) {
            if ((sp->st_realtype = (kltype_t *)
                        dbg_find_typenum(sp->st_real_type))) {
                  set_pointers((dbg_type_t *)sp->st_realtype);
            }
      }
      if (sp->st_index_type && !sp->st_indextype) {
            if ((sp->st_indextype = (kltype_t *)
                        dbg_find_typenum(sp->st_index_type))) {
                  set_pointers((dbg_type_t *)sp->st_indextype);
            }
      }
      if (sp->st_element_type && !sp->st_elementtype) {
            if ((sp->st_elementtype = (kltype_t *)
                        dbg_find_typenum(sp->st_element_type))) {
                  set_pointers((dbg_type_t *)sp->st_elementtype);
            }
      }
}

/*
 * process_sym()
 */
static void
process_sym(dbg_type_t *sp)
{
      dbg_type_t *mp;

      if (!sp) {
            return;
      }
      set_pointers(sp);
      if ((sp->st_type == KLT_STRUCT) || (sp->st_type == KLT_UNION)) {
            mp = (dbg_type_t *)sp->st_member;
            while (mp) {
                  if (mp->st_offset == 0) {
                        mp->st_offset = (mp->st_bit_offset / 8);
                  }
                  if (mp->st_size == 0) {
                        mp->st_size = (mp->st_bit_size / 8);
                        if (mp->st_bit_size % 8) {
                              mp->st_size++;
                        }
                        if (((mp->st_bit_offset % 8) +
                              (mp->st_bit_size % 8)) > 8) {
                              mp->st_size++;
                        }
                  }
                  mp->st_klt.kl_bit_offset = (mp->st_bit_offset % 8);
                  set_pointers(mp);
                  mp = (dbg_type_t *)mp->st_member;
            }
      } 
}

/*
 * st_open_namelist() -- get stab entries from object or archive file
 */
int
st_open_namelist(char *filename, int flags)
{
      bfd *archive = NULL;
      bfd *object= NULL;

      kl_reset_error();

      /* Set a flag to indicate that we are in the process of 
       * opening a namelist. This allows some routines to be 
       * used during initialization and for symbol lookup.
       */
      opening_st_namelist = 1;

      /* Allocate a private data structure and link it into the 
       * current namelist record.
       */
      nmlist[curnmlist].private = calloc(1, sizeof(st_namelist_t));

      /* Initialize global values
       */
      G_srcfile = 0;               
      G_incfile = 0;               
      G_symnum = -2;                  
      G_type = 0;                  
      G_stroffset = 0;             
      G_desc = 0;                
      G_value = 0;       
      G_stabp = 0;           
      G_stabs_end = 0;       
      G_flags = flags;

      while(!(kl_open_elf(filename, &object, &archive))){
            G_abfd = object;
            if (get_debug_entries()) {
                  /* XXX - error msg/error code/return val */
                  fprintf(KL_ERRORFP, 
                        "Could not get stab or dwarf2 entries "
                        "from file %s\n", filename);
            }
            G_symnum = -2;
            G_stabp = 0;
            G_stabs_end = 0;
            if(archive){
                  ABFD=archive;
            } else {
                  ABFD=object;
            } 
      }

      if(KL_ERROR){
            return(1);
      }

      opening_st_namelist = 0;

      return(0);
}

/*
 * st_setup_typeinfo()
 */
int
st_setup_typeinfo(void)
{
      dbg_sym_t *stp, *nstp;
      dbg_type_t *sp;

      /* Walk through the list of primary symbols (not embedded symbols)
       * and flesh them out. We don't need to back through the embedded
       * symbols because the are completely set up before they get 
       * inserted.
       */
      stp = initsyms;
      while (stp) {
            (void)setup_stabs_typeinfo(stp);
            nstp = NEXT_INITSYM(stp);
            NEXT_INITSYM(stp) = (dbg_sym_t *)NULL;
            stp = nstp;
      }
      initsyms = initsyms_end = (dbg_sym_t*)NULL;

      /* We should now have a linked list of all known symbols.
       * Walk through this list and finish processing each of
       * the symbols. We have to do this in two passes to 
       * ensure that we have everything in place before 
       * generating typestrings.
       */
      stp = allsyms;
      while (stp) {
            if ((sp = (dbg_type_t *)stp->sym_kltype)) {
                  process_sym(sp);
            }
            stp = NEXT_ALLSYM(stp);
      }

      /* Final pass. Generate the typestrings -- unlinking all the
       * sym records as we go along.
       */
      stp = allsyms;
      while (stp) {
            if ((sp = (dbg_type_t *)stp->sym_kltype)) {
                  (void)get_typestring(sp);
            }
            nstp = NEXT_ALLSYM(stp);
            NEXT_ALLSYM(stp) = (dbg_sym_t *)NULL;
            stp->sym_state = DBG_SETUP_DONE;
            stp = nstp;
      }
      allsyms = allsyms_end = (dbg_sym_t *)NULL;
      return(0);
}

Generated by  Doxygen 1.6.0   Back to index