Commit 672e6f59 authored by Jim Ingham's avatar Jim Ingham
Browse files

Add a method "GetEntryPoint" to the ObjectFile class, and implement it on...

Add a method "GetEntryPoint" to the ObjectFile class, and implement it on MachO & ELF - though the ELF implementation is probably a little weak.  Then use this method in place of directly looking for "start" in the ThreadPlanCallFunction constructor to find the stopping point for our function evaluation.

llvm-svn: 127194
parent 77ad1dc5
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -339,6 +339,17 @@ public:
    virtual lldb_private::Address
    GetImageInfoAddress () { return Address(); }
    
    //------------------------------------------------------------------
    /// Returns the address of the Entry Point in this object file - if
    /// the object file doesn't have an entry point (because it is not an
    /// executable file) then an invalid address is returned.
    ///
    /// @return
    ///     Returns the entry address for this module.
    //------------------------------------------------------------------
    virtual lldb_private::Address
    GetEntryPointAddress () { return Address();}

protected:
    //------------------------------------------------------------------
    // Member variables.
+28 −0
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/FileSpecList.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Stream.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Host/Host.h"

#define CASE_AND_STREAM(s, def, width)                  \
@@ -276,6 +278,32 @@ ObjectFileELF::GetImageInfoAddress()
    return Address();
}

lldb_private::Address
ObjectFileELF::GetEntryPointAddress () 
{
    // If the object file is not an executable it can't hold the entry point.  m_entry_point_address
    // is initialized to an invalid address, so we can just return that.
    // If m_entry_point_address is valid it means we've found it already, so return the cached value.
    
    if (!IsExecutable() || m_entry_point_address.IsValid())
        return m_entry_point_address;
    
    // FIXME: This is just looking for the "start" symbol, but that will fail if "start" is stripped.
    // There's probably a better way in ELF to find the start address of an executable module.
    
    SymbolContextList contexts;
    SymbolContext context;
    if (!m_module->FindSymbolsWithNameAndType(ConstString ("start"), lldb::eSymbolTypeCode, contexts))
        return m_entry_point_address;
    
    contexts.GetContextAtIndex(0, context);
    
    m_entry_point_address = context.symbol->GetValue();
    
    return m_entry_point_address;

}

//----------------------------------------------------------------------
// ParseDependentModules
//----------------------------------------------------------------------
+6 −0
Original line number Diff line number Diff line
@@ -116,6 +116,9 @@ public:
    virtual lldb_private::Address
    GetImageInfoAddress();
    
    virtual lldb_private::Address
    GetEntryPointAddress ();

