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 11349cc55cSDimitry Andric #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h" 12349cc55cSDimitry Andric 13349cc55cSDimitry Andric #include "lldb/Core/Module.h" 14349cc55cSDimitry Andric #include "lldb/Core/ModuleList.h" 15349cc55cSDimitry Andric #include "lldb/Core/Section.h" 16349cc55cSDimitry Andric #include "lldb/Target/MemoryRegionInfo.h" 17349cc55cSDimitry Andric #include "lldb/Target/Process.h" 18349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h" 19349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h" 20349cc55cSDimitry Andric #include "lldb/Target/ThreadList.h" 21349cc55cSDimitry Andric #include "lldb/Utility/DataExtractor.h" 22349cc55cSDimitry Andric #include "lldb/Utility/RegisterValue.h" 23349cc55cSDimitry Andric 24349cc55cSDimitry Andric #include "llvm/ADT/StringRef.h" 25349cc55cSDimitry Andric #include "llvm/BinaryFormat/Minidump.h" 26349cc55cSDimitry Andric #include "llvm/Support/ConvertUTF.h" 27349cc55cSDimitry Andric #include "llvm/Support/Error.h" 28349cc55cSDimitry Andric 29349cc55cSDimitry Andric #include "Plugins/Process/minidump/MinidumpTypes.h" 30349cc55cSDimitry Andric 31349cc55cSDimitry Andric #include <cinttypes> 32349cc55cSDimitry Andric 33349cc55cSDimitry Andric using namespace lldb; 34349cc55cSDimitry Andric using namespace lldb_private; 35349cc55cSDimitry Andric using namespace llvm::minidump; 36349cc55cSDimitry Andric 37349cc55cSDimitry Andric void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) { 38349cc55cSDimitry Andric LocationDescriptor loc; 39349cc55cSDimitry Andric loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size); 40349cc55cSDimitry Andric // Stream will begin at the current end of data section 41349cc55cSDimitry Andric loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 42349cc55cSDimitry Andric 43349cc55cSDimitry Andric Directory dir; 44349cc55cSDimitry Andric dir.Type = static_cast<llvm::support::little_t<StreamType>>(type); 45349cc55cSDimitry Andric dir.Location = loc; 46349cc55cSDimitry Andric 47349cc55cSDimitry Andric m_directories.push_back(dir); 48349cc55cSDimitry Andric } 49349cc55cSDimitry Andric 50349cc55cSDimitry Andric Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) { 51349cc55cSDimitry Andric Status error; 52349cc55cSDimitry Andric AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo)); 53349cc55cSDimitry Andric 54349cc55cSDimitry Andric llvm::minidump::ProcessorArchitecture arch; 55349cc55cSDimitry Andric switch (target_triple.getArch()) { 56349cc55cSDimitry Andric case llvm::Triple::ArchType::x86_64: 57349cc55cSDimitry Andric arch = ProcessorArchitecture::AMD64; 58349cc55cSDimitry Andric break; 59349cc55cSDimitry Andric case llvm::Triple::ArchType::x86: 60349cc55cSDimitry Andric arch = ProcessorArchitecture::X86; 61349cc55cSDimitry Andric break; 62349cc55cSDimitry Andric case llvm::Triple::ArchType::arm: 63349cc55cSDimitry Andric arch = ProcessorArchitecture::ARM; 64349cc55cSDimitry Andric break; 65349cc55cSDimitry Andric case llvm::Triple::ArchType::aarch64: 66349cc55cSDimitry Andric arch = ProcessorArchitecture::ARM64; 67349cc55cSDimitry Andric break; 68349cc55cSDimitry Andric case llvm::Triple::ArchType::mips64: 69349cc55cSDimitry Andric case llvm::Triple::ArchType::mips64el: 70349cc55cSDimitry Andric case llvm::Triple::ArchType::mips: 71349cc55cSDimitry Andric case llvm::Triple::ArchType::mipsel: 72349cc55cSDimitry Andric arch = ProcessorArchitecture::MIPS; 73349cc55cSDimitry Andric break; 74349cc55cSDimitry Andric case llvm::Triple::ArchType::ppc64: 75349cc55cSDimitry Andric case llvm::Triple::ArchType::ppc: 76349cc55cSDimitry Andric case llvm::Triple::ArchType::ppc64le: 77349cc55cSDimitry Andric arch = ProcessorArchitecture::PPC; 78349cc55cSDimitry Andric break; 79349cc55cSDimitry Andric default: 80349cc55cSDimitry Andric error.SetErrorStringWithFormat("Architecture %s not supported.", 81349cc55cSDimitry Andric target_triple.getArchName().str().c_str()); 82349cc55cSDimitry Andric return error; 83349cc55cSDimitry Andric }; 84349cc55cSDimitry Andric 85349cc55cSDimitry Andric llvm::support::little_t<OSPlatform> platform_id; 86349cc55cSDimitry Andric switch (target_triple.getOS()) { 87349cc55cSDimitry Andric case llvm::Triple::OSType::Linux: 88349cc55cSDimitry Andric if (target_triple.getEnvironment() == 89349cc55cSDimitry Andric llvm::Triple::EnvironmentType::Android) 90349cc55cSDimitry Andric platform_id = OSPlatform::Android; 91349cc55cSDimitry Andric else 92349cc55cSDimitry Andric platform_id = OSPlatform::Linux; 93349cc55cSDimitry Andric break; 94349cc55cSDimitry Andric case llvm::Triple::OSType::Win32: 95349cc55cSDimitry Andric platform_id = OSPlatform::Win32NT; 96349cc55cSDimitry Andric break; 97349cc55cSDimitry Andric case llvm::Triple::OSType::MacOSX: 98349cc55cSDimitry Andric platform_id = OSPlatform::MacOSX; 99349cc55cSDimitry Andric break; 100349cc55cSDimitry Andric case llvm::Triple::OSType::IOS: 101349cc55cSDimitry Andric platform_id = OSPlatform::IOS; 102349cc55cSDimitry Andric break; 103349cc55cSDimitry Andric default: 104349cc55cSDimitry Andric error.SetErrorStringWithFormat("OS %s not supported.", 105349cc55cSDimitry Andric target_triple.getOSName().str().c_str()); 106349cc55cSDimitry Andric return error; 107349cc55cSDimitry Andric }; 108349cc55cSDimitry Andric 109349cc55cSDimitry Andric llvm::minidump::SystemInfo sys_info; 110349cc55cSDimitry Andric sys_info.ProcessorArch = 111349cc55cSDimitry Andric static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch); 112349cc55cSDimitry Andric // Global offset to beginning of a csd_string in a data section 113349cc55cSDimitry Andric sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>( 114349cc55cSDimitry Andric GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo)); 115349cc55cSDimitry Andric sys_info.PlatformId = platform_id; 116349cc55cSDimitry Andric m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo)); 117349cc55cSDimitry Andric 118*04eeddc0SDimitry Andric std::string csd_string; 119349cc55cSDimitry Andric 120349cc55cSDimitry Andric error = WriteString(csd_string, &m_data); 121349cc55cSDimitry Andric if (error.Fail()) { 122349cc55cSDimitry Andric error.SetErrorString("Unable to convert the csd string to UTF16."); 123349cc55cSDimitry Andric return error; 124349cc55cSDimitry Andric } 125349cc55cSDimitry Andric 126349cc55cSDimitry Andric return error; 127349cc55cSDimitry Andric } 128349cc55cSDimitry Andric 129349cc55cSDimitry Andric Status WriteString(const std::string &to_write, 130349cc55cSDimitry Andric lldb_private::DataBufferHeap *buffer) { 131349cc55cSDimitry Andric Status error; 132349cc55cSDimitry Andric // let the StringRef eat also null termination char 133349cc55cSDimitry Andric llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1); 134349cc55cSDimitry Andric llvm::SmallVector<llvm::UTF16, 128> to_write_utf16; 135349cc55cSDimitry Andric 136349cc55cSDimitry Andric bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16); 137349cc55cSDimitry Andric if (!converted) { 138349cc55cSDimitry Andric error.SetErrorStringWithFormat( 139349cc55cSDimitry Andric "Unable to convert the string to UTF16. Failed to convert %s", 140349cc55cSDimitry Andric to_write.c_str()); 141349cc55cSDimitry Andric return error; 142349cc55cSDimitry Andric } 143349cc55cSDimitry Andric 144349cc55cSDimitry Andric // size of the UTF16 string should be written without the null termination 145349cc55cSDimitry Andric // character that is stored in 2 bytes 146349cc55cSDimitry Andric llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2); 147349cc55cSDimitry Andric 148349cc55cSDimitry Andric buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t)); 149349cc55cSDimitry Andric buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes()); 150349cc55cSDimitry Andric 151349cc55cSDimitry Andric return error; 152349cc55cSDimitry Andric } 153349cc55cSDimitry Andric 154349cc55cSDimitry Andric llvm::Expected<uint64_t> getModuleFileSize(Target &target, 155349cc55cSDimitry Andric const ModuleSP &mod) { 156349cc55cSDimitry Andric SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection(); 157349cc55cSDimitry Andric uint64_t SizeOfImage = 0; 158349cc55cSDimitry Andric 159349cc55cSDimitry Andric if (!sect_sp) { 160349cc55cSDimitry Andric return llvm::createStringError(std::errc::operation_not_supported, 161349cc55cSDimitry Andric "Couldn't obtain the section information."); 162349cc55cSDimitry Andric } 163349cc55cSDimitry Andric lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target); 164349cc55cSDimitry Andric // Use memory size since zero fill sections, like ".bss", will be smaller on 165349cc55cSDimitry Andric // disk. 166349cc55cSDimitry Andric lldb::addr_t sect_size = sect_sp->GetByteSize(); 167349cc55cSDimitry Andric // This will usually be zero, but make sure to calculate the BaseOfImage 168349cc55cSDimitry Andric // offset. 169349cc55cSDimitry Andric const lldb::addr_t base_sect_offset = 170349cc55cSDimitry Andric mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) - 171349cc55cSDimitry Andric sect_addr; 172349cc55cSDimitry Andric SizeOfImage = sect_size - base_sect_offset; 173349cc55cSDimitry Andric lldb::addr_t next_sect_addr = sect_addr + sect_size; 174349cc55cSDimitry Andric Address sect_so_addr; 175349cc55cSDimitry Andric target.ResolveLoadAddress(next_sect_addr, sect_so_addr); 176349cc55cSDimitry Andric lldb::SectionSP next_sect_sp = sect_so_addr.GetSection(); 177349cc55cSDimitry Andric while (next_sect_sp && 178349cc55cSDimitry Andric next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) { 179349cc55cSDimitry Andric sect_size = sect_sp->GetByteSize(); 180349cc55cSDimitry Andric SizeOfImage += sect_size; 181349cc55cSDimitry Andric next_sect_addr += sect_size; 182349cc55cSDimitry Andric target.ResolveLoadAddress(next_sect_addr, sect_so_addr); 183349cc55cSDimitry Andric next_sect_sp = sect_so_addr.GetSection(); 184349cc55cSDimitry Andric } 185349cc55cSDimitry Andric 186349cc55cSDimitry Andric return SizeOfImage; 187349cc55cSDimitry Andric } 188349cc55cSDimitry Andric 189349cc55cSDimitry Andric // ModuleList stream consists of a number of modules, followed by an array 190349cc55cSDimitry Andric // of llvm::minidump::Module's structures. Every structure informs about a 191349cc55cSDimitry Andric // single module. Additional data of variable length, such as module's names, 192349cc55cSDimitry Andric // are stored just after the ModuleList stream. The llvm::minidump::Module 193349cc55cSDimitry Andric // structures point to this helper data by global offset. 194349cc55cSDimitry Andric Status MinidumpFileBuilder::AddModuleList(Target &target) { 195349cc55cSDimitry Andric constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module); 196349cc55cSDimitry Andric Status error; 197349cc55cSDimitry Andric 198349cc55cSDimitry Andric const ModuleList &modules = target.GetImages(); 199349cc55cSDimitry Andric llvm::support::ulittle32_t modules_count = 200349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(modules.GetSize()); 201349cc55cSDimitry Andric 202349cc55cSDimitry Andric // This helps us with getting the correct global offset in minidump 203349cc55cSDimitry Andric // file later, when we will be setting up offsets from the 204349cc55cSDimitry Andric // the llvm::minidump::Module's structures into helper data 205349cc55cSDimitry Andric size_t size_before = GetCurrentDataEndOffset(); 206349cc55cSDimitry Andric 207349cc55cSDimitry Andric // This is the size of the main part of the ModuleList stream. 208349cc55cSDimitry Andric // It consists of a module number and corresponding number of 209349cc55cSDimitry Andric // structs describing individual modules 210349cc55cSDimitry Andric size_t module_stream_size = 211349cc55cSDimitry Andric sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size; 212349cc55cSDimitry Andric 213349cc55cSDimitry Andric // Adding directory describing this stream. 214349cc55cSDimitry Andric AddDirectory(StreamType::ModuleList, module_stream_size); 215349cc55cSDimitry Andric 216349cc55cSDimitry Andric m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t)); 217349cc55cSDimitry Andric 218349cc55cSDimitry Andric // Temporary storage for the helper data (of variable length) 219349cc55cSDimitry Andric // as these cannot be dumped to m_data before dumping entire 220349cc55cSDimitry Andric // array of module structures. 221349cc55cSDimitry Andric DataBufferHeap helper_data; 222349cc55cSDimitry Andric 223349cc55cSDimitry Andric for (size_t i = 0; i < modules_count; ++i) { 224349cc55cSDimitry Andric ModuleSP mod = modules.GetModuleAtIndex(i); 225349cc55cSDimitry Andric std::string module_name = mod->GetSpecificationDescription(); 226349cc55cSDimitry Andric auto maybe_mod_size = getModuleFileSize(target, mod); 227349cc55cSDimitry Andric if (!maybe_mod_size) { 228349cc55cSDimitry Andric error.SetErrorStringWithFormat("Unable to get the size of module %s.", 229349cc55cSDimitry Andric module_name.c_str()); 230349cc55cSDimitry Andric return error; 231349cc55cSDimitry Andric } 232349cc55cSDimitry Andric 233349cc55cSDimitry Andric uint64_t mod_size = std::move(*maybe_mod_size); 234349cc55cSDimitry Andric 235349cc55cSDimitry Andric llvm::support::ulittle32_t signature = 236349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>( 237349cc55cSDimitry Andric static_cast<uint32_t>(minidump::CvSignature::ElfBuildId)); 238349cc55cSDimitry Andric auto uuid = mod->GetUUID().GetBytes(); 239349cc55cSDimitry Andric 240349cc55cSDimitry Andric VSFixedFileInfo info; 241349cc55cSDimitry Andric info.Signature = static_cast<llvm::support::ulittle32_t>(0u); 242349cc55cSDimitry Andric info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u); 243349cc55cSDimitry Andric info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u); 244349cc55cSDimitry Andric info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u); 245349cc55cSDimitry Andric info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u); 246349cc55cSDimitry Andric info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u); 247349cc55cSDimitry Andric info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u); 248349cc55cSDimitry Andric info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u); 249349cc55cSDimitry Andric info.FileOS = static_cast<llvm::support::ulittle32_t>(0u); 250349cc55cSDimitry Andric info.FileType = static_cast<llvm::support::ulittle32_t>(0u); 251349cc55cSDimitry Andric info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u); 252349cc55cSDimitry Andric info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u); 253349cc55cSDimitry Andric info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u); 254349cc55cSDimitry Andric 255349cc55cSDimitry Andric LocationDescriptor ld; 256349cc55cSDimitry Andric ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u); 257349cc55cSDimitry Andric ld.RVA = static_cast<llvm::support::ulittle32_t>(0u); 258349cc55cSDimitry Andric 259349cc55cSDimitry Andric // Setting up LocationDescriptor for uuid string. The global offset into 260349cc55cSDimitry Andric // minidump file is calculated. 261349cc55cSDimitry Andric LocationDescriptor ld_cv; 262349cc55cSDimitry Andric ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>( 263349cc55cSDimitry Andric sizeof(llvm::support::ulittle32_t) + uuid.size()); 264349cc55cSDimitry Andric ld_cv.RVA = static_cast<llvm::support::ulittle32_t>( 265349cc55cSDimitry Andric size_before + module_stream_size + helper_data.GetByteSize()); 266349cc55cSDimitry Andric 267349cc55cSDimitry Andric helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t)); 268349cc55cSDimitry Andric helper_data.AppendData(uuid.begin(), uuid.size()); 269349cc55cSDimitry Andric 270349cc55cSDimitry Andric llvm::minidump::Module m; 271349cc55cSDimitry Andric m.BaseOfImage = static_cast<llvm::support::ulittle64_t>( 272349cc55cSDimitry Andric mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target)); 273349cc55cSDimitry Andric m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size); 274349cc55cSDimitry Andric m.Checksum = static_cast<llvm::support::ulittle32_t>(0); 275*04eeddc0SDimitry Andric m.TimeDateStamp = 276*04eeddc0SDimitry Andric static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); 277349cc55cSDimitry Andric m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>( 278349cc55cSDimitry Andric size_before + module_stream_size + helper_data.GetByteSize()); 279349cc55cSDimitry Andric m.VersionInfo = info; 280349cc55cSDimitry Andric m.CvRecord = ld_cv; 281349cc55cSDimitry Andric m.MiscRecord = ld; 282349cc55cSDimitry Andric 283349cc55cSDimitry Andric error = WriteString(module_name, &helper_data); 284349cc55cSDimitry Andric 285349cc55cSDimitry Andric if (error.Fail()) 286349cc55cSDimitry Andric return error; 287349cc55cSDimitry Andric 288349cc55cSDimitry Andric m_data.AppendData(&m, sizeof(llvm::minidump::Module)); 289349cc55cSDimitry Andric } 290349cc55cSDimitry Andric 291349cc55cSDimitry Andric m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 292349cc55cSDimitry Andric return error; 293349cc55cSDimitry Andric } 294349cc55cSDimitry Andric 295349cc55cSDimitry Andric uint16_t read_register_u16_raw(RegisterContext *reg_ctx, 296349cc55cSDimitry Andric const std::string ®_name) { 297349cc55cSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 298349cc55cSDimitry Andric if (!reg_info) 299349cc55cSDimitry Andric return 0; 300349cc55cSDimitry Andric lldb_private::RegisterValue reg_value; 301349cc55cSDimitry Andric bool success = reg_ctx->ReadRegister(reg_info, reg_value); 302349cc55cSDimitry Andric if (!success) 303349cc55cSDimitry Andric return 0; 304349cc55cSDimitry Andric return reg_value.GetAsUInt16(); 305349cc55cSDimitry Andric } 306349cc55cSDimitry Andric 307349cc55cSDimitry Andric uint32_t read_register_u32_raw(RegisterContext *reg_ctx, 308349cc55cSDimitry Andric const std::string ®_name) { 309349cc55cSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 310349cc55cSDimitry Andric if (!reg_info) 311349cc55cSDimitry Andric return 0; 312349cc55cSDimitry Andric lldb_private::RegisterValue reg_value; 313349cc55cSDimitry Andric bool success = reg_ctx->ReadRegister(reg_info, reg_value); 314349cc55cSDimitry Andric if (!success) 315349cc55cSDimitry Andric return 0; 316349cc55cSDimitry Andric return reg_value.GetAsUInt32(); 317349cc55cSDimitry Andric } 318349cc55cSDimitry Andric 319349cc55cSDimitry Andric uint64_t read_register_u64_raw(RegisterContext *reg_ctx, 320349cc55cSDimitry Andric const std::string ®_name) { 321349cc55cSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 322349cc55cSDimitry Andric if (!reg_info) 323349cc55cSDimitry Andric return 0; 324349cc55cSDimitry Andric lldb_private::RegisterValue reg_value; 325349cc55cSDimitry Andric bool success = reg_ctx->ReadRegister(reg_info, reg_value); 326349cc55cSDimitry Andric if (!success) 327349cc55cSDimitry Andric return 0; 328349cc55cSDimitry Andric return reg_value.GetAsUInt64(); 329349cc55cSDimitry Andric } 330349cc55cSDimitry Andric 331349cc55cSDimitry Andric llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx, 332349cc55cSDimitry Andric const std::string ®_name) { 333349cc55cSDimitry Andric return static_cast<llvm::support::ulittle16_t>( 334349cc55cSDimitry Andric read_register_u16_raw(reg_ctx, reg_name)); 335349cc55cSDimitry Andric } 336349cc55cSDimitry Andric 337349cc55cSDimitry Andric llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx, 338349cc55cSDimitry Andric const std::string ®_name) { 339349cc55cSDimitry Andric return static_cast<llvm::support::ulittle32_t>( 340349cc55cSDimitry Andric read_register_u32_raw(reg_ctx, reg_name)); 341349cc55cSDimitry Andric } 342349cc55cSDimitry Andric 343349cc55cSDimitry Andric llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx, 344349cc55cSDimitry Andric const std::string ®_name) { 345349cc55cSDimitry Andric return static_cast<llvm::support::ulittle64_t>( 346349cc55cSDimitry Andric read_register_u64_raw(reg_ctx, reg_name)); 347349cc55cSDimitry Andric } 348349cc55cSDimitry Andric 349349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64 350349cc55cSDimitry Andric GetThreadContext_64(RegisterContext *reg_ctx) { 351349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64 thread_context; 352349cc55cSDimitry Andric thread_context.context_flags = static_cast<uint32_t>( 353349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag | 354349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Control | 355349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments | 356349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer); 357349cc55cSDimitry Andric thread_context.rax = read_register_u64(reg_ctx, "rax"); 358349cc55cSDimitry Andric thread_context.rbx = read_register_u64(reg_ctx, "rbx"); 359349cc55cSDimitry Andric thread_context.rcx = read_register_u64(reg_ctx, "rcx"); 360349cc55cSDimitry Andric thread_context.rdx = read_register_u64(reg_ctx, "rdx"); 361349cc55cSDimitry Andric thread_context.rdi = read_register_u64(reg_ctx, "rdi"); 362349cc55cSDimitry Andric thread_context.rsi = read_register_u64(reg_ctx, "rsi"); 363349cc55cSDimitry Andric thread_context.rbp = read_register_u64(reg_ctx, "rbp"); 364349cc55cSDimitry Andric thread_context.rsp = read_register_u64(reg_ctx, "rsp"); 365349cc55cSDimitry Andric thread_context.r8 = read_register_u64(reg_ctx, "r8"); 366349cc55cSDimitry Andric thread_context.r9 = read_register_u64(reg_ctx, "r9"); 367349cc55cSDimitry Andric thread_context.r10 = read_register_u64(reg_ctx, "r10"); 368349cc55cSDimitry Andric thread_context.r11 = read_register_u64(reg_ctx, "r11"); 369349cc55cSDimitry Andric thread_context.r12 = read_register_u64(reg_ctx, "r12"); 370349cc55cSDimitry Andric thread_context.r13 = read_register_u64(reg_ctx, "r13"); 371349cc55cSDimitry Andric thread_context.r14 = read_register_u64(reg_ctx, "r14"); 372349cc55cSDimitry Andric thread_context.r15 = read_register_u64(reg_ctx, "r15"); 373349cc55cSDimitry Andric thread_context.rip = read_register_u64(reg_ctx, "rip"); 374349cc55cSDimitry Andric thread_context.eflags = read_register_u32(reg_ctx, "rflags"); 375349cc55cSDimitry Andric thread_context.cs = read_register_u16(reg_ctx, "cs"); 376349cc55cSDimitry Andric thread_context.fs = read_register_u16(reg_ctx, "fs"); 377349cc55cSDimitry Andric thread_context.gs = read_register_u16(reg_ctx, "gs"); 378349cc55cSDimitry Andric thread_context.ss = read_register_u16(reg_ctx, "ss"); 379349cc55cSDimitry Andric thread_context.ds = read_register_u16(reg_ctx, "ds"); 380349cc55cSDimitry Andric return thread_context; 381349cc55cSDimitry Andric } 382349cc55cSDimitry Andric 383349cc55cSDimitry Andric // Function returns start and size of the memory region that contains 384349cc55cSDimitry Andric // memory location pointed to by the current stack pointer. 385349cc55cSDimitry Andric llvm::Expected<std::pair<addr_t, addr_t>> 386349cc55cSDimitry Andric findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) { 387349cc55cSDimitry Andric MemoryRegionInfo range_info; 388349cc55cSDimitry Andric Status error = process_sp->GetMemoryRegionInfo(rsp, range_info); 389349cc55cSDimitry Andric // Skip failed memory region requests or any regions with no permissions. 390349cc55cSDimitry Andric if (error.Fail() || range_info.GetLLDBPermissions() == 0) 391349cc55cSDimitry Andric return llvm::createStringError( 392349cc55cSDimitry Andric std::errc::not_supported, 393349cc55cSDimitry Andric "unable to load stack segment of the process"); 394349cc55cSDimitry Andric 395349cc55cSDimitry Andric const addr_t addr = range_info.GetRange().GetRangeBase(); 396349cc55cSDimitry Andric const addr_t size = range_info.GetRange().GetByteSize(); 397349cc55cSDimitry Andric 398349cc55cSDimitry Andric if (size == 0) 399349cc55cSDimitry Andric return llvm::createStringError(std::errc::not_supported, 400349cc55cSDimitry Andric "stack segment of the process is empty"); 401349cc55cSDimitry Andric 402349cc55cSDimitry Andric return std::make_pair(addr, size); 403349cc55cSDimitry Andric } 404349cc55cSDimitry Andric 405349cc55cSDimitry Andric Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { 406349cc55cSDimitry Andric constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread); 407349cc55cSDimitry Andric lldb_private::ThreadList thread_list = process_sp->GetThreadList(); 408349cc55cSDimitry Andric 409349cc55cSDimitry Andric // size of the entire thread stream consists of: 410349cc55cSDimitry Andric // number of threads and threads array 411349cc55cSDimitry Andric size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) + 412349cc55cSDimitry Andric thread_list.GetSize() * minidump_thread_size; 413349cc55cSDimitry Andric // save for the ability to set up RVA 414349cc55cSDimitry Andric size_t size_before = GetCurrentDataEndOffset(); 415349cc55cSDimitry Andric 416349cc55cSDimitry Andric AddDirectory(StreamType::ThreadList, thread_stream_size); 417349cc55cSDimitry Andric 418349cc55cSDimitry Andric llvm::support::ulittle32_t thread_count = 419349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_list.GetSize()); 420349cc55cSDimitry Andric m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t)); 421349cc55cSDimitry Andric 422349cc55cSDimitry Andric DataBufferHeap helper_data; 423349cc55cSDimitry Andric 424349cc55cSDimitry Andric const uint32_t num_threads = thread_list.GetSize(); 425349cc55cSDimitry Andric 426349cc55cSDimitry Andric for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 427349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); 428349cc55cSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 429349cc55cSDimitry Andric Status error; 430349cc55cSDimitry Andric 431349cc55cSDimitry Andric if (!reg_ctx_sp) { 432349cc55cSDimitry Andric error.SetErrorString("Unable to get the register context."); 433349cc55cSDimitry Andric return error; 434349cc55cSDimitry Andric } 435349cc55cSDimitry Andric RegisterContext *reg_ctx = reg_ctx_sp.get(); 436349cc55cSDimitry Andric auto thread_context = GetThreadContext_64(reg_ctx); 437349cc55cSDimitry Andric uint64_t rsp = read_register_u64_raw(reg_ctx, "rsp"); 438349cc55cSDimitry Andric auto expected_address_range = findStackHelper(process_sp, rsp); 439349cc55cSDimitry Andric 440349cc55cSDimitry Andric if (!expected_address_range) { 441349cc55cSDimitry Andric error.SetErrorString("Unable to get the stack address."); 442349cc55cSDimitry Andric return error; 443349cc55cSDimitry Andric } 444349cc55cSDimitry Andric 445349cc55cSDimitry Andric std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range); 446349cc55cSDimitry Andric uint64_t addr = range.first; 447349cc55cSDimitry Andric uint64_t size = range.second; 448349cc55cSDimitry Andric 449349cc55cSDimitry Andric auto data_up = std::make_unique<DataBufferHeap>(size, 0); 450349cc55cSDimitry Andric const size_t stack_bytes_read = 451349cc55cSDimitry Andric process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 452349cc55cSDimitry Andric 453349cc55cSDimitry Andric if (error.Fail()) 454349cc55cSDimitry Andric return error; 455349cc55cSDimitry Andric 456349cc55cSDimitry Andric LocationDescriptor stack_memory; 457349cc55cSDimitry Andric stack_memory.DataSize = 458349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(stack_bytes_read); 459349cc55cSDimitry Andric stack_memory.RVA = static_cast<llvm::support::ulittle32_t>( 460349cc55cSDimitry Andric size_before + thread_stream_size + helper_data.GetByteSize()); 461349cc55cSDimitry Andric 462349cc55cSDimitry Andric MemoryDescriptor stack; 463349cc55cSDimitry Andric stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr); 464349cc55cSDimitry Andric stack.Memory = stack_memory; 465349cc55cSDimitry Andric 466349cc55cSDimitry Andric helper_data.AppendData(data_up->GetBytes(), stack_bytes_read); 467349cc55cSDimitry Andric 468349cc55cSDimitry Andric LocationDescriptor thread_context_memory_locator; 469349cc55cSDimitry Andric thread_context_memory_locator.DataSize = 470349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(sizeof(thread_context)); 471349cc55cSDimitry Andric thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>( 472349cc55cSDimitry Andric size_before + thread_stream_size + helper_data.GetByteSize()); 473349cc55cSDimitry Andric 474349cc55cSDimitry Andric helper_data.AppendData( 475349cc55cSDimitry Andric &thread_context, 476349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpContext_x86_64)); 477349cc55cSDimitry Andric 478349cc55cSDimitry Andric llvm::minidump::Thread t; 479349cc55cSDimitry Andric t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 480349cc55cSDimitry Andric t.SuspendCount = static_cast<llvm::support::ulittle32_t>( 481349cc55cSDimitry Andric (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0); 482349cc55cSDimitry Andric t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0); 483349cc55cSDimitry Andric t.Priority = static_cast<llvm::support::ulittle32_t>(0); 484349cc55cSDimitry Andric t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0); 485349cc55cSDimitry Andric t.Stack = stack, t.Context = thread_context_memory_locator; 486349cc55cSDimitry Andric 487349cc55cSDimitry Andric m_data.AppendData(&t, sizeof(llvm::minidump::Thread)); 488349cc55cSDimitry Andric } 489349cc55cSDimitry Andric 490349cc55cSDimitry Andric m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 491349cc55cSDimitry Andric return Status(); 492349cc55cSDimitry Andric } 493349cc55cSDimitry Andric 494349cc55cSDimitry Andric Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) { 495349cc55cSDimitry Andric Status error; 496349cc55cSDimitry Andric lldb_private::ThreadList thread_list = process_sp->GetThreadList(); 497349cc55cSDimitry Andric 498349cc55cSDimitry Andric const uint32_t num_threads = thread_list.GetSize(); 499349cc55cSDimitry Andric uint32_t stop_reason_thread_idx = 0; 500349cc55cSDimitry Andric for (stop_reason_thread_idx = 0; stop_reason_thread_idx < num_threads; 501349cc55cSDimitry Andric ++stop_reason_thread_idx) { 502349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx)); 503349cc55cSDimitry Andric StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 504349cc55cSDimitry Andric 505349cc55cSDimitry Andric if (stop_info_sp && stop_info_sp->IsValid()) 506349cc55cSDimitry Andric break; 507349cc55cSDimitry Andric } 508349cc55cSDimitry Andric 509349cc55cSDimitry Andric if (stop_reason_thread_idx == num_threads) { 510349cc55cSDimitry Andric error.SetErrorString("No stop reason thread found."); 511349cc55cSDimitry Andric return error; 512349cc55cSDimitry Andric } 513349cc55cSDimitry Andric 514349cc55cSDimitry Andric constexpr size_t minidump_exception_size = 515349cc55cSDimitry Andric sizeof(llvm::minidump::ExceptionStream); 516349cc55cSDimitry Andric AddDirectory(StreamType::Exception, minidump_exception_size); 517349cc55cSDimitry Andric size_t size_before = GetCurrentDataEndOffset(); 518349cc55cSDimitry Andric 519349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx)); 520349cc55cSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 521349cc55cSDimitry Andric RegisterContext *reg_ctx = reg_ctx_sp.get(); 522349cc55cSDimitry Andric auto thread_context = GetThreadContext_64(reg_ctx); 523349cc55cSDimitry Andric StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 524349cc55cSDimitry Andric 525349cc55cSDimitry Andric DataBufferHeap helper_data; 526349cc55cSDimitry Andric 527349cc55cSDimitry Andric LocationDescriptor thread_context_memory_locator; 528349cc55cSDimitry Andric thread_context_memory_locator.DataSize = 529349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(sizeof(thread_context)); 530349cc55cSDimitry Andric thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>( 531349cc55cSDimitry Andric size_before + minidump_exception_size + helper_data.GetByteSize()); 532349cc55cSDimitry Andric 533349cc55cSDimitry Andric helper_data.AppendData( 534349cc55cSDimitry Andric &thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64)); 535349cc55cSDimitry Andric 536349cc55cSDimitry Andric Exception exp_record; 537349cc55cSDimitry Andric exp_record.ExceptionCode = 538349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue()); 539349cc55cSDimitry Andric exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0); 540349cc55cSDimitry Andric exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0); 541349cc55cSDimitry Andric exp_record.ExceptionAddress = read_register_u64(reg_ctx, "rip"); 542349cc55cSDimitry Andric exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0); 543349cc55cSDimitry Andric exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 544349cc55cSDimitry Andric // exp_record.ExceptionInformation; 545349cc55cSDimitry Andric 546349cc55cSDimitry Andric ExceptionStream exp_stream; 547349cc55cSDimitry Andric exp_stream.ThreadId = 548349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 549349cc55cSDimitry Andric exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 550349cc55cSDimitry Andric exp_stream.ExceptionRecord = exp_record; 551349cc55cSDimitry Andric exp_stream.ThreadContext = thread_context_memory_locator; 552349cc55cSDimitry Andric 553349cc55cSDimitry Andric m_data.AppendData(&exp_stream, minidump_exception_size); 554349cc55cSDimitry Andric m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 555349cc55cSDimitry Andric return error; 556349cc55cSDimitry Andric } 557349cc55cSDimitry Andric 558349cc55cSDimitry Andric lldb_private::Status 559349cc55cSDimitry Andric MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp) { 560349cc55cSDimitry Andric Status error; 561349cc55cSDimitry Andric 562349cc55cSDimitry Andric if (error.Fail()) { 563349cc55cSDimitry Andric error.SetErrorString("Process doesn't support getting memory region info."); 564349cc55cSDimitry Andric return error; 565349cc55cSDimitry Andric } 566349cc55cSDimitry Andric 567349cc55cSDimitry Andric // Get interesting addresses 568349cc55cSDimitry Andric std::vector<size_t> interesting_addresses; 569349cc55cSDimitry Andric auto thread_list = process_sp->GetThreadList(); 570349cc55cSDimitry Andric for (size_t i = 0; i < thread_list.GetSize(); ++i) { 571349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(i)); 572349cc55cSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 573349cc55cSDimitry Andric RegisterContext *reg_ctx = reg_ctx_sp.get(); 574349cc55cSDimitry Andric 575349cc55cSDimitry Andric interesting_addresses.push_back(read_register_u64(reg_ctx, "rsp")); 576349cc55cSDimitry Andric interesting_addresses.push_back(read_register_u64(reg_ctx, "rip")); 577349cc55cSDimitry Andric } 578349cc55cSDimitry Andric 579349cc55cSDimitry Andric DataBufferHeap helper_data; 580349cc55cSDimitry Andric std::vector<MemoryDescriptor> mem_descriptors; 581349cc55cSDimitry Andric 582349cc55cSDimitry Andric std::set<addr_t> visited_region_base_addresses; 583349cc55cSDimitry Andric for (size_t interesting_address : interesting_addresses) { 584349cc55cSDimitry Andric MemoryRegionInfo range_info; 585349cc55cSDimitry Andric error = process_sp->GetMemoryRegionInfo(interesting_address, range_info); 586349cc55cSDimitry Andric // Skip failed memory region requests or any regions with no permissions. 587349cc55cSDimitry Andric if (error.Fail() || range_info.GetLLDBPermissions() == 0) 588349cc55cSDimitry Andric continue; 589349cc55cSDimitry Andric const addr_t addr = range_info.GetRange().GetRangeBase(); 590349cc55cSDimitry Andric // Skip any regions we have already saved out. 591349cc55cSDimitry Andric if (visited_region_base_addresses.insert(addr).second == false) 592349cc55cSDimitry Andric continue; 593349cc55cSDimitry Andric const addr_t size = range_info.GetRange().GetByteSize(); 594349cc55cSDimitry Andric if (size == 0) 595349cc55cSDimitry Andric continue; 596349cc55cSDimitry Andric auto data_up = std::make_unique<DataBufferHeap>(size, 0); 597349cc55cSDimitry Andric const size_t bytes_read = 598349cc55cSDimitry Andric process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 599349cc55cSDimitry Andric if (bytes_read == 0) 600349cc55cSDimitry Andric continue; 601349cc55cSDimitry Andric // We have a good memory region with valid bytes to store. 602349cc55cSDimitry Andric LocationDescriptor memory_dump; 603349cc55cSDimitry Andric memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read); 604349cc55cSDimitry Andric memory_dump.RVA = 605349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 606349cc55cSDimitry Andric MemoryDescriptor memory_desc; 607349cc55cSDimitry Andric memory_desc.StartOfMemoryRange = 608349cc55cSDimitry Andric static_cast<llvm::support::ulittle64_t>(addr); 609349cc55cSDimitry Andric memory_desc.Memory = memory_dump; 610349cc55cSDimitry Andric mem_descriptors.push_back(memory_desc); 611349cc55cSDimitry Andric m_data.AppendData(data_up->GetBytes(), bytes_read); 612349cc55cSDimitry Andric } 613349cc55cSDimitry Andric 614349cc55cSDimitry Andric AddDirectory(StreamType::MemoryList, 615349cc55cSDimitry Andric sizeof(llvm::support::ulittle32_t) + 616349cc55cSDimitry Andric mem_descriptors.size() * 617349cc55cSDimitry Andric sizeof(llvm::minidump::MemoryDescriptor)); 618349cc55cSDimitry Andric llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size()); 619349cc55cSDimitry Andric 620349cc55cSDimitry Andric m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t)); 621349cc55cSDimitry Andric for (auto memory_descriptor : mem_descriptors) { 622349cc55cSDimitry Andric m_data.AppendData(&memory_descriptor, 623349cc55cSDimitry Andric sizeof(llvm::minidump::MemoryDescriptor)); 624349cc55cSDimitry Andric } 625349cc55cSDimitry Andric 626349cc55cSDimitry Andric return error; 627349cc55cSDimitry Andric } 628349cc55cSDimitry Andric 629349cc55cSDimitry Andric void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) { 630349cc55cSDimitry Andric AddDirectory(StreamType::MiscInfo, 631349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 632349cc55cSDimitry Andric 633349cc55cSDimitry Andric lldb_private::minidump::MinidumpMiscInfo misc_info; 634349cc55cSDimitry Andric misc_info.size = static_cast<llvm::support::ulittle32_t>( 635349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 636349cc55cSDimitry Andric // Default set flags1 to 0, in case that we will not be able to 637349cc55cSDimitry Andric // get any information 638349cc55cSDimitry Andric misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0); 639349cc55cSDimitry Andric 640349cc55cSDimitry Andric lldb_private::ProcessInstanceInfo process_info; 641349cc55cSDimitry Andric process_sp->GetProcessInfo(process_info); 642349cc55cSDimitry Andric if (process_info.ProcessIDIsValid()) { 643349cc55cSDimitry Andric // Set flags1 to reflect that PID is filled in 644349cc55cSDimitry Andric misc_info.flags1 = 645349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>( 646349cc55cSDimitry Andric lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID)); 647349cc55cSDimitry Andric misc_info.process_id = 648349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID()); 649349cc55cSDimitry Andric } 650349cc55cSDimitry Andric 651349cc55cSDimitry Andric m_data.AppendData(&misc_info, 652349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 653349cc55cSDimitry Andric } 654349cc55cSDimitry Andric 655349cc55cSDimitry Andric std::unique_ptr<llvm::MemoryBuffer> 656349cc55cSDimitry Andric getFileStreamHelper(const std::string &path) { 657349cc55cSDimitry Andric auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path); 658349cc55cSDimitry Andric if (!maybe_stream) 659349cc55cSDimitry Andric return nullptr; 660349cc55cSDimitry Andric return std::move(maybe_stream.get()); 661349cc55cSDimitry Andric } 662349cc55cSDimitry Andric 663349cc55cSDimitry Andric void MinidumpFileBuilder::AddLinuxFileStreams( 664349cc55cSDimitry Andric const lldb::ProcessSP &process_sp) { 665349cc55cSDimitry Andric std::vector<std::pair<StreamType, std::string>> files_with_stream_types = { 666349cc55cSDimitry Andric {StreamType::LinuxCPUInfo, "/proc/cpuinfo"}, 667349cc55cSDimitry Andric {StreamType::LinuxLSBRelease, "/etc/lsb-release"}, 668349cc55cSDimitry Andric }; 669349cc55cSDimitry Andric 670349cc55cSDimitry Andric lldb_private::ProcessInstanceInfo process_info; 671349cc55cSDimitry Andric process_sp->GetProcessInfo(process_info); 672349cc55cSDimitry Andric if (process_info.ProcessIDIsValid()) { 673349cc55cSDimitry Andric lldb::pid_t pid = process_info.GetProcessID(); 674349cc55cSDimitry Andric std::string pid_str = std::to_string(pid); 675349cc55cSDimitry Andric files_with_stream_types.push_back( 676349cc55cSDimitry Andric {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"}); 677349cc55cSDimitry Andric files_with_stream_types.push_back( 678349cc55cSDimitry Andric {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"}); 679349cc55cSDimitry Andric files_with_stream_types.push_back( 680349cc55cSDimitry Andric {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"}); 681349cc55cSDimitry Andric files_with_stream_types.push_back( 682349cc55cSDimitry Andric {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"}); 683349cc55cSDimitry Andric files_with_stream_types.push_back( 684349cc55cSDimitry Andric {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"}); 685349cc55cSDimitry Andric files_with_stream_types.push_back( 686349cc55cSDimitry Andric {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"}); 687349cc55cSDimitry Andric files_with_stream_types.push_back( 688349cc55cSDimitry Andric {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"}); 689349cc55cSDimitry Andric } 690349cc55cSDimitry Andric 691349cc55cSDimitry Andric for (const auto &entry : files_with_stream_types) { 692349cc55cSDimitry Andric StreamType stream = entry.first; 693349cc55cSDimitry Andric std::string path = entry.second; 694349cc55cSDimitry Andric auto memory_buffer = getFileStreamHelper(path); 695349cc55cSDimitry Andric 696349cc55cSDimitry Andric if (memory_buffer) { 697349cc55cSDimitry Andric size_t size = memory_buffer->getBufferSize(); 698349cc55cSDimitry Andric if (size == 0) 699349cc55cSDimitry Andric continue; 700349cc55cSDimitry Andric AddDirectory(stream, size); 701349cc55cSDimitry Andric m_data.AppendData(memory_buffer->getBufferStart(), size); 702349cc55cSDimitry Andric } 703349cc55cSDimitry Andric } 704349cc55cSDimitry Andric } 705349cc55cSDimitry Andric 706349cc55cSDimitry Andric Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const { 707349cc55cSDimitry Andric constexpr size_t header_size = sizeof(llvm::minidump::Header); 708349cc55cSDimitry Andric constexpr size_t directory_size = sizeof(llvm::minidump::Directory); 709349cc55cSDimitry Andric 710349cc55cSDimitry Andric // write header 711349cc55cSDimitry Andric llvm::minidump::Header header; 712349cc55cSDimitry Andric header.Signature = static_cast<llvm::support::ulittle32_t>( 713349cc55cSDimitry Andric llvm::minidump::Header::MagicSignature); 714349cc55cSDimitry Andric header.Version = static_cast<llvm::support::ulittle32_t>( 715349cc55cSDimitry Andric llvm::minidump::Header::MagicVersion); 716349cc55cSDimitry Andric header.NumberOfStreams = 717349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum()); 718349cc55cSDimitry Andric header.StreamDirectoryRVA = 719349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 720349cc55cSDimitry Andric header.Checksum = static_cast<llvm::support::ulittle32_t>( 721349cc55cSDimitry Andric 0u), // not used in most of the writers 722349cc55cSDimitry Andric header.TimeDateStamp = 723*04eeddc0SDimitry Andric static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); 724349cc55cSDimitry Andric header.Flags = 725349cc55cSDimitry Andric static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag 726349cc55cSDimitry Andric 727349cc55cSDimitry Andric Status error; 728349cc55cSDimitry Andric size_t bytes_written; 729349cc55cSDimitry Andric 730349cc55cSDimitry Andric bytes_written = header_size; 731349cc55cSDimitry Andric error = core_file->Write(&header, bytes_written); 732349cc55cSDimitry Andric if (error.Fail() || bytes_written != header_size) { 733349cc55cSDimitry Andric if (bytes_written != header_size) 734349cc55cSDimitry Andric error.SetErrorStringWithFormat( 735349cc55cSDimitry Andric "unable to write the header (written %zd/%zd)", bytes_written, 736349cc55cSDimitry Andric header_size); 737349cc55cSDimitry Andric return error; 738349cc55cSDimitry Andric } 739349cc55cSDimitry Andric 740349cc55cSDimitry Andric // write data 741349cc55cSDimitry Andric bytes_written = m_data.GetByteSize(); 742349cc55cSDimitry Andric error = core_file->Write(m_data.GetBytes(), bytes_written); 743349cc55cSDimitry Andric if (error.Fail() || bytes_written != m_data.GetByteSize()) { 744349cc55cSDimitry Andric if (bytes_written != m_data.GetByteSize()) 745349cc55cSDimitry Andric error.SetErrorStringWithFormat( 746349cc55cSDimitry Andric "unable to write the data (written %zd/%" PRIu64 ")", bytes_written, 747349cc55cSDimitry Andric m_data.GetByteSize()); 748349cc55cSDimitry Andric return error; 749349cc55cSDimitry Andric } 750349cc55cSDimitry Andric 751349cc55cSDimitry Andric // write directories 752349cc55cSDimitry Andric for (const Directory &dir : m_directories) { 753349cc55cSDimitry Andric bytes_written = directory_size; 754349cc55cSDimitry Andric error = core_file->Write(&dir, bytes_written); 755349cc55cSDimitry Andric if (error.Fail() || bytes_written != directory_size) { 756349cc55cSDimitry Andric if (bytes_written != directory_size) 757349cc55cSDimitry Andric error.SetErrorStringWithFormat( 758349cc55cSDimitry Andric "unable to write the directory (written %zd/%zd)", bytes_written, 759349cc55cSDimitry Andric directory_size); 760349cc55cSDimitry Andric return error; 761349cc55cSDimitry Andric } 762349cc55cSDimitry Andric } 763349cc55cSDimitry Andric 764349cc55cSDimitry Andric return error; 765349cc55cSDimitry Andric } 766349cc55cSDimitry Andric 767349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetDirectoriesNum() const { 768349cc55cSDimitry Andric return m_directories.size(); 769349cc55cSDimitry Andric } 770349cc55cSDimitry Andric 771349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const { 772349cc55cSDimitry Andric return sizeof(llvm::minidump::Header) + m_data.GetByteSize(); 773349cc55cSDimitry Andric } 774