brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.0 KiB · 6a0b0ff Raw
298 lines · cpp
1//===-- SymbolVendorMacOSX.cpp --------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "SymbolVendorMacOSX.h"10 11#include <cstring>12 13#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"14#include "lldb/Core/Module.h"15#include "lldb/Core/ModuleSpec.h"16#include "lldb/Core/PluginManager.h"17#include "lldb/Core/Section.h"18#include "lldb/Host/Host.h"19#include "lldb/Host/XML.h"20#include "lldb/Symbol/ObjectFile.h"21#include "lldb/Target/Target.h"22#include "lldb/Utility/StreamString.h"23#include "lldb/Utility/Timer.h"24 25using namespace lldb;26using namespace lldb_private;27 28LLDB_PLUGIN_DEFINE(SymbolVendorMacOSX)29 30// SymbolVendorMacOSX constructor31SymbolVendorMacOSX::SymbolVendorMacOSX(const lldb::ModuleSP &module_sp)32    : SymbolVendor(module_sp) {}33 34static bool UUIDsMatch(Module *module, ObjectFile *ofile,35                       lldb_private::Stream *feedback_strm) {36  if (module && ofile) {37    // Make sure the UUIDs match38    lldb_private::UUID dsym_uuid = ofile->GetUUID();39    if (!dsym_uuid) {40      if (feedback_strm) {41        feedback_strm->PutCString(42            "warning: failed to get the uuid for object file: '");43        ofile->GetFileSpec().Dump(feedback_strm->AsRawOstream());44        feedback_strm->PutCString("\n");45      }46      return false;47    }48 49    if (dsym_uuid == module->GetUUID())50      return true;51 52    // Emit some warning messages since the UUIDs do not match!53    if (feedback_strm) {54      feedback_strm->PutCString(55          "warning: UUID mismatch detected between modules:\n    ");56      module->GetUUID().Dump(*feedback_strm);57      feedback_strm->PutChar(' ');58      module->GetFileSpec().Dump(feedback_strm->AsRawOstream());59      feedback_strm->PutCString("\n    ");60      dsym_uuid.Dump(*feedback_strm);61      feedback_strm->PutChar(' ');62      ofile->GetFileSpec().Dump(feedback_strm->AsRawOstream());63      feedback_strm->EOL();64    }65  }66  return false;67}68 69void SymbolVendorMacOSX::Initialize() {70  PluginManager::RegisterPlugin(GetPluginNameStatic(),71                                GetPluginDescriptionStatic(), CreateInstance);72}73 74void SymbolVendorMacOSX::Terminate() {75  PluginManager::UnregisterPlugin(CreateInstance);76}77 78llvm::StringRef SymbolVendorMacOSX::GetPluginDescriptionStatic() {79  return "Symbol vendor for MacOSX that looks for dSYM files that match "80         "executables.";81}82 83// CreateInstance84//85// Platforms can register a callback to use when creating symbol vendors to86// allow for complex debug information file setups, and to also allow for87// finding separate debug information files.88SymbolVendor *89SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp,90                                   lldb_private::Stream *feedback_strm) {91  if (!module_sp)92    return NULL;93 94  ObjectFile *obj_file =95      llvm::dyn_cast_or_null<ObjectFileMachO>(module_sp->GetObjectFile());96  if (!obj_file)97    return NULL;98 99  static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);100  Timer scoped_timer(func_cat,101                     "SymbolVendorMacOSX::CreateInstance (module = %s)",102                     module_sp->GetFileSpec().GetPath().c_str());103  SymbolVendorMacOSX *symbol_vendor = new SymbolVendorMacOSX(module_sp);104  if (symbol_vendor) {105    char path[PATH_MAX];106    path[0] = '\0';107 108    // Try and locate the dSYM file on Mac OS X109    static Timer::Category func_cat2(110        "SymbolVendorMacOSX::CreateInstance() locate dSYM");111    Timer scoped_timer2(112        func_cat2,113        "SymbolVendorMacOSX::CreateInstance (module = %s) locate dSYM",114        module_sp->GetFileSpec().GetPath().c_str());115 116    // First check to see if the module has a symbol file in mind already. If117    // it does, then we MUST use that.118    FileSpec dsym_fspec(module_sp->GetSymbolFileFileSpec());119 120    ObjectFileSP dsym_objfile_sp;121    // On Darwin, we store the debug information either in object files,122    // using the debug map to tie them to the executable, or in a dSYM.  We123    // pass through this routine both for binaries and for .o files, but in the124    // latter case there will never be an external debug file.  So we shouldn't125    // do all the stats needed to find it.126    if (!dsym_fspec && module_sp->GetObjectFile()->CalculateType() !=127        ObjectFile::eTypeObjectFile) {128      // No symbol file was specified in the module, lets try and find one129      // ourselves.130      FileSpec file_spec = obj_file->GetFileSpec();131      if (!file_spec)132        file_spec = module_sp->GetFileSpec();133 134      ModuleSpec module_spec(file_spec, module_sp->GetArchitecture());135      module_spec.GetUUID() = module_sp->GetUUID();136      FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();137 138      dsym_fspec = PluginManager::LocateExecutableSymbolFile(139          module_spec, search_paths, module_sp->GetSymbolLocatorStatistics());140      if (module_spec.GetSourceMappingList().GetSize())141        module_sp->GetSourceMappingList().Append(142            module_spec.GetSourceMappingList(), true);143    }144 145    if (dsym_fspec) {146      // Compute dSYM root.147      std::string dsym_root = dsym_fspec.GetPath();148      const size_t pos = dsym_root.find("/Contents/Resources/");149      dsym_root = pos != std::string::npos ? dsym_root.substr(0, pos) : "";150 151      DataBufferSP dsym_file_data_sp;152      lldb::offset_t dsym_file_data_offset = 0;153      dsym_objfile_sp =154          ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0,155                                 FileSystem::Instance().GetByteSize(dsym_fspec),156                                 dsym_file_data_sp, dsym_file_data_offset);157      // Important to save the dSYM FileSpec so we don't call158      // PluginManager::LocateExecutableSymbolFile a second time while trying to159      // add the symbol ObjectFile to this Module.160      if (dsym_objfile_sp && !module_sp->GetSymbolFileFileSpec()) {161        module_sp->SetSymbolFileFileSpec(dsym_fspec);162      }163      if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm)) {164        // We need a XML parser if we hope to parse a plist...165        if (XMLDocument::XMLEnabled()) {166          if (module_sp->GetSourceMappingList().IsEmpty()) {167            lldb_private::UUID dsym_uuid = dsym_objfile_sp->GetUUID();168            if (dsym_uuid) {169              std::string uuid_str = dsym_uuid.GetAsString();170              if (!uuid_str.empty() && !dsym_root.empty()) {171                char dsym_uuid_plist_path[PATH_MAX];172                snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path),173                         "%s/Contents/Resources/%s.plist", dsym_root.c_str(),174                         uuid_str.c_str());175                FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path);176                if (FileSystem::Instance().Exists(dsym_uuid_plist_spec)) {177                  ApplePropertyList plist(dsym_uuid_plist_path);178                  if (plist) {179                    std::string DBGBuildSourcePath;180                    std::string DBGSourcePath;181 182                    // DBGSourcePathRemapping is a dictionary in the plist183                    // with keys which are DBGBuildSourcePath file paths and184                    // values which are DBGSourcePath file paths185 186                    StructuredData::ObjectSP plist_sp =187                        plist.GetStructuredData();188                    if (plist_sp.get() && plist_sp->GetAsDictionary() &&189                        plist_sp->GetAsDictionary()->HasKey(190                            "DBGSourcePathRemapping") &&191                        plist_sp->GetAsDictionary()192                            ->GetValueForKey("DBGSourcePathRemapping")193                            ->GetAsDictionary()) {194 195                      // If DBGVersion 1 or DBGVersion missing, ignore196                      // DBGSourcePathRemapping. If DBGVersion 2, strip last two197                      // components of path remappings from198                      //                  entries to fix an issue with a199                      //                  specific set of DBGSourcePathRemapping200                      //                  entries that lldb worked with.201                      // If DBGVersion 3, trust & use the source path remappings202                      // as-is.203                      //204 205                      bool new_style_source_remapping_dictionary = false;206                      bool do_truncate_remapping_names = false;207                      std::string original_DBGSourcePath_value = DBGSourcePath;208                      if (plist_sp->GetAsDictionary()->HasKey("DBGVersion")) {209                        std::string version_string =210                            std::string(plist_sp->GetAsDictionary()211                                            ->GetValueForKey("DBGVersion")212                                            ->GetStringValue(""));213                        if (!version_string.empty() &&214                            isdigit(version_string[0])) {215                          int version_number = atoi(version_string.c_str());216                          if (version_number > 1) {217                            new_style_source_remapping_dictionary = true;218                          }219                          if (version_number == 2) {220                            do_truncate_remapping_names = true;221                          }222                        }223                      }224 225                      StructuredData::Dictionary *remappings_dict =226                          plist_sp->GetAsDictionary()227                              ->GetValueForKey("DBGSourcePathRemapping")228                              ->GetAsDictionary();229                      remappings_dict->ForEach(230                          [&module_sp, new_style_source_remapping_dictionary,231                           original_DBGSourcePath_value,232                           do_truncate_remapping_names](233                              llvm::StringRef key,234                              StructuredData::Object *object) -> bool {235                            if (object && object->GetAsString()) {236 237                              // key is DBGBuildSourcePath238                              // object is DBGSourcePath239                              std::string DBGSourcePath =240                                  std::string(object->GetStringValue());241                              if (!new_style_source_remapping_dictionary &&242                                  !original_DBGSourcePath_value.empty()) {243                                DBGSourcePath = original_DBGSourcePath_value;244                              }245                              module_sp->GetSourceMappingList().Append(246                                  key, DBGSourcePath, true);247                              // With version 2 of DBGSourcePathRemapping, we248                              // can chop off the last two filename parts249                              // from the source remapping and get a more250                              // general source remapping that still works.251                              // Add this as another option in addition to252                              // the full source path remap.253                              if (do_truncate_remapping_names) {254                                FileSpec build_path(key);255                                FileSpec source_path(DBGSourcePath.c_str());256                                build_path.RemoveLastPathComponent();257                                build_path.RemoveLastPathComponent();258                                source_path.RemoveLastPathComponent();259                                source_path.RemoveLastPathComponent();260                                module_sp->GetSourceMappingList().Append(261                                    build_path.GetPath(), source_path.GetPath(),262                                    true);263                              }264                            }265                            return true;266                          });267                    }268 269                    // If we have a DBGBuildSourcePath + DBGSourcePath pair,270                    // append those to the source path remappings.271 272                    plist.GetValueAsString("DBGBuildSourcePath",273                                           DBGBuildSourcePath);274                    plist.GetValueAsString("DBGSourcePath", DBGSourcePath);275                    if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {276                      module_sp->GetSourceMappingList().Append(277                          DBGBuildSourcePath, DBGSourcePath, true);278                    }279                  }280                }281              }282            }283          }284        }285 286        symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);287        return symbol_vendor;288      }289    }290 291    // Just create our symbol vendor using the current objfile as this is292    // either an executable with no dSYM (that we could locate), an executable293    // with a dSYM that has a UUID that doesn't match.294    symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this());295  }296  return symbol_vendor;297}298