
/***************************************************************************
**
**    $Header$
**
**    $Log$
** 
****************************************************************************/

/*-------------------------------------------------------------------------
** Name: SYMADDR.CPP
**
** Title: Address Lookup Routines
**
** Purpose:
**  Supplies the routines defined in symblsvr.h for looking up a symbol by
**  its address.  "address" is an abstract term which can be:
**      physical address
**      offset from stack frame context
**      register index for register variables
**
** Status: PRELIMINARY
**
** $Log$
** 
** $Header:   D:/EPSLDV1/SRC/LOG/SYMADDR.CPP   1.7.1.0.1.0   11 Nov 1996 12:59:30   ZJRD  $
**
** Copyright (C) 1995 Microtek International.  All rights reserved.
**
**------------------------------------------------------------------------*/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#include "stdafx.h"                      
#include "symblsvr.h"
#include "symbase.h"
#include "symbyadr.h"

                       /****************************
                        *                          *
                        *        EXTERNALS         *
                        *                          *
                        ****************************/

extern BaseIndexTable bit; // base index table
extern MemPool st;         // symbol table

//--------------------------------------------------------------------------
// AdlookupResetCacheVars
//--------------------------------------------------------------------------
VOID AdlookupResetCacheVars(VOID);

                        /***************************
                        *                          *
                        *         GLOBALS          *
                        *                          *
                        ****************************/
BOOLEAN FilterPublics = FALSE; // used to gate by-addr search to ignore
                               // publics or not

                        /***************************
                        *                          *
                        *      LOCAL STATICS       *
                        *                          *
                        ****************************/

PRIVATE TABLE_OFFSET cachedAddrLookupBaseOffset;

                       /****************************
                        *                          *
                        *     EXECUTABLE CODE      *
                        *                          *
                        ****************************/


//--------------------------------------------------------------------------
// AdlookupResetCacheVars
//--------------------------------------------------------------------------
VOID AdlookupResetCacheVars(VOID) {

   cachedAddrLookupBaseOffset = NULL_SYMBOL;
}

//--------------------------------------------------------------------------
// SymMapAddr2Symbol
//
// Purpose:
//    Map an abstract address to a symbol that contains it.  It returns
//    the symbol with a starting address closest to the requested
//    address.  It also returns its type and parent information.  This
//    routine returns a symbol descriptor, then the caller
//    makes another call to get specific information about the symbol.
//
// Input parameters;
//    addr: abstract address to be looked up.
//
// Output parameters:
//    memoryClass:
//       what basic symbol class; to be completed with hints when they are
//       implemented.  If an address match is not found, the memoryClass
//       value gives the caller more general information about the address
//    symbolType: basic symbol type - part of every symbol
//    offset:
//        distance the requested address is from the function's start address
//    outputSymbol:
//        descriptor to the symbol found that is closest to the requested addr
//    funcDescriptor: offset to parent function; can be a function or unnamed
//        block; NULL if none exists
//    moduleDescriptor: offset to parent module; NULL if none exists
//
// Error:
//    Error reported if address type is not linear or virtual
//    Error reported if no symbol match is found.
//
// Rules:
//    When a base is found that contains the requested address, do a binary
//       search on the ByAddressTable to find a symbol that contains the
//       requested address.  It is possible not to find the address because
//       the end address may not include the address requested; i.e. some
//       symbols like labels may have a range of 1.  Return error
//       ER_ADDRESS_NOT_FOUND if this occurs.
//    Search down in the table for an address range whose start address is
//       closer to the requested address.  Stop when it exceeds requested addr
//    Initialize return descriptors to NULL.
//    Access symbol.  Fill in <symbolType>, <offset>, <memoryClass>, and
//       <outputSymbol>. If any parent is a function, fill in
//       <funcDescriptor>.  If any parent is a module (may be a public which
//       points to root) fill in <moduleDescriptor>.
//
//------------------------------------------------------------------------
RETCODE WINAPI
SymMapAddr2Symbol(ADDRESS_TYPE   inputAddr,
                  MEM_ADDR_CLASS *memoryClass,
                  SYM_TYPE_TYPE  *symbolType,
                  U32            *offset,
                  SYM_DESCRIPTOR *outputSymbol,
                  SYM_DESCRIPTOR *funcDescriptor,
                  SYM_DESCRIPTOR *moduleDescriptor)  {

   RETCODE           err;
   TABLE_OFFSET      tableOffset, byAddrOffset;
   BaseSymbol        *basePtr;       // ptr to Base object
   ByAddressTable    *byAddrPtr;     // ptr to by-address table object
   COMMON_SYMBOL_HEADER *symPtr;     // ptr to a symbol common header
   SYMBOL_INFO_TYPE  symbolInfo;
   
   // initialize the return parameters to the status of the address NOT FOUND
   *memoryClass = UNDEFINED_ADDR;
   *symbolType =  SYM_UNDEFINED;
   *offset = 0L;
   *outputSymbol = *funcDescriptor = *moduleDescriptor = NULL_SYMBOL;

   // get new by-address table offset or generate error if not a valid index
   if ((err=bit.GetOffset((BASE_INDEX)inputAddr.segType, tableOffset)) != GOOD)
      return(err);

   // tableOffset is always valid at this point and is the offset
   // into st pointing to the base; need to dereference into an
   // actual base ptr
   basePtr = (BaseSymbol *)st.GetHugeDataPtr(tableOffset);

   if (!basePtr->CompareAddrVars(inputAddr.addr))
      return ER_ADDRESS_NOT_FOUND;  // "Cannot find address in symbol table"

   // do a binary search on by-addr table for symbol match
   byAddrOffset = basePtr->GetByAddressTableOffset();
   byAddrPtr = (ByAddressTable *)st.GetHugeDataPtr(byAddrOffset);
   if (GOOD != byAddrPtr->SearchForAddr(inputAddr.addr,
                                        FilterPublics,
                                        symbolInfo)) {
      return ER_ADDRESS_NOT_FOUND;  // "Cannot find address in symbol table"
   }
   cachedAddrLookupBaseOffset = tableOffset;  // save away found base object

   //**************************************************
   // symbolInfo structure holds symbol information found
   // now reusing tableOffset
   //**************************************************

   // save information retrieved
   *offset = symbolInfo.delta;
   *outputSymbol = tableOffset = symbolInfo.symbolOffset;
   symPtr = (COMMON_SYMBOL_HEADER *)st.GetHugeDataPtr(tableOffset);
   // must mask packed structure to get unsigned value for switch statement
   *symbolType = (SYM_TYPE_TYPE)(symPtr->typeIndex.symType & 0xF);
   // set memoryClass to code or data;  previously set to UNDEFINED_ADDR
   switch (*symbolType) {
      case SYM_GLOBAL_VAR:
      case SYM_LOCAL_VAR:
      case SYM_USER_DEFINED_VAR:
      case SYM_PUBLIC_VAR:
         *memoryClass = DATA_ADDR;
         break;

      default:
         *memoryClass = CODE_ADDR;
         break;
   }  // end of switch

   // fill in the funcDescriptor and moduleDescriptor fields; must follow the
   // parent symbol linkages

   SYM_TYPE_TYPE     tmpType;
   BOOLEAN           funcFound = FALSE;

   while (tableOffset != NULL_SYMBOL) {
      // get symbol pointer, then its type
      symPtr = (COMMON_SYMBOL_HEADER *)st.GetHugeDataPtr(tableOffset);
      tmpType = (SYM_TYPE_TYPE)((symPtr->typeIndex.symType) & 0xF);
      switch(tmpType) {
         case SYM_ROOT:
         case SYM_UNDEFINED:
            return GOOD;

         case SYM_MODULE:
            *moduleDescriptor = tableOffset;
            return GOOD;

         case SYM_BLOCK:
            break;      // don't stop at block; find function parent

         case SYM_FUNCTION:  // match function or block
            if (!funcFound) {
               *funcDescriptor = tableOffset;  // found parent function
               funcFound = TRUE;  // once found, ignore any other higher
                                  // level nested functions
               break;
            }
      } // end of switch
      tableOffset = symPtr->symParentOffset;
   } // end of while loop
   return GOOD;
}  // end of SymMapAddr2Symbol


