1 //===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // Project includes 11 #include "MinidumpParser.h" 12 #include "NtStructures.h" 13 #include "RegisterContextMinidump_x86_32.h" 14 15 // Other libraries and framework includes 16 #include "lldb/Target/MemoryRegionInfo.h" 17 18 // C includes 19 // C++ includes 20 #include <map> 21 22 using namespace lldb_private; 23 using namespace minidump; 24 25 llvm::Optional<MinidumpParser> 26 MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) { 27 if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) { 28 return llvm::None; 29 } 30 31 llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(), 32 sizeof(MinidumpHeader)); 33 const MinidumpHeader *header = MinidumpHeader::Parse(header_data); 34 35 if (header == nullptr) { 36 return llvm::None; 37 } 38 39 lldb::offset_t directory_list_offset = header->stream_directory_rva; 40 // check if there is enough data for the parsing of the directory list 41 if ((directory_list_offset + 42 sizeof(MinidumpDirectory) * header->streams_count) > 43 data_buf_sp->GetByteSize()) { 44 return llvm::None; 45 } 46 47 const MinidumpDirectory *directory = nullptr; 48 Status error; 49 llvm::ArrayRef<uint8_t> directory_data( 50 data_buf_sp->GetBytes() + directory_list_offset, 51 sizeof(MinidumpDirectory) * header->streams_count); 52 llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map; 53 54 for (uint32_t i = 0; i < header->streams_count; ++i) { 55 error = consumeObject(directory_data, directory); 56 if (error.Fail()) { 57 return llvm::None; 58 } 59 directory_map[static_cast<const uint32_t>(directory->stream_type)] = 60 directory->location; 61 } 62 63 return MinidumpParser(data_buf_sp, header, std::move(directory_map)); 64 } 65 66 MinidumpParser::MinidumpParser( 67 const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, 68 llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map) 69 : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) { 70 } 71 72 llvm::ArrayRef<uint8_t> MinidumpParser::GetData() { 73 return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(), 74 m_data_sp->GetByteSize()); 75 } 76 77 llvm::ArrayRef<uint8_t> 78 MinidumpParser::GetStream(MinidumpStreamType stream_type) { 79 auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type)); 80 if (iter == m_directory_map.end()) 81 return {}; 82 83 // check if there is enough data 84 if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize()) 85 return {}; 86 87 return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva, 88 iter->second.data_size); 89 } 90 91 llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) { 92 auto arr_ref = m_data_sp->GetData(); 93 if (rva > arr_ref.size()) 94 return llvm::None; 95 arr_ref = arr_ref.drop_front(rva); 96 return parseMinidumpString(arr_ref); 97 } 98 99 UUID MinidumpParser::GetModuleUUID(const MinidumpModule *module) { 100 auto cv_record = 101 GetData().slice(module->CV_record.rva, module->CV_record.data_size); 102 103 // Read the CV record signature 104 const llvm::support::ulittle32_t *signature = nullptr; 105 Status error = consumeObject(cv_record, signature); 106 if (error.Fail()) 107 return UUID(); 108 109 const CvSignature cv_signature = 110 static_cast<CvSignature>(static_cast<const uint32_t>(*signature)); 111 112 if (cv_signature == CvSignature::Pdb70) { 113 // PDB70 record 114 const CvRecordPdb70 *pdb70_uuid = nullptr; 115 Status error = consumeObject(cv_record, pdb70_uuid); 116 if (!error.Fail()) 117 return UUID::fromData(pdb70_uuid, sizeof(*pdb70_uuid)); 118 } else if (cv_signature == CvSignature::ElfBuildId) 119 return UUID::fromData(cv_record); 120 121 return UUID(); 122 } 123 124 llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() { 125 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList); 126 127 if (data.size() == 0) 128 return llvm::None; 129 130 return MinidumpThread::ParseThreadList(data); 131 } 132 133 llvm::ArrayRef<uint8_t> 134 MinidumpParser::GetThreadContext(const MinidumpThread &td) { 135 if (td.thread_context.rva + td.thread_context.data_size > GetData().size()) 136 return {}; 137 138 return GetData().slice(td.thread_context.rva, td.thread_context.data_size); 139 } 140 141 llvm::ArrayRef<uint8_t> 142 MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) { 143 // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If 144 // the minidump was captured with a 64-bit debugger, then the CONTEXT we just 145 // grabbed from the mini_dump_thread is the one for the 64-bit "native" 146 // process rather than the 32-bit "guest" process we care about. In this 147 // case, we can get the 32-bit CONTEXT from the TEB (Thread Environment 148 // Block) of the 64-bit process. 149 auto teb_mem = GetMemory(td.teb, sizeof(TEB64)); 150 if (teb_mem.empty()) 151 return {}; 152 153 const TEB64 *wow64teb; 154 Status error = consumeObject(teb_mem, wow64teb); 155 if (error.Fail()) 156 return {}; 157 158 // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure 159 // that includes the 32-bit CONTEXT (after a ULONG). See: 160 // https://msdn.microsoft.com/en-us/library/ms681670.aspx 161 auto context = 162 GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32)); 163 if (context.size() < sizeof(MinidumpContext_x86_32)) 164 return {}; 165 166 return context; 167 // NOTE: We don't currently use the TEB for anything else. If we 168 // need it in the future, the 32-bit TEB is located according to the address 169 // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]). 170 } 171 172 const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() { 173 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo); 174 175 if (data.size() == 0) 176 return nullptr; 177 178 return MinidumpSystemInfo::Parse(data); 179 } 180 181 ArchSpec MinidumpParser::GetArchitecture() { 182 ArchSpec arch_spec; 183 const MinidumpSystemInfo *system_info = GetSystemInfo(); 184 185 if (!system_info) 186 return arch_spec; 187 188 // TODO what to do about big endiand flavors of arm ? 189 // TODO set the arm subarch stuff if the minidump has info about it 190 191 llvm::Triple triple; 192 triple.setVendor(llvm::Triple::VendorType::UnknownVendor); 193 194 const MinidumpCPUArchitecture arch = 195 static_cast<const MinidumpCPUArchitecture>( 196 static_cast<const uint32_t>(system_info->processor_arch)); 197 198 switch (arch) { 199 case MinidumpCPUArchitecture::X86: 200 triple.setArch(llvm::Triple::ArchType::x86); 201 break; 202 case MinidumpCPUArchitecture::AMD64: 203 triple.setArch(llvm::Triple::ArchType::x86_64); 204 break; 205 case MinidumpCPUArchitecture::ARM: 206 triple.setArch(llvm::Triple::ArchType::arm); 207 break; 208 case MinidumpCPUArchitecture::ARM64: 209 triple.setArch(llvm::Triple::ArchType::aarch64); 210 break; 211 default: 212 triple.setArch(llvm::Triple::ArchType::UnknownArch); 213 break; 214 } 215 216 const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>( 217 static_cast<const uint32_t>(system_info->platform_id)); 218 219 // TODO add all of the OSes that Minidump/breakpad distinguishes? 220 switch (os) { 221 case MinidumpOSPlatform::Win32S: 222 case MinidumpOSPlatform::Win32Windows: 223 case MinidumpOSPlatform::Win32NT: 224 case MinidumpOSPlatform::Win32CE: 225 triple.setOS(llvm::Triple::OSType::Win32); 226 break; 227 case MinidumpOSPlatform::Linux: 228 triple.setOS(llvm::Triple::OSType::Linux); 229 break; 230 case MinidumpOSPlatform::MacOSX: 231 triple.setOS(llvm::Triple::OSType::MacOSX); 232 break; 233 case MinidumpOSPlatform::Android: 234 triple.setOS(llvm::Triple::OSType::Linux); 235 triple.setEnvironment(llvm::Triple::EnvironmentType::Android); 236 break; 237 default: 238 triple.setOS(llvm::Triple::OSType::UnknownOS); 239 break; 240 } 241 242 arch_spec.SetTriple(triple); 243 244 return arch_spec; 245 } 246 247 const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() { 248 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo); 249 250 if (data.size() == 0) 251 return nullptr; 252 253 return MinidumpMiscInfo::Parse(data); 254 } 255 256 llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() { 257 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxProcStatus); 258 259 if (data.size() == 0) 260 return llvm::None; 261 262 return LinuxProcStatus::Parse(data); 263 } 264 265 llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() { 266 const MinidumpMiscInfo *misc_info = GetMiscInfo(); 267 if (misc_info != nullptr) { 268 return misc_info->GetPid(); 269 } 270 271 llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus(); 272 if (proc_status.hasValue()) { 273 return proc_status->GetPid(); 274 } 275 276 return llvm::None; 277 } 278 279 llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() { 280 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ModuleList); 281 282 if (data.size() == 0) 283 return {}; 284 285 return MinidumpModule::ParseModuleList(data); 286 } 287 288 std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() { 289 llvm::ArrayRef<MinidumpModule> modules = GetModuleList(); 290 // map module_name -> pair(load_address, pointer to module struct in memory) 291 llvm::StringMap<std::pair<uint64_t, const MinidumpModule *>> lowest_addr; 292 293 std::vector<const MinidumpModule *> filtered_modules; 294 295 llvm::Optional<std::string> name; 296 std::string module_name; 297 298 for (const auto &module : modules) { 299 name = GetMinidumpString(module.module_name_rva); 300 301 if (!name) 302 continue; 303 304 module_name = name.getValue(); 305 306 auto iter = lowest_addr.end(); 307 bool exists; 308 std::tie(iter, exists) = lowest_addr.try_emplace( 309 module_name, std::make_pair(module.base_of_image, &module)); 310 311 if (exists && module.base_of_image < iter->second.first) 312 iter->second = std::make_pair(module.base_of_image, &module); 313 } 314 315 filtered_modules.reserve(lowest_addr.size()); 316 for (const auto &module : lowest_addr) { 317 filtered_modules.push_back(module.second.second); 318 } 319 320 return filtered_modules; 321 } 322 323 const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() { 324 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception); 325 326 if (data.size() == 0) 327 return nullptr; 328 329 return MinidumpExceptionStream::Parse(data); 330 } 331 332 llvm::Optional<minidump::Range> 333 MinidumpParser::FindMemoryRange(lldb::addr_t addr) { 334 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList); 335 llvm::ArrayRef<uint8_t> data64 = GetStream(MinidumpStreamType::Memory64List); 336 337 if (data.empty() && data64.empty()) 338 return llvm::None; 339 340 if (!data.empty()) { 341 llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list = 342 MinidumpMemoryDescriptor::ParseMemoryList(data); 343 344 if (memory_list.empty()) 345 return llvm::None; 346 347 for (const auto &memory_desc : memory_list) { 348 const MinidumpLocationDescriptor &loc_desc = memory_desc.memory; 349 const lldb::addr_t range_start = memory_desc.start_of_memory_range; 350 const size_t range_size = loc_desc.data_size; 351 352 if (loc_desc.rva + loc_desc.data_size > GetData().size()) 353 return llvm::None; 354 355 if (range_start <= addr && addr < range_start + range_size) { 356 return minidump::Range(range_start, 357 GetData().slice(loc_desc.rva, range_size)); 358 } 359 } 360 } 361 362 // Some Minidumps have a Memory64ListStream that captures all the heap memory 363 // (full-memory Minidumps). We can't exactly use the same loop as above, 364 // because the Minidump uses slightly different data structures to describe 365 // those 366 367 if (!data64.empty()) { 368 llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list; 369 uint64_t base_rva; 370 std::tie(memory64_list, base_rva) = 371 MinidumpMemoryDescriptor64::ParseMemory64List(data64); 372 373 if (memory64_list.empty()) 374 return llvm::None; 375 376 for (const auto &memory_desc64 : memory64_list) { 377 const lldb::addr_t range_start = memory_desc64.start_of_memory_range; 378 const size_t range_size = memory_desc64.data_size; 379 380 if (base_rva + range_size > GetData().size()) 381 return llvm::None; 382 383 if (range_start <= addr && addr < range_start + range_size) { 384 return minidump::Range(range_start, 385 GetData().slice(base_rva, range_size)); 386 } 387 base_rva += range_size; 388 } 389 } 390 391 return llvm::None; 392 } 393 394 llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr, 395 size_t size) { 396 // I don't have a sense of how frequently this is called or how many memory 397 // ranges a Minidump typically has, so I'm not sure if searching for the 398 // appropriate range linearly each time is stupid. Perhaps we should build 399 // an index for faster lookups. 400 llvm::Optional<minidump::Range> range = FindMemoryRange(addr); 401 if (!range) 402 return {}; 403 404 // There's at least some overlap between the beginning of the desired range 405 // (addr) and the current range. Figure out where the overlap begins and how 406 // much overlap there is. 407 408 const size_t offset = addr - range->start; 409 410 if (addr < range->start || offset >= range->range_ref.size()) 411 return {}; 412 413 const size_t overlap = std::min(size, range->range_ref.size() - offset); 414 return range->range_ref.slice(offset, overlap); 415 } 416 417 llvm::Optional<MemoryRegionInfo> 418 MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) { 419 MemoryRegionInfo info; 420 llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList); 421 if (data.empty()) 422 return llvm::None; 423 424 std::vector<const MinidumpMemoryInfo *> mem_info_list = 425 MinidumpMemoryInfo::ParseMemoryInfoList(data); 426 if (mem_info_list.empty()) 427 return llvm::None; 428 429 const auto yes = MemoryRegionInfo::eYes; 430 const auto no = MemoryRegionInfo::eNo; 431 432 const MinidumpMemoryInfo *next_entry = nullptr; 433 for (const auto &entry : mem_info_list) { 434 const auto head = entry->base_address; 435 const auto tail = head + entry->region_size; 436 437 if (head <= load_addr && load_addr < tail) { 438 info.GetRange().SetRangeBase( 439 (entry->state != uint32_t(MinidumpMemoryInfoState::MemFree)) 440 ? head 441 : load_addr); 442 info.GetRange().SetRangeEnd(tail); 443 444 const uint32_t PageNoAccess = 445 static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess); 446 info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no); 447 448 const uint32_t PageWritable = 449 static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable); 450 info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no); 451 452 const uint32_t PageExecutable = static_cast<uint32_t>( 453 MinidumpMemoryProtectionContants::PageExecutable); 454 info.SetExecutable((entry->protect & PageExecutable) != 0 ? yes : no); 455 456 const uint32_t MemFree = 457 static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree); 458 info.SetMapped((entry->state != MemFree) ? yes : no); 459 460 return info; 461 } else if (head > load_addr && 462 (next_entry == nullptr || head < next_entry->base_address)) { 463 // In case there is no region containing load_addr keep track of the 464 // nearest region after load_addr so we can return the distance to it. 465 next_entry = entry; 466 } 467 } 468 469 // No containing region found. Create an unmapped region that extends to the 470 // next region or LLDB_INVALID_ADDRESS 471 info.GetRange().SetRangeBase(load_addr); 472 info.GetRange().SetRangeEnd((next_entry != nullptr) ? next_entry->base_address 473 : LLDB_INVALID_ADDRESS); 474 info.SetReadable(no); 475 info.SetWritable(no); 476 info.SetExecutable(no); 477 info.SetMapped(no); 478 479 // Note that the memory info list doesn't seem to contain ranges in kernel 480 // space, so if you're walking a stack that has kernel frames, the stack may 481 // appear truncated. 482 return info; 483 } 484