//===-- Address.cpp ---------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Core/Address.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/Symbol/SymbolVendor.h"

#include "llvm/ADT/Triple.h"

using namespace lldb;
using namespace lldb_private;

static size_t
ReadBytes (ExecutionContextScope *exe_scope, const Address &address, void *dst, size_t dst_len)
{
    if (exe_scope == NULL)
        return 0;

    TargetSP target_sp (exe_scope->CalculateTarget());
    if (target_sp)
    {
        Error error;
        bool prefer_file_cache = false;
        return target_sp->ReadMemory (address, prefer_file_cache, dst, dst_len, error);
    }
    return 0;
}

static bool
GetByteOrderAndAddressSize (ExecutionContextScope *exe_scope, const Address &address, ByteOrder& byte_order, uint32_t& addr_size)
{
    byte_order = eByteOrderInvalid;
    addr_size = 0;
    if (exe_scope == NULL)
        return false;

    TargetSP target_sp (exe_scope->CalculateTarget());
    if (target_sp)
    {
        byte_order = target_sp->GetArchitecture().GetByteOrder();
        addr_size = target_sp->GetArchitecture().GetAddressByteSize();
    }

    if (byte_order == eByteOrderInvalid || addr_size == 0)
    {
        ModuleSP module_sp (address.GetModule());
        if (module_sp)
        {
            byte_order = module_sp->GetArchitecture().GetByteOrder();
            addr_size = module_sp->GetArchitecture().GetAddressByteSize();
        }
    }
    return byte_order != eByteOrderInvalid && addr_size != 0;
}

static uint64_t
ReadUIntMax64 (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, bool &success)
{
    uint64_t uval64 = 0;
    if (exe_scope == NULL || byte_size > sizeof(uint64_t))
    {
        success = false;
        return 0;
    }
    uint64_t buf = 0;

    success = ReadBytes (exe_scope, address, &buf, byte_size) == byte_size;
    if (success)
    {
        ByteOrder byte_order = eByteOrderInvalid;
        uint32_t addr_size = 0;
        if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
        {
            DataExtractor data (&buf, sizeof(buf), byte_order, addr_size);
            lldb::offset_t offset = 0;
            uval64 = data.GetU64(&offset);
        }
        else
            success = false;
    }
    return uval64;
}

static bool
ReadAddress (ExecutionContextScope *exe_scope, const Address &address, uint32_t pointer_size, Address &deref_so_addr)
{
    if (exe_scope == NULL)
        return false;


    bool success = false;
    addr_t deref_addr = ReadUIntMax64 (exe_scope, address, pointer_size, success);
    if (success)
    {
        ExecutionContext exe_ctx;
        exe_scope->CalculateExecutionContext(exe_ctx);
        // If we have any sections that are loaded, try and resolve using the
        // section load list
        Target *target = exe_ctx.GetTargetPtr();
        if (target && !target->GetSectionLoadList().IsEmpty())
        {
            if (target->GetSectionLoadList().ResolveLoadAddress (deref_addr, deref_so_addr))
                return true;
        }
        else
        {
            // If we were not running, yet able to read an integer, we must
            // have a module
            ModuleSP module_sp (address.GetModule());

            assert (module_sp);
            if (module_sp->ResolveFileAddress(deref_addr, deref_so_addr))
                return true;
        }

        // We couldn't make "deref_addr" into a section offset value, but we were
        // able to read the address, so we return a section offset address with
        // no section and "deref_addr" as the offset (address).
        deref_so_addr.SetRawAddress(deref_addr);
        return true;
    }
    return false;
}

static bool
DumpUInt (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, Stream* strm)
{
    if (exe_scope == NULL || byte_size == 0)
        return 0;
    std::vector<uint8_t> buf(byte_size, 0);

    if (ReadBytes (exe_scope, address, &buf[0], buf.size()) == buf.size())
    {
        ByteOrder byte_order = eByteOrderInvalid;
        uint32_t addr_size = 0;
        if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
        {
            DataExtractor data (&buf.front(), buf.size(), byte_order, addr_size);

            data.Dump (strm,
                       0,                 // Start offset in "data"
                       eFormatHex,        // Print as characters
                       buf.size(),        // Size of item
                       1,                 // Items count
                       UINT32_MAX,        // num per line
                       LLDB_INVALID_ADDRESS,// base address
                       0,                 // bitfield bit size
                       0);                // bitfield bit offset

            return true;
        }
    }
    return false;
}


