1 //===-- ProcessMinidump.cpp -------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // Project includes 11 #include "ProcessMinidump.h" 12 #include "ThreadMinidump.h" 13 14 // Other libraries and framework includes 15 #include "lldb/Core/Module.h" 16 #include "lldb/Core/ModuleSpec.h" 17 #include "lldb/Core/PluginManager.h" 18 #include "lldb/Core/Section.h" 19 #include "lldb/Core/State.h" 20 #include "lldb/Target/DynamicLoader.h" 21 #include "lldb/Target/MemoryRegionInfo.h" 22 #include "lldb/Target/SectionLoadList.h" 23 #include "lldb/Target/Target.h" 24 #include "lldb/Target/UnixSignals.h" 25 #include "lldb/Utility/DataBufferLLVM.h" 26 #include "lldb/Utility/LLDBAssert.h" 27 #include "lldb/Utility/Log.h" 28 29 #include "llvm/Support/MemoryBuffer.h" 30 #include "llvm/Support/Threading.h" 31 32 // C includes 33 // C++ includes 34 35 using namespace lldb; 36 using namespace lldb_private; 37 using namespace minidump; 38 39 //------------------------------------------------------------------ 40 /// A placeholder module used for minidumps, where the original 41 /// object files may not be available (so we can't parse the object 42 /// files to extract the set of sections/segments) 43 /// 44 /// This placeholder module has a single synthetic section (.module_image) 45 /// which represents the module memory range covering the whole module. 46 //------------------------------------------------------------------ 47 class PlaceholderModule : public Module { 48 public: 49 PlaceholderModule(const FileSpec &file_spec, const ArchSpec &arch) : 50 Module(file_spec, arch) {} 51 52 // Creates a synthetic module section covering the whole module image 53 // (and sets the section load address as well) 54 void CreateImageSection(const MinidumpModule *module, Target& target) { 55 const ConstString section_name(".module_image"); 56 lldb::SectionSP section_sp(new Section( 57 shared_from_this(), // Module to which this section belongs. 58 nullptr, // ObjectFile 59 0, // Section ID. 60 section_name, // Section name. 61 eSectionTypeContainer, // Section type. 62 module->base_of_image, // VM address. 63 module->size_of_image, // VM size in bytes of this section. 64 0, // Offset of this section in the file. 65 module->size_of_image, // Size of the section as found in the file. 66 12, // Alignment of the section (log2) 67 0, // Flags for this section. 68 1)); // Number of host bytes per target byte 69 section_sp->SetPermissions(ePermissionsExecutable | ePermissionsReadable); 70 GetSectionList()->AddSection(section_sp); 71 target.GetSectionLoadList().SetSectionLoadAddress( 72 section_sp, module->base_of_image); 73 } 74 75 ObjectFile *GetObjectFile() override { return nullptr; } 76 77 SectionList *GetSectionList() override { 78 return Module::GetUnifiedSectionList(); 79 } 80 }; 81 82 ConstString ProcessMinidump::GetPluginNameStatic() { 83 static ConstString g_name("minidump"); 84 return g_name; 85 } 86 87 const char *ProcessMinidump::GetPluginDescriptionStatic() { 88 return "Minidump plug-in."; 89 } 90 91 lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, 92 lldb::ListenerSP listener_sp, 93 const FileSpec *crash_file) { 94 if (!crash_file) 95 return nullptr; 96 97 lldb::ProcessSP process_sp; 98 // Read enough data for the Minidump header 99 constexpr size_t header_size = sizeof(MinidumpHeader); 100 auto DataPtr = 101 DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), header_size, 0); 102 if (!DataPtr) 103 return nullptr; 104 105 assert(DataPtr->GetByteSize() == header_size); 106 107 // first, only try to parse the header, beacuse we need to be fast 108 llvm::ArrayRef<uint8_t> HeaderBytes = DataPtr->GetData(); 109 const MinidumpHeader *header = MinidumpHeader::Parse(HeaderBytes); 110 if (header == nullptr) 111 return nullptr; 112 113 auto AllData = DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), -1, 0); 114 if (!AllData) 115 return nullptr; 116 117 auto minidump_parser = MinidumpParser::Create(AllData); 118 // check if the parser object is valid 119 if (!minidump_parser) 120 return nullptr; 121 122 return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file, 123 minidump_parser.getValue()); 124 } 125 126 bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp, 127 bool plugin_specified_by_name) { 128 return true; 129 } 130 131 ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp, 132 lldb::ListenerSP listener_sp, 133 const FileSpec &core_file, 134 MinidumpParser minidump_parser) 135 : Process(target_sp, listener_sp), m_minidump_parser(minidump_parser), 136 m_core_file(core_file), m_is_wow64(false) {} 137 138 ProcessMinidump::~ProcessMinidump() { 139 Clear(); 140 // We need to call finalize on the process before destroying ourselves 141 // to make sure all of the broadcaster cleanup goes as planned. If we 142 // destruct this class, then Process::~Process() might have problems 143 // trying to fully destroy the broadcaster. 144 Finalize(); 145 } 146 147 void ProcessMinidump::Initialize() { 148 static llvm::once_flag g_once_flag; 149 150 llvm::call_once(g_once_flag, []() { 151 PluginManager::RegisterPlugin(GetPluginNameStatic(), 152 GetPluginDescriptionStatic(), 153 ProcessMinidump::CreateInstance); 154 }); 155 } 156 157 void ProcessMinidump::Terminate() { 158 PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance); 159 } 160 161 Status ProcessMinidump::DoLoadCore() { 162 Status error; 163 164 m_thread_list = m_minidump_parser.GetThreads(); 165 m_active_exception = m_minidump_parser.GetExceptionStream(); 166 ReadModuleList(); 167 GetTarget().SetArchitecture(GetArchitecture()); 168 169 llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid(); 170 if (!pid) { 171 error.SetErrorString("failed to parse PID"); 172 return error; 173 } 174 SetID(pid.getValue()); 175 176 return error; 177 } 178 179 DynamicLoader *ProcessMinidump::GetDynamicLoader() { 180 if (m_dyld_ap.get() == nullptr) 181 m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr)); 182 return m_dyld_ap.get(); 183 } 184 185 ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); } 186 187 uint32_t ProcessMinidump::GetPluginVersion() { return 1; } 188 189 Status ProcessMinidump::DoDestroy() { return Status(); } 190 191 void ProcessMinidump::RefreshStateAfterStop() { 192 if (!m_active_exception) 193 return; 194 195 if (m_active_exception->exception_record.exception_code == 196 MinidumpException::DumpRequested) { 197 return; 198 } 199 200 lldb::StopInfoSP stop_info; 201 lldb::ThreadSP stop_thread; 202 203 Process::m_thread_list.SetSelectedThreadByID(m_active_exception->thread_id); 204 stop_thread = Process::m_thread_list.GetSelectedThread(); 205 ArchSpec arch = GetArchitecture(); 206 207 if (arch.GetTriple().getOS() == llvm::Triple::Linux) { 208 stop_info = StopInfo::CreateStopReasonWithSignal( 209 *stop_thread, m_active_exception->exception_record.exception_code); 210 } else { 211 std::string desc; 212 llvm::raw_string_ostream desc_stream(desc); 213 desc_stream << "Exception " 214 << llvm::format_hex( 215 m_active_exception->exception_record.exception_code, 8) 216 << " encountered at address " 217 << llvm::format_hex( 218 m_active_exception->exception_record.exception_address, 219 8); 220 stop_info = StopInfo::CreateStopReasonWithException( 221 *stop_thread, desc_stream.str().c_str()); 222 } 223 224 stop_thread->SetStopInfo(stop_info); 225 } 226 227 bool ProcessMinidump::IsAlive() { return true; } 228 229 bool ProcessMinidump::WarnBeforeDetach() const { return false; } 230 231 size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size, 232 Status &error) { 233 // Don't allow the caching that lldb_private::Process::ReadMemory does 234 // since we have it all cached in our dump file anyway. 235 return DoReadMemory(addr, buf, size, error); 236 } 237 238 size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, 239 Status &error) { 240 241 llvm::ArrayRef<uint8_t> mem = m_minidump_parser.GetMemory(addr, size); 242 if (mem.empty()) { 243 error.SetErrorString("could not parse memory info"); 244 return 0; 245 } 246 247 std::memcpy(buf, mem.data(), mem.size()); 248 return mem.size(); 249 } 250 251 ArchSpec ProcessMinidump::GetArchitecture() { 252 if (!m_is_wow64) { 253 return m_minidump_parser.GetArchitecture(); 254 } 255 256 llvm::Triple triple; 257 triple.setVendor(llvm::Triple::VendorType::UnknownVendor); 258 triple.setArch(llvm::Triple::ArchType::x86); 259 triple.setOS(llvm::Triple::OSType::Win32); 260 return ArchSpec(triple); 261 } 262 263 Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, 264 MemoryRegionInfo &range_info) { 265 Status error; 266 auto info = m_minidump_parser.GetMemoryRegionInfo(load_addr); 267 if (!info) { 268 error.SetErrorString("No valid MemoryRegionInfo found!"); 269 return error; 270 } 271 range_info = info.getValue(); 272 return error; 273 } 274 275 void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); } 276 277 bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list, 278 ThreadList &new_thread_list) { 279 uint32_t num_threads = 0; 280 if (m_thread_list.size() > 0) 281 num_threads = m_thread_list.size(); 282 283 for (lldb::tid_t tid = 0; tid < num_threads; ++tid) { 284 llvm::ArrayRef<uint8_t> context; 285 if (!m_is_wow64) 286 context = m_minidump_parser.GetThreadContext(m_thread_list[tid]); 287 else 288 context = m_minidump_parser.GetThreadContextWow64(m_thread_list[tid]); 289 290 lldb::ThreadSP thread_sp( 291 new ThreadMinidump(*this, m_thread_list[tid], context)); 292 new_thread_list.AddThread(thread_sp); 293 } 294 return new_thread_list.GetSize(false) > 0; 295 } 296 297 void ProcessMinidump::ReadModuleList() { 298 std::vector<const MinidumpModule *> filtered_modules = 299 m_minidump_parser.GetFilteredModuleList(); 300 301 for (auto module : filtered_modules) { 302 llvm::Optional<std::string> name = 303 m_minidump_parser.GetMinidumpString(module->module_name_rva); 304 305 if (!name) 306 continue; 307 308 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES)); 309 if (log) { 310 log->Printf("ProcessMinidump::%s found module: name: %s %#010" PRIx64 311 "-%#010" PRIx64 " size: %" PRIu32, 312 __FUNCTION__, name.getValue().c_str(), 313 uint64_t(module->base_of_image), 314 module->base_of_image + module->size_of_image, 315 uint32_t(module->size_of_image)); 316 } 317 318 // check if the process is wow64 - a 32 bit windows process running on a 319 // 64 bit windows 320 if (llvm::StringRef(name.getValue()).endswith_lower("wow64.dll")) { 321 m_is_wow64 = true; 322 } 323 324 const auto file_spec = 325 FileSpec(name.getValue(), true, GetArchitecture().GetTriple()); 326 ModuleSpec module_spec = file_spec; 327 Status error; 328 lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error); 329 if (!module_sp || error.Fail()) { 330 // We failed to locate a matching local object file. Fortunately, 331 // the minidump format encodes enough information about each module's 332 // memory range to allow us to create placeholder modules. 333 // 334 // This enables most LLDB functionality involving address-to-module 335 // translations (ex. identifing the module for a stack frame PC) and 336 // modules/sections commands (ex. target modules list, ...) 337 auto placeholder_module = 338 std::make_shared<PlaceholderModule>(file_spec, GetArchitecture()); 339 placeholder_module->CreateImageSection(module, GetTarget()); 340 module_sp = placeholder_module; 341 GetTarget().GetImages().Append(module_sp); 342 } 343 344 if (log) { 345 log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__, 346 name.getValue().c_str()); 347 } 348 349 bool load_addr_changed = false; 350 module_sp->SetLoadAddress(GetTarget(), module->base_of_image, false, 351 load_addr_changed); 352 } 353 } 354 355 bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) { 356 info.Clear(); 357 info.SetProcessID(GetID()); 358 info.SetArchitecture(GetArchitecture()); 359 lldb::ModuleSP module_sp = GetTarget().GetExecutableModule(); 360 if (module_sp) { 361 const bool add_exe_file_as_first_arg = false; 362 info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(), 363 add_exe_file_as_first_arg); 364 } 365 return true; 366 } 367