EAAddressRep

Introduction

The AddressRep module defines a set of classes in EACallstack that facilitate the retrieval of symbol information associated with an instruction address. (In EACallstack, addresses for the current instruction and the subroutines on a thread's callstack can be acquired by using the functions defined in the Callstack namespace.)

Once an instruction address has been obtained, AddressRep can be used to look up the following types of symbol information for the address:

AddressRep provides all of the above information while running on the target platform.

In order for symbol information to be retrieved, a symbol database is required. On some platforms, this database is located within the executable itself, and on others, the database can be located in a separate file. The table below shows the currently supported symbol database formats on each platform supported by EACallstack:

PDB
(external to exe)

DWARF3
(embedded in exe)

Map
(external to exe)

XBox 360 / VC++

Supported

Supported

PS3 / GCC

Not supported

Supported

Win32 / VC++

Supported

 Supported*

Supported

Mac OS X / GCC
 
Supported
Supported
Linux / GCC
 
Supported
Supported
Win32 / GCC
 
Supported
Supported

*Not a format used by the platform. Supported for allowing external tools to read symbol information.

Generally, the same symbol database file used by the native debugger application for the platform is used by AddressRep for the symbol lookup.

Interface

The AddressRepType enumeration (from EAAddressRep.h) defines the  following information types that can be retrieved:

/// AddressRepType
///
/// These are intentionally incremental values of 0, 1, 2, etc. 
///
enum AddressRepType
{
    kARTFileLine = 0,   /// Source code file path plus line number in the file, beginning with 1.
    kARTFunctionOffset, /// Function name plus byte count of instructions into the address.
    kARTSource,         /// Source code text.
    kARTAddress,        /// The address as a hex number. 
    kARTCount           /// Count of AddressRepTypes
};

The AddressRepLookup class:

/// AddressRepLookup
///
/// Implements a direct lookup of address information from a symbol database file.
/// Normally you will want to use the AddressRepCache class instead of this, as that class
/// will cache lookup results and run much faster under most practical circumstances.
///
/// AddressRepLookupBase is a base class which holds platform-specific data.
///
class AddressRepLookup : public AddressRepLookupBase
{
public:
    AddressRepLookup();
   ~AddressRepLookup();
 
    /// GetAddressRep
    ///
    /// Looks up one or more of the given AddressRepType values.
    /// Returns flags indicating which of the AddressRepType values were successfully looked up.
    /// We have a single function for all three types because it is much faster
    /// to do lookups of multiple types at the same time.
    /// The input pRepArray and pIntValueArray need to have a capacity for all AddressRepTypes
    /// (i.e. kARTCount), as each result is written to its position in the array.
    /// Unused results are set to empty strings.
    /// The kARTAddress AddressRepType always succeeds, as it is merely a translation
    /// of a pointer to a hex number.
    ///
    /// Example usage:
    ///     FixedString pStringResults[kARTCount];
    ///     int pIntResults[kARTCount];
    ///     int inputFlags = (1 << kARTFunctionOffset) | (1 << kARTFileLine) | (1 << kARTSource);
    ///     int outputFlags;
    ///
    ///     outputFlags = addressRepLookup.GetAddressRep(inputFlags, pSomeAddress, pStringResults, pIntResults);
    ///
    ///     if(outputFlags & (1 << kARTFileLine))
    ///         printf("File: %s, line: %d", pStringResults[kARTFileLine].c_str(), pIntResults[kARTFileLine]);
    ///
    int GetAddressRep(int addressRepTypeFlags, const void* pAddress, FixedString* pRepArray, int* pIntValueArray);

    /// AddDatabaseFile
    ///
    /// Adds a symbol database for use when looking up symbols for a program address.
    /// A variety of symbol database formats are supported, including PDB, DWARF3 (contained
    /// in ELF/SELF executables), and Map files. Currently the type of database is
    /// determined by the file extension in the path provided.
    ///
    bool AddDatabaseFile(const char16_t* pDatabaseFilePath)
        { return mAddressRepLookup.AddDatabaseFile(pDatabaseFilePath); } 

    /// AddSourceDirectory
    ///
    /// Adds a file system directory to the set we use to find file source code.
    /// If a given directory is the root of a tree of source directories, you need only
    /// supply the root directory. Since most symbol databases store full paths
    /// to source files, often only the home directory or root drive location of
    /// the source code is required when loading source text from the host PC.
    ///
    void AddSourceDirectory(const char16_t* pSourceDirectory)
};

The AddressRepCache class has an interface identical to that of AddressRepLookup described above.

There are also global accessor and mutator functions for defining a default AddressRepCache :

/// GetAddressRepCache
/// Retrieves the default global AddressRepCache object.
AddressRepCache* GetAddressRepCache();

/// SetAddressRepCache
/// Sets the default global AddressRepCache object.
/// Returns the old AddressRepCache object.
/// The old AddressRepCache is not deleted, as this function is 
/// merely an accessor modifier.
AddressRepCache* SetAddressRepCache(AddressRepCache* pAddressRepCache);

Example Usage

The functionality of AddressRep is made available to the user via two classes:

Both classes provide the same interface; however, AddressRepCache should be used if the same instruction address will be looked up multiple times. AddressRepCache, as its name implies, caches the result of the lookup, since reading a symbol database is an expensive operation.

The following sample code demonstrates the initialization of an AddressRepLookup object:

// Get the path to the current executable.
// (Note that GetCurrentProcessPath does not work on all platforms at the time of this writing.)
char16_t dbPath[EA::IO::kMaxPathLength];
EA::Process::GetCurrentProcessPath(dbPath);
 
// Initialize an AddressRepLookup object.
AddressRepLookupSet addressRepLookup;

// Add the executable path as a possible symbol database.
// Platforms using DWARF3 have debugging symbols embedded in the executable.
addressRepLookup.AddDatabaseFile(dbPath);

// Set the database file extension to .pdb, and add it as a potential database.
Strcpy16(EA::IO::GetFileExtension(dbPath), L".pdb");
addressRepLookup.AddDatabaseFile(dbPath);

// Set the database file extension to .map, and add it as a potential database.
Strcpy16(EA::IO::GetFileExtension(dbPath), L".map");
addressRepLookup.AddDatabaseFile(dbPath);

// Add source file directories for source code lookups.
addressRepLookup.AddSourceDirectory(L"C:\\");       // Most common case for Win32
addressRepLookup.AddSourceDirectory(L"/app_home/"); // Most common case for PS3

The following sample code demonstrates the usage of AddressRepLookup to look up the symbol information for a program address using the object initialized above:

void*  pCallstack[32];
size_t nCallstackDepth = EA::Callstack::GetCallstack(pCallstack, 32, NULL);

for(size_t i = 0; i < nCallstackDepth; ++i)
{
    EA::Callstack::FixedString strResults[kARTCount];
    int         pIntResults[kARTCount];

    const int   nInputFlags = (1 << kARTFunctionOffset) | (1 << kARTFileLine) | (1 << kARTSource) | (1 << kARTAddress);
    const int   nOutputFlags = addressRepLookup.GetAddressRep(nInputFlags, pCallstack[i], strResults, pIntResults);

    printf("    Address:  %s\n", strResults[kARTAddress].c_str());

    if(nOutputFlags & (1 << kARTFunctionOffset))
    {
        printf("    Function: %s\n", strResults[kARTFunctionOffset].c_str());
        printf("    Offset:   %d\n", pIntResults[kARTFunctionOffset]);
    }

    if(nOutputFlags & (1 << kARTFileLine))
    {
        printf("    File:     %s\n", strResults[kARTFileLine].c_str());
        printf("    Line:     %d\n", pIntResults[kARTFileLine]);
    }

    if(nOutputFlags & (1 << kARTSource))
    {
        printf("    Source:\n");
        printf(strResults[kARTSource].c_str());
    }

    printf("\n");
}

Usage of AddressRepCache is identical to AddressRepLookup.