static size_t
ReadCStringFromMemory (ExecutionContextScope *exe_scope, const Address &address, Stream *strm)
{
    if (exe_scope == NULL)
        return 0;
    const size_t k_buf_len = 256;
    char buf[k_buf_len+1];
    buf[k_buf_len] = '\0'; // NULL terminate

    // Byte order and address size don't matter for C string dumping..
    DataExtractor data (buf, sizeof(buf), lldb::endian::InlHostByteOrder(), 4);
    size_t total_len = 0;
    size_t bytes_read;
    Address curr_address(address);
    strm->PutChar ('"');
    while ((bytes_read = ReadBytes (exe_scope, curr_address, buf, k_buf_len)) > 0)
    {
        size_t len = strlen(buf);
        if (len == 0)
            break;
        if (len > bytes_read)
            len = bytes_read;

        data.Dump (strm,
                   0,                 // Start offset in "data"
                   eFormatChar,       // Print as characters
                   1,                 // Size of item (1 byte for a char!)
                   len,               // How many bytes to print?
                   UINT32_MAX,        // num per line
                   LLDB_INVALID_ADDRESS,// base address
                   0,                 // bitfield bit size

                   0);                // bitfield bit offset

        total_len += bytes_read;

        if (len < k_buf_len)
            break;
        curr_address.SetOffset (curr_address.GetOffset() + bytes_read);
    }
    strm->PutChar ('"');
    return total_len;
}

Address::Address (lldb::addr_t abs_addr) :
    m_section_wp (),
    m_offset (abs_addr)
{
}

Address::Address (addr_t address, const SectionList *section_list) :
    m_section_wp (),
    m_offset (LLDB_INVALID_ADDRESS)
{
    ResolveAddressUsingFileSections(address, section_list);
}

const Address&
Address::operator= (const Address& rhs)
{
    if (this != &rhs)
    {
        m_section_wp = rhs.m_section_wp;
        m_offset = rhs.m_offset.load();
    }
    return *this;
}

bool
Address::ResolveAddressUsingFileSections (addr_t file_addr, const SectionList *section_list)
{
    if (section_list)
    {
        SectionSP section_sp (section_list->FindSectionContainingFileAddress(file_addr));
        m_section_wp = section_sp;
        if (section_sp)
        {
            assert( section_sp->ContainsFileAddress(file_addr) );
            m_offset = file_addr - section_sp->GetFileAddress();
            return true;    // Successfully transformed addr into a section offset address
        }
    }
    m_offset = file_addr;
    return false;       // Failed to resolve this address to a section offset value
}

ModuleSP
Address::GetModule () const
{
    lldb::ModuleSP module_sp;
    SectionSP section_sp (GetSection());
    if (section_sp)
        module_sp = section_sp->GetModule();
    return module_sp;
}

addr_t
Address::GetFileAddress () const
{
    SectionSP section_sp (GetSection());
    if (section_sp)
    {
        addr_t sect_file_addr = section_sp->GetFileAddress();
        if (sect_file_addr == LLDB_INVALID_ADDRESS)
        {
            // Section isn't resolved, we can't return a valid file address
            return LLDB_INVALID_ADDRESS;
        }
        // We have a valid file range, so we can return the file based
        // address by adding the file base address to our offset
        return sect_file_addr + m_offset;
    }
    else if (SectionWasDeletedPrivate())
    {
        // Used to have a valid section but it got deleted so the
        // offset doesn't mean anything without the section
        return LLDB_INVALID_ADDRESS;
    }
    // No section, we just return the offset since it is the value in this case
    return m_offset;
}

addr_t
Address::GetLoadAddress (Target *target) const
{
    SectionSP section_sp (GetSection());
    if (section_sp)
    {
        if (target)
        {
            addr_t sect_load_addr = section_sp->GetLoadBaseAddress (target);

            if (sect_load_addr != LLDB_INVALID_ADDRESS)
            {
                // We have a valid file range, so we can return the file based
                // address by adding the file base address to our offset
                return sect_load_addr + m_offset;
            }
        }
    }
    else if (SectionWasDeletedPrivate())
    {
        // Used to have a valid section but it got deleted so the
        // offset doesn't mean anything without the section
        return LLDB_INVALID_ADDRESS;
    }
    else
    {
        // We don't have a section so the offset is the load address
        return m_offset;
    }
    // The section isn't resolved or an invalid target was passed in
    // so we can't return a valid load address.
    return LLDB_INVALID_ADDRESS;
}

