1 //===-- MinidumpParser.cpp ---------------------------------------*- C++
2 //-*-===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 // Project includes
12 #include "MinidumpParser.h"
13 
14 // Other libraries and framework includes
15 // C includes
16 // C++ includes
17 
18 using namespace lldb_private;
19 using namespace minidump;
20 
21 llvm::Optional<MinidumpParser>
22 MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) {
23   if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) {
24     return llvm::None;
25   }
26 
27   llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(),
28                                       sizeof(MinidumpHeader));
29   const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
30 
31   if (header == nullptr) {
32     return llvm::None;
33   }
34 
35   lldb::offset_t directory_list_offset = header->stream_directory_rva;
36   // check if there is enough data for the parsing of the directory list
37   if ((directory_list_offset +
38        sizeof(MinidumpDirectory) * header->streams_count) >
39       data_buf_sp->GetByteSize()) {
40     return llvm::None;
41   }
42 
43   const MinidumpDirectory *directory = nullptr;
44   Error error;
45   llvm::ArrayRef<uint8_t> directory_data(
46       data_buf_sp->GetBytes() + directory_list_offset,
47       sizeof(MinidumpDirectory) * header->streams_count);
48   llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map;
49 
50   for (uint32_t i = 0; i < header->streams_count; ++i) {
51     error = consumeObject(directory_data, directory);
52     if (error.Fail()) {
53       return llvm::None;
54     }
55     directory_map[static_cast<const uint32_t>(directory->stream_type)] =
56         directory->location;
57   }
58 
59   MinidumpParser parser(data_buf_sp, header, directory_map);
60   return llvm::Optional<MinidumpParser>(parser);
61 }
62 
63 MinidumpParser::MinidumpParser(
64     const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header,
65     const llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &directory_map)
66     : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) {
67 }
68 
69 lldb::offset_t MinidumpParser::GetByteSize() {
70   return m_data_sp->GetByteSize();
71 }
72 
73 llvm::Optional<llvm::ArrayRef<uint8_t>>
74 MinidumpParser::GetStream(MinidumpStreamType stream_type) {
75   auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type));
76   if (iter == m_directory_map.end())
77     return llvm::None;
78 
79   // check if there is enough data
80   if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
81     return llvm::None;
82 
83   llvm::ArrayRef<uint8_t> arr_ref(m_data_sp->GetBytes() + iter->second.rva,
84                                   iter->second.data_size);
85   return llvm::Optional<llvm::ArrayRef<uint8_t>>(arr_ref);
86 }
87 
88 llvm::Optional<std::vector<const MinidumpThread *>>
89 MinidumpParser::GetThreads() {
90   llvm::Optional<llvm::ArrayRef<uint8_t>> data =
91       GetStream(MinidumpStreamType::ThreadList);
92 
93   if (!data)
94     return llvm::None;
95 
96   return MinidumpThread::ParseThreadList(data.getValue());
97 }
98 
99 const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
100   llvm::Optional<llvm::ArrayRef<uint8_t>> data =
101       GetStream(MinidumpStreamType::SystemInfo);
102 
103   if (!data)
104     return nullptr;
105 
106   return MinidumpSystemInfo::Parse(data.getValue());
107 }
108 
109 ArchSpec MinidumpParser::GetArchitecture() {
110   ArchSpec arch_spec;
111   arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS);
112   arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor);
113   arch_spec.GetTriple().setArch(llvm::Triple::ArchType::UnknownArch);
114 
115   // TODO should we add the OS type here, or somewhere else ?
116 
117   const MinidumpSystemInfo *system_info = GetSystemInfo();
118 
119   if (!system_info)
120     return arch_spec;
121 
122   // TODO what to do about big endiand flavors of arm ?
123   // TODO set the arm subarch stuff if the minidump has info about it
124 
125   const MinidumpCPUArchitecture arch =
126       static_cast<const MinidumpCPUArchitecture>(
127           static_cast<const uint32_t>(system_info->processor_arch));
128   switch (arch) {
129   case MinidumpCPUArchitecture::X86:
130     arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86);
131     break;
132   case MinidumpCPUArchitecture::AMD64:
133     arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86_64);
134     break;
135   case MinidumpCPUArchitecture::ARM:
136     arch_spec.GetTriple().setArch(llvm::Triple::ArchType::arm);
137     break;
138   case MinidumpCPUArchitecture::ARM64:
139     arch_spec.GetTriple().setArch(llvm::Triple::ArchType::aarch64);
140     break;
141   }
142 
143   return arch_spec;
144 }
145 
146 const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
147   llvm::Optional<llvm::ArrayRef<uint8_t>> data =
148       GetStream(MinidumpStreamType::MiscInfo);
149 
150   if (!data)
151     return nullptr;
152 
153   return MinidumpMiscInfo::Parse(data.getValue());
154 }
155