diff options
Diffstat (limited to 'source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp')
| -rw-r--r-- | source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp | 268 | 
1 files changed, 221 insertions, 47 deletions
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 9ef4e9c3c9b1..84ecfdc67bee 100644 --- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -18,21 +18,16 @@  #include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"  #include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"  #include "lldb/Core/ArchSpec.h" -#include "lldb/Core/DataBuffer.h"  #include "lldb/Core/Debugger.h" -#include "lldb/Core/Error.h"  #include "lldb/Core/FileSpecList.h" -#include "lldb/Core/Log.h"  #include "lldb/Core/Module.h"  #include "lldb/Core/ModuleSpec.h"  #include "lldb/Core/PluginManager.h"  #include "lldb/Core/RangeMap.h" +#include "lldb/Core/RegisterValue.h"  #include "lldb/Core/Section.h"  #include "lldb/Core/StreamFile.h" -#include "lldb/Core/StreamString.h"  #include "lldb/Core/Timer.h" -#include "lldb/Core/UUID.h" -#include "lldb/Host/FileSpec.h"  #include "lldb/Host/Host.h"  #include "lldb/Symbol/DWARFCallFrameInfo.h"  #include "lldb/Symbol/ObjectFile.h" @@ -44,9 +39,17 @@  #include "lldb/Target/Target.h"  #include "lldb/Target/Thread.h"  #include "lldb/Target/ThreadList.h" +#include "lldb/Utility/DataBufferLLVM.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/UUID.h"  #include "lldb/Utility/SafeMachO.h" +#include "llvm/Support/MemoryBuffer.h" +  #include "ObjectFileMachO.h"  #if defined(__APPLE__) &&                                                      \ @@ -57,6 +60,8 @@  #ifndef __APPLE__  #include "Utility/UuidCompatibility.h" +#else +#include <uuid/uuid.h>  #endif  #define THUMB_ADDRESS_BIT_MASK 0xfffffffffffffffeull @@ -857,22 +862,30 @@ ObjectFile *ObjectFileMachO::CreateInstance(const lldb::ModuleSP &module_sp,                                              lldb::offset_t file_offset,                                              lldb::offset_t length) {    if (!data_sp) { -    data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); +    data_sp = +        DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset); +    if (!data_sp) +      return nullptr;      data_offset = 0;    } -  if (ObjectFileMachO::MagicBytesMatch(data_sp, data_offset, length)) { -    // Update the data to contain the entire file if it doesn't already -    if (data_sp->GetByteSize() < length) { -      data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); -      data_offset = 0; -    } -    std::unique_ptr<ObjectFile> objfile_ap(new ObjectFileMachO( -        module_sp, data_sp, data_offset, file, file_offset, length)); -    if (objfile_ap.get() && objfile_ap->ParseHeader()) -      return objfile_ap.release(); +  if (!ObjectFileMachO::MagicBytesMatch(data_sp, data_offset, length)) +    return nullptr; + +  // Update the data to contain the entire file if it doesn't already +  if (data_sp->GetByteSize() < length) { +    data_sp = +        DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset); +    if (!data_sp) +      return nullptr; +    data_offset = 0;    } -  return NULL; +  auto objfile_ap = llvm::make_unique<ObjectFileMachO>( +      module_sp, data_sp, data_offset, file, file_offset, length); +  if (!objfile_ap || !objfile_ap->ParseHeader()) +    return nullptr; + +  return objfile_ap.release();  }  ObjectFile *ObjectFileMachO::CreateMemoryInstance( @@ -901,7 +914,8 @@ size_t ObjectFileMachO::GetModuleSpecifications(        size_t header_and_load_cmds =            header.sizeofcmds + MachHeaderSizeFromMagic(header.magic);        if (header_and_load_cmds >= data_sp->GetByteSize()) { -        data_sp = file.ReadFileContents(file_offset, header_and_load_cmds); +        data_sp = DataBufferLLVM::CreateSliceFromPath( +            file.GetPath(), header_and_load_cmds, file_offset);          data.SetData(data_sp);          data_offset = MachHeaderSizeFromMagic(header.magic);        } @@ -1113,8 +1127,8 @@ bool ObjectFileMachO::ParseHeader() {                    ReadMemory(process_sp, m_memory_addr, header_and_lc_size);              } else {                // Read in all only the load command data from the file on disk -              data_sp = -                  m_file.ReadFileContents(m_file_offset, header_and_lc_size); +              data_sp = DataBufferLLVM::CreateSliceFromPath( +                  m_file.GetPath(), header_and_lc_size, m_file_offset);                if (data_sp->GetByteSize() != header_and_lc_size)                  return false;              } @@ -2085,22 +2099,23 @@ UUID ObjectFileMachO::GetSharedCacheUUID(FileSpec dyld_shared_cache,                                           const ByteOrder byte_order,                                           const uint32_t addr_byte_size) {    UUID dsc_uuid; -  DataBufferSP dsc_data_sp = dyld_shared_cache.MemoryMapFileContentsIfLocal( -      0, sizeof(struct lldb_copy_dyld_cache_header_v1)); -  if (dsc_data_sp) { -    DataExtractor dsc_header_data(dsc_data_sp, byte_order, addr_byte_size); - -    char version_str[7]; -    lldb::offset_t offset = 0; -    memcpy(version_str, dsc_header_data.GetData(&offset, 6), 6); -    version_str[6] = '\0'; -    if (strcmp(version_str, "dyld_v") == 0) { -      offset = offsetof(struct lldb_copy_dyld_cache_header_v1, uuid); -      uint8_t uuid_bytes[sizeof(uuid_t)]; -      memcpy(uuid_bytes, dsc_header_data.GetData(&offset, sizeof(uuid_t)), -             sizeof(uuid_t)); -      dsc_uuid.SetBytes(uuid_bytes); -    } +  DataBufferSP DscData = DataBufferLLVM::CreateSliceFromPath( +      dyld_shared_cache.GetPath(), +      sizeof(struct lldb_copy_dyld_cache_header_v1), 0); +  if (!DscData) +    return dsc_uuid; +  DataExtractor dsc_header_data(DscData, byte_order, addr_byte_size); + +  char version_str[7]; +  lldb::offset_t offset = 0; +  memcpy(version_str, dsc_header_data.GetData(&offset, 6), 6); +  version_str[6] = '\0'; +  if (strcmp(version_str, "dyld_v") == 0) { +    offset = offsetof(struct lldb_copy_dyld_cache_header_v1, uuid); +    uint8_t uuid_bytes[sizeof(uuid_t)]; +    memcpy(uuid_bytes, dsc_header_data.GetData(&offset, sizeof(uuid_t)), +           sizeof(uuid_t)); +    dsc_uuid.SetBytes(uuid_bytes);    }    return dsc_uuid;  } @@ -2692,8 +2707,9 @@ size_t ObjectFileMachO::ParseSymtab() {        // Process the dyld shared cache header to find the unmapped symbols -      DataBufferSP dsc_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal( -          0, sizeof(struct lldb_copy_dyld_cache_header_v1)); +      DataBufferSP dsc_data_sp = DataBufferLLVM::CreateSliceFromPath( +          dsc_filespec.GetPath(), sizeof(struct lldb_copy_dyld_cache_header_v1), +          0);        if (!dsc_uuid.IsValid()) {          dsc_uuid = GetSharedCacheUUID(dsc_filespec, byte_order, addr_byte_size);        } @@ -2726,9 +2742,11 @@ size_t ObjectFileMachO::ParseSymtab() {              mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v1)) {            DataBufferSP dsc_mapping_info_data_sp = -              dsc_filespec.MemoryMapFileContentsIfLocal( -                  mappingOffset, -                  sizeof(struct lldb_copy_dyld_cache_mapping_info)); +              DataBufferLLVM::CreateSliceFromPath( +                  dsc_filespec.GetPath(), +                  sizeof(struct lldb_copy_dyld_cache_mapping_info), +                  mappingOffset); +            DataExtractor dsc_mapping_info_data(dsc_mapping_info_data_sp,                                                byte_order, addr_byte_size);            offset = 0; @@ -2750,9 +2768,12 @@ size_t ObjectFileMachO::ParseSymtab() {            if (localSymbolsOffset && localSymbolsSize) {              // Map the local symbols -            if (DataBufferSP dsc_local_symbols_data_sp = -                    dsc_filespec.MemoryMapFileContentsIfLocal( -                        localSymbolsOffset, localSymbolsSize)) { +            DataBufferSP dsc_local_symbols_data_sp = +                DataBufferLLVM::CreateSliceFromPath(dsc_filespec.GetPath(), +                                               localSymbolsSize, +                                               localSymbolsOffset); + +            if (dsc_local_symbols_data_sp) {                DataExtractor dsc_local_symbols_data(dsc_local_symbols_data_sp,                                                     byte_order, addr_byte_size); @@ -5034,6 +5055,7 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {      lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);      std::vector<std::string> rpath_paths;      std::vector<std::string> rpath_relative_paths; +    std::vector<std::string> at_exec_relative_paths;      const bool resolve_path = false; // Don't resolve the dependent file paths                                       // since they may not reside on this system      uint32_t i; @@ -5059,6 +5081,10 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {              if (path[0] == '@') {                if (strncmp(path, "@rpath", strlen("@rpath")) == 0)                  rpath_relative_paths.push_back(path + strlen("@rpath")); +              else if (strncmp(path, "@executable_path",  +                       strlen("@executable_path")) == 0) +                at_exec_relative_paths.push_back(path  +                                                 + strlen("@executable_path"));              } else {                FileSpec file_spec(path, resolve_path);                if (files.AppendIfUnique(file_spec)) @@ -5074,10 +5100,11 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {        offset = cmd_offset + load_cmd.cmdsize;      } +    FileSpec this_file_spec(m_file); +    this_file_spec.ResolvePath(); +          if (!rpath_paths.empty()) {        // Fixup all LC_RPATH values to be absolute paths -      FileSpec this_file_spec(m_file); -      this_file_spec.ResolvePath();        std::string loader_path("@loader_path");        std::string executable_path("@executable_path");        for (auto &rpath : rpath_paths) { @@ -5107,6 +5134,23 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {          }        }      } + +    // We may have @executable_paths but no RPATHS.  Figure those out here. +    // Only do this if this object file is the executable.  We have no way to +    // get back to the actual executable otherwise, so we won't get the right +    // path. +    if (!at_exec_relative_paths.empty() && CalculateType() == eTypeExecutable) { +      FileSpec exec_dir = this_file_spec.CopyByRemovingLastPathComponent(); +      for (const auto &at_exec_relative_path : at_exec_relative_paths) { +        FileSpec file_spec =  +            exec_dir.CopyByAppendingPathComponent(at_exec_relative_path); +        file_spec = file_spec.GetNormalizedPath(); +        if (file_spec.Exists() && files.AppendIfUnique(file_spec)) { +          count++; +          break; +        } +      } +    }    }    return count;  } @@ -5312,6 +5356,136 @@ uint32_t ObjectFileMachO::GetNumThreadContexts() {    return m_thread_context_offsets.GetSize();  } +std::string ObjectFileMachO::GetIdentifierString() { +  std::string result; +  ModuleSP module_sp(GetModule()); +  if (module_sp) { +    std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + +    // First, look over the load commands for an LC_NOTE load command +    // with data_owner string "kern ver str" & use that if found. +    lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); +    for (uint32_t i = 0; i < m_header.ncmds; ++i) { +      const uint32_t cmd_offset = offset; +      load_command lc; +      if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) +          break; +      if (lc.cmd == LC_NOTE) +      { +          char data_owner[17]; +          m_data.CopyData (offset, 16, data_owner); +          data_owner[16] = '\0'; +          offset += 16; +          uint64_t fileoff = m_data.GetU64_unchecked (&offset); +          uint64_t size = m_data.GetU64_unchecked (&offset); + +          // "kern ver str" has a uint32_t version and then a +          // nul terminated c-string. +          if (strcmp ("kern ver str", data_owner) == 0) +          { +              offset = fileoff; +              uint32_t version; +              if (m_data.GetU32 (&offset, &version, 1) != nullptr) +              { +                  if (version == 1) +                  { +                      uint32_t strsize = size - sizeof (uint32_t); +                      char *buf = (char*) malloc (strsize); +                      if (buf) +                      { +                          m_data.CopyData (offset, strsize, buf); +                          buf[strsize - 1] = '\0'; +                          result = buf; +                          if (buf) +                              free (buf); +                          return result; +                      } +                  } +              } +          } +      } +      offset = cmd_offset + lc.cmdsize; +    } + +    // Second, make a pass over the load commands looking for an +    // obsolete LC_IDENT load command. +    offset = MachHeaderSizeFromMagic(m_header.magic); +    for (uint32_t i = 0; i < m_header.ncmds; ++i) { +      const uint32_t cmd_offset = offset; +      struct ident_command ident_command; +      if (m_data.GetU32(&offset, &ident_command, 2) == NULL) +        break; +      if (ident_command.cmd == LC_IDENT && ident_command.cmdsize != 0) { +        char *buf = (char *) malloc (ident_command.cmdsize); +        if (buf != nullptr  +            && m_data.CopyData (offset, ident_command.cmdsize, buf) == ident_command.cmdsize) { +          buf[ident_command.cmdsize - 1] = '\0'; +          result = buf; +        } +        if (buf) +          free (buf); +      } +      offset = cmd_offset + ident_command.cmdsize; +    } + +  } +  return result; +} + +bool ObjectFileMachO::GetCorefileMainBinaryInfo (addr_t &address, UUID &uuid) { +  address = LLDB_INVALID_ADDRESS; +  uuid.Clear(); +  ModuleSP module_sp(GetModule()); +  if (module_sp) { +    std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); +    lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); +    for (uint32_t i = 0; i < m_header.ncmds; ++i) { +      const uint32_t cmd_offset = offset; +      load_command lc; +      if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) +          break; +      if (lc.cmd == LC_NOTE) +      { +          char data_owner[17]; +          memset (data_owner, 0, sizeof (data_owner)); +          m_data.CopyData (offset, 16, data_owner); +          offset += 16; +          uint64_t fileoff = m_data.GetU64_unchecked (&offset); +          uint64_t size = m_data.GetU64_unchecked (&offset); + +          // "main bin spec" (main binary specification) data payload is formatted: +          //    uint32_t version       [currently 1] +          //    uint32_t type          [0 == unspecified, 1 == kernel, 2 == user process] +          //    uint64_t address       [ UINT64_MAX if address not specified ] +          //    uuid_t   uuid          [ all zero's if uuid not specified ] +          //    uint32_t log2_pagesize [ process page size in log base 2, e.g. 4k pages are 12.  0 for unspecified ] + +          if (strcmp ("main bin spec", data_owner) == 0 && size >= 32) +          { +              offset = fileoff; +              uint32_t version; +              if (m_data.GetU32 (&offset, &version, 1) != nullptr && version == 1) +              { +                  uint32_t type = 0; +                  uuid_t raw_uuid; +                  memset (raw_uuid, 0, sizeof (uuid_t)); + +                  if (m_data.GetU32 (&offset, &type, 1) +                      && m_data.GetU64 (&offset, &address, 1) +                      && m_data.CopyData (offset, sizeof (uuid_t), raw_uuid) != 0 +                      && uuid.SetBytes (raw_uuid, sizeof (uuid_t))) +                  { +                      return true; +                  } +              } +          } +      } +      offset = cmd_offset + lc.cmdsize; +    } +  } +  return false; +} +  lldb::RegisterContextSP  ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx,                                           lldb_private::Thread &thread) {  | 
