1//===-- MinidumpFileBuilder.cpp -------------------------------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "MinidumpFileBuilder.h" 10 11#include "Plugins/Process/minidump/RegisterContextMinidump_ARM64.h" 12#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h" 13 14#include "lldb/Core/Module.h" 15#include "lldb/Core/ModuleList.h" 16#include "lldb/Core/Section.h" 17#include "lldb/Target/MemoryRegionInfo.h" 18#include "lldb/Target/Process.h" 19#include "lldb/Target/RegisterContext.h" 20#include "lldb/Target/StopInfo.h" 21#include "lldb/Target/ThreadList.h" 22#include "lldb/Utility/DataExtractor.h" 23#include "lldb/Utility/RegisterValue.h" 24 25#include "llvm/ADT/StringRef.h" 26#include "llvm/BinaryFormat/Minidump.h" 27#include "llvm/Support/ConvertUTF.h" 28#include "llvm/Support/Error.h" 29 30#include "Plugins/Process/minidump/MinidumpTypes.h" 31 32#include <cinttypes> 33 34using namespace lldb; 35using namespace lldb_private; 36using namespace llvm::minidump; 37 38void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) { 39 LocationDescriptor loc; 40 loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size); 41 // Stream will begin at the current end of data section 42 loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 43 44 Directory dir; 45 dir.Type = static_cast<llvm::support::little_t<StreamType>>(type); 46 dir.Location = loc; 47 48 m_directories.push_back(dir); 49} 50 51Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) { 52 Status error; 53 AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo)); 54 55 llvm::minidump::ProcessorArchitecture arch; 56 switch (target_triple.getArch()) { 57 case llvm::Triple::ArchType::x86_64: 58 arch = ProcessorArchitecture::AMD64; 59 break; 60 case llvm::Triple::ArchType::x86: 61 arch = ProcessorArchitecture::X86; 62 break; 63 case llvm::Triple::ArchType::arm: 64 arch = ProcessorArchitecture::ARM; 65 break; 66 case llvm::Triple::ArchType::aarch64: 67 arch = ProcessorArchitecture::ARM64; 68 break; 69 case llvm::Triple::ArchType::mips64: 70 case llvm::Triple::ArchType::mips64el: 71 case llvm::Triple::ArchType::mips: 72 case llvm::Triple::ArchType::mipsel: 73 arch = ProcessorArchitecture::MIPS; 74 break; 75 case llvm::Triple::ArchType::ppc64: 76 case llvm::Triple::ArchType::ppc: 77 case llvm::Triple::ArchType::ppc64le: 78 arch = ProcessorArchitecture::PPC; 79 break; 80 default: 81 error.SetErrorStringWithFormat("Architecture %s not supported.", 82 target_triple.getArchName().str().c_str()); 83 return error; 84 }; 85 86 llvm::support::little_t<OSPlatform> platform_id; 87 switch (target_triple.getOS()) { 88 case llvm::Triple::OSType::Linux: 89 if (target_triple.getEnvironment() == 90 llvm::Triple::EnvironmentType::Android) 91 platform_id = OSPlatform::Android; 92 else 93 platform_id = OSPlatform::Linux; 94 break; 95 case llvm::Triple::OSType::Win32: 96 platform_id = OSPlatform::Win32NT; 97 break; 98 case llvm::Triple::OSType::MacOSX: 99 platform_id = OSPlatform::MacOSX; 100 break; 101 case llvm::Triple::OSType::IOS: 102 platform_id = OSPlatform::IOS; 103 break; 104 default: 105 error.SetErrorStringWithFormat("OS %s not supported.", 106 target_triple.getOSName().str().c_str()); 107 return error; 108 }; 109 110 llvm::minidump::SystemInfo sys_info; 111 sys_info.ProcessorArch = 112 static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch); 113 // Global offset to beginning of a csd_string in a data section 114 sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>( 115 GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo)); 116 sys_info.PlatformId = platform_id; 117 m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo)); 118 119 std::string csd_string; 120 121 error = WriteString(csd_string, &m_data); 122 if (error.Fail()) { 123 error.SetErrorString("Unable to convert the csd string to UTF16."); 124 return error; 125 } 126 127 return error; 128} 129 130Status WriteString(const std::string &to_write, 131 lldb_private::DataBufferHeap *buffer) { 132 Status error; 133 // let the StringRef eat also null termination char 134 llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1); 135 llvm::SmallVector<llvm::UTF16, 128> to_write_utf16; 136 137 bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16); 138 if (!converted) { 139 error.SetErrorStringWithFormat( 140 "Unable to convert the string to UTF16. Failed to convert %s", 141 to_write.c_str()); 142 return error; 143 } 144 145 // size of the UTF16 string should be written without the null termination 146 // character that is stored in 2 bytes 147 llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2); 148 149 buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t)); 150 buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes()); 151 152 return error; 153} 154 155llvm::Expected<uint64_t> getModuleFileSize(Target &target, 156 const ModuleSP &mod) { 157 SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection(); 158 uint64_t SizeOfImage = 0; 159 160 if (!sect_sp) { 161 return llvm::createStringError(std::errc::operation_not_supported, 162 "Couldn't obtain the section information."); 163 } 164 lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target); 165 // Use memory size since zero fill sections, like ".bss", will be smaller on 166 // disk. 167 lldb::addr_t sect_size = sect_sp->GetByteSize(); 168 // This will usually be zero, but make sure to calculate the BaseOfImage 169 // offset. 170 const lldb::addr_t base_sect_offset = 171 mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) - 172 sect_addr; 173 SizeOfImage = sect_size - base_sect_offset; 174 lldb::addr_t next_sect_addr = sect_addr + sect_size; 175 Address sect_so_addr; 176 target.ResolveLoadAddress(next_sect_addr, sect_so_addr); 177 lldb::SectionSP next_sect_sp = sect_so_addr.GetSection(); 178 while (next_sect_sp && 179 next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) { 180 sect_size = sect_sp->GetByteSize(); 181 SizeOfImage += sect_size; 182 next_sect_addr += sect_size; 183 target.ResolveLoadAddress(next_sect_addr, sect_so_addr); 184 next_sect_sp = sect_so_addr.GetSection(); 185 } 186 187 return SizeOfImage; 188} 189 190// ModuleList stream consists of a number of modules, followed by an array 191// of llvm::minidump::Module's structures. Every structure informs about a 192// single module. Additional data of variable length, such as module's names, 193// are stored just after the ModuleList stream. The llvm::minidump::Module 194// structures point to this helper data by global offset. 195Status MinidumpFileBuilder::AddModuleList(Target &target) { 196 constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module); 197 Status error; 198 199 const ModuleList &modules = target.GetImages(); 200 llvm::support::ulittle32_t modules_count = 201 static_cast<llvm::support::ulittle32_t>(modules.GetSize()); 202 203 // This helps us with getting the correct global offset in minidump 204 // file later, when we will be setting up offsets from the 205 // the llvm::minidump::Module's structures into helper data 206 size_t size_before = GetCurrentDataEndOffset(); 207 208 // This is the size of the main part of the ModuleList stream. 209 // It consists of a module number and corresponding number of 210 // structs describing individual modules 211 size_t module_stream_size = 212 sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size; 213 214 // Adding directory describing this stream. 215 AddDirectory(StreamType::ModuleList, module_stream_size); 216 217 m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t)); 218 219 // Temporary storage for the helper data (of variable length) 220 // as these cannot be dumped to m_data before dumping entire 221 // array of module structures. 222 DataBufferHeap helper_data; 223 224 for (size_t i = 0; i < modules_count; ++i) { 225 ModuleSP mod = modules.GetModuleAtIndex(i); 226 std::string module_name = mod->GetSpecificationDescription(); 227 auto maybe_mod_size = getModuleFileSize(target, mod); 228 if (!maybe_mod_size) { 229 error.SetErrorStringWithFormat("Unable to get the size of module %s.", 230 module_name.c_str()); 231 return error; 232 } 233 234 uint64_t mod_size = std::move(*maybe_mod_size); 235 236 llvm::support::ulittle32_t signature = 237 static_cast<llvm::support::ulittle32_t>( 238 static_cast<uint32_t>(minidump::CvSignature::ElfBuildId)); 239 auto uuid = mod->GetUUID().GetBytes(); 240 241 VSFixedFileInfo info; 242 info.Signature = static_cast<llvm::support::ulittle32_t>(0u); 243 info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u); 244 info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u); 245 info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u); 246 info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u); 247 info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u); 248 info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u); 249 info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u); 250 info.FileOS = static_cast<llvm::support::ulittle32_t>(0u); 251 info.FileType = static_cast<llvm::support::ulittle32_t>(0u); 252 info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u); 253 info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u); 254 info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u); 255 256 LocationDescriptor ld; 257 ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u); 258 ld.RVA = static_cast<llvm::support::ulittle32_t>(0u); 259 260 // Setting up LocationDescriptor for uuid string. The global offset into 261 // minidump file is calculated. 262 LocationDescriptor ld_cv; 263 ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>( 264 sizeof(llvm::support::ulittle32_t) + uuid.size()); 265 ld_cv.RVA = static_cast<llvm::support::ulittle32_t>( 266 size_before + module_stream_size + helper_data.GetByteSize()); 267 268 helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t)); 269 helper_data.AppendData(uuid.begin(), uuid.size()); 270 271 llvm::minidump::Module m; 272 m.BaseOfImage = static_cast<llvm::support::ulittle64_t>( 273 mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target)); 274 m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size); 275 m.Checksum = static_cast<llvm::support::ulittle32_t>(0); 276 m.TimeDateStamp = 277 static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); 278 m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>( 279 size_before + module_stream_size + helper_data.GetByteSize()); 280 m.VersionInfo = info; 281 m.CvRecord = ld_cv; 282 m.MiscRecord = ld; 283 284 error = WriteString(module_name, &helper_data); 285 286 if (error.Fail()) 287 return error; 288 289 m_data.AppendData(&m, sizeof(llvm::minidump::Module)); 290 } 291 292 m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 293 return error; 294} 295 296uint16_t read_register_u16_raw(RegisterContext *reg_ctx, 297 llvm::StringRef reg_name) { 298 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 299 if (!reg_info) 300 return 0; 301 lldb_private::RegisterValue reg_value; 302 bool success = reg_ctx->ReadRegister(reg_info, reg_value); 303 if (!success) 304 return 0; 305 return reg_value.GetAsUInt16(); 306} 307 308uint32_t read_register_u32_raw(RegisterContext *reg_ctx, 309 llvm::StringRef reg_name) { 310 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 311 if (!reg_info) 312 return 0; 313 lldb_private::RegisterValue reg_value; 314 bool success = reg_ctx->ReadRegister(reg_info, reg_value); 315 if (!success) 316 return 0; 317 return reg_value.GetAsUInt32(); 318} 319 320uint64_t read_register_u64_raw(RegisterContext *reg_ctx, 321 llvm::StringRef reg_name) { 322 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 323 if (!reg_info) 324 return 0; 325 lldb_private::RegisterValue reg_value; 326 bool success = reg_ctx->ReadRegister(reg_info, reg_value); 327 if (!success) 328 return 0; 329 return reg_value.GetAsUInt64(); 330} 331 332llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx, 333 llvm::StringRef reg_name) { 334 return static_cast<llvm::support::ulittle16_t>( 335 read_register_u16_raw(reg_ctx, reg_name)); 336} 337 338llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx, 339 llvm::StringRef reg_name) { 340 return static_cast<llvm::support::ulittle32_t>( 341 read_register_u32_raw(reg_ctx, reg_name)); 342} 343 344llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx, 345 llvm::StringRef reg_name) { 346 return static_cast<llvm::support::ulittle64_t>( 347 read_register_u64_raw(reg_ctx, reg_name)); 348} 349 350void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name, 351 uint8_t *dst) { 352 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 353 if (reg_info) { 354 lldb_private::RegisterValue reg_value; 355 if (reg_ctx->ReadRegister(reg_info, reg_value)) { 356 Status error; 357 uint32_t bytes_copied = reg_value.GetAsMemoryData( 358 *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error); 359 if (bytes_copied == 16) 360 return; 361 } 362 } 363 // If anything goes wrong, then zero out the register value. 364 memset(dst, 0, 16); 365} 366 367lldb_private::minidump::MinidumpContext_x86_64 368GetThreadContext_x86_64(RegisterContext *reg_ctx) { 369 lldb_private::minidump::MinidumpContext_x86_64 thread_context = {}; 370 thread_context.p1_home = {}; 371 thread_context.context_flags = static_cast<uint32_t>( 372 lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag | 373 lldb_private::minidump::MinidumpContext_x86_64_Flags::Control | 374 lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments | 375 lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer); 376 thread_context.rax = read_register_u64(reg_ctx, "rax"); 377 thread_context.rbx = read_register_u64(reg_ctx, "rbx"); 378 thread_context.rcx = read_register_u64(reg_ctx, "rcx"); 379 thread_context.rdx = read_register_u64(reg_ctx, "rdx"); 380 thread_context.rdi = read_register_u64(reg_ctx, "rdi"); 381 thread_context.rsi = read_register_u64(reg_ctx, "rsi"); 382 thread_context.rbp = read_register_u64(reg_ctx, "rbp"); 383 thread_context.rsp = read_register_u64(reg_ctx, "rsp"); 384 thread_context.r8 = read_register_u64(reg_ctx, "r8"); 385 thread_context.r9 = read_register_u64(reg_ctx, "r9"); 386 thread_context.r10 = read_register_u64(reg_ctx, "r10"); 387 thread_context.r11 = read_register_u64(reg_ctx, "r11"); 388 thread_context.r12 = read_register_u64(reg_ctx, "r12"); 389 thread_context.r13 = read_register_u64(reg_ctx, "r13"); 390 thread_context.r14 = read_register_u64(reg_ctx, "r14"); 391 thread_context.r15 = read_register_u64(reg_ctx, "r15"); 392 thread_context.rip = read_register_u64(reg_ctx, "rip"); 393 thread_context.eflags = read_register_u32(reg_ctx, "rflags"); 394 thread_context.cs = read_register_u16(reg_ctx, "cs"); 395 thread_context.fs = read_register_u16(reg_ctx, "fs"); 396 thread_context.gs = read_register_u16(reg_ctx, "gs"); 397 thread_context.ss = read_register_u16(reg_ctx, "ss"); 398 thread_context.ds = read_register_u16(reg_ctx, "ds"); 399 return thread_context; 400} 401 402minidump::RegisterContextMinidump_ARM64::Context 403GetThreadContext_ARM64(RegisterContext *reg_ctx) { 404 minidump::RegisterContextMinidump_ARM64::Context thread_context = {}; 405 thread_context.context_flags = static_cast<uint32_t>( 406 minidump::RegisterContextMinidump_ARM64::Flags::ARM64_Flag | 407 minidump::RegisterContextMinidump_ARM64::Flags::Integer | 408 minidump::RegisterContextMinidump_ARM64::Flags::FloatingPoint); 409 char reg_name[16]; 410 for (uint32_t i = 0; i < 31; ++i) { 411 snprintf(reg_name, sizeof(reg_name), "x%u", i); 412 thread_context.x[i] = read_register_u64(reg_ctx, reg_name); 413 } 414 // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt 415 // name set to "x31" 416 thread_context.x[31] = read_register_u64(reg_ctx, "sp"); 417 thread_context.pc = read_register_u64(reg_ctx, "pc"); 418 thread_context.cpsr = read_register_u32(reg_ctx, "cpsr"); 419 thread_context.fpsr = read_register_u32(reg_ctx, "fpsr"); 420 thread_context.fpcr = read_register_u32(reg_ctx, "fpcr"); 421 for (uint32_t i = 0; i < 32; ++i) { 422 snprintf(reg_name, sizeof(reg_name), "v%u", i); 423 read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]); 424 } 425 return thread_context; 426} 427 428class ArchThreadContexts { 429 llvm::Triple::ArchType m_arch; 430 union { 431 lldb_private::minidump::MinidumpContext_x86_64 x86_64; 432 lldb_private::minidump::RegisterContextMinidump_ARM64::Context arm64; 433 }; 434 435public: 436 ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {} 437 438 bool prepareRegisterContext(RegisterContext *reg_ctx) { 439 switch (m_arch) { 440 case llvm::Triple::ArchType::x86_64: 441 x86_64 = GetThreadContext_x86_64(reg_ctx); 442 return true; 443 case llvm::Triple::ArchType::aarch64: 444 arm64 = GetThreadContext_ARM64(reg_ctx); 445 return true; 446 default: 447 break; 448 } 449 return false; 450 } 451 452 const void *data() const { return &x86_64; } 453 454 size_t size() const { 455 switch (m_arch) { 456 case llvm::Triple::ArchType::x86_64: 457 return sizeof(x86_64); 458 case llvm::Triple::ArchType::aarch64: 459 return sizeof(arm64); 460 default: 461 break; 462 } 463 return 0; 464 } 465}; 466 467// Function returns start and size of the memory region that contains 468// memory location pointed to by the current stack pointer. 469llvm::Expected<std::pair<addr_t, addr_t>> 470findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) { 471 MemoryRegionInfo range_info; 472 Status error = process_sp->GetMemoryRegionInfo(rsp, range_info); 473 // Skip failed memory region requests or any regions with no permissions. 474 if (error.Fail() || range_info.GetLLDBPermissions() == 0) 475 return llvm::createStringError( 476 std::errc::not_supported, 477 "unable to load stack segment of the process"); 478 479 const addr_t addr = range_info.GetRange().GetRangeBase(); 480 const addr_t size = range_info.GetRange().GetByteSize(); 481 482 if (size == 0) 483 return llvm::createStringError(std::errc::not_supported, 484 "stack segment of the process is empty"); 485 486 return std::make_pair(addr, size); 487} 488 489Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { 490 constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread); 491 lldb_private::ThreadList thread_list = process_sp->GetThreadList(); 492 493 // size of the entire thread stream consists of: 494 // number of threads and threads array 495 size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) + 496 thread_list.GetSize() * minidump_thread_size; 497 // save for the ability to set up RVA 498 size_t size_before = GetCurrentDataEndOffset(); 499 500 AddDirectory(StreamType::ThreadList, thread_stream_size); 501 502 llvm::support::ulittle32_t thread_count = 503 static_cast<llvm::support::ulittle32_t>(thread_list.GetSize()); 504 m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t)); 505 506 DataBufferHeap helper_data; 507 508 const uint32_t num_threads = thread_list.GetSize(); 509 510 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 511 ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); 512 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 513 Status error; 514 515 if (!reg_ctx_sp) { 516 error.SetErrorString("Unable to get the register context."); 517 return error; 518 } 519 RegisterContext *reg_ctx = reg_ctx_sp.get(); 520 Target &target = process_sp->GetTarget(); 521 const ArchSpec &arch = target.GetArchitecture(); 522 ArchThreadContexts thread_context(arch.GetMachine()); 523 if (!thread_context.prepareRegisterContext(reg_ctx)) { 524 error.SetErrorStringWithFormat( 525 "architecture %s not supported.", 526 arch.GetTriple().getArchName().str().c_str()); 527 return error; 528 } 529 uint64_t sp = reg_ctx->GetSP(); 530 auto expected_address_range = findStackHelper(process_sp, sp); 531 532 if (!expected_address_range) { 533 consumeError(expected_address_range.takeError()); 534 error.SetErrorString("Unable to get the stack address."); 535 return error; 536 } 537 538 std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range); 539 uint64_t addr = range.first; 540 uint64_t size = range.second; 541 542 auto data_up = std::make_unique<DataBufferHeap>(size, 0); 543 const size_t stack_bytes_read = 544 process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 545 546 if (error.Fail()) 547 return error; 548 549 LocationDescriptor stack_memory; 550 stack_memory.DataSize = 551 static_cast<llvm::support::ulittle32_t>(stack_bytes_read); 552 stack_memory.RVA = static_cast<llvm::support::ulittle32_t>( 553 size_before + thread_stream_size + helper_data.GetByteSize()); 554 555 MemoryDescriptor stack; 556 stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr); 557 stack.Memory = stack_memory; 558 559 helper_data.AppendData(data_up->GetBytes(), stack_bytes_read); 560 561 LocationDescriptor thread_context_memory_locator; 562 thread_context_memory_locator.DataSize = 563 static_cast<llvm::support::ulittle32_t>(thread_context.size()); 564 thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>( 565 size_before + thread_stream_size + helper_data.GetByteSize()); 566 // Cache thie thread context memory so we can reuse for exceptions. 567 m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator; 568 569 helper_data.AppendData(thread_context.data(), thread_context.size()); 570 571 llvm::minidump::Thread t; 572 t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 573 t.SuspendCount = static_cast<llvm::support::ulittle32_t>( 574 (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0); 575 t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0); 576 t.Priority = static_cast<llvm::support::ulittle32_t>(0); 577 t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0); 578 t.Stack = stack, t.Context = thread_context_memory_locator; 579 580 m_data.AppendData(&t, sizeof(llvm::minidump::Thread)); 581 } 582 583 m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 584 return Status(); 585} 586 587void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) { 588 lldb_private::ThreadList thread_list = process_sp->GetThreadList(); 589 590 const uint32_t num_threads = thread_list.GetSize(); 591 for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 592 ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); 593 StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 594 bool add_exception = false; 595 if (stop_info_sp) { 596 switch (stop_info_sp->GetStopReason()) { 597 case eStopReasonSignal: 598 case eStopReasonException: 599 add_exception = true; 600 break; 601 default: 602 break; 603 } 604 } 605 if (add_exception) { 606 constexpr size_t minidump_exception_size = 607 sizeof(llvm::minidump::ExceptionStream); 608 AddDirectory(StreamType::Exception, minidump_exception_size); 609 StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 610 RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 611 Exception exp_record = {}; 612 exp_record.ExceptionCode = 613 static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue()); 614 exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0); 615 exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0); 616 exp_record.ExceptionAddress = reg_ctx_sp->GetPC(); 617 exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0); 618 exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 619 // exp_record.ExceptionInformation; 620 621 ExceptionStream exp_stream; 622 exp_stream.ThreadId = 623 static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 624 exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 625 exp_stream.ExceptionRecord = exp_record; 626 auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID()); 627 if (Iter != m_tid_to_reg_ctx.end()) { 628 exp_stream.ThreadContext = Iter->second; 629 } else { 630 exp_stream.ThreadContext.DataSize = 0; 631 exp_stream.ThreadContext.RVA = 0; 632 } 633 m_data.AppendData(&exp_stream, minidump_exception_size); 634 } 635 } 636} 637 638lldb_private::Status 639MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp, 640 lldb::SaveCoreStyle core_style) { 641 Status error; 642 Process::CoreFileMemoryRanges core_ranges; 643 error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges); 644 if (error.Fail()) { 645 error.SetErrorString("Process doesn't support getting memory region info."); 646 return error; 647 } 648 649 DataBufferHeap helper_data; 650 std::vector<MemoryDescriptor> mem_descriptors; 651 for (const auto &core_range : core_ranges) { 652 // Skip empty memory regions or any regions with no permissions. 653 if (core_range.range.empty() || core_range.lldb_permissions == 0) 654 continue; 655 const addr_t addr = core_range.range.start(); 656 const addr_t size = core_range.range.size(); 657 auto data_up = std::make_unique<DataBufferHeap>(size, 0); 658 const size_t bytes_read = 659 process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 660 if (bytes_read == 0) 661 continue; 662 // We have a good memory region with valid bytes to store. 663 LocationDescriptor memory_dump; 664 memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read); 665 memory_dump.RVA = 666 static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 667 MemoryDescriptor memory_desc; 668 memory_desc.StartOfMemoryRange = 669 static_cast<llvm::support::ulittle64_t>(addr); 670 memory_desc.Memory = memory_dump; 671 mem_descriptors.push_back(memory_desc); 672 m_data.AppendData(data_up->GetBytes(), bytes_read); 673 } 674 675 AddDirectory(StreamType::MemoryList, 676 sizeof(llvm::support::ulittle32_t) + 677 mem_descriptors.size() * 678 sizeof(llvm::minidump::MemoryDescriptor)); 679 llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size()); 680 681 m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t)); 682 for (auto memory_descriptor : mem_descriptors) { 683 m_data.AppendData(&memory_descriptor, 684 sizeof(llvm::minidump::MemoryDescriptor)); 685 } 686 687 return error; 688} 689 690void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) { 691 AddDirectory(StreamType::MiscInfo, 692 sizeof(lldb_private::minidump::MinidumpMiscInfo)); 693 694 lldb_private::minidump::MinidumpMiscInfo misc_info; 695 misc_info.size = static_cast<llvm::support::ulittle32_t>( 696 sizeof(lldb_private::minidump::MinidumpMiscInfo)); 697 // Default set flags1 to 0, in case that we will not be able to 698 // get any information 699 misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0); 700 701 lldb_private::ProcessInstanceInfo process_info; 702 process_sp->GetProcessInfo(process_info); 703 if (process_info.ProcessIDIsValid()) { 704 // Set flags1 to reflect that PID is filled in 705 misc_info.flags1 = 706 static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>( 707 lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID)); 708 misc_info.process_id = 709 static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID()); 710 } 711 712 m_data.AppendData(&misc_info, 713 sizeof(lldb_private::minidump::MinidumpMiscInfo)); 714} 715 716std::unique_ptr<llvm::MemoryBuffer> 717getFileStreamHelper(const std::string &path) { 718 auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path); 719 if (!maybe_stream) 720 return nullptr; 721 return std::move(maybe_stream.get()); 722} 723 724void MinidumpFileBuilder::AddLinuxFileStreams( 725 const lldb::ProcessSP &process_sp) { 726 std::vector<std::pair<StreamType, std::string>> files_with_stream_types = { 727 {StreamType::LinuxCPUInfo, "/proc/cpuinfo"}, 728 {StreamType::LinuxLSBRelease, "/etc/lsb-release"}, 729 }; 730 731 lldb_private::ProcessInstanceInfo process_info; 732 process_sp->GetProcessInfo(process_info); 733 if (process_info.ProcessIDIsValid()) { 734 lldb::pid_t pid = process_info.GetProcessID(); 735 std::string pid_str = std::to_string(pid); 736 files_with_stream_types.push_back( 737 {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"}); 738 files_with_stream_types.push_back( 739 {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"}); 740 files_with_stream_types.push_back( 741 {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"}); 742 files_with_stream_types.push_back( 743 {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"}); 744 files_with_stream_types.push_back( 745 {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"}); 746 files_with_stream_types.push_back( 747 {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"}); 748 files_with_stream_types.push_back( 749 {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"}); 750 } 751 752 for (const auto &entry : files_with_stream_types) { 753 StreamType stream = entry.first; 754 std::string path = entry.second; 755 auto memory_buffer = getFileStreamHelper(path); 756 757 if (memory_buffer) { 758 size_t size = memory_buffer->getBufferSize(); 759 if (size == 0) 760 continue; 761 AddDirectory(stream, size); 762 m_data.AppendData(memory_buffer->getBufferStart(), size); 763 } 764 } 765} 766 767Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const { 768 constexpr size_t header_size = sizeof(llvm::minidump::Header); 769 constexpr size_t directory_size = sizeof(llvm::minidump::Directory); 770 771 // write header 772 llvm::minidump::Header header; 773 header.Signature = static_cast<llvm::support::ulittle32_t>( 774 llvm::minidump::Header::MagicSignature); 775 header.Version = static_cast<llvm::support::ulittle32_t>( 776 llvm::minidump::Header::MagicVersion); 777 header.NumberOfStreams = 778 static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum()); 779 header.StreamDirectoryRVA = 780 static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 781 header.Checksum = static_cast<llvm::support::ulittle32_t>( 782 0u), // not used in most of the writers 783 header.TimeDateStamp = 784 static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); 785 header.Flags = 786 static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag 787 788 Status error; 789 size_t bytes_written; 790 791 bytes_written = header_size; 792 error = core_file->Write(&header, bytes_written); 793 if (error.Fail() || bytes_written != header_size) { 794 if (bytes_written != header_size) 795 error.SetErrorStringWithFormat( 796 "unable to write the header (written %zd/%zd)", bytes_written, 797 header_size); 798 return error; 799 } 800 801 // write data 802 bytes_written = m_data.GetByteSize(); 803 error = core_file->Write(m_data.GetBytes(), bytes_written); 804 if (error.Fail() || bytes_written != m_data.GetByteSize()) { 805 if (bytes_written != m_data.GetByteSize()) 806 error.SetErrorStringWithFormat( 807 "unable to write the data (written %zd/%" PRIu64 ")", bytes_written, 808 m_data.GetByteSize()); 809 return error; 810 } 811 812 // write directories 813 for (const Directory &dir : m_directories) { 814 bytes_written = directory_size; 815 error = core_file->Write(&dir, bytes_written); 816 if (error.Fail() || bytes_written != directory_size) { 817 if (bytes_written != directory_size) 818 error.SetErrorStringWithFormat( 819 "unable to write the directory (written %zd/%zd)", bytes_written, 820 directory_size); 821 return error; 822 } 823 } 824 825 return error; 826} 827 828size_t MinidumpFileBuilder::GetDirectoriesNum() const { 829 return m_directories.size(); 830} 831 832size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const { 833 return sizeof(llvm::minidump::Header) + m_data.GetByteSize(); 834} 835