addr_t
Address::GetCallableLoadAddress (Target *target, bool is_indirect) const
{
    addr_t code_addr = LLDB_INVALID_ADDRESS;
    
    if (is_indirect && target)
    {
        ProcessSP processSP = target->GetProcessSP();
        Error error;
        if (processSP.get())
        {
            code_addr = processSP->ResolveIndirectFunction(this, error);
            if (!error.Success())
                code_addr = LLDB_INVALID_ADDRESS;
        }
    }
    else
    {
        code_addr = GetLoadAddress (target);
    }
    
    if (code_addr == LLDB_INVALID_ADDRESS)
        return code_addr;
    
    if (target)
        return target->GetCallableLoadAddress (code_addr, GetAddressClass());
    return code_addr;
}

bool
Address::SetCallableLoadAddress (lldb::addr_t load_addr, Target *target)
{
    if (SetLoadAddress (load_addr, target))
    {
        if (target)
            m_offset = target->GetCallableLoadAddress(m_offset, GetAddressClass());
        return true;
    }
    return false;
}

addr_t
Address::GetOpcodeLoadAddress (Target *target) const
{
    addr_t code_addr = GetLoadAddress (target);
    if (code_addr != LLDB_INVALID_ADDRESS)
        code_addr = target->GetOpcodeLoadAddress (code_addr, GetAddressClass());
    return code_addr;
}

bool
Address::SetOpcodeLoadAddress (lldb::addr_t load_addr, Target *target)
{
    if (SetLoadAddress (load_addr, target))
    {
        if (target)
            m_offset = target->GetOpcodeLoadAddress (m_offset, GetAddressClass());
        return true;
    }
    return false;
}

