text: //===-- SBModule.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/API/SBModule.h"
  #include "lldb/API/SBAddress.h"
  #include "lldb/API/SBFileSpec.h"
  #include "lldb/API/SBModuleSpec.h"
  #include "lldb/API/SBProcess.h"
  #include "lldb/API/SBStream.h"
  #include "lldb/API/SBSymbolContextList.h"
  #include "lldb/Core/Log.h"
  #include "lldb/Core/Module.h"
  #include "lldb/Core/Section.h"
  #include "lldb/Core/StreamString.h"
  #include "lldb/Core/ValueObjectList.h"
  #include "lldb/Core/ValueObjectVariable.h"
  #include "lldb/Symbol/ObjectFile.h"
  #include "lldb/Symbol/SymbolFile.h"
  #include "lldb/Symbol/SymbolVendor.h"
  #include "lldb/Symbol/Symtab.h"
  #include "lldb/Symbol/TypeSystem.h"
  #include "lldb/Symbol/VariableList.h"
  #include "lldb/Target/Language.h"
  #include "lldb/Target/Target.h"
  
  using namespace lldb;
  using namespace lldb_private;
  
  SBModule::SBModule() : m_opaque_sp() {}
  
  SBModule::SBModule(const lldb::ModuleSP &module_sp) : m_opaque_sp(module_sp) {}
  
  SBModule::SBModule(const SBModuleSpec &module_spec) : m_opaque_sp() {
    ModuleSP module_sp;
    Error error = ModuleList::GetSharedModule(*module_spec.m_opaque_ap, module_sp,
                                              NULL, NULL, NULL);
    if (module_sp)
      SetSP(module_sp);
  }
  
  SBModule::SBModule(const SBModule &rhs) : m_opaque_sp(rhs.m_opaque_sp) {}
  
  SBModule::SBModule(lldb::SBProcess &process, lldb::addr_t header_addr)
      : m_opaque_sp() {
    ProcessSP process_sp(process.GetSP());
    if (process_sp) {
      m_opaque_sp = process_sp->ReadModuleFromMemory(FileSpec(), header_addr);
      if (m_opaque_sp) {
        Target &target = process_sp->GetTarget();
        bool changed = false;
        m_opaque_sp->SetLoadAddress(target, 0, true, changed);
        target.GetImages().Append(m_opaque_sp);
      }
    }
  }
  
  const SBModule &SBModule::operator=(const SBModule &rhs) {
    if (this != &rhs)
      m_opaque_sp = rhs.m_opaque_sp;
    return *this;
  }
  
  SBModule::~SBModule() {}
  
  bool SBModule::IsValid() const { return m_opaque_sp.get() != NULL; }
  
  void SBModule::Clear() { m_opaque_sp.reset(); }
  
  SBFileSpec SBModule::GetFileSpec() const {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
  
    SBFileSpec file_spec;
    ModuleSP module_sp(GetSP());
    if (module_sp)
      file_spec.SetFileSpec(module_sp->GetFileSpec());
  
    if (log)
      log->Printf("SBModule(%p)::GetFileSpec () => SBFileSpec(%p)",
                  static_cast<void *>(module_sp.get()),
                  static_cast<const void *>(file_spec.get()));
  
    return file_spec;
  }
  
  lldb::SBFileSpec SBModule::GetPlatformFileSpec() const {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
  
    SBFileSpec file_spec;
    ModuleSP module_sp(GetSP());
    if (module_sp)
      file_spec.SetFileSpec(module_sp->GetPlatformFileSpec());
  
    if (log)
      log->Printf("SBModule(%p)::GetPlatformFileSpec () => SBFileSpec(%p)",
                  static_cast<void *>(module_sp.get()),
                  static_cast<const void *>(file_spec.get()));
  
    return file_spec;
  }
  
  bool SBModule::SetPlatformFileSpec(const lldb::SBFileSpec &platform_file) {
    bool result = false;
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
  
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      module_sp->SetPlatformFileSpec(*platform_file);
      result = true;
    }
  
    if (log)
      log->Printf("SBModule(%p)::SetPlatformFileSpec (SBFileSpec(%p (%s)) => %i",
                  static_cast<void *>(module_sp.get()),
                  static_cast<const void *>(platform_file.get()),
                  platform_file->GetPath().c_str(), result);
    return result;
  }
  
  lldb::SBFileSpec SBModule::GetRemoteInstallFileSpec() {
    SBFileSpec sb_file_spec;
    ModuleSP module_sp(GetSP());
    if (module_sp)
      sb_file_spec.SetFileSpec(module_sp->GetRemoteInstallFileSpec());
    return sb_file_spec;
  }
  
  bool SBModule::SetRemoteInstallFileSpec(lldb::SBFileSpec &file) {
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      module_sp->SetRemoteInstallFileSpec(file.ref());
      return true;
    }
    return false;
  }
  
  const uint8_t *SBModule::GetUUIDBytes() const {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
  
    const uint8_t *uuid_bytes = NULL;
    ModuleSP module_sp(GetSP());
    if (module_sp)
      uuid_bytes = (const uint8_t *)module_sp->GetUUID().GetBytes();
  
    if (log) {
      if (uuid_bytes) {
        StreamString s;
        module_sp->GetUUID().Dump(&s);
        log->Printf("SBModule(%p)::GetUUIDBytes () => %s",
                    static_cast<void *>(module_sp.get()), s.GetData());
      } else
        log->Printf("SBModule(%p)::GetUUIDBytes () => NULL",
                    static_cast<void *>(module_sp.get()));
    }
    return uuid_bytes;
  }
  
  const char *SBModule::GetUUIDString() const {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
  
    const char *uuid_cstr = NULL;
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      // We are going to return a "const char *" value through the public
      // API, so we need to constify it so it gets added permanently the
      // string pool and then we don't need to worry about the lifetime of the
      // string as it will never go away once it has been put into the ConstString
      // string pool
      uuid_cstr = ConstString(module_sp->GetUUID().GetAsString()).GetCString();
    }
  
    if (uuid_cstr && uuid_cstr[0]) {
      if (log)
        log->Printf("SBModule(%p)::GetUUIDString () => %s",
                    static_cast<void *>(module_sp.get()), uuid_cstr);
      return uuid_cstr;
    }
  
    if (log)
      log->Printf("SBModule(%p)::GetUUIDString () => NULL",
                  static_cast<void *>(module_sp.get()));
    return NULL;
  }
  
  bool SBModule::operator==(const SBModule &rhs) const {
    if (m_opaque_sp)
      return m_opaque_sp.get() == rhs.m_opaque_sp.get();
    return false;
  }
  
  bool SBModule::operator!=(const SBModule &rhs) const {
    if (m_opaque_sp)
      return m_opaque_sp.get() != rhs.m_opaque_sp.get();
    return false;
  }
  
  ModuleSP SBModule::GetSP() const { return m_opaque_sp; }
  
  void SBModule::SetSP(const ModuleSP &module_sp) { m_opaque_sp = module_sp; }
  
  SBAddress SBModule::ResolveFileAddress(lldb::addr_t vm_addr) {
    lldb::SBAddress sb_addr;
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      Address addr;
      if (module_sp->ResolveFileAddress(vm_addr, addr))
        sb_addr.ref() = addr;
    }
    return sb_addr;
  }
  
  SBSymbolContext
  SBModule::ResolveSymbolContextForAddress(const SBAddress &addr,
                                           uint32_t resolve_scope) {
    SBSymbolContext sb_sc;
    ModuleSP module_sp(GetSP());
    if (module_sp && addr.IsValid())
      module_sp->ResolveSymbolContextForAddress(addr.ref(), resolve_scope,
                                                *sb_sc);
    return sb_sc;
  }
  
  bool SBModule::GetDescription(SBStream &description) {
    Stream &strm = description.ref();
  
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      module_sp->GetDescription(&strm);
    } else
      strm.PutCString("No value");
  
    return true;
  }
  
  uint32_t SBModule::GetNumCompileUnits() {
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      return module_sp->GetNumCompileUnits();
    }
    return 0;
  }
  
  SBCompileUnit SBModule::GetCompileUnitAtIndex(uint32_t index) {
    SBCompileUnit sb_cu;
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(index);
      sb_cu.reset(cu_sp.get());
    }
    return sb_cu;
  }
  
  static Symtab *GetUnifiedSymbolTable(const lldb::ModuleSP &module_sp) {
    if (module_sp) {
      SymbolVendor *symbols = module_sp->GetSymbolVendor();
      if (symbols)
        return symbols->GetSymtab();
    }
    return NULL;
  }
  
  size_t SBModule::GetNumSymbols() {
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      Symtab *symtab = GetUnifiedSymbolTable(module_sp);
      if (symtab)
        return symtab->GetNumSymbols();
    }
    return 0;
  }
  
  SBSymbol SBModule::GetSymbolAtIndex(size_t idx) {
    SBSymbol sb_symbol;
    ModuleSP module_sp(GetSP());
    Symtab *symtab = GetUnifiedSymbolTable(module_sp);
    if (symtab)
      sb_symbol.SetSymbol(symtab->SymbolAtIndex(idx));
    return sb_symbol;
  }
  
  lldb::SBSymbol SBModule::FindSymbol(const char *name,
                                      lldb::SymbolType symbol_type) {
    SBSymbol sb_symbol;
    if (name && name[0]) {
      ModuleSP module_sp(GetSP());
      Symtab *symtab = GetUnifiedSymbolTable(module_sp);
      if (symtab)
        sb_symbol.SetSymbol(symtab->FindFirstSymbolWithNameAndType(
            ConstString(name), symbol_type, Symtab::eDebugAny,
            Symtab::eVisibilityAny));
    }
    return sb_symbol;
  }
  
  lldb::SBSymbolContextList SBModule::FindSymbols(const char *name,
                                                  lldb::SymbolType symbol_type) {
    SBSymbolContextList sb_sc_list;
    if (name && name[0]) {
      ModuleSP module_sp(GetSP());
      Symtab *symtab = GetUnifiedSymbolTable(module_sp);
      if (symtab) {
        std::vector<uint32_t> matching_symbol_indexes;
        const size_t num_matches = symtab->FindAllSymbolsWithNameAndType(
            ConstString(name), symbol_type, matching_symbol_indexes);
        if (num_matches) {
          SymbolContext sc;
          sc.module_sp = module_sp;
          SymbolContextList &sc_list = *sb_sc_list;
          for (size_t i = 0; i < num_matches; ++i) {
            sc.symbol = symtab->SymbolAtIndex(matching_symbol_indexes[i]);
            if (sc.symbol)
              sc_list.Append(sc);
          }
        }
      }
    }
    return sb_sc_list;
  }
  
  size_t SBModule::GetNumSections() {
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      // Give the symbol vendor a chance to add to the unified section list.
      module_sp->GetSymbolVendor();
      SectionList *section_list = module_sp->GetSectionList();
      if (section_list)
        return section_list->GetSize();
    }
    return 0;
  }
  
  SBSection SBModule::GetSectionAtIndex(size_t idx) {
    SBSection sb_section;
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      // Give the symbol vendor a chance to add to the unified section list.
      module_sp->GetSymbolVendor();
      SectionList *section_list = module_sp->GetSectionList();
  
      if (section_list)
        sb_section.SetSP(section_list->GetSectionAtIndex(idx));
    }
    return sb_section;
  }
  
  lldb::SBSymbolContextList SBModule::FindFunctions(const char *name,
                                                    uint32_t name_type_mask) {
    lldb::SBSymbolContextList sb_sc_list;
    ModuleSP module_sp(GetSP());
    if (name && module_sp) {
      const bool append = true;
      const bool symbols_ok = true;
      const bool inlines_ok = true;
      module_sp->FindFunctions(ConstString(name), NULL, name_type_mask,
                               symbols_ok, inlines_ok, append, *sb_sc_list);
    }
    return sb_sc_list;
  }
  
  SBValueList SBModule::FindGlobalVariables(SBTarget &target, const char *name,
                                            uint32_t max_matches) {
    SBValueList sb_value_list;
    ModuleSP module_sp(GetSP());
    if (name && module_sp) {
      VariableList variable_list;
      const uint32_t match_count = module_sp->FindGlobalVariables(
          ConstString(name), NULL, false, max_matches, variable_list);
  
      if (match_count > 0) {
        for (uint32_t i = 0; i < match_count; ++i) {
          lldb::ValueObjectSP valobj_sp;
          TargetSP target_sp(target.GetSP());
          valobj_sp = ValueObjectVariable::Create(
              target_sp.get(), variable_list.GetVariableAtIndex(i));
          if (valobj_sp)
            sb_value_list.Append(SBValue(valobj_sp));
        }
      }
    }
  
    return sb_value_list;
  }
  
  lldb::SBValue SBModule::FindFirstGlobalVariable(lldb::SBTarget &target,
                                                  const char *name) {
    SBValueList sb_value_list(FindGlobalVariables(target, name, 1));
    if (sb_value_list.IsValid() && sb_value_list.GetSize() > 0)
      return sb_value_list.GetValueAtIndex(0);
    return SBValue();
  }
  
  lldb::SBType SBModule::FindFirstType(const char *name_cstr) {
    SBType sb_type;
    ModuleSP module_sp(GetSP());
    if (name_cstr && module_sp) {
      SymbolContext sc;
      const bool exact_match = false;
      ConstString name(name_cstr);
  
      sb_type = SBType(module_sp->FindFirstType(sc, name, exact_match));
  
      if (!sb_type.IsValid()) {
        TypeSystem *type_system =
            module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
        if (type_system)
          sb_type = SBType(type_system->GetBuiltinTypeByName(name));
      }
    }
    return sb_type;
  }
  
  lldb::SBType SBModule::GetBasicType(lldb::BasicType type) {
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      TypeSystem *type_system =
          module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
      if (type_system)
        return SBType(type_system->GetBasicTypeFromAST(type));
    }
    return SBType();
  }
  
  lldb::SBTypeList SBModule::FindTypes(const char *type) {
    SBTypeList retval;
  
    ModuleSP module_sp(GetSP());
    if (type && module_sp) {
      SymbolContext sc;
      TypeList type_list;
      const bool exact_match = false;
      ConstString name(type);
      llvm::DenseSet<SymbolFile *> searched_symbol_files;
      const uint32_t num_matches = module_sp->FindTypes(
          sc, name, exact_match, UINT32_MAX, searched_symbol_files, type_list);
  
      if (num_matches > 0) {
        for (size_t idx = 0; idx < num_matches; idx++) {
          TypeSP type_sp(type_list.GetTypeAtIndex(idx));
          if (type_sp)
            retval.Append(SBType(type_sp));
        }
      } else {
        TypeSystem *type_system =
            module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
        if (type_system) {
          CompilerType compiler_type = type_system->GetBuiltinTypeByName(name);
          if (compiler_type)
            retval.Append(SBType(compiler_type));
        }
      }
    }
  
    return retval;
  }
  
  lldb::SBType SBModule::GetTypeByID(lldb::user_id_t uid) {
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      SymbolVendor *vendor = module_sp->GetSymbolVendor();
      if (vendor) {
        Type *type_ptr = vendor->ResolveTypeUID(uid);
        if (type_ptr)
          return SBType(type_ptr->shared_from_this());
      }
    }
    return SBType();
  }
  
  lldb::SBTypeList SBModule::GetTypes(uint32_t type_mask) {
    SBTypeList sb_type_list;
  
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      SymbolVendor *vendor = module_sp->GetSymbolVendor();
      if (vendor) {
        TypeList type_list;
        vendor->GetTypes(NULL, type_mask, type_list);
        sb_type_list.m_opaque_ap->Append(type_list);
      }
    }
    return sb_type_list;
  }
  
  SBSection SBModule::FindSection(const char *sect_name) {
    SBSection sb_section;
  
    ModuleSP module_sp(GetSP());
    if (sect_name && module_sp) {
      // Give the symbol vendor a chance to add to the unified section list.
      module_sp->GetSymbolVendor();
      SectionList *section_list = module_sp->GetSectionList();
      if (section_list) {
        ConstString const_sect_name(sect_name);
        SectionSP section_sp(section_list->FindSectionByName(const_sect_name));
        if (section_sp) {
          sb_section.SetSP(section_sp);
        }
      }
    }
    return sb_section;
  }
  
  lldb::ByteOrder SBModule::GetByteOrder() {
    ModuleSP module_sp(GetSP());
    if (module_sp)
      return module_sp->GetArchitecture().GetByteOrder();
    return eByteOrderInvalid;
  }
  
  const char *SBModule::GetTriple() {
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      std::string triple(module_sp->GetArchitecture().GetTriple().str());
      // Unique the string so we don't run into ownership issues since
      // the const strings put the string into the string pool once and
      // the strings never comes out
      ConstString const_triple(triple.c_str());
      return const_triple.GetCString();
    }
    return NULL;
  }
  
  uint32_t SBModule::GetAddressByteSize() {
    ModuleSP module_sp(GetSP());
    if (module_sp)
      return module_sp->GetArchitecture().GetAddressByteSize();
    return sizeof(void *);
  }
  
  uint32_t SBModule::GetVersion(uint32_t *versions, uint32_t num_versions) {
    ModuleSP module_sp(GetSP());
    if (module_sp)
      return module_sp->GetVersion(versions, num_versions);
    else {
      if (versions && num_versions) {
        for (uint32_t i = 0; i < num_versions; ++i)
          versions[i] = UINT32_MAX;
      }
      return 0;
    }
  }
  
  lldb::SBFileSpec SBModule::GetSymbolFileSpec() const {
    lldb::SBFileSpec sb_file_spec;
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      SymbolVendor *symbol_vendor_ptr = module_sp->GetSymbolVendor();
      if (symbol_vendor_ptr)
        sb_file_spec.SetFileSpec(symbol_vendor_ptr->GetMainFileSpec());
    }
    return sb_file_spec;
  }
  
  lldb::SBAddress SBModule::GetObjectFileHeaderAddress() const {
    lldb::SBAddress sb_addr;
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      ObjectFile *objfile_ptr = module_sp->GetObjectFile();
      if (objfile_ptr)
        sb_addr.ref() = objfile_ptr->GetHeaderAddress();
    }
    return sb_addr;
  }
  
  lldb::SBError SBModule::IsTypeSystemCompatible(lldb::LanguageType language) {
    SBError sb_error;
    ModuleSP module_sp(GetSP());
    if (module_sp) {
      TypeSystem *type_system = module_sp->GetTypeSystemForLanguage(language);
      if (type_system) {
        sb_error.SetError(type_system->IsCompatible());
      } else {
        sb_error.SetErrorStringWithFormat(
            "no type system for language %s",
            Language::GetNameForLanguageType(language));
      }
    } else {
      sb_error.SetErrorString("invalid module");
    }
    return sb_error;
  }
  