1 //===-- SystemInitializerCommon.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 "lldb/Initialization/SystemInitializerCommon.h"
10 
11 #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
12 #include "lldb/Host/FileSystem.h"
13 #include "lldb/Host/Host.h"
14 #include "lldb/Host/HostInfo.h"
15 #include "lldb/Host/Socket.h"
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/ReproducerProvider.h"
18 #include "lldb/Utility/Timer.h"
19 #include "lldb/lldb-private.h"
20 
21 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
22 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
23 #endif
24 
25 #if defined(_WIN32)
26 #include "Plugins/Process/Windows/Common/ProcessWindowsLog.h"
27 #include "lldb/Host/windows/windows.h"
28 #include <crtdbg.h>
29 #endif
30 
31 #include "llvm/Support/TargetSelect.h"
32 
33 #include <string>
34 
35 using namespace lldb_private;
36 using namespace lldb_private::repro;
37 
SystemInitializerCommon()38 SystemInitializerCommon::SystemInitializerCommon() {}
39 
~SystemInitializerCommon()40 SystemInitializerCommon::~SystemInitializerCommon() {}
41 
42 /// Initialize the FileSystem based on the current reproducer mode.
InitializeFileSystem()43 static llvm::Error InitializeFileSystem() {
44   auto &r = repro::Reproducer::Instance();
45   if (repro::Loader *loader = r.GetLoader()) {
46     FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>();
47     if (vfs_mapping) {
48       if (llvm::Error e = FileSystem::Initialize(vfs_mapping))
49         return e;
50     } else {
51       FileSystem::Initialize();
52     }
53 
54     // Set the current working directory form the reproducer.
55     llvm::Expected<std::string> working_dir =
56         repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
57     if (!working_dir)
58       return working_dir.takeError();
59     if (std::error_code ec = FileSystem::Instance()
60                                  .GetVirtualFileSystem()
61                                  ->setCurrentWorkingDirectory(*working_dir)) {
62       return llvm::errorCodeToError(ec);
63     }
64 
65     // Set the home directory from the reproducer.
66     llvm::Expected<std::string> home_dir =
67         repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
68     if (!home_dir)
69       return home_dir.takeError();
70     FileSystem::Instance().SetHomeDirectory(*home_dir);
71 
72     return llvm::Error::success();
73   }
74 
75   if (repro::Generator *g = r.GetGenerator()) {
76     repro::VersionProvider &vp = g->GetOrCreate<repro::VersionProvider>();
77     vp.SetVersion(lldb_private::GetVersion());
78 
79     repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>();
80     FileSystem::Initialize(fp.GetFileCollector());
81 
82     fp.RecordInterestingDirectory(
83         g->GetOrCreate<repro::WorkingDirectoryProvider>().GetDirectory());
84     fp.RecordInterestingDirectory(
85         g->GetOrCreate<repro::HomeDirectoryProvider>().GetDirectory());
86 
87     return llvm::Error::success();
88   }
89 
90   FileSystem::Initialize();
91   return llvm::Error::success();
92 }
93 
Initialize()94 llvm::Error SystemInitializerCommon::Initialize() {
95 #if defined(_WIN32)
96   const char *disable_crash_dialog_var = getenv("LLDB_DISABLE_CRASH_DIALOG");
97   if (disable_crash_dialog_var &&
98       llvm::StringRef(disable_crash_dialog_var).equals_lower("true")) {
99     // This will prevent Windows from displaying a dialog box requiring user
100     // interaction when
101     // LLDB crashes.  This is mostly useful when automating LLDB, for example
102     // via the test
103     // suite, so that a crash in LLDB does not prevent completion of the test
104     // suite.
105     ::SetErrorMode(GetErrorMode() | SEM_FAILCRITICALERRORS |
106                    SEM_NOGPFAULTERRORBOX);
107 
108     _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
109     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
110     _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
111     _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
112     _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
113     _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
114   }
115 #endif
116 
117   // If the reproducer wasn't initialized before, we can safely assume it's
118   // off.
119   if (!Reproducer::Initialized()) {
120     if (auto e = Reproducer::Initialize(ReproducerMode::Off, llvm::None))
121       return e;
122   }
123 
124   if (auto e = InitializeFileSystem())
125     return e;
126 
127   Log::Initialize();
128   HostInfo::Initialize();
129 
130   llvm::Error error = Socket::Initialize();
131   if (error)
132     return error;
133 
134   static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
135   Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
136 
137   process_gdb_remote::ProcessGDBRemoteLog::Initialize();
138 
139 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
140   ProcessPOSIXLog::Initialize();
141 #endif
142 #if defined(_WIN32)
143   ProcessWindowsLog::Initialize();
144 #endif
145 
146   return llvm::Error::success();
147 }
148 
Terminate()149 void SystemInitializerCommon::Terminate() {
150   static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
151   Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
152 
153 #if defined(_WIN32)
154   ProcessWindowsLog::Terminate();
155 #endif
156 
157   Socket::Terminate();
158   HostInfo::Terminate();
159   Log::DisableAllLogChannels();
160   FileSystem::Terminate();
161   Reproducer::Terminate();
162 }
163