bool
Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style, uint32_t addr_size) const
{
    // If the section was NULL, only load address is going to work unless we are
    // trying to deref a pointer
    SectionSP section_sp (GetSection());
    if (!section_sp && style != DumpStyleResolvedPointerDescription)
        style = DumpStyleLoadAddress;

    ExecutionContext exe_ctx (exe_scope);
    Target *target = exe_ctx.GetTargetPtr();
    // If addr_byte_size is UINT32_MAX, then determine the correct address
    // byte size for the process or default to the size of addr_t
    if (addr_size == UINT32_MAX)
    {
        if (target)
            addr_size = target->GetArchitecture().GetAddressByteSize ();
        else
            addr_size = sizeof(addr_t);
    }

    Address so_addr;
    switch (style)
    {
    case DumpStyleInvalid:
        return false;

    case DumpStyleSectionNameOffset:
        if (section_sp)
        {
            section_sp->DumpName(s);
            s->Printf (" + %" PRIu64, m_offset.load());
        }
        else
        {
            s->Address(m_offset, addr_size);
        }
        break;

    case DumpStyleSectionPointerOffset:
        s->Printf("(Section *)%p + ", static_cast<void*>(section_sp.get()));
        s->Address(m_offset, addr_size);
        break;

    case DumpStyleModuleWithFileAddress:
        if (section_sp)
        {
            s->Printf("%s[", section_sp->GetModule()->GetFileSpec().GetFilename().AsCString("<Unknown>"));
        }
        // Fall through
    case DumpStyleFileAddress:
        {
            addr_t file_addr = GetFileAddress();
            if (file_addr == LLDB_INVALID_ADDRESS)
            {
                if (fallback_style != DumpStyleInvalid)
                    return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
                return false;
            }
            s->Address (file_addr, addr_size);
            if (style == DumpStyleModuleWithFileAddress && section_sp)
                s->PutChar(']');
        }
        break;

    case DumpStyleLoadAddress:
        {
            addr_t load_addr = GetLoadAddress (target);
            if (load_addr == LLDB_INVALID_ADDRESS)
            {
                if (fallback_style != DumpStyleInvalid)
                    return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
                return false;
            }
            s->Address (load_addr, addr_size);
        }
        break;

    case DumpStyleResolvedDescription:
    case DumpStyleResolvedDescriptionNoModule:
    case DumpStyleResolvedDescriptionNoFunctionArguments:
    case DumpStyleNoFunctionName:
        if (IsSectionOffset())
        {
            uint32_t pointer_size = 4;
            ModuleSP module_sp (GetModule());
            if (target)
                pointer_size = target->GetArchitecture().GetAddressByteSize();
            else if (module_sp)
                pointer_size = module_sp->GetArchitecture().GetAddressByteSize();

            bool showed_info = false;
            if (section_sp)
            {
                SectionType sect_type = section_sp->GetType();
                switch (sect_type)
                {
                case eSectionTypeData:
                    if (module_sp)
                    {
                        SymbolVendor *sym_vendor = module_sp->GetSymbolVendor();
                        if (sym_vendor)
                        {
                            Symtab *symtab = sym_vendor->GetSymtab();
                            if (symtab)
                            {
                                const addr_t file_Addr = GetFileAddress();
                                Symbol *symbol = symtab->FindSymbolContainingFileAddress (file_Addr);
                                if (symbol)
                                {
                                    const char *symbol_name = symbol->GetName().AsCString();
                                    if (symbol_name)
                                    {
                                        s->PutCString(symbol_name);
                                        addr_t delta = file_Addr - symbol->GetAddress().GetFileAddress();
                                        if (delta)
                                            s->Printf(" + %" PRIu64, delta);
                                        showed_info = true;
                                    }
                                }
                            }
                        }
                    }
                    break;

                case eSectionTypeDataCString:
                    // Read the C string from memory and display it
                    showed_info = true;
                    ReadCStringFromMemory (exe_scope, *this, s);
                    break;

                case eSectionTypeDataCStringPointers:
                    {
                        if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
                        {
#if VERBOSE_OUTPUT
                            s->PutCString("(char *)");
                            so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
                            s->PutCString(": ");
#endif
                            showed_info = true;
                            ReadCStringFromMemory (exe_scope, so_addr, s);
                        }
                    }
                    break;

                case eSectionTypeDataObjCMessageRefs:
                    {
                        if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
                        {
                            if (target && so_addr.IsSectionOffset())
                            {
                                SymbolContext func_sc;
                                target->GetImages().ResolveSymbolContextForAddress (so_addr,
                                                                                             eSymbolContextEverything,
                                                                                             func_sc);
                                if (func_sc.function || func_sc.symbol)
                                {
                                    showed_info = true;
#if VERBOSE_OUTPUT
                                    s->PutCString ("(objc_msgref *) -> { (func*)");
                                    so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
#else
                                    s->PutCString ("{ ");
#endif
                                    Address cstr_addr(*this);
                                    cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size);
                                    func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true, true);
                                    if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr))
                                    {
#if VERBOSE_OUTPUT
                                        s->PutCString("), (char *)");
                                        so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
                                        s->PutCString(" (");
#else
                                        s->PutCString(", ");
#endif
                                        ReadCStringFromMemory (exe_scope, so_addr, s);
                                    }
#if VERBOSE_OUTPUT
                                    s->PutCString(") }");
#else
                                    s->PutCString(" }");
#endif
                                }
                            }
                        }
                    }
                    break;

                case eSectionTypeDataObjCCFStrings:
                    {
                        Address cfstring_data_addr(*this);
                        cfstring_data_addr.SetOffset(cfstring_data_addr.GetOffset() + (2 * pointer_size));
                        if (ReadAddress (exe_scope, cfstring_data_addr, pointer_size, so_addr))
                        {
#if VERBOSE_OUTPUT
                            s->PutCString("(CFString *) ");
                            cfstring_data_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
                            s->PutCString(" -> @");
#else
                            s->PutChar('@');
#endif
                            if (so_addr.Dump(s, exe_scope, DumpStyleResolvedDescription))
                                showed_info = true;
                        }
                    }
                    break;

                case eSectionTypeData4:
                    // Read the 4 byte data and display it
                    showed_info = true;
                    s->PutCString("(uint32_t) ");
                    DumpUInt (exe_scope, *this, 4, s);
                    break;

                case eSectionTypeData8:
                    // Read the 8 byte data and display it
                    showed_info = true;
                    s->PutCString("(uint64_t) ");
                    DumpUInt (exe_scope, *this, 8, s);
                    break;

                case eSectionTypeData16:
                    // Read the 16 byte data and display it
                    showed_info = true;
                    s->PutCString("(uint128_t) ");
                    DumpUInt (exe_scope, *this, 16, s);
                    break;

                case eSectionTypeDataPointers:
                    // Read the pointer data and display it
                    {
                        if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
                        {
                            s->PutCString ("(void *)");
                            so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);

                            showed_info = true;
                            if (so_addr.IsSectionOffset())
                            {
                                SymbolContext pointer_sc;
                                if (target)
                                {
                                    target->GetImages().ResolveSymbolContextForAddress (so_addr,
                                                                                                 eSymbolContextEverything,
                                                                                                 pointer_sc);
                                    if (pointer_sc.function || pointer_sc.symbol)
                                    {
                                        s->PutCString(": ");
                                        pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true, true);
                                    }
                                }
                            }
                        }
                    }
                    break;

                default:
                    break;
                }
            }

            if (!showed_info)
            {
                if (module_sp)
                {
                    SymbolContext sc;
                    module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything | eSymbolContextVariable, sc);
                    if (sc.function || sc.symbol)
                    {
                        bool show_stop_context = true;
                        const bool show_module = (style == DumpStyleResolvedDescription);
                        const bool show_fullpaths = false; 
                        const bool show_inlined_frames = true;
                        const bool show_function_arguments = (style != DumpStyleResolvedDescriptionNoFunctionArguments);
                        const bool show_function_name = (style != DumpStyleNoFunctionName);
                        if (sc.function == NULL && sc.symbol != NULL)
                        {
                            // If we have just a symbol make sure it is in the right section
                            if (sc.symbol->ValueIsAddress())
                            {
                                if (sc.symbol->GetAddress().GetSection() != GetSection())
                                {
                                    // don't show the module if the symbol is a trampoline symbol
                                    show_stop_context = false;
                                }
                            }
                        }
                        if (show_stop_context)
                        {
                            // We have a function or a symbol from the same
                            // sections as this address.
                            sc.DumpStopContext (s, 
                                                exe_scope, 
                                                *this, 
                                                show_fullpaths, 
                                                show_module, 
                                                show_inlined_frames,
                                                show_function_arguments,
                                                show_function_name);
                        }
                        else
                        {
                            // We found a symbol but it was in a different
                            // section so it isn't the symbol we should be
                            // showing, just show the section name + offset
                            Dump (s, exe_scope, DumpStyleSectionNameOffset);
                        }
                    }
                }
            }
        }
        else
        {
            if (fallback_style != DumpStyleInvalid)
                return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
            return false;
        }
        break;

    case DumpStyleDetailedSymbolContext:
        if (IsSectionOffset())
        {
            ModuleSP module_sp (GetModule());
            if (module_sp)
            {
                SymbolContext sc;
                module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything | eSymbolContextVariable, sc);
                if (sc.symbol)
                {
                    // If we have just a symbol make sure it is in the same section
                    // as our address. If it isn't, then we might have just found
                    // the last symbol that came before the address that we are 
                    // looking up that has nothing to do with our address lookup.
                    if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddress().GetSection() != GetSection())
                        sc.symbol = NULL;
                }
                sc.GetDescription(s, eDescriptionLevelBrief, target);
                
                if (sc.block)
                {
                    bool can_create = true;
                    bool get_parent_variables = true;
                    bool stop_if_block_is_inlined_function = false;
                    VariableList variable_list;
                    sc.block->AppendVariables (can_create,
                                               get_parent_variables, 
                                               stop_if_block_is_inlined_function, 
                                               &variable_list);
                    
                    const size_t num_variables = variable_list.GetSize();
                    for (size_t var_idx = 0; var_idx < num_variables; ++var_idx)
                    {
                        Variable *var = variable_list.GetVariableAtIndex (var_idx).get();
                        if (var && var->LocationIsValidForAddress (*this))
                        {
                            s->Indent();
                            s->Printf ("   Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\"",
                                       var->GetID(),
                                       var->GetName().GetCString());
                            Type *type = var->GetType();
                            if (type)
                                s->Printf(", type = \"%s\"", type->GetName().GetCString());
                            else
                                s->PutCString(", type = <unknown>");
                            s->PutCString(", location = ");
                            var->DumpLocationForAddress(s, *this);
                            s->PutCString(", decl = ");
                            var->GetDeclaration().DumpStopContext(s, false);
                            s->EOL();
                        }
                    }
                }
            }
        }
        else
        {
            if (fallback_style != DumpStyleInvalid)
                return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
            return false;
        }
        break;
    case DumpStyleResolvedPointerDescription:
        {
            Process *process = exe_ctx.GetProcessPtr();
            if (process)
            {
                addr_t load_addr = GetLoadAddress (target);
                if (load_addr != LLDB_INVALID_ADDRESS)
                {
                    Error memory_error;
                    addr_t dereferenced_load_addr = process->ReadPointerFromMemory(load_addr, memory_error);
                    if (dereferenced_load_addr != LLDB_INVALID_ADDRESS)
                    {
                        Address dereferenced_addr;
                        if (dereferenced_addr.SetLoadAddress(dereferenced_load_addr, target))
                        {
                            StreamString strm;
                            if (dereferenced_addr.Dump (&strm, exe_scope, DumpStyleResolvedDescription, DumpStyleInvalid, addr_size))
                            {
                                s->Address (dereferenced_load_addr, addr_size, " -> ", " ");
                                s->Write(strm.GetData(), strm.GetSize());
                                return true;
                            }
                        }
                    }
                }
            }
            if (fallback_style != DumpStyleInvalid)
                return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
            return false;
        }
        break;
    }

    return true;
}

