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 11804eeddc0SDimitry 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); 27504eeddc0SDimitry Andric m.TimeDateStamp = 27604eeddc0SDimitry 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; 352*fcaf7f86SDimitry Andric thread_context.p1_home = {}; 353349cc55cSDimitry Andric thread_context.context_flags = static_cast<uint32_t>( 354349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag | 355349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Control | 356349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments | 357349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer); 358349cc55cSDimitry Andric thread_context.rax = read_register_u64(reg_ctx, "rax"); 359349cc55cSDimitry Andric thread_context.rbx = read_register_u64(reg_ctx, "rbx"); 360349cc55cSDimitry Andric thread_context.rcx = read_register_u64(reg_ctx, "rcx"); 361349cc55cSDimitry Andric thread_context.rdx = read_register_u64(reg_ctx, "rdx"); 362349cc55cSDimitry Andric thread_context.rdi = read_register_u64(reg_ctx, "rdi"); 363349cc55cSDimitry Andric thread_context.rsi = read_register_u64(reg_ctx, "rsi"); 364349cc55cSDimitry Andric thread_context.rbp = read_register_u64(reg_ctx, "rbp"); 365349cc55cSDimitry Andric thread_context.rsp = read_register_u64(reg_ctx, "rsp"); 366349cc55cSDimitry Andric thread_context.r8 = read_register_u64(reg_ctx, "r8"); 367349cc55cSDimitry Andric thread_context.r9 = read_register_u64(reg_ctx, "r9"); 368349cc55cSDimitry Andric thread_context.r10 = read_register_u64(reg_ctx, "r10"); 369349cc55cSDimitry Andric thread_context.r11 = read_register_u64(reg_ctx, "r11"); 370349cc55cSDimitry Andric thread_context.r12 = read_register_u64(reg_ctx, "r12"); 371349cc55cSDimitry Andric thread_context.r13 = read_register_u64(reg_ctx, "r13"); 372349cc55cSDimitry Andric thread_context.r14 = read_register_u64(reg_ctx, "r14"); 373349cc55cSDimitry Andric thread_context.r15 = read_register_u64(reg_ctx, "r15"); 374349cc55cSDimitry Andric thread_context.rip = read_register_u64(reg_ctx, "rip"); 375349cc55cSDimitry Andric thread_context.eflags = read_register_u32(reg_ctx, "rflags"); 376349cc55cSDimitry Andric thread_context.cs = read_register_u16(reg_ctx, "cs"); 377349cc55cSDimitry Andric thread_context.fs = read_register_u16(reg_ctx, "fs"); 378349cc55cSDimitry Andric thread_context.gs = read_register_u16(reg_ctx, "gs"); 379349cc55cSDimitry Andric thread_context.ss = read_register_u16(reg_ctx, "ss"); 380349cc55cSDimitry Andric thread_context.ds = read_register_u16(reg_ctx, "ds"); 381349cc55cSDimitry Andric return thread_context; 382349cc55cSDimitry Andric } 383349cc55cSDimitry Andric 384349cc55cSDimitry Andric // Function returns start and size of the memory region that contains 385349cc55cSDimitry Andric // memory location pointed to by the current stack pointer. 386349cc55cSDimitry Andric llvm::Expected<std::pair<addr_t, addr_t>> 387349cc55cSDimitry Andric findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) { 388349cc55cSDimitry Andric MemoryRegionInfo range_info; 389349cc55cSDimitry Andric Status error = process_sp->GetMemoryRegionInfo(rsp, range_info); 390349cc55cSDimitry Andric // Skip failed memory region requests or any regions with no permissions. 391349cc55cSDimitry Andric if (error.Fail() || range_info.GetLLDBPermissions() == 0) 392349cc55cSDimitry Andric return llvm::createStringError( 393349cc55cSDimitry Andric std::errc::not_supported, 394349cc55cSDimitry Andric "unable to load stack segment of the process"); 395349cc55cSDimitry Andric 396349cc55cSDimitry Andric const addr_t addr = range_info.GetRange().GetRangeBase(); 397349cc55cSDimitry Andric const addr_t size = range_info.GetRange().GetByteSize(); 398349cc55cSDimitry Andric 399349cc55cSDimitry Andric if (size == 0) 400349cc55cSDimitry Andric return llvm::createStringError(std::errc::not_supported, 401349cc55cSDimitry Andric "stack segment of the process is empty"); 402349cc55cSDimitry Andric 403349cc55cSDimitry Andric return std::make_pair(addr, size); 404349cc55cSDimitry Andric } 405349cc55cSDimitry Andric 406349cc55cSDimitry Andric Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { 407349cc55cSDimitry Andric constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread); 408349cc55cSDimitry Andric lldb_private::ThreadList thread_list = process_sp->GetThreadList(); 409349cc55cSDimitry Andric 410349cc55cSDimitry Andric // size of the entire thread stream consists of: 411349cc55cSDimitry Andric // number of threads and threads array 412349cc55cSDimitry Andric size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) + 413349cc55cSDimitry Andric thread_list.GetSize() * minidump_thread_size; 414349cc55cSDimitry Andric // save for the ability to set up RVA 415349cc55cSDimitry Andric size_t size_before = GetCurrentDataEndOffset(); 416349cc55cSDimitry Andric 417349cc55cSDimitry Andric AddDirectory(StreamType::ThreadList, thread_stream_size); 418349cc55cSDimitry Andric 419349cc55cSDimitry Andric llvm::support::ulittle32_t thread_count = 420349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_list.GetSize()); 421349cc55cSDimitry Andric m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t)); 422349cc55cSDimitry Andric 423349cc55cSDimitry Andric DataBufferHeap helper_data; 424349cc55cSDimitry Andric 425349cc55cSDimitry Andric const uint32_t num_threads = thread_list.GetSize(); 426349cc55cSDimitry Andric 427349cc55cSDimitry Andric for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 428349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); 429349cc55cSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 430349cc55cSDimitry Andric Status error; 431349cc55cSDimitry Andric 432349cc55cSDimitry Andric if (!reg_ctx_sp) { 433349cc55cSDimitry Andric error.SetErrorString("Unable to get the register context."); 434349cc55cSDimitry Andric return error; 435349cc55cSDimitry Andric } 436349cc55cSDimitry Andric RegisterContext *reg_ctx = reg_ctx_sp.get(); 437349cc55cSDimitry Andric auto thread_context = GetThreadContext_64(reg_ctx); 438349cc55cSDimitry Andric uint64_t rsp = read_register_u64_raw(reg_ctx, "rsp"); 439349cc55cSDimitry Andric auto expected_address_range = findStackHelper(process_sp, rsp); 440349cc55cSDimitry Andric 441349cc55cSDimitry Andric if (!expected_address_range) { 442349cc55cSDimitry Andric error.SetErrorString("Unable to get the stack address."); 443349cc55cSDimitry Andric return error; 444349cc55cSDimitry Andric } 445349cc55cSDimitry Andric 446349cc55cSDimitry Andric std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range); 447349cc55cSDimitry Andric uint64_t addr = range.first; 448349cc55cSDimitry Andric uint64_t size = range.second; 449349cc55cSDimitry Andric 450349cc55cSDimitry Andric auto data_up = std::make_unique<DataBufferHeap>(size, 0); 451349cc55cSDimitry Andric const size_t stack_bytes_read = 452349cc55cSDimitry Andric process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 453349cc55cSDimitry Andric 454349cc55cSDimitry Andric if (error.Fail()) 455349cc55cSDimitry Andric return error; 456349cc55cSDimitry Andric 457349cc55cSDimitry Andric LocationDescriptor stack_memory; 458349cc55cSDimitry Andric stack_memory.DataSize = 459349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(stack_bytes_read); 460349cc55cSDimitry Andric stack_memory.RVA = static_cast<llvm::support::ulittle32_t>( 461349cc55cSDimitry Andric size_before + thread_stream_size + helper_data.GetByteSize()); 462349cc55cSDimitry Andric 463349cc55cSDimitry Andric MemoryDescriptor stack; 464349cc55cSDimitry Andric stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr); 465349cc55cSDimitry Andric stack.Memory = stack_memory; 466349cc55cSDimitry Andric 467349cc55cSDimitry Andric helper_data.AppendData(data_up->GetBytes(), stack_bytes_read); 468349cc55cSDimitry Andric 469349cc55cSDimitry Andric LocationDescriptor thread_context_memory_locator; 470349cc55cSDimitry Andric thread_context_memory_locator.DataSize = 471349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(sizeof(thread_context)); 472349cc55cSDimitry Andric thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>( 473349cc55cSDimitry Andric size_before + thread_stream_size + helper_data.GetByteSize()); 474349cc55cSDimitry Andric 475349cc55cSDimitry Andric helper_data.AppendData( 476349cc55cSDimitry Andric &thread_context, 477349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpContext_x86_64)); 478349cc55cSDimitry Andric 479349cc55cSDimitry Andric llvm::minidump::Thread t; 480349cc55cSDimitry Andric t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 481349cc55cSDimitry Andric t.SuspendCount = static_cast<llvm::support::ulittle32_t>( 482349cc55cSDimitry Andric (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0); 483349cc55cSDimitry Andric t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0); 484349cc55cSDimitry Andric t.Priority = static_cast<llvm::support::ulittle32_t>(0); 485349cc55cSDimitry Andric t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0); 486349cc55cSDimitry Andric t.Stack = stack, t.Context = thread_context_memory_locator; 487349cc55cSDimitry Andric 488349cc55cSDimitry Andric m_data.AppendData(&t, sizeof(llvm::minidump::Thread)); 489349cc55cSDimitry Andric } 490349cc55cSDimitry Andric 491349cc55cSDimitry Andric m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 492349cc55cSDimitry Andric return Status(); 493349cc55cSDimitry Andric } 494349cc55cSDimitry Andric 495349cc55cSDimitry Andric Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) { 496349cc55cSDimitry Andric Status error; 497349cc55cSDimitry Andric lldb_private::ThreadList thread_list = process_sp->GetThreadList(); 498349cc55cSDimitry Andric 499349cc55cSDimitry Andric const uint32_t num_threads = thread_list.GetSize(); 500349cc55cSDimitry Andric uint32_t stop_reason_thread_idx = 0; 501349cc55cSDimitry Andric for (stop_reason_thread_idx = 0; stop_reason_thread_idx < num_threads; 502349cc55cSDimitry Andric ++stop_reason_thread_idx) { 503349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx)); 504349cc55cSDimitry Andric StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 505349cc55cSDimitry Andric 506349cc55cSDimitry Andric if (stop_info_sp && stop_info_sp->IsValid()) 507349cc55cSDimitry Andric break; 508349cc55cSDimitry Andric } 509349cc55cSDimitry Andric 510349cc55cSDimitry Andric if (stop_reason_thread_idx == num_threads) { 511349cc55cSDimitry Andric error.SetErrorString("No stop reason thread found."); 512349cc55cSDimitry Andric return error; 513349cc55cSDimitry Andric } 514349cc55cSDimitry Andric 515349cc55cSDimitry Andric constexpr size_t minidump_exception_size = 516349cc55cSDimitry Andric sizeof(llvm::minidump::ExceptionStream); 517349cc55cSDimitry Andric AddDirectory(StreamType::Exception, minidump_exception_size); 518349cc55cSDimitry Andric size_t size_before = GetCurrentDataEndOffset(); 519349cc55cSDimitry Andric 520349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx)); 521349cc55cSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 522349cc55cSDimitry Andric RegisterContext *reg_ctx = reg_ctx_sp.get(); 523349cc55cSDimitry Andric auto thread_context = GetThreadContext_64(reg_ctx); 524349cc55cSDimitry Andric StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 525349cc55cSDimitry Andric 526349cc55cSDimitry Andric DataBufferHeap helper_data; 527349cc55cSDimitry Andric 528349cc55cSDimitry Andric LocationDescriptor thread_context_memory_locator; 529349cc55cSDimitry Andric thread_context_memory_locator.DataSize = 530349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(sizeof(thread_context)); 531349cc55cSDimitry Andric thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>( 532349cc55cSDimitry Andric size_before + minidump_exception_size + helper_data.GetByteSize()); 533349cc55cSDimitry Andric 534349cc55cSDimitry Andric helper_data.AppendData( 535349cc55cSDimitry Andric &thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64)); 536349cc55cSDimitry Andric 537349cc55cSDimitry Andric Exception exp_record; 538349cc55cSDimitry Andric exp_record.ExceptionCode = 539349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue()); 540349cc55cSDimitry Andric exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0); 541349cc55cSDimitry Andric exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0); 542349cc55cSDimitry Andric exp_record.ExceptionAddress = read_register_u64(reg_ctx, "rip"); 543349cc55cSDimitry Andric exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0); 544349cc55cSDimitry Andric exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 545349cc55cSDimitry Andric // exp_record.ExceptionInformation; 546349cc55cSDimitry Andric 547349cc55cSDimitry Andric ExceptionStream exp_stream; 548349cc55cSDimitry Andric exp_stream.ThreadId = 549349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 550349cc55cSDimitry Andric exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 551349cc55cSDimitry Andric exp_stream.ExceptionRecord = exp_record; 552349cc55cSDimitry Andric exp_stream.ThreadContext = thread_context_memory_locator; 553349cc55cSDimitry Andric 554349cc55cSDimitry Andric m_data.AppendData(&exp_stream, minidump_exception_size); 555349cc55cSDimitry Andric m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 556349cc55cSDimitry Andric return error; 557349cc55cSDimitry Andric } 558349cc55cSDimitry Andric 559349cc55cSDimitry Andric lldb_private::Status 560349cc55cSDimitry Andric MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp) { 561349cc55cSDimitry Andric Status error; 562349cc55cSDimitry Andric 563349cc55cSDimitry Andric if (error.Fail()) { 564349cc55cSDimitry Andric error.SetErrorString("Process doesn't support getting memory region info."); 565349cc55cSDimitry Andric return error; 566349cc55cSDimitry Andric } 567349cc55cSDimitry Andric 568349cc55cSDimitry Andric // Get interesting addresses 569349cc55cSDimitry Andric std::vector<size_t> interesting_addresses; 570349cc55cSDimitry Andric auto thread_list = process_sp->GetThreadList(); 571349cc55cSDimitry Andric for (size_t i = 0; i < thread_list.GetSize(); ++i) { 572349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(i)); 573349cc55cSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 574349cc55cSDimitry Andric RegisterContext *reg_ctx = reg_ctx_sp.get(); 575349cc55cSDimitry Andric 576349cc55cSDimitry Andric interesting_addresses.push_back(read_register_u64(reg_ctx, "rsp")); 577349cc55cSDimitry Andric interesting_addresses.push_back(read_register_u64(reg_ctx, "rip")); 578349cc55cSDimitry Andric } 579349cc55cSDimitry Andric 580349cc55cSDimitry Andric DataBufferHeap helper_data; 581349cc55cSDimitry Andric std::vector<MemoryDescriptor> mem_descriptors; 582349cc55cSDimitry Andric 583349cc55cSDimitry Andric std::set<addr_t> visited_region_base_addresses; 584349cc55cSDimitry Andric for (size_t interesting_address : interesting_addresses) { 585349cc55cSDimitry Andric MemoryRegionInfo range_info; 586349cc55cSDimitry Andric error = process_sp->GetMemoryRegionInfo(interesting_address, range_info); 587349cc55cSDimitry Andric // Skip failed memory region requests or any regions with no permissions. 588349cc55cSDimitry Andric if (error.Fail() || range_info.GetLLDBPermissions() == 0) 589349cc55cSDimitry Andric continue; 590349cc55cSDimitry Andric const addr_t addr = range_info.GetRange().GetRangeBase(); 591349cc55cSDimitry Andric // Skip any regions we have already saved out. 592349cc55cSDimitry Andric if (visited_region_base_addresses.insert(addr).second == false) 593349cc55cSDimitry Andric continue; 594349cc55cSDimitry Andric const addr_t size = range_info.GetRange().GetByteSize(); 595349cc55cSDimitry Andric if (size == 0) 596349cc55cSDimitry Andric continue; 597349cc55cSDimitry Andric auto data_up = std::make_unique<DataBufferHeap>(size, 0); 598349cc55cSDimitry Andric const size_t bytes_read = 599349cc55cSDimitry Andric process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 600349cc55cSDimitry Andric if (bytes_read == 0) 601349cc55cSDimitry Andric continue; 602349cc55cSDimitry Andric // We have a good memory region with valid bytes to store. 603349cc55cSDimitry Andric LocationDescriptor memory_dump; 604349cc55cSDimitry Andric memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read); 605349cc55cSDimitry Andric memory_dump.RVA = 606349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 607349cc55cSDimitry Andric MemoryDescriptor memory_desc; 608349cc55cSDimitry Andric memory_desc.StartOfMemoryRange = 609349cc55cSDimitry Andric static_cast<llvm::support::ulittle64_t>(addr); 610349cc55cSDimitry Andric memory_desc.Memory = memory_dump; 611349cc55cSDimitry Andric mem_descriptors.push_back(memory_desc); 612349cc55cSDimitry Andric m_data.AppendData(data_up->GetBytes(), bytes_read); 613349cc55cSDimitry Andric } 614349cc55cSDimitry Andric 615349cc55cSDimitry Andric AddDirectory(StreamType::MemoryList, 616349cc55cSDimitry Andric sizeof(llvm::support::ulittle32_t) + 617349cc55cSDimitry Andric mem_descriptors.size() * 618349cc55cSDimitry Andric sizeof(llvm::minidump::MemoryDescriptor)); 619349cc55cSDimitry Andric llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size()); 620349cc55cSDimitry Andric 621349cc55cSDimitry Andric m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t)); 622349cc55cSDimitry Andric for (auto memory_descriptor : mem_descriptors) { 623349cc55cSDimitry Andric m_data.AppendData(&memory_descriptor, 624349cc55cSDimitry Andric sizeof(llvm::minidump::MemoryDescriptor)); 625349cc55cSDimitry Andric } 626349cc55cSDimitry Andric 627349cc55cSDimitry Andric return error; 628349cc55cSDimitry Andric } 629349cc55cSDimitry Andric 630349cc55cSDimitry Andric void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) { 631349cc55cSDimitry Andric AddDirectory(StreamType::MiscInfo, 632349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 633349cc55cSDimitry Andric 634349cc55cSDimitry Andric lldb_private::minidump::MinidumpMiscInfo misc_info; 635349cc55cSDimitry Andric misc_info.size = static_cast<llvm::support::ulittle32_t>( 636349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 637349cc55cSDimitry Andric // Default set flags1 to 0, in case that we will not be able to 638349cc55cSDimitry Andric // get any information 639349cc55cSDimitry Andric misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0); 640349cc55cSDimitry Andric 641349cc55cSDimitry Andric lldb_private::ProcessInstanceInfo process_info; 642349cc55cSDimitry Andric process_sp->GetProcessInfo(process_info); 643349cc55cSDimitry Andric if (process_info.ProcessIDIsValid()) { 644349cc55cSDimitry Andric // Set flags1 to reflect that PID is filled in 645349cc55cSDimitry Andric misc_info.flags1 = 646349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>( 647349cc55cSDimitry Andric lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID)); 648349cc55cSDimitry Andric misc_info.process_id = 649349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID()); 650349cc55cSDimitry Andric } 651349cc55cSDimitry Andric 652349cc55cSDimitry Andric m_data.AppendData(&misc_info, 653349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 654349cc55cSDimitry Andric } 655349cc55cSDimitry Andric 656349cc55cSDimitry Andric std::unique_ptr<llvm::MemoryBuffer> 657349cc55cSDimitry Andric getFileStreamHelper(const std::string &path) { 658349cc55cSDimitry Andric auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path); 659349cc55cSDimitry Andric if (!maybe_stream) 660349cc55cSDimitry Andric return nullptr; 661349cc55cSDimitry Andric return std::move(maybe_stream.get()); 662349cc55cSDimitry Andric } 663349cc55cSDimitry Andric 664349cc55cSDimitry Andric void MinidumpFileBuilder::AddLinuxFileStreams( 665349cc55cSDimitry Andric const lldb::ProcessSP &process_sp) { 666349cc55cSDimitry Andric std::vector<std::pair<StreamType, std::string>> files_with_stream_types = { 667349cc55cSDimitry Andric {StreamType::LinuxCPUInfo, "/proc/cpuinfo"}, 668349cc55cSDimitry Andric {StreamType::LinuxLSBRelease, "/etc/lsb-release"}, 669349cc55cSDimitry Andric }; 670349cc55cSDimitry Andric 671349cc55cSDimitry Andric lldb_private::ProcessInstanceInfo process_info; 672349cc55cSDimitry Andric process_sp->GetProcessInfo(process_info); 673349cc55cSDimitry Andric if (process_info.ProcessIDIsValid()) { 674349cc55cSDimitry Andric lldb::pid_t pid = process_info.GetProcessID(); 675349cc55cSDimitry Andric std::string pid_str = std::to_string(pid); 676349cc55cSDimitry Andric files_with_stream_types.push_back( 677349cc55cSDimitry Andric {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"}); 678349cc55cSDimitry Andric files_with_stream_types.push_back( 679349cc55cSDimitry Andric {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"}); 680349cc55cSDimitry Andric files_with_stream_types.push_back( 681349cc55cSDimitry Andric {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"}); 682349cc55cSDimitry Andric files_with_stream_types.push_back( 683349cc55cSDimitry Andric {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"}); 684349cc55cSDimitry Andric files_with_stream_types.push_back( 685349cc55cSDimitry Andric {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"}); 686349cc55cSDimitry Andric files_with_stream_types.push_back( 687349cc55cSDimitry Andric {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"}); 688349cc55cSDimitry Andric files_with_stream_types.push_back( 689349cc55cSDimitry Andric {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"}); 690349cc55cSDimitry Andric } 691349cc55cSDimitry Andric 692349cc55cSDimitry Andric for (const auto &entry : files_with_stream_types) { 693349cc55cSDimitry Andric StreamType stream = entry.first; 694349cc55cSDimitry Andric std::string path = entry.second; 695349cc55cSDimitry Andric auto memory_buffer = getFileStreamHelper(path); 696349cc55cSDimitry Andric 697349cc55cSDimitry Andric if (memory_buffer) { 698349cc55cSDimitry Andric size_t size = memory_buffer->getBufferSize(); 699349cc55cSDimitry Andric if (size == 0) 700349cc55cSDimitry Andric continue; 701349cc55cSDimitry Andric AddDirectory(stream, size); 702349cc55cSDimitry Andric m_data.AppendData(memory_buffer->getBufferStart(), size); 703349cc55cSDimitry Andric } 704349cc55cSDimitry Andric } 705349cc55cSDimitry Andric } 706349cc55cSDimitry Andric 707349cc55cSDimitry Andric Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const { 708349cc55cSDimitry Andric constexpr size_t header_size = sizeof(llvm::minidump::Header); 709349cc55cSDimitry Andric constexpr size_t directory_size = sizeof(llvm::minidump::Directory); 710349cc55cSDimitry Andric 711349cc55cSDimitry Andric // write header 712349cc55cSDimitry Andric llvm::minidump::Header header; 713349cc55cSDimitry Andric header.Signature = static_cast<llvm::support::ulittle32_t>( 714349cc55cSDimitry Andric llvm::minidump::Header::MagicSignature); 715349cc55cSDimitry Andric header.Version = static_cast<llvm::support::ulittle32_t>( 716349cc55cSDimitry Andric llvm::minidump::Header::MagicVersion); 717349cc55cSDimitry Andric header.NumberOfStreams = 718349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum()); 719349cc55cSDimitry Andric header.StreamDirectoryRVA = 720349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 721349cc55cSDimitry Andric header.Checksum = static_cast<llvm::support::ulittle32_t>( 722349cc55cSDimitry Andric 0u), // not used in most of the writers 723349cc55cSDimitry Andric header.TimeDateStamp = 72404eeddc0SDimitry Andric static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); 725349cc55cSDimitry Andric header.Flags = 726349cc55cSDimitry Andric static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag 727349cc55cSDimitry Andric 728349cc55cSDimitry Andric Status error; 729349cc55cSDimitry Andric size_t bytes_written; 730349cc55cSDimitry Andric 731349cc55cSDimitry Andric bytes_written = header_size; 732349cc55cSDimitry Andric error = core_file->Write(&header, bytes_written); 733349cc55cSDimitry Andric if (error.Fail() || bytes_written != header_size) { 734349cc55cSDimitry Andric if (bytes_written != header_size) 735349cc55cSDimitry Andric error.SetErrorStringWithFormat( 736349cc55cSDimitry Andric "unable to write the header (written %zd/%zd)", bytes_written, 737349cc55cSDimitry Andric header_size); 738349cc55cSDimitry Andric return error; 739349cc55cSDimitry Andric } 740349cc55cSDimitry Andric 741349cc55cSDimitry Andric // write data 742349cc55cSDimitry Andric bytes_written = m_data.GetByteSize(); 743349cc55cSDimitry Andric error = core_file->Write(m_data.GetBytes(), bytes_written); 744349cc55cSDimitry Andric if (error.Fail() || bytes_written != m_data.GetByteSize()) { 745349cc55cSDimitry Andric if (bytes_written != m_data.GetByteSize()) 746349cc55cSDimitry Andric error.SetErrorStringWithFormat( 747349cc55cSDimitry Andric "unable to write the data (written %zd/%" PRIu64 ")", bytes_written, 748349cc55cSDimitry Andric m_data.GetByteSize()); 749349cc55cSDimitry Andric return error; 750349cc55cSDimitry Andric } 751349cc55cSDimitry Andric 752349cc55cSDimitry Andric // write directories 753349cc55cSDimitry Andric for (const Directory &dir : m_directories) { 754349cc55cSDimitry Andric bytes_written = directory_size; 755349cc55cSDimitry Andric error = core_file->Write(&dir, bytes_written); 756349cc55cSDimitry Andric if (error.Fail() || bytes_written != directory_size) { 757349cc55cSDimitry Andric if (bytes_written != directory_size) 758349cc55cSDimitry Andric error.SetErrorStringWithFormat( 759349cc55cSDimitry Andric "unable to write the directory (written %zd/%zd)", bytes_written, 760349cc55cSDimitry Andric directory_size); 761349cc55cSDimitry Andric return error; 762349cc55cSDimitry Andric } 763349cc55cSDimitry Andric } 764349cc55cSDimitry Andric 765349cc55cSDimitry Andric return error; 766349cc55cSDimitry Andric } 767349cc55cSDimitry Andric 768349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetDirectoriesNum() const { 769349cc55cSDimitry Andric return m_directories.size(); 770349cc55cSDimitry Andric } 771349cc55cSDimitry Andric 772349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const { 773349cc55cSDimitry Andric return sizeof(llvm::minidump::Header) + m_data.GetByteSize(); 774349cc55cSDimitry Andric } 775