1349cc55cSDimitry Andric //===-- MinidumpFileBuilder.cpp -------------------------------------------===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric 9349cc55cSDimitry Andric #include "MinidumpFileBuilder.h" 10349cc55cSDimitry Andric 115f757f3fSDimitry Andric #include "Plugins/Process/minidump/RegisterContextMinidump_ARM64.h" 12349cc55cSDimitry Andric #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h" 13349cc55cSDimitry Andric 14349cc55cSDimitry Andric #include "lldb/Core/Module.h" 15349cc55cSDimitry Andric #include "lldb/Core/ModuleList.h" 16349cc55cSDimitry Andric #include "lldb/Core/Section.h" 17*0fca6ea1SDimitry Andric #include "lldb/Target/ABI.h" 18349cc55cSDimitry Andric #include "lldb/Target/MemoryRegionInfo.h" 19349cc55cSDimitry Andric #include "lldb/Target/Process.h" 20349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h" 21349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h" 22349cc55cSDimitry Andric #include "lldb/Target/ThreadList.h" 23*0fca6ea1SDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 24349cc55cSDimitry Andric #include "lldb/Utility/DataExtractor.h" 25*0fca6ea1SDimitry Andric #include "lldb/Utility/LLDBLog.h" 26*0fca6ea1SDimitry Andric #include "lldb/Utility/Log.h" 27*0fca6ea1SDimitry Andric #include "lldb/Utility/RangeMap.h" 28349cc55cSDimitry Andric #include "lldb/Utility/RegisterValue.h" 29349cc55cSDimitry Andric 30349cc55cSDimitry Andric #include "llvm/ADT/StringRef.h" 31349cc55cSDimitry Andric #include "llvm/BinaryFormat/Minidump.h" 32349cc55cSDimitry Andric #include "llvm/Support/ConvertUTF.h" 33*0fca6ea1SDimitry Andric #include "llvm/Support/Endian.h" 34349cc55cSDimitry Andric #include "llvm/Support/Error.h" 35*0fca6ea1SDimitry Andric #include "llvm/TargetParser/Triple.h" 36349cc55cSDimitry Andric 37349cc55cSDimitry Andric #include "Plugins/Process/minidump/MinidumpTypes.h" 38*0fca6ea1SDimitry Andric #include "lldb/lldb-enumerations.h" 39*0fca6ea1SDimitry Andric #include "lldb/lldb-forward.h" 40*0fca6ea1SDimitry Andric #include "lldb/lldb-types.h" 41349cc55cSDimitry Andric 42*0fca6ea1SDimitry Andric #include <algorithm> 43349cc55cSDimitry Andric #include <cinttypes> 44*0fca6ea1SDimitry Andric #include <climits> 45*0fca6ea1SDimitry Andric #include <cstddef> 46*0fca6ea1SDimitry Andric #include <cstdint> 47*0fca6ea1SDimitry Andric #include <functional> 48*0fca6ea1SDimitry Andric #include <iostream> 49*0fca6ea1SDimitry Andric #include <set> 50*0fca6ea1SDimitry Andric #include <utility> 51*0fca6ea1SDimitry Andric #include <vector> 52349cc55cSDimitry Andric 53349cc55cSDimitry Andric using namespace lldb; 54349cc55cSDimitry Andric using namespace lldb_private; 55349cc55cSDimitry Andric using namespace llvm::minidump; 56349cc55cSDimitry Andric 57*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() { 58*0fca6ea1SDimitry Andric // First set the offset on the file, and on the bytes saved 59*0fca6ea1SDimitry Andric m_saved_data_size = HEADER_SIZE; 60*0fca6ea1SDimitry Andric // We know we will have at least Misc, SystemInfo, Modules, and ThreadList 61*0fca6ea1SDimitry Andric // (corresponding memory list for stacks) And an additional memory list for 62*0fca6ea1SDimitry Andric // non-stacks. 63*0fca6ea1SDimitry Andric lldb_private::Target &target = m_process_sp->GetTarget(); 64*0fca6ea1SDimitry Andric m_expected_directories = 6; 65*0fca6ea1SDimitry Andric // Check if OS is linux and reserve directory space for all linux specific 66*0fca6ea1SDimitry Andric // breakpad extension directories. 67*0fca6ea1SDimitry Andric if (target.GetArchitecture().GetTriple().getOS() == 68*0fca6ea1SDimitry Andric llvm::Triple::OSType::Linux) 69*0fca6ea1SDimitry Andric m_expected_directories += 9; 70*0fca6ea1SDimitry Andric 71*0fca6ea1SDimitry Andric // Go through all of the threads and check for exceptions. 72*0fca6ea1SDimitry Andric lldb_private::ThreadList thread_list = m_process_sp->GetThreadList(); 73*0fca6ea1SDimitry Andric const uint32_t num_threads = thread_list.GetSize(); 74*0fca6ea1SDimitry Andric for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 75*0fca6ea1SDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); 76*0fca6ea1SDimitry Andric StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 77*0fca6ea1SDimitry Andric if (stop_info_sp) { 78*0fca6ea1SDimitry Andric const StopReason &stop_reason = stop_info_sp->GetStopReason(); 79*0fca6ea1SDimitry Andric if (stop_reason == StopReason::eStopReasonException || 80*0fca6ea1SDimitry Andric stop_reason == StopReason::eStopReasonSignal) 81*0fca6ea1SDimitry Andric m_expected_directories++; 82*0fca6ea1SDimitry Andric } 83*0fca6ea1SDimitry Andric } 84*0fca6ea1SDimitry Andric 85*0fca6ea1SDimitry Andric m_saved_data_size += 86*0fca6ea1SDimitry Andric m_expected_directories * sizeof(llvm::minidump::Directory); 87*0fca6ea1SDimitry Andric Status error; 88*0fca6ea1SDimitry Andric offset_t new_offset = m_core_file->SeekFromStart(m_saved_data_size); 89*0fca6ea1SDimitry Andric if (new_offset != m_saved_data_size) 90*0fca6ea1SDimitry Andric error.SetErrorStringWithFormat("Failed to fill in header and directory " 91*0fca6ea1SDimitry Andric "sections. Written / Expected (%" PRIx64 92*0fca6ea1SDimitry Andric " / %" PRIx64 ")", 93*0fca6ea1SDimitry Andric new_offset, m_saved_data_size); 94*0fca6ea1SDimitry Andric 95*0fca6ea1SDimitry Andric return error; 96*0fca6ea1SDimitry Andric } 97*0fca6ea1SDimitry Andric 98*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddDirectory(StreamType type, 99*0fca6ea1SDimitry Andric uint64_t stream_size) { 100*0fca6ea1SDimitry Andric // We explicitly cast type, an 32b enum, to uint32_t to avoid warnings. 101*0fca6ea1SDimitry Andric Status error; 102*0fca6ea1SDimitry Andric if (GetCurrentDataEndOffset() > UINT32_MAX) { 103*0fca6ea1SDimitry Andric error.SetErrorStringWithFormat("Unable to add directory for stream type " 104*0fca6ea1SDimitry Andric "%x, offset is greater then 32 bit limit.", 105*0fca6ea1SDimitry Andric (uint32_t)type); 106*0fca6ea1SDimitry Andric return error; 107*0fca6ea1SDimitry Andric } 108*0fca6ea1SDimitry Andric 109*0fca6ea1SDimitry Andric if (m_directories.size() + 1 > m_expected_directories) { 110*0fca6ea1SDimitry Andric error.SetErrorStringWithFormat( 111*0fca6ea1SDimitry Andric "Unable to add directory for stream type %x, exceeded expected number " 112*0fca6ea1SDimitry Andric "of directories %zu.", 113*0fca6ea1SDimitry Andric (uint32_t)type, m_expected_directories); 114*0fca6ea1SDimitry Andric return error; 115*0fca6ea1SDimitry Andric } 116*0fca6ea1SDimitry Andric 117349cc55cSDimitry Andric LocationDescriptor loc; 118349cc55cSDimitry Andric loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size); 119349cc55cSDimitry Andric // Stream will begin at the current end of data section 120349cc55cSDimitry Andric loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 121349cc55cSDimitry Andric 122349cc55cSDimitry Andric Directory dir; 123349cc55cSDimitry Andric dir.Type = static_cast<llvm::support::little_t<StreamType>>(type); 124349cc55cSDimitry Andric dir.Location = loc; 125349cc55cSDimitry Andric 126349cc55cSDimitry Andric m_directories.push_back(dir); 127*0fca6ea1SDimitry Andric return error; 128349cc55cSDimitry Andric } 129349cc55cSDimitry Andric 130*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddSystemInfo() { 131349cc55cSDimitry Andric Status error; 132*0fca6ea1SDimitry Andric const llvm::Triple &target_triple = 133*0fca6ea1SDimitry Andric m_process_sp->GetTarget().GetArchitecture().GetTriple(); 134*0fca6ea1SDimitry Andric error = 135349cc55cSDimitry Andric AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo)); 136*0fca6ea1SDimitry Andric if (error.Fail()) 137*0fca6ea1SDimitry Andric return error; 138349cc55cSDimitry Andric 139349cc55cSDimitry Andric llvm::minidump::ProcessorArchitecture arch; 140349cc55cSDimitry Andric switch (target_triple.getArch()) { 141349cc55cSDimitry Andric case llvm::Triple::ArchType::x86_64: 142349cc55cSDimitry Andric arch = ProcessorArchitecture::AMD64; 143349cc55cSDimitry Andric break; 144349cc55cSDimitry Andric case llvm::Triple::ArchType::x86: 145349cc55cSDimitry Andric arch = ProcessorArchitecture::X86; 146349cc55cSDimitry Andric break; 147349cc55cSDimitry Andric case llvm::Triple::ArchType::arm: 148349cc55cSDimitry Andric arch = ProcessorArchitecture::ARM; 149349cc55cSDimitry Andric break; 150349cc55cSDimitry Andric case llvm::Triple::ArchType::aarch64: 151349cc55cSDimitry Andric arch = ProcessorArchitecture::ARM64; 152349cc55cSDimitry Andric break; 153349cc55cSDimitry Andric case llvm::Triple::ArchType::mips64: 154349cc55cSDimitry Andric case llvm::Triple::ArchType::mips64el: 155349cc55cSDimitry Andric case llvm::Triple::ArchType::mips: 156349cc55cSDimitry Andric case llvm::Triple::ArchType::mipsel: 157349cc55cSDimitry Andric arch = ProcessorArchitecture::MIPS; 158349cc55cSDimitry Andric break; 159349cc55cSDimitry Andric case llvm::Triple::ArchType::ppc64: 160349cc55cSDimitry Andric case llvm::Triple::ArchType::ppc: 161349cc55cSDimitry Andric case llvm::Triple::ArchType::ppc64le: 162349cc55cSDimitry Andric arch = ProcessorArchitecture::PPC; 163349cc55cSDimitry Andric break; 164349cc55cSDimitry Andric default: 165349cc55cSDimitry Andric error.SetErrorStringWithFormat("Architecture %s not supported.", 166349cc55cSDimitry Andric target_triple.getArchName().str().c_str()); 167349cc55cSDimitry Andric return error; 168349cc55cSDimitry Andric }; 169349cc55cSDimitry Andric 170349cc55cSDimitry Andric llvm::support::little_t<OSPlatform> platform_id; 171349cc55cSDimitry Andric switch (target_triple.getOS()) { 172349cc55cSDimitry Andric case llvm::Triple::OSType::Linux: 173349cc55cSDimitry Andric if (target_triple.getEnvironment() == 174349cc55cSDimitry Andric llvm::Triple::EnvironmentType::Android) 175349cc55cSDimitry Andric platform_id = OSPlatform::Android; 176349cc55cSDimitry Andric else 177349cc55cSDimitry Andric platform_id = OSPlatform::Linux; 178349cc55cSDimitry Andric break; 179349cc55cSDimitry Andric case llvm::Triple::OSType::Win32: 180349cc55cSDimitry Andric platform_id = OSPlatform::Win32NT; 181349cc55cSDimitry Andric break; 182349cc55cSDimitry Andric case llvm::Triple::OSType::MacOSX: 183349cc55cSDimitry Andric platform_id = OSPlatform::MacOSX; 184349cc55cSDimitry Andric break; 185349cc55cSDimitry Andric case llvm::Triple::OSType::IOS: 186349cc55cSDimitry Andric platform_id = OSPlatform::IOS; 187349cc55cSDimitry Andric break; 188349cc55cSDimitry Andric default: 189349cc55cSDimitry Andric error.SetErrorStringWithFormat("OS %s not supported.", 190349cc55cSDimitry Andric target_triple.getOSName().str().c_str()); 191349cc55cSDimitry Andric return error; 192349cc55cSDimitry Andric }; 193349cc55cSDimitry Andric 194349cc55cSDimitry Andric llvm::minidump::SystemInfo sys_info; 195349cc55cSDimitry Andric sys_info.ProcessorArch = 196349cc55cSDimitry Andric static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch); 197349cc55cSDimitry Andric // Global offset to beginning of a csd_string in a data section 198349cc55cSDimitry Andric sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>( 199349cc55cSDimitry Andric GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo)); 200349cc55cSDimitry Andric sys_info.PlatformId = platform_id; 201349cc55cSDimitry Andric m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo)); 202349cc55cSDimitry Andric 20304eeddc0SDimitry Andric std::string csd_string; 204349cc55cSDimitry Andric 205349cc55cSDimitry Andric error = WriteString(csd_string, &m_data); 206349cc55cSDimitry Andric if (error.Fail()) { 207349cc55cSDimitry Andric error.SetErrorString("Unable to convert the csd string to UTF16."); 208349cc55cSDimitry Andric return error; 209349cc55cSDimitry Andric } 210349cc55cSDimitry Andric 211349cc55cSDimitry Andric return error; 212349cc55cSDimitry Andric } 213349cc55cSDimitry Andric 214349cc55cSDimitry Andric Status WriteString(const std::string &to_write, 215349cc55cSDimitry Andric lldb_private::DataBufferHeap *buffer) { 216349cc55cSDimitry Andric Status error; 217349cc55cSDimitry Andric // let the StringRef eat also null termination char 218349cc55cSDimitry Andric llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1); 219349cc55cSDimitry Andric llvm::SmallVector<llvm::UTF16, 128> to_write_utf16; 220349cc55cSDimitry Andric 221349cc55cSDimitry Andric bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16); 222349cc55cSDimitry Andric if (!converted) { 223349cc55cSDimitry Andric error.SetErrorStringWithFormat( 224349cc55cSDimitry Andric "Unable to convert the string to UTF16. Failed to convert %s", 225349cc55cSDimitry Andric to_write.c_str()); 226349cc55cSDimitry Andric return error; 227349cc55cSDimitry Andric } 228349cc55cSDimitry Andric 229349cc55cSDimitry Andric // size of the UTF16 string should be written without the null termination 230349cc55cSDimitry Andric // character that is stored in 2 bytes 231349cc55cSDimitry Andric llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2); 232349cc55cSDimitry Andric 233349cc55cSDimitry Andric buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t)); 234349cc55cSDimitry Andric buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes()); 235349cc55cSDimitry Andric 236349cc55cSDimitry Andric return error; 237349cc55cSDimitry Andric } 238349cc55cSDimitry Andric 239349cc55cSDimitry Andric llvm::Expected<uint64_t> getModuleFileSize(Target &target, 240349cc55cSDimitry Andric const ModuleSP &mod) { 241*0fca6ea1SDimitry Andric // JIT module has the same vm and file size. 242349cc55cSDimitry Andric uint64_t SizeOfImage = 0; 243*0fca6ea1SDimitry Andric if (mod->GetObjectFile()->CalculateType() == ObjectFile::Type::eTypeJIT) { 244*0fca6ea1SDimitry Andric for (const auto §ion : *mod->GetObjectFile()->GetSectionList()) { 245*0fca6ea1SDimitry Andric SizeOfImage += section->GetByteSize(); 246*0fca6ea1SDimitry Andric } 247*0fca6ea1SDimitry Andric return SizeOfImage; 248*0fca6ea1SDimitry Andric } 249*0fca6ea1SDimitry Andric SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection(); 250349cc55cSDimitry Andric 251349cc55cSDimitry Andric if (!sect_sp) { 252349cc55cSDimitry Andric return llvm::createStringError(std::errc::operation_not_supported, 253349cc55cSDimitry Andric "Couldn't obtain the section information."); 254349cc55cSDimitry Andric } 255349cc55cSDimitry Andric lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target); 256349cc55cSDimitry Andric // Use memory size since zero fill sections, like ".bss", will be smaller on 257349cc55cSDimitry Andric // disk. 258349cc55cSDimitry Andric lldb::addr_t sect_size = sect_sp->GetByteSize(); 259349cc55cSDimitry Andric // This will usually be zero, but make sure to calculate the BaseOfImage 260349cc55cSDimitry Andric // offset. 261349cc55cSDimitry Andric const lldb::addr_t base_sect_offset = 262349cc55cSDimitry Andric mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) - 263349cc55cSDimitry Andric sect_addr; 264349cc55cSDimitry Andric SizeOfImage = sect_size - base_sect_offset; 265349cc55cSDimitry Andric lldb::addr_t next_sect_addr = sect_addr + sect_size; 266349cc55cSDimitry Andric Address sect_so_addr; 267349cc55cSDimitry Andric target.ResolveLoadAddress(next_sect_addr, sect_so_addr); 268349cc55cSDimitry Andric lldb::SectionSP next_sect_sp = sect_so_addr.GetSection(); 269349cc55cSDimitry Andric while (next_sect_sp && 270349cc55cSDimitry Andric next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) { 271349cc55cSDimitry Andric sect_size = sect_sp->GetByteSize(); 272349cc55cSDimitry Andric SizeOfImage += sect_size; 273349cc55cSDimitry Andric next_sect_addr += sect_size; 274349cc55cSDimitry Andric target.ResolveLoadAddress(next_sect_addr, sect_so_addr); 275349cc55cSDimitry Andric next_sect_sp = sect_so_addr.GetSection(); 276349cc55cSDimitry Andric } 277349cc55cSDimitry Andric 278349cc55cSDimitry Andric return SizeOfImage; 279349cc55cSDimitry Andric } 280349cc55cSDimitry Andric 281349cc55cSDimitry Andric // ModuleList stream consists of a number of modules, followed by an array 282349cc55cSDimitry Andric // of llvm::minidump::Module's structures. Every structure informs about a 283349cc55cSDimitry Andric // single module. Additional data of variable length, such as module's names, 284349cc55cSDimitry Andric // are stored just after the ModuleList stream. The llvm::minidump::Module 285349cc55cSDimitry Andric // structures point to this helper data by global offset. 286*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddModuleList() { 287349cc55cSDimitry Andric constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module); 288349cc55cSDimitry Andric Status error; 289349cc55cSDimitry Andric 290*0fca6ea1SDimitry Andric lldb_private::Target &target = m_process_sp->GetTarget(); 291349cc55cSDimitry Andric const ModuleList &modules = target.GetImages(); 292349cc55cSDimitry Andric llvm::support::ulittle32_t modules_count = 293349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(modules.GetSize()); 294349cc55cSDimitry Andric 295349cc55cSDimitry Andric // This helps us with getting the correct global offset in minidump 296349cc55cSDimitry Andric // file later, when we will be setting up offsets from the 297349cc55cSDimitry Andric // the llvm::minidump::Module's structures into helper data 298349cc55cSDimitry Andric size_t size_before = GetCurrentDataEndOffset(); 299349cc55cSDimitry Andric 300349cc55cSDimitry Andric // This is the size of the main part of the ModuleList stream. 301349cc55cSDimitry Andric // It consists of a module number and corresponding number of 302349cc55cSDimitry Andric // structs describing individual modules 303349cc55cSDimitry Andric size_t module_stream_size = 304349cc55cSDimitry Andric sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size; 305349cc55cSDimitry Andric 306349cc55cSDimitry Andric // Adding directory describing this stream. 307*0fca6ea1SDimitry Andric error = AddDirectory(StreamType::ModuleList, module_stream_size); 308*0fca6ea1SDimitry Andric if (error.Fail()) 309*0fca6ea1SDimitry Andric return error; 310349cc55cSDimitry Andric 311349cc55cSDimitry Andric m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t)); 312349cc55cSDimitry Andric 313349cc55cSDimitry Andric // Temporary storage for the helper data (of variable length) 314349cc55cSDimitry Andric // as these cannot be dumped to m_data before dumping entire 315349cc55cSDimitry Andric // array of module structures. 316349cc55cSDimitry Andric DataBufferHeap helper_data; 317349cc55cSDimitry Andric 318349cc55cSDimitry Andric for (size_t i = 0; i < modules_count; ++i) { 319349cc55cSDimitry Andric ModuleSP mod = modules.GetModuleAtIndex(i); 320349cc55cSDimitry Andric std::string module_name = mod->GetSpecificationDescription(); 321349cc55cSDimitry Andric auto maybe_mod_size = getModuleFileSize(target, mod); 322349cc55cSDimitry Andric if (!maybe_mod_size) { 323*0fca6ea1SDimitry Andric llvm::Error mod_size_err = maybe_mod_size.takeError(); 324*0fca6ea1SDimitry Andric llvm::handleAllErrors(std::move(mod_size_err), 325*0fca6ea1SDimitry Andric [&](const llvm::ErrorInfoBase &E) { 326*0fca6ea1SDimitry Andric error.SetErrorStringWithFormat( 327*0fca6ea1SDimitry Andric "Unable to get the size of module %s: %s.", 328*0fca6ea1SDimitry Andric module_name.c_str(), E.message().c_str()); 329*0fca6ea1SDimitry Andric }); 330349cc55cSDimitry Andric return error; 331349cc55cSDimitry Andric } 332349cc55cSDimitry Andric 333349cc55cSDimitry Andric uint64_t mod_size = std::move(*maybe_mod_size); 334349cc55cSDimitry Andric 335349cc55cSDimitry Andric llvm::support::ulittle32_t signature = 336349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>( 337349cc55cSDimitry Andric static_cast<uint32_t>(minidump::CvSignature::ElfBuildId)); 338349cc55cSDimitry Andric auto uuid = mod->GetUUID().GetBytes(); 339349cc55cSDimitry Andric 340349cc55cSDimitry Andric VSFixedFileInfo info; 341349cc55cSDimitry Andric info.Signature = static_cast<llvm::support::ulittle32_t>(0u); 342349cc55cSDimitry Andric info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u); 343349cc55cSDimitry Andric info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u); 344349cc55cSDimitry Andric info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u); 345349cc55cSDimitry Andric info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u); 346349cc55cSDimitry Andric info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u); 347349cc55cSDimitry Andric info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u); 348349cc55cSDimitry Andric info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u); 349349cc55cSDimitry Andric info.FileOS = static_cast<llvm::support::ulittle32_t>(0u); 350349cc55cSDimitry Andric info.FileType = static_cast<llvm::support::ulittle32_t>(0u); 351349cc55cSDimitry Andric info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u); 352349cc55cSDimitry Andric info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u); 353349cc55cSDimitry Andric info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u); 354349cc55cSDimitry Andric 355349cc55cSDimitry Andric LocationDescriptor ld; 356349cc55cSDimitry Andric ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u); 357349cc55cSDimitry Andric ld.RVA = static_cast<llvm::support::ulittle32_t>(0u); 358349cc55cSDimitry Andric 359349cc55cSDimitry Andric // Setting up LocationDescriptor for uuid string. The global offset into 360349cc55cSDimitry Andric // minidump file is calculated. 361349cc55cSDimitry Andric LocationDescriptor ld_cv; 362349cc55cSDimitry Andric ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>( 363349cc55cSDimitry Andric sizeof(llvm::support::ulittle32_t) + uuid.size()); 364349cc55cSDimitry Andric ld_cv.RVA = static_cast<llvm::support::ulittle32_t>( 365349cc55cSDimitry Andric size_before + module_stream_size + helper_data.GetByteSize()); 366349cc55cSDimitry Andric 367349cc55cSDimitry Andric helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t)); 368349cc55cSDimitry Andric helper_data.AppendData(uuid.begin(), uuid.size()); 369349cc55cSDimitry Andric 370349cc55cSDimitry Andric llvm::minidump::Module m; 371349cc55cSDimitry Andric m.BaseOfImage = static_cast<llvm::support::ulittle64_t>( 372349cc55cSDimitry Andric mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target)); 373349cc55cSDimitry Andric m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size); 374349cc55cSDimitry Andric m.Checksum = static_cast<llvm::support::ulittle32_t>(0); 37504eeddc0SDimitry Andric m.TimeDateStamp = 37604eeddc0SDimitry Andric static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); 377349cc55cSDimitry Andric m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>( 378349cc55cSDimitry Andric size_before + module_stream_size + helper_data.GetByteSize()); 379349cc55cSDimitry Andric m.VersionInfo = info; 380349cc55cSDimitry Andric m.CvRecord = ld_cv; 381349cc55cSDimitry Andric m.MiscRecord = ld; 382349cc55cSDimitry Andric 383349cc55cSDimitry Andric error = WriteString(module_name, &helper_data); 384349cc55cSDimitry Andric 385349cc55cSDimitry Andric if (error.Fail()) 386349cc55cSDimitry Andric return error; 387349cc55cSDimitry Andric 388349cc55cSDimitry Andric m_data.AppendData(&m, sizeof(llvm::minidump::Module)); 389349cc55cSDimitry Andric } 390349cc55cSDimitry Andric 391349cc55cSDimitry Andric m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 392349cc55cSDimitry Andric return error; 393349cc55cSDimitry Andric } 394349cc55cSDimitry Andric 395349cc55cSDimitry Andric uint16_t read_register_u16_raw(RegisterContext *reg_ctx, 3965f757f3fSDimitry Andric llvm::StringRef reg_name) { 397349cc55cSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 398349cc55cSDimitry Andric if (!reg_info) 399349cc55cSDimitry Andric return 0; 400349cc55cSDimitry Andric lldb_private::RegisterValue reg_value; 401349cc55cSDimitry Andric bool success = reg_ctx->ReadRegister(reg_info, reg_value); 402349cc55cSDimitry Andric if (!success) 403349cc55cSDimitry Andric return 0; 404349cc55cSDimitry Andric return reg_value.GetAsUInt16(); 405349cc55cSDimitry Andric } 406349cc55cSDimitry Andric 407349cc55cSDimitry Andric uint32_t read_register_u32_raw(RegisterContext *reg_ctx, 4085f757f3fSDimitry Andric llvm::StringRef reg_name) { 409349cc55cSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 410349cc55cSDimitry Andric if (!reg_info) 411349cc55cSDimitry Andric return 0; 412349cc55cSDimitry Andric lldb_private::RegisterValue reg_value; 413349cc55cSDimitry Andric bool success = reg_ctx->ReadRegister(reg_info, reg_value); 414349cc55cSDimitry Andric if (!success) 415349cc55cSDimitry Andric return 0; 416349cc55cSDimitry Andric return reg_value.GetAsUInt32(); 417349cc55cSDimitry Andric } 418349cc55cSDimitry Andric 419349cc55cSDimitry Andric uint64_t read_register_u64_raw(RegisterContext *reg_ctx, 4205f757f3fSDimitry Andric llvm::StringRef reg_name) { 421349cc55cSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 422349cc55cSDimitry Andric if (!reg_info) 423349cc55cSDimitry Andric return 0; 424349cc55cSDimitry Andric lldb_private::RegisterValue reg_value; 425349cc55cSDimitry Andric bool success = reg_ctx->ReadRegister(reg_info, reg_value); 426349cc55cSDimitry Andric if (!success) 427349cc55cSDimitry Andric return 0; 428349cc55cSDimitry Andric return reg_value.GetAsUInt64(); 429349cc55cSDimitry Andric } 430349cc55cSDimitry Andric 431349cc55cSDimitry Andric llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx, 4325f757f3fSDimitry Andric llvm::StringRef reg_name) { 433349cc55cSDimitry Andric return static_cast<llvm::support::ulittle16_t>( 434349cc55cSDimitry Andric read_register_u16_raw(reg_ctx, reg_name)); 435349cc55cSDimitry Andric } 436349cc55cSDimitry Andric 437349cc55cSDimitry Andric llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx, 4385f757f3fSDimitry Andric llvm::StringRef reg_name) { 439349cc55cSDimitry Andric return static_cast<llvm::support::ulittle32_t>( 440349cc55cSDimitry Andric read_register_u32_raw(reg_ctx, reg_name)); 441349cc55cSDimitry Andric } 442349cc55cSDimitry Andric 443349cc55cSDimitry Andric llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx, 4445f757f3fSDimitry Andric llvm::StringRef reg_name) { 445349cc55cSDimitry Andric return static_cast<llvm::support::ulittle64_t>( 446349cc55cSDimitry Andric read_register_u64_raw(reg_ctx, reg_name)); 447349cc55cSDimitry Andric } 448349cc55cSDimitry Andric 4495f757f3fSDimitry Andric void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name, 4505f757f3fSDimitry Andric uint8_t *dst) { 4515f757f3fSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 4525f757f3fSDimitry Andric if (reg_info) { 4535f757f3fSDimitry Andric lldb_private::RegisterValue reg_value; 4545f757f3fSDimitry Andric if (reg_ctx->ReadRegister(reg_info, reg_value)) { 4555f757f3fSDimitry Andric Status error; 4565f757f3fSDimitry Andric uint32_t bytes_copied = reg_value.GetAsMemoryData( 4575f757f3fSDimitry Andric *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error); 4585f757f3fSDimitry Andric if (bytes_copied == 16) 4595f757f3fSDimitry Andric return; 4605f757f3fSDimitry Andric } 4615f757f3fSDimitry Andric } 4625f757f3fSDimitry Andric // If anything goes wrong, then zero out the register value. 4635f757f3fSDimitry Andric memset(dst, 0, 16); 4645f757f3fSDimitry Andric } 4655f757f3fSDimitry Andric 466349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64 4675f757f3fSDimitry Andric GetThreadContext_x86_64(RegisterContext *reg_ctx) { 468972a253aSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64 thread_context = {}; 469fcaf7f86SDimitry Andric thread_context.p1_home = {}; 470349cc55cSDimitry Andric thread_context.context_flags = static_cast<uint32_t>( 471349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag | 472349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Control | 473349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments | 474349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer); 475349cc55cSDimitry Andric thread_context.rax = read_register_u64(reg_ctx, "rax"); 476349cc55cSDimitry Andric thread_context.rbx = read_register_u64(reg_ctx, "rbx"); 477349cc55cSDimitry Andric thread_context.rcx = read_register_u64(reg_ctx, "rcx"); 478349cc55cSDimitry Andric thread_context.rdx = read_register_u64(reg_ctx, "rdx"); 479349cc55cSDimitry Andric thread_context.rdi = read_register_u64(reg_ctx, "rdi"); 480349cc55cSDimitry Andric thread_context.rsi = read_register_u64(reg_ctx, "rsi"); 481349cc55cSDimitry Andric thread_context.rbp = read_register_u64(reg_ctx, "rbp"); 482349cc55cSDimitry Andric thread_context.rsp = read_register_u64(reg_ctx, "rsp"); 483349cc55cSDimitry Andric thread_context.r8 = read_register_u64(reg_ctx, "r8"); 484349cc55cSDimitry Andric thread_context.r9 = read_register_u64(reg_ctx, "r9"); 485349cc55cSDimitry Andric thread_context.r10 = read_register_u64(reg_ctx, "r10"); 486349cc55cSDimitry Andric thread_context.r11 = read_register_u64(reg_ctx, "r11"); 487349cc55cSDimitry Andric thread_context.r12 = read_register_u64(reg_ctx, "r12"); 488349cc55cSDimitry Andric thread_context.r13 = read_register_u64(reg_ctx, "r13"); 489349cc55cSDimitry Andric thread_context.r14 = read_register_u64(reg_ctx, "r14"); 490349cc55cSDimitry Andric thread_context.r15 = read_register_u64(reg_ctx, "r15"); 491349cc55cSDimitry Andric thread_context.rip = read_register_u64(reg_ctx, "rip"); 492349cc55cSDimitry Andric thread_context.eflags = read_register_u32(reg_ctx, "rflags"); 493349cc55cSDimitry Andric thread_context.cs = read_register_u16(reg_ctx, "cs"); 494349cc55cSDimitry Andric thread_context.fs = read_register_u16(reg_ctx, "fs"); 495349cc55cSDimitry Andric thread_context.gs = read_register_u16(reg_ctx, "gs"); 496349cc55cSDimitry Andric thread_context.ss = read_register_u16(reg_ctx, "ss"); 497349cc55cSDimitry Andric thread_context.ds = read_register_u16(reg_ctx, "ds"); 498349cc55cSDimitry Andric return thread_context; 499349cc55cSDimitry Andric } 500349cc55cSDimitry Andric 5015f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Context 5025f757f3fSDimitry Andric GetThreadContext_ARM64(RegisterContext *reg_ctx) { 5035f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Context thread_context = {}; 5045f757f3fSDimitry Andric thread_context.context_flags = static_cast<uint32_t>( 5055f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Flags::ARM64_Flag | 5065f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Flags::Integer | 5075f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Flags::FloatingPoint); 5085f757f3fSDimitry Andric char reg_name[16]; 5095f757f3fSDimitry Andric for (uint32_t i = 0; i < 31; ++i) { 5105f757f3fSDimitry Andric snprintf(reg_name, sizeof(reg_name), "x%u", i); 5115f757f3fSDimitry Andric thread_context.x[i] = read_register_u64(reg_ctx, reg_name); 5125f757f3fSDimitry Andric } 5135f757f3fSDimitry Andric // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt 5145f757f3fSDimitry Andric // name set to "x31" 5155f757f3fSDimitry Andric thread_context.x[31] = read_register_u64(reg_ctx, "sp"); 5165f757f3fSDimitry Andric thread_context.pc = read_register_u64(reg_ctx, "pc"); 5175f757f3fSDimitry Andric thread_context.cpsr = read_register_u32(reg_ctx, "cpsr"); 5185f757f3fSDimitry Andric thread_context.fpsr = read_register_u32(reg_ctx, "fpsr"); 5195f757f3fSDimitry Andric thread_context.fpcr = read_register_u32(reg_ctx, "fpcr"); 5205f757f3fSDimitry Andric for (uint32_t i = 0; i < 32; ++i) { 5215f757f3fSDimitry Andric snprintf(reg_name, sizeof(reg_name), "v%u", i); 5225f757f3fSDimitry Andric read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]); 5235f757f3fSDimitry Andric } 5245f757f3fSDimitry Andric return thread_context; 5255f757f3fSDimitry Andric } 5265f757f3fSDimitry Andric 5275f757f3fSDimitry Andric class ArchThreadContexts { 5285f757f3fSDimitry Andric llvm::Triple::ArchType m_arch; 5295f757f3fSDimitry Andric union { 5305f757f3fSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64 x86_64; 5315f757f3fSDimitry Andric lldb_private::minidump::RegisterContextMinidump_ARM64::Context arm64; 5325f757f3fSDimitry Andric }; 5335f757f3fSDimitry Andric 5345f757f3fSDimitry Andric public: 5355f757f3fSDimitry Andric ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {} 5365f757f3fSDimitry Andric 5375f757f3fSDimitry Andric bool prepareRegisterContext(RegisterContext *reg_ctx) { 5385f757f3fSDimitry Andric switch (m_arch) { 5395f757f3fSDimitry Andric case llvm::Triple::ArchType::x86_64: 5405f757f3fSDimitry Andric x86_64 = GetThreadContext_x86_64(reg_ctx); 5415f757f3fSDimitry Andric return true; 5425f757f3fSDimitry Andric case llvm::Triple::ArchType::aarch64: 5435f757f3fSDimitry Andric arm64 = GetThreadContext_ARM64(reg_ctx); 5445f757f3fSDimitry Andric return true; 5455f757f3fSDimitry Andric default: 5465f757f3fSDimitry Andric break; 5475f757f3fSDimitry Andric } 5485f757f3fSDimitry Andric return false; 5495f757f3fSDimitry Andric } 5505f757f3fSDimitry Andric 5515f757f3fSDimitry Andric const void *data() const { return &x86_64; } 5525f757f3fSDimitry Andric 5535f757f3fSDimitry Andric size_t size() const { 5545f757f3fSDimitry Andric switch (m_arch) { 5555f757f3fSDimitry Andric case llvm::Triple::ArchType::x86_64: 5565f757f3fSDimitry Andric return sizeof(x86_64); 5575f757f3fSDimitry Andric case llvm::Triple::ArchType::aarch64: 5585f757f3fSDimitry Andric return sizeof(arm64); 5595f757f3fSDimitry Andric default: 5605f757f3fSDimitry Andric break; 5615f757f3fSDimitry Andric } 5625f757f3fSDimitry Andric return 0; 5635f757f3fSDimitry Andric } 5645f757f3fSDimitry Andric }; 5655f757f3fSDimitry Andric 566*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::FixThreadStacks() { 567*0fca6ea1SDimitry Andric Status error; 568*0fca6ea1SDimitry Andric // If we have anything in the heap flush it. 569*0fca6ea1SDimitry Andric FlushBufferToDisk(); 570*0fca6ea1SDimitry Andric m_core_file->SeekFromStart(m_thread_list_start); 571*0fca6ea1SDimitry Andric for (auto &pair : m_thread_by_range_end) { 572*0fca6ea1SDimitry Andric // The thread objects will get a new memory descriptor added 573*0fca6ea1SDimitry Andric // When we are emitting the memory list and then we write it here 574*0fca6ea1SDimitry Andric const llvm::minidump::Thread &thread = pair.second; 575*0fca6ea1SDimitry Andric size_t bytes_to_write = sizeof(llvm::minidump::Thread); 576*0fca6ea1SDimitry Andric size_t bytes_written = bytes_to_write; 577*0fca6ea1SDimitry Andric error = m_core_file->Write(&thread, bytes_written); 578*0fca6ea1SDimitry Andric if (error.Fail() || bytes_to_write != bytes_written) { 579*0fca6ea1SDimitry Andric error.SetErrorStringWithFormat( 580*0fca6ea1SDimitry Andric "Wrote incorrect number of bytes to minidump file. (written %zd/%zd)", 581*0fca6ea1SDimitry Andric bytes_written, bytes_to_write); 582*0fca6ea1SDimitry Andric return error; 583*0fca6ea1SDimitry Andric } 584349cc55cSDimitry Andric } 585349cc55cSDimitry Andric 586*0fca6ea1SDimitry Andric return error; 587*0fca6ea1SDimitry Andric } 588*0fca6ea1SDimitry Andric 589*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddThreadList() { 590349cc55cSDimitry Andric constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread); 591*0fca6ea1SDimitry Andric lldb_private::ThreadList thread_list = m_process_sp->GetThreadList(); 592349cc55cSDimitry Andric 593349cc55cSDimitry Andric // size of the entire thread stream consists of: 594349cc55cSDimitry Andric // number of threads and threads array 595349cc55cSDimitry Andric size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) + 596349cc55cSDimitry Andric thread_list.GetSize() * minidump_thread_size; 597349cc55cSDimitry Andric // save for the ability to set up RVA 598349cc55cSDimitry Andric size_t size_before = GetCurrentDataEndOffset(); 599*0fca6ea1SDimitry Andric Status error; 600*0fca6ea1SDimitry Andric error = AddDirectory(StreamType::ThreadList, thread_stream_size); 601*0fca6ea1SDimitry Andric if (error.Fail()) 602*0fca6ea1SDimitry Andric return error; 603349cc55cSDimitry Andric 604349cc55cSDimitry Andric llvm::support::ulittle32_t thread_count = 605349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_list.GetSize()); 606349cc55cSDimitry Andric m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t)); 607349cc55cSDimitry Andric 608*0fca6ea1SDimitry Andric // Take the offset after the thread count. 609*0fca6ea1SDimitry Andric m_thread_list_start = GetCurrentDataEndOffset(); 610349cc55cSDimitry Andric DataBufferHeap helper_data; 611349cc55cSDimitry Andric 612349cc55cSDimitry Andric const uint32_t num_threads = thread_list.GetSize(); 613*0fca6ea1SDimitry Andric Log *log = GetLog(LLDBLog::Object); 614349cc55cSDimitry Andric for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 615349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); 616349cc55cSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 617349cc55cSDimitry Andric 618349cc55cSDimitry Andric if (!reg_ctx_sp) { 619349cc55cSDimitry Andric error.SetErrorString("Unable to get the register context."); 620349cc55cSDimitry Andric return error; 621349cc55cSDimitry Andric } 622349cc55cSDimitry Andric RegisterContext *reg_ctx = reg_ctx_sp.get(); 623*0fca6ea1SDimitry Andric Target &target = m_process_sp->GetTarget(); 6245f757f3fSDimitry Andric const ArchSpec &arch = target.GetArchitecture(); 6255f757f3fSDimitry Andric ArchThreadContexts thread_context(arch.GetMachine()); 6265f757f3fSDimitry Andric if (!thread_context.prepareRegisterContext(reg_ctx)) { 6275f757f3fSDimitry Andric error.SetErrorStringWithFormat( 6285f757f3fSDimitry Andric "architecture %s not supported.", 6295f757f3fSDimitry Andric arch.GetTriple().getArchName().str().c_str()); 6305f757f3fSDimitry Andric return error; 6315f757f3fSDimitry Andric } 632*0fca6ea1SDimitry Andric 6335f757f3fSDimitry Andric uint64_t sp = reg_ctx->GetSP(); 634*0fca6ea1SDimitry Andric MemoryRegionInfo sp_region; 635*0fca6ea1SDimitry Andric m_process_sp->GetMemoryRegionInfo(sp, sp_region); 636349cc55cSDimitry Andric 637*0fca6ea1SDimitry Andric // Emit a blank descriptor 638349cc55cSDimitry Andric MemoryDescriptor stack; 639*0fca6ea1SDimitry Andric LocationDescriptor empty_label; 640*0fca6ea1SDimitry Andric empty_label.DataSize = 0; 641*0fca6ea1SDimitry Andric empty_label.RVA = 0; 642*0fca6ea1SDimitry Andric stack.Memory = empty_label; 643*0fca6ea1SDimitry Andric stack.StartOfMemoryRange = 0; 644349cc55cSDimitry Andric LocationDescriptor thread_context_memory_locator; 645349cc55cSDimitry Andric thread_context_memory_locator.DataSize = 6465f757f3fSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_context.size()); 647349cc55cSDimitry Andric thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>( 648349cc55cSDimitry Andric size_before + thread_stream_size + helper_data.GetByteSize()); 6495f757f3fSDimitry Andric // Cache thie thread context memory so we can reuse for exceptions. 6505f757f3fSDimitry Andric m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator; 651349cc55cSDimitry Andric 652*0fca6ea1SDimitry Andric LLDB_LOGF(log, "AddThreadList for thread %d: thread_context %zu bytes", 653*0fca6ea1SDimitry Andric thread_idx, thread_context.size()); 6545f757f3fSDimitry Andric helper_data.AppendData(thread_context.data(), thread_context.size()); 655349cc55cSDimitry Andric 656349cc55cSDimitry Andric llvm::minidump::Thread t; 657349cc55cSDimitry Andric t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 658349cc55cSDimitry Andric t.SuspendCount = static_cast<llvm::support::ulittle32_t>( 659349cc55cSDimitry Andric (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0); 660349cc55cSDimitry Andric t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0); 661349cc55cSDimitry Andric t.Priority = static_cast<llvm::support::ulittle32_t>(0); 662349cc55cSDimitry Andric t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0); 663349cc55cSDimitry Andric t.Stack = stack, t.Context = thread_context_memory_locator; 664349cc55cSDimitry Andric 665*0fca6ea1SDimitry Andric // We save off the stack object so we can circle back and clean it up. 666*0fca6ea1SDimitry Andric m_thread_by_range_end[sp_region.GetRange().GetRangeEnd()] = t; 667349cc55cSDimitry Andric m_data.AppendData(&t, sizeof(llvm::minidump::Thread)); 668349cc55cSDimitry Andric } 669349cc55cSDimitry Andric 670*0fca6ea1SDimitry Andric LLDB_LOGF(log, "AddThreadList(): total helper_data %" PRIx64 " bytes", 671*0fca6ea1SDimitry Andric helper_data.GetByteSize()); 672349cc55cSDimitry Andric m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 673349cc55cSDimitry Andric return Status(); 674349cc55cSDimitry Andric } 675349cc55cSDimitry Andric 676*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddExceptions() { 677*0fca6ea1SDimitry Andric lldb_private::ThreadList thread_list = m_process_sp->GetThreadList(); 678*0fca6ea1SDimitry Andric Status error; 679349cc55cSDimitry Andric const uint32_t num_threads = thread_list.GetSize(); 6805f757f3fSDimitry Andric for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 6815f757f3fSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); 682349cc55cSDimitry Andric StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 6835f757f3fSDimitry Andric bool add_exception = false; 6845f757f3fSDimitry Andric if (stop_info_sp) { 6855f757f3fSDimitry Andric switch (stop_info_sp->GetStopReason()) { 6865f757f3fSDimitry Andric case eStopReasonSignal: 6875f757f3fSDimitry Andric case eStopReasonException: 6885f757f3fSDimitry Andric add_exception = true; 6895f757f3fSDimitry Andric break; 6905f757f3fSDimitry Andric default: 691349cc55cSDimitry Andric break; 692349cc55cSDimitry Andric } 693349cc55cSDimitry Andric } 6945f757f3fSDimitry Andric if (add_exception) { 695349cc55cSDimitry Andric constexpr size_t minidump_exception_size = 696349cc55cSDimitry Andric sizeof(llvm::minidump::ExceptionStream); 697*0fca6ea1SDimitry Andric error = AddDirectory(StreamType::Exception, minidump_exception_size); 698*0fca6ea1SDimitry Andric if (error.Fail()) 699*0fca6ea1SDimitry Andric return error; 700*0fca6ea1SDimitry Andric 701349cc55cSDimitry Andric StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 7025f757f3fSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 703972a253aSDimitry Andric Exception exp_record = {}; 704349cc55cSDimitry Andric exp_record.ExceptionCode = 705349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue()); 706349cc55cSDimitry Andric exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0); 707349cc55cSDimitry Andric exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0); 7085f757f3fSDimitry Andric exp_record.ExceptionAddress = reg_ctx_sp->GetPC(); 709349cc55cSDimitry Andric exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0); 710349cc55cSDimitry Andric exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 711349cc55cSDimitry Andric // exp_record.ExceptionInformation; 712349cc55cSDimitry Andric 713349cc55cSDimitry Andric ExceptionStream exp_stream; 714349cc55cSDimitry Andric exp_stream.ThreadId = 715349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 716349cc55cSDimitry Andric exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 717349cc55cSDimitry Andric exp_stream.ExceptionRecord = exp_record; 7185f757f3fSDimitry Andric auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID()); 7195f757f3fSDimitry Andric if (Iter != m_tid_to_reg_ctx.end()) { 7205f757f3fSDimitry Andric exp_stream.ThreadContext = Iter->second; 7215f757f3fSDimitry Andric } else { 7225f757f3fSDimitry Andric exp_stream.ThreadContext.DataSize = 0; 7235f757f3fSDimitry Andric exp_stream.ThreadContext.RVA = 0; 7245f757f3fSDimitry Andric } 725349cc55cSDimitry Andric m_data.AppendData(&exp_stream, minidump_exception_size); 7265f757f3fSDimitry Andric } 7275f757f3fSDimitry Andric } 728*0fca6ea1SDimitry Andric 729*0fca6ea1SDimitry Andric return error; 730349cc55cSDimitry Andric } 731349cc55cSDimitry Andric 732*0fca6ea1SDimitry Andric lldb_private::Status MinidumpFileBuilder::AddMiscInfo() { 733349cc55cSDimitry Andric Status error; 734*0fca6ea1SDimitry Andric error = AddDirectory(StreamType::MiscInfo, 735349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 736*0fca6ea1SDimitry Andric if (error.Fail()) 737*0fca6ea1SDimitry Andric return error; 738349cc55cSDimitry Andric 739349cc55cSDimitry Andric lldb_private::minidump::MinidumpMiscInfo misc_info; 740349cc55cSDimitry Andric misc_info.size = static_cast<llvm::support::ulittle32_t>( 741349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 742349cc55cSDimitry Andric // Default set flags1 to 0, in case that we will not be able to 743349cc55cSDimitry Andric // get any information 744349cc55cSDimitry Andric misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0); 745349cc55cSDimitry Andric 746349cc55cSDimitry Andric lldb_private::ProcessInstanceInfo process_info; 747*0fca6ea1SDimitry Andric m_process_sp->GetProcessInfo(process_info); 748349cc55cSDimitry Andric if (process_info.ProcessIDIsValid()) { 749349cc55cSDimitry Andric // Set flags1 to reflect that PID is filled in 750349cc55cSDimitry Andric misc_info.flags1 = 751349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>( 752349cc55cSDimitry Andric lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID)); 753349cc55cSDimitry Andric misc_info.process_id = 754349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID()); 755349cc55cSDimitry Andric } 756349cc55cSDimitry Andric 757349cc55cSDimitry Andric m_data.AppendData(&misc_info, 758349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 759*0fca6ea1SDimitry Andric return error; 760349cc55cSDimitry Andric } 761349cc55cSDimitry Andric 762349cc55cSDimitry Andric std::unique_ptr<llvm::MemoryBuffer> 763349cc55cSDimitry Andric getFileStreamHelper(const std::string &path) { 764349cc55cSDimitry Andric auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path); 765349cc55cSDimitry Andric if (!maybe_stream) 766349cc55cSDimitry Andric return nullptr; 767349cc55cSDimitry Andric return std::move(maybe_stream.get()); 768349cc55cSDimitry Andric } 769349cc55cSDimitry Andric 770*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddLinuxFileStreams() { 771*0fca6ea1SDimitry Andric Status error; 772*0fca6ea1SDimitry Andric // No-op if we are not on linux. 773*0fca6ea1SDimitry Andric if (m_process_sp->GetTarget().GetArchitecture().GetTriple().getOS() != 774*0fca6ea1SDimitry Andric llvm::Triple::Linux) 775*0fca6ea1SDimitry Andric return error; 776*0fca6ea1SDimitry Andric 777349cc55cSDimitry Andric std::vector<std::pair<StreamType, std::string>> files_with_stream_types = { 778349cc55cSDimitry Andric {StreamType::LinuxCPUInfo, "/proc/cpuinfo"}, 779349cc55cSDimitry Andric {StreamType::LinuxLSBRelease, "/etc/lsb-release"}, 780349cc55cSDimitry Andric }; 781349cc55cSDimitry Andric 782349cc55cSDimitry Andric lldb_private::ProcessInstanceInfo process_info; 783*0fca6ea1SDimitry Andric m_process_sp->GetProcessInfo(process_info); 784349cc55cSDimitry Andric if (process_info.ProcessIDIsValid()) { 785349cc55cSDimitry Andric lldb::pid_t pid = process_info.GetProcessID(); 786349cc55cSDimitry Andric std::string pid_str = std::to_string(pid); 787349cc55cSDimitry Andric files_with_stream_types.push_back( 788349cc55cSDimitry Andric {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"}); 789349cc55cSDimitry Andric files_with_stream_types.push_back( 790349cc55cSDimitry Andric {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"}); 791349cc55cSDimitry Andric files_with_stream_types.push_back( 792349cc55cSDimitry Andric {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"}); 793349cc55cSDimitry Andric files_with_stream_types.push_back( 794349cc55cSDimitry Andric {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"}); 795349cc55cSDimitry Andric files_with_stream_types.push_back( 796349cc55cSDimitry Andric {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"}); 797349cc55cSDimitry Andric files_with_stream_types.push_back( 798349cc55cSDimitry Andric {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"}); 799349cc55cSDimitry Andric files_with_stream_types.push_back( 800349cc55cSDimitry Andric {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"}); 801349cc55cSDimitry Andric } 802349cc55cSDimitry Andric 803349cc55cSDimitry Andric for (const auto &entry : files_with_stream_types) { 804349cc55cSDimitry Andric StreamType stream = entry.first; 805349cc55cSDimitry Andric std::string path = entry.second; 806349cc55cSDimitry Andric auto memory_buffer = getFileStreamHelper(path); 807349cc55cSDimitry Andric 808349cc55cSDimitry Andric if (memory_buffer) { 809349cc55cSDimitry Andric size_t size = memory_buffer->getBufferSize(); 810349cc55cSDimitry Andric if (size == 0) 811349cc55cSDimitry Andric continue; 812*0fca6ea1SDimitry Andric error = AddDirectory(stream, size); 813*0fca6ea1SDimitry Andric if (error.Fail()) 814*0fca6ea1SDimitry Andric return error; 815349cc55cSDimitry Andric m_data.AppendData(memory_buffer->getBufferStart(), size); 816349cc55cSDimitry Andric } 817349cc55cSDimitry Andric } 818*0fca6ea1SDimitry Andric 819*0fca6ea1SDimitry Andric return error; 820349cc55cSDimitry Andric } 821349cc55cSDimitry Andric 822*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddMemoryList(SaveCoreStyle core_style) { 823*0fca6ea1SDimitry Andric Status error; 824349cc55cSDimitry Andric 825*0fca6ea1SDimitry Andric // We first save the thread stacks to ensure they fit in the first UINT32_MAX 826*0fca6ea1SDimitry Andric // bytes of the core file. Thread structures in minidump files can only use 827*0fca6ea1SDimitry Andric // 32 bit memory descriptiors, so we emit them first to ensure the memory is 828*0fca6ea1SDimitry Andric // in accessible with a 32 bit offset. 829*0fca6ea1SDimitry Andric Process::CoreFileMemoryRanges ranges_32; 830*0fca6ea1SDimitry Andric Process::CoreFileMemoryRanges ranges_64; 831*0fca6ea1SDimitry Andric error = m_process_sp->CalculateCoreFileSaveRanges( 832*0fca6ea1SDimitry Andric SaveCoreStyle::eSaveCoreStackOnly, ranges_32); 833*0fca6ea1SDimitry Andric if (error.Fail()) 834*0fca6ea1SDimitry Andric return error; 835*0fca6ea1SDimitry Andric 836*0fca6ea1SDimitry Andric // Calculate totalsize including the current offset. 837*0fca6ea1SDimitry Andric uint64_t total_size = GetCurrentDataEndOffset(); 838*0fca6ea1SDimitry Andric total_size += ranges_32.size() * sizeof(llvm::minidump::MemoryDescriptor); 839*0fca6ea1SDimitry Andric std::unordered_set<addr_t> stack_start_addresses; 840*0fca6ea1SDimitry Andric for (const auto &core_range : ranges_32) { 841*0fca6ea1SDimitry Andric stack_start_addresses.insert(core_range.range.start()); 842*0fca6ea1SDimitry Andric total_size += core_range.range.size(); 843*0fca6ea1SDimitry Andric } 844*0fca6ea1SDimitry Andric 845*0fca6ea1SDimitry Andric if (total_size >= UINT32_MAX) { 846*0fca6ea1SDimitry Andric error.SetErrorStringWithFormat("Unable to write minidump. Stack memory " 847*0fca6ea1SDimitry Andric "exceeds 32b limit. (Num Stacks %zu)", 848*0fca6ea1SDimitry Andric ranges_32.size()); 849*0fca6ea1SDimitry Andric return error; 850*0fca6ea1SDimitry Andric } 851*0fca6ea1SDimitry Andric 852*0fca6ea1SDimitry Andric Process::CoreFileMemoryRanges all_core_memory_ranges; 853*0fca6ea1SDimitry Andric if (core_style != SaveCoreStyle::eSaveCoreStackOnly) { 854*0fca6ea1SDimitry Andric error = m_process_sp->CalculateCoreFileSaveRanges(core_style, 855*0fca6ea1SDimitry Andric all_core_memory_ranges); 856*0fca6ea1SDimitry Andric if (error.Fail()) 857*0fca6ea1SDimitry Andric return error; 858*0fca6ea1SDimitry Andric } 859*0fca6ea1SDimitry Andric 860*0fca6ea1SDimitry Andric // After saving the stacks, we start packing as much as we can into 32b. 861*0fca6ea1SDimitry Andric // We apply a generous padding here so that the Directory, MemoryList and 862*0fca6ea1SDimitry Andric // Memory64List sections all begin in 32b addressable space. 863*0fca6ea1SDimitry Andric // Then anything overflow extends into 64b addressable space. 864*0fca6ea1SDimitry Andric // All core memeroy ranges will either container nothing on stacks only 865*0fca6ea1SDimitry Andric // or all the memory ranges including stacks 866*0fca6ea1SDimitry Andric if (!all_core_memory_ranges.empty()) 867*0fca6ea1SDimitry Andric total_size += 868*0fca6ea1SDimitry Andric 256 + (all_core_memory_ranges.size() - stack_start_addresses.size()) * 869*0fca6ea1SDimitry Andric sizeof(llvm::minidump::MemoryDescriptor_64); 870*0fca6ea1SDimitry Andric 871*0fca6ea1SDimitry Andric for (const auto &core_range : all_core_memory_ranges) { 872*0fca6ea1SDimitry Andric const addr_t range_size = core_range.range.size(); 873*0fca6ea1SDimitry Andric if (stack_start_addresses.count(core_range.range.start()) > 0) 874*0fca6ea1SDimitry Andric // Don't double save stacks. 875*0fca6ea1SDimitry Andric continue; 876*0fca6ea1SDimitry Andric 877*0fca6ea1SDimitry Andric if (total_size + range_size < UINT32_MAX) { 878*0fca6ea1SDimitry Andric ranges_32.push_back(core_range); 879*0fca6ea1SDimitry Andric total_size += range_size; 880*0fca6ea1SDimitry Andric } else { 881*0fca6ea1SDimitry Andric ranges_64.push_back(core_range); 882*0fca6ea1SDimitry Andric } 883*0fca6ea1SDimitry Andric } 884*0fca6ea1SDimitry Andric 885*0fca6ea1SDimitry Andric error = AddMemoryList_32(ranges_32); 886*0fca6ea1SDimitry Andric if (error.Fail()) 887*0fca6ea1SDimitry Andric return error; 888*0fca6ea1SDimitry Andric 889*0fca6ea1SDimitry Andric // Add the remaining memory as a 64b range. 890*0fca6ea1SDimitry Andric if (!ranges_64.empty()) { 891*0fca6ea1SDimitry Andric error = AddMemoryList_64(ranges_64); 892*0fca6ea1SDimitry Andric if (error.Fail()) 893*0fca6ea1SDimitry Andric return error; 894*0fca6ea1SDimitry Andric } 895*0fca6ea1SDimitry Andric 896*0fca6ea1SDimitry Andric return FixThreadStacks(); 897*0fca6ea1SDimitry Andric } 898*0fca6ea1SDimitry Andric 899*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::DumpHeader() const { 900349cc55cSDimitry Andric // write header 901349cc55cSDimitry Andric llvm::minidump::Header header; 902349cc55cSDimitry Andric header.Signature = static_cast<llvm::support::ulittle32_t>( 903349cc55cSDimitry Andric llvm::minidump::Header::MagicSignature); 904349cc55cSDimitry Andric header.Version = static_cast<llvm::support::ulittle32_t>( 905349cc55cSDimitry Andric llvm::minidump::Header::MagicVersion); 906349cc55cSDimitry Andric header.NumberOfStreams = 907*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle32_t>(m_directories.size()); 908*0fca6ea1SDimitry Andric // We write the directories right after the header. 909349cc55cSDimitry Andric header.StreamDirectoryRVA = 910*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle32_t>(HEADER_SIZE); 911349cc55cSDimitry Andric header.Checksum = static_cast<llvm::support::ulittle32_t>( 912349cc55cSDimitry Andric 0u), // not used in most of the writers 913349cc55cSDimitry Andric header.TimeDateStamp = 91404eeddc0SDimitry Andric static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); 915349cc55cSDimitry Andric header.Flags = 916349cc55cSDimitry Andric static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag 917349cc55cSDimitry Andric 918349cc55cSDimitry Andric Status error; 919349cc55cSDimitry Andric size_t bytes_written; 920349cc55cSDimitry Andric 921*0fca6ea1SDimitry Andric m_core_file->SeekFromStart(0); 922*0fca6ea1SDimitry Andric bytes_written = HEADER_SIZE; 923*0fca6ea1SDimitry Andric error = m_core_file->Write(&header, bytes_written); 924*0fca6ea1SDimitry Andric if (error.Fail() || bytes_written != HEADER_SIZE) { 925*0fca6ea1SDimitry Andric if (bytes_written != HEADER_SIZE) 926349cc55cSDimitry Andric error.SetErrorStringWithFormat( 927*0fca6ea1SDimitry Andric "Unable to write the minidump header (written %zd/%zd)", 928*0fca6ea1SDimitry Andric bytes_written, HEADER_SIZE); 929*0fca6ea1SDimitry Andric return error; 930*0fca6ea1SDimitry Andric } 931349cc55cSDimitry Andric return error; 932349cc55cSDimitry Andric } 933349cc55cSDimitry Andric 934*0fca6ea1SDimitry Andric offset_t MinidumpFileBuilder::GetCurrentDataEndOffset() const { 935*0fca6ea1SDimitry Andric return m_data.GetByteSize() + m_saved_data_size; 936349cc55cSDimitry Andric } 937349cc55cSDimitry Andric 938*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::DumpDirectories() const { 939*0fca6ea1SDimitry Andric Status error; 940*0fca6ea1SDimitry Andric size_t bytes_written; 941*0fca6ea1SDimitry Andric m_core_file->SeekFromStart(HEADER_SIZE); 942349cc55cSDimitry Andric for (const Directory &dir : m_directories) { 943*0fca6ea1SDimitry Andric bytes_written = DIRECTORY_SIZE; 944*0fca6ea1SDimitry Andric error = m_core_file->Write(&dir, bytes_written); 945*0fca6ea1SDimitry Andric if (error.Fail() || bytes_written != DIRECTORY_SIZE) { 946*0fca6ea1SDimitry Andric if (bytes_written != DIRECTORY_SIZE) 947349cc55cSDimitry Andric error.SetErrorStringWithFormat( 948349cc55cSDimitry Andric "unable to write the directory (written %zd/%zd)", bytes_written, 949*0fca6ea1SDimitry Andric DIRECTORY_SIZE); 950349cc55cSDimitry Andric return error; 951349cc55cSDimitry Andric } 952349cc55cSDimitry Andric } 953349cc55cSDimitry Andric 954349cc55cSDimitry Andric return error; 955349cc55cSDimitry Andric } 956349cc55cSDimitry Andric 957*0fca6ea1SDimitry Andric static uint64_t 958*0fca6ea1SDimitry Andric GetLargestRangeSize(const Process::CoreFileMemoryRanges &ranges) { 959*0fca6ea1SDimitry Andric uint64_t max_size = 0; 960*0fca6ea1SDimitry Andric for (const auto &core_range : ranges) 961*0fca6ea1SDimitry Andric max_size = std::max(max_size, core_range.range.size()); 962*0fca6ea1SDimitry Andric return max_size; 963349cc55cSDimitry Andric } 964349cc55cSDimitry Andric 965*0fca6ea1SDimitry Andric Status 966*0fca6ea1SDimitry Andric MinidumpFileBuilder::AddMemoryList_32(Process::CoreFileMemoryRanges &ranges) { 967*0fca6ea1SDimitry Andric std::vector<MemoryDescriptor> descriptors; 968*0fca6ea1SDimitry Andric Status error; 969*0fca6ea1SDimitry Andric if (ranges.size() == 0) 970*0fca6ea1SDimitry Andric return error; 971*0fca6ea1SDimitry Andric 972*0fca6ea1SDimitry Andric Log *log = GetLog(LLDBLog::Object); 973*0fca6ea1SDimitry Andric size_t region_index = 0; 974*0fca6ea1SDimitry Andric auto data_up = 975*0fca6ea1SDimitry Andric std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0); 976*0fca6ea1SDimitry Andric for (const auto &core_range : ranges) { 977*0fca6ea1SDimitry Andric // Take the offset before we write. 978*0fca6ea1SDimitry Andric const offset_t offset_for_data = GetCurrentDataEndOffset(); 979*0fca6ea1SDimitry Andric const addr_t addr = core_range.range.start(); 980*0fca6ea1SDimitry Andric const addr_t size = core_range.range.size(); 981*0fca6ea1SDimitry Andric const addr_t end = core_range.range.end(); 982*0fca6ea1SDimitry Andric 983*0fca6ea1SDimitry Andric LLDB_LOGF(log, 984*0fca6ea1SDimitry Andric "AddMemoryList %zu/%zu reading memory for region " 985*0fca6ea1SDimitry Andric "(%" PRIx64 " bytes) [%" PRIx64 ", %" PRIx64 ")", 986*0fca6ea1SDimitry Andric region_index, ranges.size(), size, addr, addr + size); 987*0fca6ea1SDimitry Andric ++region_index; 988*0fca6ea1SDimitry Andric 989*0fca6ea1SDimitry Andric const size_t bytes_read = 990*0fca6ea1SDimitry Andric m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 991*0fca6ea1SDimitry Andric if (error.Fail() || bytes_read == 0) { 992*0fca6ea1SDimitry Andric LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s", 993*0fca6ea1SDimitry Andric bytes_read, error.AsCString()); 994*0fca6ea1SDimitry Andric // Just skip sections with errors or zero bytes in 32b mode 995*0fca6ea1SDimitry Andric continue; 996*0fca6ea1SDimitry Andric } else if (bytes_read != size) { 997*0fca6ea1SDimitry Andric LLDB_LOGF( 998*0fca6ea1SDimitry Andric log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes", 999*0fca6ea1SDimitry Andric addr, size); 1000*0fca6ea1SDimitry Andric } 1001*0fca6ea1SDimitry Andric 1002*0fca6ea1SDimitry Andric MemoryDescriptor descriptor; 1003*0fca6ea1SDimitry Andric descriptor.StartOfMemoryRange = 1004*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle64_t>(addr); 1005*0fca6ea1SDimitry Andric descriptor.Memory.DataSize = 1006*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle32_t>(bytes_read); 1007*0fca6ea1SDimitry Andric descriptor.Memory.RVA = 1008*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle32_t>(offset_for_data); 1009*0fca6ea1SDimitry Andric descriptors.push_back(descriptor); 1010*0fca6ea1SDimitry Andric if (m_thread_by_range_end.count(end) > 0) 1011*0fca6ea1SDimitry Andric m_thread_by_range_end[end].Stack = descriptor; 1012*0fca6ea1SDimitry Andric 1013*0fca6ea1SDimitry Andric // Add the data to the buffer, flush as needed. 1014*0fca6ea1SDimitry Andric error = AddData(data_up->GetBytes(), bytes_read); 1015*0fca6ea1SDimitry Andric if (error.Fail()) 1016*0fca6ea1SDimitry Andric return error; 1017*0fca6ea1SDimitry Andric } 1018*0fca6ea1SDimitry Andric 1019*0fca6ea1SDimitry Andric // Add a directory that references this list 1020*0fca6ea1SDimitry Andric // With a size of the number of ranges as a 32 bit num 1021*0fca6ea1SDimitry Andric // And then the size of all the ranges 1022*0fca6ea1SDimitry Andric error = AddDirectory(StreamType::MemoryList, 1023*0fca6ea1SDimitry Andric sizeof(llvm::support::ulittle32_t) + 1024*0fca6ea1SDimitry Andric descriptors.size() * 1025*0fca6ea1SDimitry Andric sizeof(llvm::minidump::MemoryDescriptor)); 1026*0fca6ea1SDimitry Andric if (error.Fail()) 1027*0fca6ea1SDimitry Andric return error; 1028*0fca6ea1SDimitry Andric 1029*0fca6ea1SDimitry Andric llvm::support::ulittle32_t memory_ranges_num = 1030*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle32_t>(descriptors.size()); 1031*0fca6ea1SDimitry Andric m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t)); 1032*0fca6ea1SDimitry Andric // For 32b we can get away with writing off the descriptors after the data. 1033*0fca6ea1SDimitry Andric // This means no cleanup loop needed. 1034*0fca6ea1SDimitry Andric m_data.AppendData(descriptors.data(), 1035*0fca6ea1SDimitry Andric descriptors.size() * sizeof(MemoryDescriptor)); 1036*0fca6ea1SDimitry Andric 1037*0fca6ea1SDimitry Andric return error; 1038*0fca6ea1SDimitry Andric } 1039*0fca6ea1SDimitry Andric 1040*0fca6ea1SDimitry Andric Status 1041*0fca6ea1SDimitry Andric MinidumpFileBuilder::AddMemoryList_64(Process::CoreFileMemoryRanges &ranges) { 1042*0fca6ea1SDimitry Andric Status error; 1043*0fca6ea1SDimitry Andric if (ranges.empty()) 1044*0fca6ea1SDimitry Andric return error; 1045*0fca6ea1SDimitry Andric 1046*0fca6ea1SDimitry Andric error = AddDirectory(StreamType::Memory64List, 1047*0fca6ea1SDimitry Andric (sizeof(llvm::support::ulittle64_t) * 2) + 1048*0fca6ea1SDimitry Andric ranges.size() * 1049*0fca6ea1SDimitry Andric sizeof(llvm::minidump::MemoryDescriptor_64)); 1050*0fca6ea1SDimitry Andric if (error.Fail()) 1051*0fca6ea1SDimitry Andric return error; 1052*0fca6ea1SDimitry Andric 1053*0fca6ea1SDimitry Andric llvm::support::ulittle64_t memory_ranges_num = 1054*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle64_t>(ranges.size()); 1055*0fca6ea1SDimitry Andric m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle64_t)); 1056*0fca6ea1SDimitry Andric // Capture the starting offset for all the descriptors so we can clean them up 1057*0fca6ea1SDimitry Andric // if needed. 1058*0fca6ea1SDimitry Andric offset_t starting_offset = 1059*0fca6ea1SDimitry Andric GetCurrentDataEndOffset() + sizeof(llvm::support::ulittle64_t); 1060*0fca6ea1SDimitry Andric // The base_rva needs to start after the directories, which is right after 1061*0fca6ea1SDimitry Andric // this 8 byte variable. 1062*0fca6ea1SDimitry Andric offset_t base_rva = 1063*0fca6ea1SDimitry Andric starting_offset + 1064*0fca6ea1SDimitry Andric (ranges.size() * sizeof(llvm::minidump::MemoryDescriptor_64)); 1065*0fca6ea1SDimitry Andric llvm::support::ulittle64_t memory_ranges_base_rva = 1066*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle64_t>(base_rva); 1067*0fca6ea1SDimitry Andric m_data.AppendData(&memory_ranges_base_rva, 1068*0fca6ea1SDimitry Andric sizeof(llvm::support::ulittle64_t)); 1069*0fca6ea1SDimitry Andric 1070*0fca6ea1SDimitry Andric bool cleanup_required = false; 1071*0fca6ea1SDimitry Andric std::vector<MemoryDescriptor_64> descriptors; 1072*0fca6ea1SDimitry Andric // Enumerate the ranges and create the memory descriptors so we can append 1073*0fca6ea1SDimitry Andric // them first 1074*0fca6ea1SDimitry Andric for (const auto core_range : ranges) { 1075*0fca6ea1SDimitry Andric // Add the space required to store the memory descriptor 1076*0fca6ea1SDimitry Andric MemoryDescriptor_64 memory_desc; 1077*0fca6ea1SDimitry Andric memory_desc.StartOfMemoryRange = 1078*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle64_t>(core_range.range.start()); 1079*0fca6ea1SDimitry Andric memory_desc.DataSize = 1080*0fca6ea1SDimitry Andric static_cast<llvm::support::ulittle64_t>(core_range.range.size()); 1081*0fca6ea1SDimitry Andric descriptors.push_back(memory_desc); 1082*0fca6ea1SDimitry Andric // Now write this memory descriptor to the buffer. 1083*0fca6ea1SDimitry Andric m_data.AppendData(&memory_desc, sizeof(MemoryDescriptor_64)); 1084*0fca6ea1SDimitry Andric } 1085*0fca6ea1SDimitry Andric 1086*0fca6ea1SDimitry Andric Log *log = GetLog(LLDBLog::Object); 1087*0fca6ea1SDimitry Andric size_t region_index = 0; 1088*0fca6ea1SDimitry Andric auto data_up = 1089*0fca6ea1SDimitry Andric std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0); 1090*0fca6ea1SDimitry Andric for (const auto &core_range : ranges) { 1091*0fca6ea1SDimitry Andric const addr_t addr = core_range.range.start(); 1092*0fca6ea1SDimitry Andric const addr_t size = core_range.range.size(); 1093*0fca6ea1SDimitry Andric 1094*0fca6ea1SDimitry Andric LLDB_LOGF(log, 1095*0fca6ea1SDimitry Andric "AddMemoryList_64 %zu/%zu reading memory for region " 1096*0fca6ea1SDimitry Andric "(%" PRIx64 "bytes) " 1097*0fca6ea1SDimitry Andric "[%" PRIx64 ", %" PRIx64 ")", 1098*0fca6ea1SDimitry Andric region_index, ranges.size(), size, addr, addr + size); 1099*0fca6ea1SDimitry Andric ++region_index; 1100*0fca6ea1SDimitry Andric 1101*0fca6ea1SDimitry Andric const size_t bytes_read = 1102*0fca6ea1SDimitry Andric m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 1103*0fca6ea1SDimitry Andric if (error.Fail()) { 1104*0fca6ea1SDimitry Andric LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s", 1105*0fca6ea1SDimitry Andric bytes_read, error.AsCString()); 1106*0fca6ea1SDimitry Andric error.Clear(); 1107*0fca6ea1SDimitry Andric cleanup_required = true; 1108*0fca6ea1SDimitry Andric descriptors[region_index].DataSize = 0; 1109*0fca6ea1SDimitry Andric } 1110*0fca6ea1SDimitry Andric if (bytes_read != size) { 1111*0fca6ea1SDimitry Andric LLDB_LOGF( 1112*0fca6ea1SDimitry Andric log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes", 1113*0fca6ea1SDimitry Andric addr, size); 1114*0fca6ea1SDimitry Andric cleanup_required = true; 1115*0fca6ea1SDimitry Andric descriptors[region_index].DataSize = bytes_read; 1116*0fca6ea1SDimitry Andric } 1117*0fca6ea1SDimitry Andric 1118*0fca6ea1SDimitry Andric // Add the data to the buffer, flush as needed. 1119*0fca6ea1SDimitry Andric error = AddData(data_up->GetBytes(), bytes_read); 1120*0fca6ea1SDimitry Andric if (error.Fail()) 1121*0fca6ea1SDimitry Andric return error; 1122*0fca6ea1SDimitry Andric } 1123*0fca6ea1SDimitry Andric 1124*0fca6ea1SDimitry Andric // Early return if there is no cleanup needed. 1125*0fca6ea1SDimitry Andric if (!cleanup_required) { 1126*0fca6ea1SDimitry Andric return error; 1127*0fca6ea1SDimitry Andric } else { 1128*0fca6ea1SDimitry Andric // Flush to disk we can make the fixes in place. 1129*0fca6ea1SDimitry Andric FlushBufferToDisk(); 1130*0fca6ea1SDimitry Andric // Fixup the descriptors that were not read correctly. 1131*0fca6ea1SDimitry Andric m_core_file->SeekFromStart(starting_offset); 1132*0fca6ea1SDimitry Andric size_t bytes_written = sizeof(MemoryDescriptor_64) * descriptors.size(); 1133*0fca6ea1SDimitry Andric error = m_core_file->Write(descriptors.data(), bytes_written); 1134*0fca6ea1SDimitry Andric if (error.Fail() || 1135*0fca6ea1SDimitry Andric bytes_written != sizeof(MemoryDescriptor_64) * descriptors.size()) { 1136*0fca6ea1SDimitry Andric error.SetErrorStringWithFormat( 1137*0fca6ea1SDimitry Andric "unable to write the memory descriptors (written %zd/%zd)", 1138*0fca6ea1SDimitry Andric bytes_written, sizeof(MemoryDescriptor_64) * descriptors.size()); 1139*0fca6ea1SDimitry Andric } 1140*0fca6ea1SDimitry Andric 1141*0fca6ea1SDimitry Andric return error; 1142*0fca6ea1SDimitry Andric } 1143*0fca6ea1SDimitry Andric } 1144*0fca6ea1SDimitry Andric 1145*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddData(const void *data, uint64_t size) { 1146*0fca6ea1SDimitry Andric // This should also get chunked, because worst case we copy over a big 1147*0fca6ea1SDimitry Andric // object / memory range, say 5gb. In that case, we'd have to allocate 10gb 1148*0fca6ea1SDimitry Andric // 5 gb for the buffer we're copying from, and then 5gb for the buffer we're 1149*0fca6ea1SDimitry Andric // copying to. Which will be short lived and immedaitely go to disk, the goal 1150*0fca6ea1SDimitry Andric // here is to limit the number of bytes we need to host in memory at any given 1151*0fca6ea1SDimitry Andric // time. 1152*0fca6ea1SDimitry Andric m_data.AppendData(data, size); 1153*0fca6ea1SDimitry Andric if (m_data.GetByteSize() > MAX_WRITE_CHUNK_SIZE) 1154*0fca6ea1SDimitry Andric return FlushBufferToDisk(); 1155*0fca6ea1SDimitry Andric 1156*0fca6ea1SDimitry Andric return Status(); 1157*0fca6ea1SDimitry Andric } 1158*0fca6ea1SDimitry Andric 1159*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::FlushBufferToDisk() { 1160*0fca6ea1SDimitry Andric Status error; 1161*0fca6ea1SDimitry Andric // Set the stream to it's end. 1162*0fca6ea1SDimitry Andric m_core_file->SeekFromStart(m_saved_data_size); 1163*0fca6ea1SDimitry Andric addr_t starting_size = m_data.GetByteSize(); 1164*0fca6ea1SDimitry Andric addr_t remaining_bytes = starting_size; 1165*0fca6ea1SDimitry Andric offset_t offset = 0; 1166*0fca6ea1SDimitry Andric 1167*0fca6ea1SDimitry Andric while (remaining_bytes > 0) { 1168*0fca6ea1SDimitry Andric size_t bytes_written = remaining_bytes; 1169*0fca6ea1SDimitry Andric // We don't care how many bytes we wrote unless we got an error 1170*0fca6ea1SDimitry Andric // so just decrement the remaining bytes. 1171*0fca6ea1SDimitry Andric error = m_core_file->Write(m_data.GetBytes() + offset, bytes_written); 1172*0fca6ea1SDimitry Andric if (error.Fail()) { 1173*0fca6ea1SDimitry Andric error.SetErrorStringWithFormat( 1174*0fca6ea1SDimitry Andric "Wrote incorrect number of bytes to minidump file. (written %" PRIx64 1175*0fca6ea1SDimitry Andric "/%" PRIx64 ")", 1176*0fca6ea1SDimitry Andric starting_size - remaining_bytes, starting_size); 1177*0fca6ea1SDimitry Andric return error; 1178*0fca6ea1SDimitry Andric } 1179*0fca6ea1SDimitry Andric 1180*0fca6ea1SDimitry Andric offset += bytes_written; 1181*0fca6ea1SDimitry Andric remaining_bytes -= bytes_written; 1182*0fca6ea1SDimitry Andric } 1183*0fca6ea1SDimitry Andric 1184*0fca6ea1SDimitry Andric m_saved_data_size += starting_size; 1185*0fca6ea1SDimitry Andric m_data.Clear(); 1186*0fca6ea1SDimitry Andric return error; 1187*0fca6ea1SDimitry Andric } 1188*0fca6ea1SDimitry Andric 1189*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::DumpFile() { 1190*0fca6ea1SDimitry Andric Status error; 1191*0fca6ea1SDimitry Andric // If anything is left unsaved, dump it. 1192*0fca6ea1SDimitry Andric error = FlushBufferToDisk(); 1193*0fca6ea1SDimitry Andric if (error.Fail()) 1194*0fca6ea1SDimitry Andric return error; 1195*0fca6ea1SDimitry Andric 1196*0fca6ea1SDimitry Andric // Overwrite the header which we filled in earlier. 1197*0fca6ea1SDimitry Andric error = DumpHeader(); 1198*0fca6ea1SDimitry Andric if (error.Fail()) 1199*0fca6ea1SDimitry Andric return error; 1200*0fca6ea1SDimitry Andric 1201*0fca6ea1SDimitry Andric // Overwrite the space saved for directories 1202*0fca6ea1SDimitry Andric error = DumpDirectories(); 1203*0fca6ea1SDimitry Andric if (error.Fail()) 1204*0fca6ea1SDimitry Andric return error; 1205*0fca6ea1SDimitry Andric 1206*0fca6ea1SDimitry Andric return error; 1207349cc55cSDimitry Andric } 1208