//--------------------------------------------------------------------------
// SymMapLinenum2FuncOrBlock
//
// Purpose:
//    Given a line number and its context, look up the most local function or
//    block that contains it.  Return the type (function or block), and a
//    descriptor to it.
//
// Error:
//    Reports error if:
//        moduleName not found
//        linenum not in module context
//        type returned is not a function or block
//--------------------------------------------------------------------------
RETCODE WINAPI
SymMapLinenum2FuncOrBlock(SYM_DESCRIPTOR module,
                          LINENUM_TYPE   linenum,
                          SYM_TYPE_TYPE  *symType,
                          SYM_DESCRIPTOR *outputSymbol)  {

   RETCODE            err;
   ADDR_RANGE_TYPE    addrRange;
   ADDRESS_TYPE       inputAddr;
   LINENUM_TYPE       actualLinenum;
   COLUMN_TYPE        actualColumn;
   LINENUM_DESCRIPTOR nextIndex;
   MEM_ADDR_CLASS memoryClass;
   U32            offset;
   SYM_DESCRIPTOR outSymbol;
   SYM_DESCRIPTOR funcDescriptor;
   SYM_DESCRIPTOR moduleDescriptor;

   
   // convert module and linenum to address
   if (GOOD != (err = SymGetLinenum(module,
                                    linenum,
                                    &addrRange,
                                    &actualLinenum,
                                    &actualColumn,
                                    &nextIndex)))
      return err;

   inputAddr.addr    = addrRange.startAddr;
   inputAddr.segType = SEG_CODE;
   // look up address for function or block that contains it
   if (GOOD != (err = SymMapAddr2Symbol(inputAddr,
                                        &memoryClass,
                                        symType,     //func input param
                                        &offset,
                                        &outSymbol,
                                        &funcDescriptor,
                                        &moduleDescriptor)))
      return err;

   *outputSymbol = outSymbol;  // copy the lowest-level descriptor to output
   // check for valid function or block type
   if (funcDescriptor == NULL_SYMBOL)
      return ER_SYMBOL_NOT_FOUND;

   return GOOD;
}  // end of SymMapLinenum2FuncOrBlock

/******************************** E O F ****************************/