bool
Address::SectionWasDeleted() const
{
    if (GetSection())
        return false;
    return SectionWasDeletedPrivate();
}

bool
Address::SectionWasDeletedPrivate() const
{
    lldb::SectionWP empty_section_wp;

    // If either call to "std::weak_ptr::owner_before(...) value returns true, this
    // indicates that m_section_wp once contained (possibly still does) a reference
    // to a valid shared pointer. This helps us know if we had a valid reference to
    // a section which is now invalid because the module it was in was unloaded/deleted,
    // or if the address doesn't have a valid reference to a section.
    return empty_section_wp.owner_before(m_section_wp) || m_section_wp.owner_before(empty_section_wp);
}

uint32_t
Address::CalculateSymbolContext (SymbolContext *sc, uint32_t resolve_scope) const
{
    sc->Clear(false);
    // Absolute addresses don't have enough information to reconstruct even their target.

    SectionSP section_sp (GetSection());
    if (section_sp)
    {
        ModuleSP module_sp (section_sp->GetModule());
        if (module_sp)
        {
            sc->module_sp = module_sp;
            if (sc->module_sp)
                return sc->module_sp->ResolveSymbolContextForAddress (*this, resolve_scope, *sc);
        }
    }
    return 0;
}

ModuleSP
Address::CalculateSymbolContextModule () const
{
    SectionSP section_sp (GetSection());
    if (section_sp)
        return section_sp->GetModule();
    return ModuleSP();
}

