blob: 80b73d6185ebe2c426eb3307ff34324082dbe56b [file] [log] [blame]
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +00001//===-- ProcessMinidump.cpp -------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +00006//
7//===----------------------------------------------------------------------===//
8
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +00009#include "ProcessMinidump.h"
10#include "ThreadMinidump.h"
11
Greg Clayton48a28c12018-12-18 00:50:11 +000012#include "lldb/Core/DumpDataExtractor.h"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000013#include "lldb/Core/Module.h"
14#include "lldb/Core/ModuleSpec.h"
15#include "lldb/Core/PluginManager.h"
16#include "lldb/Core/Section.h"
Greg Clayton48a28c12018-12-18 00:50:11 +000017#include "lldb/Interpreter/CommandInterpreter.h"
18#include "lldb/Interpreter/CommandObject.h"
19#include "lldb/Interpreter/CommandObjectMultiword.h"
20#include "lldb/Interpreter/CommandReturnObject.h"
21#include "lldb/Interpreter/OptionArgParser.h"
22#include "lldb/Interpreter/OptionGroupBoolean.h"
Leonard Mosescu40b832e2018-08-23 21:34:33 +000023#include "lldb/Target/JITLoaderList.h"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000024#include "lldb/Target/MemoryRegionInfo.h"
Leonard Mosescu47196a22018-04-18 23:10:46 +000025#include "lldb/Target/SectionLoadList.h"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000026#include "lldb/Target/Target.h"
27#include "lldb/Target/UnixSignals.h"
28#include "lldb/Utility/LLDBAssert.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000029#include "lldb/Utility/Log.h"
Pavel Labathd821c992018-08-07 11:07:21 +000030#include "lldb/Utility/State.h"
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000031
Zachary Turner3f4a4b32017-02-24 18:56:49 +000032#include "llvm/Support/MemoryBuffer.h"
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +000033#include "llvm/Support/Threading.h"
34
Greg Clayton19c8f392018-08-06 16:56:10 +000035#include "Plugins/Process/Utility/StopInfoMachException.h"
Leonard Mosescu0d057902019-01-07 17:55:42 +000036
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000037// C includes
38// C++ includes
39
Leonard Mosescu47196a22018-04-18 23:10:46 +000040using namespace lldb;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +000041using namespace lldb_private;
42using namespace minidump;
43
Pavel Labath734648b2019-02-11 09:32:08 +000044namespace {
45
46/// A minimal ObjectFile implementation providing a dummy object file for the
47/// cases when the real module binary is not available. This allows the module
48/// to show up in "image list" and symbols to be added to it.
49class PlaceholderObjectFile : public ObjectFile {
Leonard Mosescu47196a22018-04-18 23:10:46 +000050public:
Pavel Labath734648b2019-02-11 09:32:08 +000051 PlaceholderObjectFile(const lldb::ModuleSP &module_sp,
52 const ModuleSpec &module_spec, lldb::offset_t base,
53 lldb::offset_t size)
54 : ObjectFile(module_sp, &module_spec.GetFileSpec(), /*file_offset*/ 0,
55 /*length*/ 0, /*data_sp*/ nullptr, /*data_offset*/ 0),
56 m_arch(module_spec.GetArchitecture()), m_uuid(module_spec.GetUUID()),
57 m_base(base), m_size(size) {
58 m_symtab_ap = llvm::make_unique<Symtab>(this);
Leonard Mosescu9fecd372018-05-02 20:06:17 +000059 }
Leonard Mosescu47196a22018-04-18 23:10:46 +000060
Pavel Labath734648b2019-02-11 09:32:08 +000061 ConstString GetPluginName() override { return ConstString("placeholder"); }
62 uint32_t GetPluginVersion() override { return 1; }
63 bool ParseHeader() override { return true; }
64 Type CalculateType() override { return eTypeUnknown; }
65 Strata CalculateStrata() override { return eStrataUnknown; }
66 uint32_t GetDependentModules(FileSpecList &file_list) override { return 0; }
67 bool IsExecutable() const override { return false; }
68 ArchSpec GetArchitecture() override { return m_arch; }
69 Symtab *GetSymtab() override { return m_symtab_ap.get(); }
70 bool IsStripped() override { return true; }
71 ByteOrder GetByteOrder() const override { return m_arch.GetByteOrder(); }
72
73 uint32_t GetAddressByteSize() const override {
74 return m_arch.GetAddressByteSize();
75 }
76
77 bool GetUUID(UUID *uuid) override {
78 *uuid = m_uuid;
79 return true;
80 }
81
82 Address GetBaseAddress() override {
83 return Address(m_sections_ap->GetSectionAtIndex(0), 0);
84 }
85
86 void CreateSections(SectionList &unified_section_list) override {
87 m_sections_ap = llvm::make_unique<SectionList>();
88 auto section_sp = std::make_shared<Section>(
89 GetModule(), this, /*sect_id*/ 0, ConstString(".module_image"),
90 eSectionTypeOther, m_base, m_size, /*file_offset*/ 0, /*file_size*/ 0,
91 /*log2align*/ 0, /*flags*/ 0);
92 m_sections_ap->AddSection(section_sp);
93 unified_section_list.AddSection(std::move(section_sp));
94 }
95
96 bool SetLoadAddress(Target &target, addr_t value,
97 bool value_is_offset) override {
98 assert(!value_is_offset);
99 assert(value == m_base);
100
101 // Create sections if they haven't been created already.
102 GetModule()->GetSectionList();
103 assert(m_sections_ap->GetNumSections(0) == 1);
104
Leonard Mosescu47196a22018-04-18 23:10:46 +0000105 target.GetSectionLoadList().SetSectionLoadAddress(
Pavel Labath734648b2019-02-11 09:32:08 +0000106 m_sections_ap->GetSectionAtIndex(0), m_base);
107 return true;
Leonard Mosescu47196a22018-04-18 23:10:46 +0000108 }
109
Pavel Labath734648b2019-02-11 09:32:08 +0000110 void Dump(Stream *s) override {
111 s->Format("Placeholder object file for {0} loaded at [{1:x}-{2:x})\n",
112 GetFileSpec(), m_base, m_base + m_size);
Leonard Mosescu47196a22018-04-18 23:10:46 +0000113 }
Pavel Labath734648b2019-02-11 09:32:08 +0000114
115private:
116 ArchSpec m_arch;
117 UUID m_uuid;
118 lldb::offset_t m_base;
119 lldb::offset_t m_size;
Leonard Mosescu47196a22018-04-18 23:10:46 +0000120};
Pavel Labath734648b2019-02-11 09:32:08 +0000121} // namespace
Leonard Mosescu47196a22018-04-18 23:10:46 +0000122
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000123ConstString ProcessMinidump::GetPluginNameStatic() {
124 static ConstString g_name("minidump");
125 return g_name;
126}
127
128const char *ProcessMinidump::GetPluginDescriptionStatic() {
129 return "Minidump plug-in.";
130}
131
132lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
133 lldb::ListenerSP listener_sp,
134 const FileSpec *crash_file) {
135 if (!crash_file)
136 return nullptr;
137
138 lldb::ProcessSP process_sp;
139 // Read enough data for the Minidump header
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000140 constexpr size_t header_size = sizeof(MinidumpHeader);
Jonas Devlieghere87e403a2018-11-12 21:24:50 +0000141 auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(),
142 header_size, 0);
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000143 if (!DataPtr)
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000144 return nullptr;
145
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000146 lldbassert(DataPtr->GetByteSize() == header_size);
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000147
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000148 // first, only try to parse the header, beacuse we need to be fast
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000149 llvm::ArrayRef<uint8_t> HeaderBytes = DataPtr->GetData();
150 const MinidumpHeader *header = MinidumpHeader::Parse(HeaderBytes);
151 if (header == nullptr)
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000152 return nullptr;
153
Jonas Devlieghere87e403a2018-11-12 21:24:50 +0000154 auto AllData =
155 FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0);
Zachary Turner3f4a4b32017-02-24 18:56:49 +0000156 if (!AllData)
157 return nullptr;
158
159 auto minidump_parser = MinidumpParser::Create(AllData);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000160 // check if the parser object is valid
Pavel Labath222fd132016-11-09 10:16:11 +0000161 if (!minidump_parser)
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000162 return nullptr;
163
164 return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file,
165 minidump_parser.getValue());
166}
167
168bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp,
169 bool plugin_specified_by_name) {
170 return true;
171}
172
173ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
174 lldb::ListenerSP listener_sp,
175 const FileSpec &core_file,
176 MinidumpParser minidump_parser)
177 : Process(target_sp, listener_sp), m_minidump_parser(minidump_parser),
178 m_core_file(core_file), m_is_wow64(false) {}
179
180ProcessMinidump::~ProcessMinidump() {
181 Clear();
Adrian Prantl05097242018-04-30 16:49:04 +0000182 // We need to call finalize on the process before destroying ourselves to
183 // make sure all of the broadcaster cleanup goes as planned. If we destruct
184 // this class, then Process::~Process() might have problems trying to fully
185 // destroy the broadcaster.
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000186 Finalize();
187}
188
189void ProcessMinidump::Initialize() {
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +0000190 static llvm::once_flag g_once_flag;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000191
Kamil Rytarowskic5f28e22017-02-06 17:55:02 +0000192 llvm::call_once(g_once_flag, []() {
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000193 PluginManager::RegisterPlugin(GetPluginNameStatic(),
194 GetPluginDescriptionStatic(),
195 ProcessMinidump::CreateInstance);
196 });
197}
198
199void ProcessMinidump::Terminate() {
200 PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
201}
202
Zachary Turner97206d52017-05-12 04:51:55 +0000203Status ProcessMinidump::DoLoadCore() {
204 Status error;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000205
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000206 // Minidump parser initialization & consistency checks
207 error = m_minidump_parser.Initialize();
208 if (error.Fail())
209 return error;
210
211 // Do we support the minidump's architecture?
212 ArchSpec arch = GetArchitecture();
213 switch (arch.GetMachine()) {
214 case llvm::Triple::x86:
215 case llvm::Triple::x86_64:
Greg Clayton19c8f392018-08-06 16:56:10 +0000216 case llvm::Triple::arm:
217 case llvm::Triple::aarch64:
218 // Any supported architectures must be listed here and also supported in
219 // ThreadMinidump::CreateRegisterContextForFrame().
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000220 break;
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000221 default:
222 error.SetErrorStringWithFormat("unsupported minidump architecture: %s",
223 arch.GetArchitectureName());
224 return error;
225 }
Greg Clayton19c8f392018-08-06 16:56:10 +0000226 GetTarget().SetArchitecture(arch, true /*set_platform*/);
Leonard Mosescu2ae3ec32018-07-12 17:27:18 +0000227
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000228 m_thread_list = m_minidump_parser.GetThreads();
229 m_active_exception = m_minidump_parser.GetExceptionStream();
230 ReadModuleList();
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000231
232 llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid();
233 if (!pid) {
234 error.SetErrorString("failed to parse PID");
235 return error;
236 }
237 SetID(pid.getValue());
238
239 return error;
240}
241
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000242ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); }
243
244uint32_t ProcessMinidump::GetPluginVersion() { return 1; }
245
Zachary Turner97206d52017-05-12 04:51:55 +0000246Status ProcessMinidump::DoDestroy() { return Status(); }
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000247
248void ProcessMinidump::RefreshStateAfterStop() {
249 if (!m_active_exception)
250 return;
251
252 if (m_active_exception->exception_record.exception_code ==
253 MinidumpException::DumpRequested) {
254 return;
255 }
256
257 lldb::StopInfoSP stop_info;
258 lldb::ThreadSP stop_thread;
259
260 Process::m_thread_list.SetSelectedThreadByID(m_active_exception->thread_id);
261 stop_thread = Process::m_thread_list.GetSelectedThread();
262 ArchSpec arch = GetArchitecture();
263
264 if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
265 stop_info = StopInfo::CreateStopReasonWithSignal(
266 *stop_thread, m_active_exception->exception_record.exception_code);
Greg Clayton19c8f392018-08-06 16:56:10 +0000267 } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) {
268 stop_info = StopInfoMachException::CreateStopReasonWithMachException(
269 *stop_thread, m_active_exception->exception_record.exception_code, 2,
270 m_active_exception->exception_record.exception_flags,
271 m_active_exception->exception_record.exception_address, 0);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000272 } else {
273 std::string desc;
274 llvm::raw_string_ostream desc_stream(desc);
275 desc_stream << "Exception "
276 << llvm::format_hex(
277 m_active_exception->exception_record.exception_code, 8)
278 << " encountered at address "
279 << llvm::format_hex(
280 m_active_exception->exception_record.exception_address,
281 8);
282 stop_info = StopInfo::CreateStopReasonWithException(
283 *stop_thread, desc_stream.str().c_str());
284 }
285
286 stop_thread->SetStopInfo(stop_info);
287}
288
289bool ProcessMinidump::IsAlive() { return true; }
290
291bool ProcessMinidump::WarnBeforeDetach() const { return false; }
292
293size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
Zachary Turner97206d52017-05-12 04:51:55 +0000294 Status &error) {
Adrian Prantl05097242018-04-30 16:49:04 +0000295 // Don't allow the caching that lldb_private::Process::ReadMemory does since
296 // we have it all cached in our dump file anyway.
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000297 return DoReadMemory(addr, buf, size, error);
298}
299
300size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
Zachary Turner97206d52017-05-12 04:51:55 +0000301 Status &error) {
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000302
303 llvm::ArrayRef<uint8_t> mem = m_minidump_parser.GetMemory(addr, size);
304 if (mem.empty()) {
305 error.SetErrorString("could not parse memory info");
306 return 0;
307 }
308
309 std::memcpy(buf, mem.data(), mem.size());
310 return mem.size();
311}
312
313ArchSpec ProcessMinidump::GetArchitecture() {
314 if (!m_is_wow64) {
315 return m_minidump_parser.GetArchitecture();
316 }
317
318 llvm::Triple triple;
319 triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
320 triple.setArch(llvm::Triple::ArchType::x86);
321 triple.setOS(llvm::Triple::OSType::Win32);
322 return ArchSpec(triple);
323}
324
Zachary Turner97206d52017-05-12 04:51:55 +0000325Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
326 MemoryRegionInfo &range_info) {
Greg Clayton026e1bf2018-12-14 19:36:01 +0000327 range_info = m_minidump_parser.GetMemoryRegionInfo(load_addr);
328 return Status();
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000329}
330
Tatyana Krasnukha92e5e362018-12-20 15:05:43 +0000331Status ProcessMinidump::GetMemoryRegions(
332 lldb_private::MemoryRegionInfos &region_list) {
333 region_list = m_minidump_parser.GetMemoryRegions();
334 return Status();
335}
336
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000337void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
338
Dimitar Vlahovski5a19c0c2016-11-01 15:48:24 +0000339bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list,
340 ThreadList &new_thread_list) {
Leonard Mosescu0d057902019-01-07 17:55:42 +0000341 for (const MinidumpThread& thread : m_thread_list) {
342 MinidumpLocationDescriptor context_location = thread.thread_context;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000343
Leonard Mosescu0d057902019-01-07 17:55:42 +0000344 // If the minidump contains an exception context, use it
345 if (m_active_exception != nullptr &&
346 m_active_exception->thread_id == thread.thread_id) {
347 context_location = m_active_exception->thread_context;
348 }
349
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000350 llvm::ArrayRef<uint8_t> context;
351 if (!m_is_wow64)
Leonard Mosescu0d057902019-01-07 17:55:42 +0000352 context = m_minidump_parser.GetThreadContext(context_location);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000353 else
Leonard Mosescu0d057902019-01-07 17:55:42 +0000354 context = m_minidump_parser.GetThreadContextWow64(thread);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000355
Leonard Mosescu0d057902019-01-07 17:55:42 +0000356 lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context));
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000357 new_thread_list.AddThread(thread_sp);
358 }
359 return new_thread_list.GetSize(false) > 0;
360}
361
362void ProcessMinidump::ReadModuleList() {
363 std::vector<const MinidumpModule *> filtered_modules =
364 m_minidump_parser.GetFilteredModuleList();
365
366 for (auto module : filtered_modules) {
367 llvm::Optional<std::string> name =
368 m_minidump_parser.GetMinidumpString(module->module_name_rva);
369
370 if (!name)
371 continue;
372
373 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
374 if (log) {
Pavel Labatheaa419c2016-11-02 10:29:47 +0000375 log->Printf("ProcessMinidump::%s found module: name: %s %#010" PRIx64
376 "-%#010" PRIx64 " size: %" PRIu32,
377 __FUNCTION__, name.getValue().c_str(),
378 uint64_t(module->base_of_image),
379 module->base_of_image + module->size_of_image,
380 uint32_t(module->size_of_image));
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000381 }
382
383 // check if the process is wow64 - a 32 bit windows process running on a
384 // 64 bit windows
385 if (llvm::StringRef(name.getValue()).endswith_lower("wow64.dll")) {
386 m_is_wow64 = true;
387 }
388
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000389 const auto uuid = m_minidump_parser.GetModuleUUID(module);
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000390 auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple());
391 FileSystem::Instance().Resolve(file_spec);
Leonard Mosescu9fecd372018-05-02 20:06:17 +0000392 ModuleSpec module_spec(file_spec, uuid);
Pavel Labath734648b2019-02-11 09:32:08 +0000393 module_spec.GetArchitecture() = GetArchitecture();
Zachary Turner97206d52017-05-12 04:51:55 +0000394 Status error;
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000395 lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
396 if (!module_sp || error.Fail()) {
Adrian Prantl05097242018-04-30 16:49:04 +0000397 // We failed to locate a matching local object file. Fortunately, the
398 // minidump format encodes enough information about each module's memory
399 // range to allow us to create placeholder modules.
Leonard Mosescu47196a22018-04-18 23:10:46 +0000400 //
401 // This enables most LLDB functionality involving address-to-module
402 // translations (ex. identifing the module for a stack frame PC) and
403 // modules/sections commands (ex. target modules list, ...)
Leonard Mosescu9ba51572018-08-07 18:00:30 +0000404 if (log) {
405 log->Printf("Unable to locate the matching object file, creating a "
406 "placeholder module for: %s",
407 name.getValue().c_str());
408 }
409
Pavel Labath734648b2019-02-11 09:32:08 +0000410 module_sp = Module::CreateModuleFromObjectFile<PlaceholderObjectFile>(
411 module_spec, module->base_of_image, module->size_of_image);
Leonard Mosescu47196a22018-04-18 23:10:46 +0000412 GetTarget().GetImages().Append(module_sp);
Dimitar Vlahovski7b18dd42016-10-31 15:35:18 +0000413 }
414
415 if (log) {
416 log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
417 name.getValue().c_str());
418 }
419
420 bool load_addr_changed = false;
421 module_sp->SetLoadAddress(GetTarget(), module->base_of_image, false,
422 load_addr_changed);
423 }
424}
Dimitar Vlahovski5a19c0c2016-11-01 15:48:24 +0000425
426bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) {
427 info.Clear();
428 info.SetProcessID(GetID());
429 info.SetArchitecture(GetArchitecture());
430 lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
431 if (module_sp) {
432 const bool add_exe_file_as_first_arg = false;
433 info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
434 add_exe_file_as_first_arg);
435 }
436 return true;
437}
Leonard Mosescu40b832e2018-08-23 21:34:33 +0000438
439// For minidumps there's no runtime generated code so we don't need JITLoader(s)
440// Avoiding them will also speed up minidump loading since JITLoaders normally
441// try to set up symbolic breakpoints, which in turn may force loading more
442// debug information than needed.
443JITLoaderList &ProcessMinidump::GetJITLoaders() {
444 if (!m_jit_loaders_ap) {
445 m_jit_loaders_ap = llvm::make_unique<JITLoaderList>();
446 }
447 return *m_jit_loaders_ap;
448}
Greg Clayton48a28c12018-12-18 00:50:11 +0000449
450#define INIT_BOOL(VAR, LONG, SHORT, DESC) \
451 VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true)
452#define APPEND_OPT(VAR) \
453 m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
454
455class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
456private:
457 OptionGroupOptions m_option_group;
458 OptionGroupBoolean m_dump_all;
459 OptionGroupBoolean m_dump_directory;
460 OptionGroupBoolean m_dump_linux_cpuinfo;
461 OptionGroupBoolean m_dump_linux_proc_status;
462 OptionGroupBoolean m_dump_linux_lsb_release;
463 OptionGroupBoolean m_dump_linux_cmdline;
464 OptionGroupBoolean m_dump_linux_environ;
465 OptionGroupBoolean m_dump_linux_auxv;
466 OptionGroupBoolean m_dump_linux_maps;
467 OptionGroupBoolean m_dump_linux_proc_stat;
468 OptionGroupBoolean m_dump_linux_proc_uptime;
469 OptionGroupBoolean m_dump_linux_proc_fd;
470 OptionGroupBoolean m_dump_linux_all;
471
472 void SetDefaultOptionsIfNoneAreSet() {
473 if (m_dump_all.GetOptionValue().GetCurrentValue() ||
474 m_dump_linux_all.GetOptionValue().GetCurrentValue() ||
475 m_dump_directory.GetOptionValue().GetCurrentValue() ||
476 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() ||
477 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() ||
478 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() ||
479 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() ||
480 m_dump_linux_environ.GetOptionValue().GetCurrentValue() ||
481 m_dump_linux_auxv.GetOptionValue().GetCurrentValue() ||
482 m_dump_linux_maps.GetOptionValue().GetCurrentValue() ||
483 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() ||
484 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() ||
485 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue())
486 return;
487 // If no options were set, then dump everything
488 m_dump_all.GetOptionValue().SetCurrentValue(true);
489 }
490 bool DumpAll() const {
491 return m_dump_all.GetOptionValue().GetCurrentValue();
492 }
493 bool DumpDirectory() const {
494 return DumpAll() ||
495 m_dump_directory.GetOptionValue().GetCurrentValue();
496 }
497 bool DumpLinux() const {
498 return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue();
499 }
500 bool DumpLinuxCPUInfo() const {
501 return DumpLinux() ||
502 m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue();
503 }
504 bool DumpLinuxProcStatus() const {
505 return DumpLinux() ||
506 m_dump_linux_proc_status.GetOptionValue().GetCurrentValue();
507 }
508 bool DumpLinuxProcStat() const {
509 return DumpLinux() ||
510 m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue();
511 }
512 bool DumpLinuxLSBRelease() const {
513 return DumpLinux() ||
514 m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue();
515 }
516 bool DumpLinuxCMDLine() const {
517 return DumpLinux() ||
518 m_dump_linux_cmdline.GetOptionValue().GetCurrentValue();
519 }
520 bool DumpLinuxEnviron() const {
521 return DumpLinux() ||
522 m_dump_linux_environ.GetOptionValue().GetCurrentValue();
523 }
524 bool DumpLinuxAuxv() const {
525 return DumpLinux() ||
526 m_dump_linux_auxv.GetOptionValue().GetCurrentValue();
527 }
528 bool DumpLinuxMaps() const {
529 return DumpLinux() ||
530 m_dump_linux_maps.GetOptionValue().GetCurrentValue();
531 }
532 bool DumpLinuxProcUptime() const {
533 return DumpLinux() ||
534 m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue();
535 }
536 bool DumpLinuxProcFD() const {
537 return DumpLinux() ||
538 m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue();
539 }
540public:
541
542 CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter)
543 : CommandObjectParsed(interpreter, "process plugin dump",
544 "Dump information from the minidump file.", NULL),
545 m_option_group(),
546 INIT_BOOL(m_dump_all, "all", 'a',
547 "Dump the everything in the minidump."),
548 INIT_BOOL(m_dump_directory, "directory", 'd',
549 "Dump the minidump directory map."),
550 INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C',
551 "Dump linux /proc/cpuinfo."),
552 INIT_BOOL(m_dump_linux_proc_status, "status", 's',
553 "Dump linux /proc/<pid>/status."),
554 INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r',
555 "Dump linux /etc/lsb-release."),
556 INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c',
557 "Dump linux /proc/<pid>/cmdline."),
558 INIT_BOOL(m_dump_linux_environ, "environ", 'e',
559 "Dump linux /proc/<pid>/environ."),
560 INIT_BOOL(m_dump_linux_auxv, "auxv", 'x',
561 "Dump linux /proc/<pid>/auxv."),
562 INIT_BOOL(m_dump_linux_maps, "maps", 'm',
563 "Dump linux /proc/<pid>/maps."),
564 INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S',
565 "Dump linux /proc/<pid>/stat."),
566 INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u',
567 "Dump linux process uptime."),
568 INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f',
569 "Dump linux /proc/<pid>/fd."),
570 INIT_BOOL(m_dump_linux_all, "linux", 'l',
571 "Dump all linux streams.") {
572 APPEND_OPT(m_dump_all);
573 APPEND_OPT(m_dump_directory);
574 APPEND_OPT(m_dump_linux_cpuinfo);
575 APPEND_OPT(m_dump_linux_proc_status);
576 APPEND_OPT(m_dump_linux_lsb_release);
577 APPEND_OPT(m_dump_linux_cmdline);
578 APPEND_OPT(m_dump_linux_environ);
579 APPEND_OPT(m_dump_linux_auxv);
580 APPEND_OPT(m_dump_linux_maps);
581 APPEND_OPT(m_dump_linux_proc_stat);
582 APPEND_OPT(m_dump_linux_proc_uptime);
583 APPEND_OPT(m_dump_linux_proc_fd);
584 APPEND_OPT(m_dump_linux_all);
585 m_option_group.Finalize();
586 }
Leonard Mosescu0d057902019-01-07 17:55:42 +0000587
Greg Clayton48a28c12018-12-18 00:50:11 +0000588 ~CommandObjectProcessMinidumpDump() {}
Leonard Mosescu0d057902019-01-07 17:55:42 +0000589
Greg Clayton48a28c12018-12-18 00:50:11 +0000590 Options *GetOptions() override { return &m_option_group; }
591
592 bool DoExecute(Args &command, CommandReturnObject &result) override {
593 const size_t argc = command.GetArgumentCount();
594 if (argc > 0) {
595 result.AppendErrorWithFormat("'%s' take no arguments, only options",
596 m_cmd_name.c_str());
597 result.SetStatus(eReturnStatusFailed);
598 return false;
599 }
600 SetDefaultOptionsIfNoneAreSet();
Leonard Mosescu0d057902019-01-07 17:55:42 +0000601
Greg Clayton48a28c12018-12-18 00:50:11 +0000602 ProcessMinidump *process = static_cast<ProcessMinidump *>(
603 m_interpreter.GetExecutionContext().GetProcessPtr());
604 result.SetStatus(eReturnStatusSuccessFinishResult);
605 Stream &s = result.GetOutputStream();
606 MinidumpParser &minidump = process->m_minidump_parser;
607 if (DumpDirectory()) {
608 s.Printf("RVA SIZE TYPE MinidumpStreamType\n");
609 s.Printf("---------- ---------- ---------- --------------------------\n");
610 for (const auto &pair: minidump.GetDirectoryMap())
611 s.Printf("0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)pair.second.rva,
612 (uint32_t)pair.second.data_size, pair.first,
613 MinidumpParser::GetStreamTypeAsString(pair.first).data());
614 s.Printf("\n");
615 }
616 auto DumpTextStream = [&](MinidumpStreamType stream_type,
Pavel Labath796984d2018-12-27 09:44:32 +0000617 llvm::StringRef label) -> void {
Greg Clayton48a28c12018-12-18 00:50:11 +0000618 auto bytes = minidump.GetStream(stream_type);
619 if (!bytes.empty()) {
620 if (label.empty())
621 label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
622 s.Printf("%s:\n%s\n\n", label.data(), bytes.data());
623 }
624 };
625 auto DumpBinaryStream = [&](MinidumpStreamType stream_type,
Pavel Labath796984d2018-12-27 09:44:32 +0000626 llvm::StringRef label) -> void {
Greg Clayton48a28c12018-12-18 00:50:11 +0000627 auto bytes = minidump.GetStream(stream_type);
628 if (!bytes.empty()) {
629 if (label.empty())
630 label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
631 s.Printf("%s:\n", label.data());
632 DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
633 process->GetAddressByteSize());
634 DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1,
635 bytes.size(), 16, 0, 0, 0);
636 s.Printf("\n\n");
637 }
638 };
639
640 if (DumpLinuxCPUInfo())
641 DumpTextStream(MinidumpStreamType::LinuxCPUInfo, "/proc/cpuinfo");
642 if (DumpLinuxProcStatus())
643 DumpTextStream(MinidumpStreamType::LinuxProcStatus, "/proc/PID/status");
644 if (DumpLinuxLSBRelease())
645 DumpTextStream(MinidumpStreamType::LinuxLSBRelease, "/etc/lsb-release");
646 if (DumpLinuxCMDLine())
647 DumpTextStream(MinidumpStreamType::LinuxCMDLine, "/proc/PID/cmdline");
648 if (DumpLinuxEnviron())
649 DumpTextStream(MinidumpStreamType::LinuxEnviron, "/proc/PID/environ");
650 if (DumpLinuxAuxv())
651 DumpBinaryStream(MinidumpStreamType::LinuxAuxv, "/proc/PID/auxv");
652 if (DumpLinuxMaps())
653 DumpTextStream(MinidumpStreamType::LinuxMaps, "/proc/PID/maps");
654 if (DumpLinuxProcStat())
655 DumpTextStream(MinidumpStreamType::LinuxProcStat, "/proc/PID/stat");
656 if (DumpLinuxProcUptime())
657 DumpTextStream(MinidumpStreamType::LinuxProcUptime, "uptime");
658 if (DumpLinuxProcFD())
659 DumpTextStream(MinidumpStreamType::LinuxProcFD, "/proc/PID/fd");
660 return true;
661 }
662};
663
664class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword {
665public:
666 CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter)
667 : CommandObjectMultiword(interpreter, "process plugin",
668 "Commands for operating on a ProcessMinidump process.",
669 "process plugin <subcommand> [<subcommand-options>]") {
670 LoadSubCommand("dump",
671 CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter)));
672 }
Leonard Mosescu0d057902019-01-07 17:55:42 +0000673
Greg Clayton48a28c12018-12-18 00:50:11 +0000674 ~CommandObjectMultiwordProcessMinidump() {}
675};
676
677CommandObject *ProcessMinidump::GetPluginCommandObject() {
678 if (!m_command_sp)
679 m_command_sp.reset(new CommandObjectMultiwordProcessMinidump(
680 GetTarget().GetDebugger().GetCommandInterpreter()));
681 return m_command_sp.get();
682}