private:
    ObjectFileELF(lldb_private::Module* module,
                  lldb::DataBufferSP& dataSP,
@@ -156,6 +159,9 @@ private:
    /// Data extractor holding the string table used to resolve section names.
    lldb_private::DataExtractor m_shstr_data;

    /// Cached value of the entry point for this module.
    lldb_private::Address  m_entry_point_address;
    
    /// Returns a 1 based index of the given section header.
    unsigned
    SectionIndex(const SectionHeaderCollIter &I);
+134 −1
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/MachO.h"

#include "ObjectFileMachO.h"

#include "lldb/Core/ArchSpec.h"
@@ -105,7 +107,8 @@ ObjectFileMachO::ObjectFileMachO(Module* module, DataBufferSP& dataSP, const Fil
    m_mutex (Mutex::eMutexTypeRecursive),
    m_header(),
    m_sections_ap(),
    m_symtab_ap()
    m_symtab_ap(),
    m_entry_point_address ()
{
    ::memset (&m_header, 0, sizeof(m_header));
    ::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
@@ -1435,6 +1438,136 @@ ObjectFileMachO::GetDependentModules (FileSpecList& files)
    return count;
}

lldb_private::Address
ObjectFileMachO::GetEntryPointAddress () 
{
    // If the object file is not an executable it can't hold the entry point.  m_entry_point_address
    // is initialized to an invalid address, so we can just return that.
    // If m_entry_point_address is valid it means we've found it already, so return the cached value.
    
    if (!IsExecutable() || m_entry_point_address.IsValid())
        return m_entry_point_address;
    
    // Otherwise, look for the UnixThread or Thread command.  The data for the Thread command is given in 
    // /usr/include/mach-o.h, but it is basically:
    //
    //  uint32_t flavor  - this is the flavor argument you would pass to thread_get_state
    //  uint32_t count   - this is the count of longs in the thread state data
    //  struct XXX_thread_state state - this is the structure from <machine/thread_status.h> corresponding to the flavor.
    //  <repeat this trio>
    // 
    // So we just keep reading the various register flavors till we find the GPR one, then read the PC out of there.
    // FIXME: We will need to have a "RegisterContext data provider" class at some point that can get all the registers
    // out of data in this form & attach them to a given thread.  That should underlie the MacOS X User process plugin,
    // and we'll also need it for the MacOS X Core File process plugin.  When we have that we can also use it here.
    //
    // For now we hard-code the offsets and flavors we need:
    //
    //

    lldb_private::Mutex::Locker locker(m_mutex);
    struct load_command load_cmd;
    uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
    uint32_t i;
    lldb::addr_t start_address = LLDB_INVALID_ADDRESS;
    bool done = false;
    
    for (i=0; i<m_header.ncmds; ++i)
    {
        const uint32_t cmd_offset = offset;
        if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
            break;

        switch (load_cmd.cmd)
        {
        case LoadCommandUnixThread:
        case LoadCommandThread:
            {
                while (offset < cmd_offset + load_cmd.cmdsize)
                {
                    uint32_t flavor = m_data.GetU32(&offset);
                    uint32_t count = m_data.GetU32(&offset);
                    if (count == 0)
                    {
                        // We've gotten off somehow, log and exit;
                        return m_entry_point_address;
                    }
                    
                    switch (m_header.cputype)
                    {
                    case llvm::MachO::CPUTypeARM:
                       if (flavor == 1) // ARM_THREAD_STATE from mach/arm/thread_status.h
                       {
                           offset += 60;  // This is the offset of pc in the GPR thread state data structure.
                           start_address = m_data.GetU32(&offset);
                           done = true;
                        }
                    break;
                    case llvm::MachO::CPUTypeI386:
                       if (flavor == 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h
                       {
                           offset += 40;  // This is the offset of eip in the GPR thread state data structure.
                           start_address = m_data.GetU32(&offset);
                           done = true;
                        }
                    break;
                    case llvm::MachO::CPUTypeX86_64:
                       if (flavor == 4) // x86_THREAD_STATE64 from mach/i386/thread_status.h
                       {
                           offset += 16 * 8;  // This is the offset of rip in the GPR thread state data structure.
                           start_address = m_data.GetU64(&offset);
                           done = true;
                        }
                    break;
                    default:
                        return m_entry_point_address;
                    }
                    // Haven't found the GPR flavor yet, skip over the data for this flavor:
                    if (done)
                        break;
                    offset += count * 4;
                }
            }
            break;

        default:
            break;
        }
        if (done)
            break;

        // Go to the next load command:
        offset = cmd_offset + load_cmd.cmdsize;
    }
    
    if (start_address != LLDB_INVALID_ADDRESS)
    {
        // We got the start address from the load commands, so now resolve that address in the sections 
        // of this ObjectFile:
        if (!m_entry_point_address.ResolveAddressUsingFileSections (start_address, GetSectionList()))
        {
            m_entry_point_address.Clear();
        }
    }
    else
    {
        // We couldn't read the UnixThread load command - maybe it wasn't there.  As a fallback look for the
        // "start" symbol in the main executable.
        
        SymbolContextList contexts;
        SymbolContext context;
        if (!m_module->FindSymbolsWithNameAndType(ConstString ("start"), lldb::eSymbolTypeCode, contexts))
            return m_entry_point_address;
        
        contexts.GetContextAtIndex(0, context);
        
        m_entry_point_address = context.symbol->GetValue();
    }
    
    return m_entry_point_address;

}

bool
ObjectFileMachO::GetArchitecture (ArchSpec &arch)
{
+4 −1
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@

#include "llvm/Support/MachO.h"

#include "lldb/Core/Address.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Symbol/ObjectFile.h"
@@ -112,7 +113,8 @@ public:
    virtual lldb_private::Log *
    EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);


    virtual lldb_private::Address
    GetEntryPointAddress ();

protected:
    mutable lldb_private::Mutex m_mutex;
@@ -123,6 +125,7 @@ protected:
    llvm::MachO::dysymtab_command m_dysymtab;
    std::vector<llvm::MachO::segment_command_64> m_mach_segments;
    std::vector<llvm::MachO::section_64> m_mach_sections;
    lldb_private::Address  m_entry_point_address;

    size_t
    ParseSections ();
Loading