CompileUnit *
Address::CalculateSymbolContextCompileUnit () const
{
    SectionSP section_sp (GetSection());
    if (section_sp)
    {
        SymbolContext sc;
        sc.module_sp = section_sp->GetModule();
        if (sc.module_sp)
        {
            sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextCompUnit, sc);
            return sc.comp_unit;
        }
    }
    return NULL;
}

Function *
Address::CalculateSymbolContextFunction () const
{
    SectionSP section_sp (GetSection());
    if (section_sp)
    {
        SymbolContext sc;
        sc.module_sp = section_sp->GetModule();
        if (sc.module_sp)
        {
            sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextFunction, sc);
            return sc.function;
        }
    }
    return NULL;
}

Block *
Address::CalculateSymbolContextBlock () const
{
    SectionSP section_sp (GetSection());
    if (section_sp)
    {
        SymbolContext sc;
        sc.module_sp = section_sp->GetModule();
        if (sc.module_sp)
        {
            sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextBlock, sc);
            return sc.block;
        }
    }
    return NULL;
}

Symbol *
Address::CalculateSymbolContextSymbol () const
{
    SectionSP section_sp (GetSection());
    if (section_sp)
    {
        SymbolContext sc;
        sc.module_sp = section_sp->GetModule();
        if (sc.module_sp)
        {
            sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextSymbol, sc);
            return sc.symbol;
        }
    }
    return NULL;
}

bool
Address::CalculateSymbolContextLineEntry (LineEntry &line_entry) const
{
    SectionSP section_sp (GetSection());
    if (section_sp)
    {
        SymbolContext sc;
        sc.module_sp = section_sp->GetModule();
        if (sc.module_sp)
        {
            sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextLineEntry, sc);
            if (sc.line_entry.IsValid())
            {
                line_entry = sc.line_entry;
                return true;
            }
        }
    }
    line_entry.Clear();
    return false;
}

int
Address::CompareFileAddress (const Address& a, const Address& b)
{
    addr_t a_file_addr = a.GetFileAddress();
    addr_t b_file_addr = b.GetFileAddress();
    if (a_file_addr < b_file_addr)
        return -1;
    if (a_file_addr > b_file_addr)
        return +1;
    return 0;
}


int
Address::CompareLoadAddress (const Address& a, const Address& b, Target *target)
{
    assert (target != NULL);
    addr_t a_load_addr = a.GetLoadAddress (target);
    addr_t b_load_addr = b.GetLoadAddress (target);
    if (a_load_addr < b_load_addr)
        return -1;
    if (a_load_addr > b_load_addr)
        return +1;
    return 0;
}

int
Address::CompareModulePointerAndOffset (const Address& a, const Address& b)
{
    ModuleSP a_module_sp (a.GetModule());
    ModuleSP b_module_sp (b.GetModule());
    Module *a_module = a_module_sp.get();
    Module *b_module = b_module_sp.get();
    if (a_module < b_module)
        return -1;
    if (a_module > b_module)
        return +1;
    // Modules are the same, just compare the file address since they should
    // be unique
    addr_t a_file_addr = a.GetFileAddress();
    addr_t b_file_addr = b.GetFileAddress();
    if (a_file_addr < b_file_addr)
        return -1;
    if (a_file_addr > b_file_addr)
        return +1;
    return 0;
}


size_t
Address::MemorySize () const
{
    // Noting special for the memory size of a single Address object,
    // it is just the size of itself.
    return sizeof(Address);
}


//----------------------------------------------------------------------
// NOTE: Be careful using this operator. It can correctly compare two 
// addresses from the same Module correctly. It can't compare two 
// addresses from different modules in any meaningful way, but it will
// compare the module pointers.
// 
// To sum things up:
// - works great for addresses within the same module
// - it works for addresses across multiple modules, but don't expect the
//   address results to make much sense
//
// This basically lets Address objects be used in ordered collection 
// classes.
//----------------------------------------------------------------------

bool
lldb_private::operator< (const Address& lhs, const Address& rhs)
{
    ModuleSP lhs_module_sp (lhs.GetModule());
    ModuleSP rhs_module_sp (rhs.GetModule());
    Module *lhs_module = lhs_module_sp.get();
    Module *rhs_module = rhs_module_sp.get();   
    if (lhs_module == rhs_module)
    {
        // Addresses are in the same module, just compare the file addresses
        return lhs.GetFileAddress() < rhs.GetFileAddress();
    }
    else
    {
        // The addresses are from different modules, just use the module
        // pointer value to get consistent ordering
        return lhs_module < rhs_module;
    }
}

bool
lldb_private::operator> (const Address& lhs, const Address& rhs)
{
    ModuleSP lhs_module_sp (lhs.GetModule());
    ModuleSP rhs_module_sp (rhs.GetModule());
    Module *lhs_module = lhs_module_sp.get();
    Module *rhs_module = rhs_module_sp.get();   
    if (lhs_module == rhs_module)
    {
        // Addresses are in the same module, just compare the file addresses
        return lhs.GetFileAddress() > rhs.GetFileAddress();
    }
    else
    {
        // The addresses are from different modules, just use the module
        // pointer value to get consistent ordering
        return lhs_module > rhs_module;
    }
}


// The operator == checks for exact equality only (same section, same offset)
bool
lldb_private::operator== (const Address& a, const Address& rhs)
{
    return  a.GetOffset()  == rhs.GetOffset() &&
            a.GetSection() == rhs.GetSection();
}
// The operator != checks for exact inequality only (differing section, or
// different offset)
bool
lldb_private::operator!= (const Address& a, const Address& rhs)
{
    return  a.GetOffset()  != rhs.GetOffset() ||
            a.GetSection() != rhs.GetSection();
}

AddressClass
Address::GetAddressClass () const
{
    ModuleSP module_sp (GetModule());
    if (module_sp)
    {
        ObjectFile *obj_file = module_sp->GetObjectFile();
        if (obj_file)
        {
            // Give the symbol vendor a chance to add to the unified section list.
            module_sp->GetSymbolVendor();
            return obj_file->GetAddressClass (GetFileAddress());
        }
    }
    return eAddressClassUnknown;
}

bool
Address::SetLoadAddress (lldb::addr_t load_addr, Target *target)
{
    if (target && target->GetSectionLoadList().ResolveLoadAddress(load_addr, *this))
        return true;
    m_section_wp.reset();
    m_offset = load_addr;
    return false;
}

