/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/driver/cc1_main.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===// |
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 | | // This is the entry point to the clang -cc1 functionality, which implements the |
10 | | // core compiler functionality along with a number of additional tools for |
11 | | // demonstration and testing purposes. |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "clang/Basic/Stack.h" |
16 | | #include "clang/Basic/TargetOptions.h" |
17 | | #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" |
18 | | #include "clang/Config/config.h" |
19 | | #include "clang/Driver/DriverDiagnostic.h" |
20 | | #include "clang/Driver/Options.h" |
21 | | #include "clang/Frontend/CompilerInstance.h" |
22 | | #include "clang/Frontend/CompilerInvocation.h" |
23 | | #include "clang/Frontend/FrontendDiagnostic.h" |
24 | | #include "clang/Frontend/TextDiagnosticBuffer.h" |
25 | | #include "clang/Frontend/TextDiagnosticPrinter.h" |
26 | | #include "clang/Frontend/Utils.h" |
27 | | #include "clang/FrontendTool/Utils.h" |
28 | | #include "llvm/ADT/Statistic.h" |
29 | | #include "llvm/Config/llvm-config.h" |
30 | | #include "llvm/LinkAllPasses.h" |
31 | | #include "llvm/MC/TargetRegistry.h" |
32 | | #include "llvm/Option/Arg.h" |
33 | | #include "llvm/Option/ArgList.h" |
34 | | #include "llvm/Option/OptTable.h" |
35 | | #include "llvm/Support/BuryPointer.h" |
36 | | #include "llvm/Support/Compiler.h" |
37 | | #include "llvm/Support/ErrorHandling.h" |
38 | | #include "llvm/Support/ManagedStatic.h" |
39 | | #include "llvm/Support/Path.h" |
40 | | #include "llvm/Support/Process.h" |
41 | | #include "llvm/Support/Signals.h" |
42 | | #include "llvm/Support/TargetSelect.h" |
43 | | #include "llvm/Support/TimeProfiler.h" |
44 | | #include "llvm/Support/Timer.h" |
45 | | #include "llvm/Support/raw_ostream.h" |
46 | | #include "llvm/Target/TargetMachine.h" |
47 | | #include <cstdio> |
48 | | |
49 | | #ifdef CLANG_HAVE_RLIMITS |
50 | | #include <sys/resource.h> |
51 | | #endif |
52 | | |
53 | | using namespace clang; |
54 | | using namespace llvm::opt; |
55 | | |
56 | | //===----------------------------------------------------------------------===// |
57 | | // Main driver |
58 | | //===----------------------------------------------------------------------===// |
59 | | |
60 | | static void LLVMErrorHandler(void *UserData, const char *Message, |
61 | 5 | bool GenCrashDiag) { |
62 | 5 | DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData); |
63 | | |
64 | 5 | Diags.Report(diag::err_fe_error_backend) << Message; |
65 | | |
66 | | // Run the interrupt handlers to make sure any special cleanups get done, in |
67 | | // particular that we remove files registered with RemoveFileOnSignal. |
68 | 5 | llvm::sys::RunInterruptHandlers(); |
69 | | |
70 | | // We cannot recover from llvm errors. When reporting a fatal error, exit |
71 | | // with status 70 to generate crash diagnostics. For BSD systems this is |
72 | | // defined as an internal software error. Otherwise, exit with status 1. |
73 | 5 | llvm::sys::Process::Exit(GenCrashDiag ? 70 : 10 ); |
74 | 5 | } |
75 | | |
76 | | #ifdef CLANG_HAVE_RLIMITS |
77 | | #if defined(__linux__) && defined(__PIE__) |
78 | | static size_t getCurrentStackAllocation() { |
79 | | // If we can't compute the current stack usage, allow for 512K of command |
80 | | // line arguments and environment. |
81 | | size_t Usage = 512 * 1024; |
82 | | if (FILE *StatFile = fopen("/proc/self/stat", "r")) { |
83 | | // We assume that the stack extends from its current address to the end of |
84 | | // the environment space. In reality, there is another string literal (the |
85 | | // program name) after the environment, but this is close enough (we only |
86 | | // need to be within 100K or so). |
87 | | unsigned long StackPtr, EnvEnd; |
88 | | // Disable silly GCC -Wformat warning that complains about length |
89 | | // modifiers on ignored format specifiers. We want to retain these |
90 | | // for documentation purposes even though they have no effect. |
91 | | #if defined(__GNUC__) && !defined(__clang__) |
92 | | #pragma GCC diagnostic push |
93 | | #pragma GCC diagnostic ignored "-Wformat" |
94 | | #endif |
95 | | if (fscanf(StatFile, |
96 | | "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu " |
97 | | "%*lu %*ld %*ld %*ld %*ld %*ld %*ld %*llu %*lu %*ld %*lu %*lu " |
98 | | "%*lu %*lu %lu %*lu %*lu %*lu %*lu %*lu %*llu %*lu %*lu %*d %*d " |
99 | | "%*u %*u %*llu %*lu %*ld %*lu %*lu %*lu %*lu %*lu %*lu %lu %*d", |
100 | | &StackPtr, &EnvEnd) == 2) { |
101 | | #if defined(__GNUC__) && !defined(__clang__) |
102 | | #pragma GCC diagnostic pop |
103 | | #endif |
104 | | Usage = StackPtr < EnvEnd ? EnvEnd - StackPtr : StackPtr - EnvEnd; |
105 | | } |
106 | | fclose(StatFile); |
107 | | } |
108 | | return Usage; |
109 | | } |
110 | | |
111 | | #include <alloca.h> |
112 | | |
113 | | LLVM_ATTRIBUTE_NOINLINE |
114 | | static void ensureStackAddressSpace() { |
115 | | // Linux kernels prior to 4.1 will sometimes locate the heap of a PIE binary |
116 | | // relatively close to the stack (they are only guaranteed to be 128MiB |
117 | | // apart). This results in crashes if we happen to heap-allocate more than |
118 | | // 128MiB before we reach our stack high-water mark. |
119 | | // |
120 | | // To avoid these crashes, ensure that we have sufficient virtual memory |
121 | | // pages allocated before we start running. |
122 | | size_t Curr = getCurrentStackAllocation(); |
123 | | const int kTargetStack = DesiredStackSize - 256 * 1024; |
124 | | if (Curr < kTargetStack) { |
125 | | volatile char *volatile Alloc = |
126 | | static_cast<volatile char *>(alloca(kTargetStack - Curr)); |
127 | | Alloc[0] = 0; |
128 | | Alloc[kTargetStack - Curr - 1] = 0; |
129 | | } |
130 | | } |
131 | | #else |
132 | 41.5k | static void ensureStackAddressSpace() {} |
133 | | #endif |
134 | | |
135 | | /// Attempt to ensure that we have at least 8MiB of usable stack space. |
136 | 41.5k | static void ensureSufficientStack() { |
137 | 41.5k | struct rlimit rlim; |
138 | 41.5k | if (getrlimit(RLIMIT_STACK, &rlim) != 0) |
139 | 0 | return; |
140 | | |
141 | | // Increase the soft stack limit to our desired level, if necessary and |
142 | | // possible. |
143 | 41.5k | if (rlim.rlim_cur != RLIM_INFINITY && |
144 | 41.5k | rlim.rlim_cur < rlim_t(DesiredStackSize)) { |
145 | | // Try to allocate sufficient stack. |
146 | 0 | if (rlim.rlim_max == RLIM_INFINITY || |
147 | 0 | rlim.rlim_max >= rlim_t(DesiredStackSize)) |
148 | 0 | rlim.rlim_cur = DesiredStackSize; |
149 | 0 | else if (rlim.rlim_cur == rlim.rlim_max) |
150 | 0 | return; |
151 | 0 | else |
152 | 0 | rlim.rlim_cur = rlim.rlim_max; |
153 | | |
154 | 0 | if (setrlimit(RLIMIT_STACK, &rlim) != 0 || |
155 | 0 | rlim.rlim_cur != DesiredStackSize) |
156 | 0 | return; |
157 | 0 | } |
158 | | |
159 | | // We should now have a stack of size at least DesiredStackSize. Ensure |
160 | | // that we can actually use that much, if necessary. |
161 | 41.5k | ensureStackAddressSpace(); |
162 | 41.5k | } |
163 | | #else |
164 | | static void ensureSufficientStack() {} |
165 | | #endif |
166 | | |
167 | | /// Print supported cpus of the given target. |
168 | 4 | static int PrintSupportedCPUs(std::string TargetStr) { |
169 | 4 | std::string Error; |
170 | 4 | const llvm::Target *TheTarget = |
171 | 4 | llvm::TargetRegistry::lookupTarget(TargetStr, Error); |
172 | 4 | if (!TheTarget) { |
173 | 0 | llvm::errs() << Error; |
174 | 0 | return 1; |
175 | 0 | } |
176 | | |
177 | | // the target machine will handle the mcpu printing |
178 | 4 | llvm::TargetOptions Options; |
179 | 4 | std::unique_ptr<llvm::TargetMachine> TheTargetMachine( |
180 | 4 | TheTarget->createTargetMachine(TargetStr, "", "+cpuhelp", Options, None)); |
181 | 4 | return 0; |
182 | 4 | } |
183 | | |
184 | 41.5k | int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { |
185 | 41.5k | ensureSufficientStack(); |
186 | | |
187 | 41.5k | std::unique_ptr<CompilerInstance> Clang(new CompilerInstance()); |
188 | 41.5k | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
189 | | |
190 | | // Register the support for object-file-wrapped Clang modules. |
191 | 41.5k | auto PCHOps = Clang->getPCHContainerOperations(); |
192 | 41.5k | PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>()); |
193 | 41.5k | PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>()); |
194 | | |
195 | | // Initialize targets first, so that --version shows registered targets. |
196 | 41.5k | llvm::InitializeAllTargets(); |
197 | 41.5k | llvm::InitializeAllTargetMCs(); |
198 | 41.5k | llvm::InitializeAllAsmPrinters(); |
199 | 41.5k | llvm::InitializeAllAsmParsers(); |
200 | | |
201 | | // Buffer diagnostics from argument parsing so that we can output them using a |
202 | | // well formed diagnostic object. |
203 | 41.5k | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); |
204 | 41.5k | TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; |
205 | 41.5k | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer); |
206 | | |
207 | | // Setup round-trip remarks for the DiagnosticsEngine used in CreateFromArgs. |
208 | 41.5k | if (find(Argv, StringRef("-Rround-trip-cc1-args")) != Argv.end()) |
209 | 2 | Diags.setSeverity(diag::remark_cc1_round_trip_generated, |
210 | 2 | diag::Severity::Remark, {}); |
211 | | |
212 | 41.5k | bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(), |
213 | 41.5k | Argv, Diags, Argv0); |
214 | | |
215 | 41.5k | if (Clang->getFrontendOpts().TimeTrace || |
216 | 41.5k | !Clang->getFrontendOpts().TimeTracePath.empty()41.5k ) { |
217 | 5 | Clang->getFrontendOpts().TimeTrace = 1; |
218 | 5 | llvm::timeTraceProfilerInitialize( |
219 | 5 | Clang->getFrontendOpts().TimeTraceGranularity, Argv0); |
220 | 5 | } |
221 | | // --print-supported-cpus takes priority over the actual compilation. |
222 | 41.5k | if (Clang->getFrontendOpts().PrintSupportedCPUs) |
223 | 4 | return PrintSupportedCPUs(Clang->getTargetOpts().Triple); |
224 | | |
225 | | // Infer the builtin include path if unspecified. |
226 | 41.5k | if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && |
227 | 41.5k | Clang->getHeaderSearchOpts().ResourceDir.empty()41.5k ) |
228 | 35.3k | Clang->getHeaderSearchOpts().ResourceDir = |
229 | 35.3k | CompilerInvocation::GetResourcesPath(Argv0, MainAddr); |
230 | | |
231 | | // Create the actual diagnostics engine. |
232 | 41.5k | Clang->createDiagnostics(); |
233 | 41.5k | if (!Clang->hasDiagnostics()) |
234 | 0 | return 1; |
235 | | |
236 | | // Set an error handler, so that any LLVM backend diagnostics go through our |
237 | | // error handler. |
238 | 41.5k | llvm::install_fatal_error_handler(LLVMErrorHandler, |
239 | 41.5k | static_cast<void*>(&Clang->getDiagnostics())); |
240 | | |
241 | 41.5k | DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics()); |
242 | 41.5k | if (!Success) { |
243 | 121 | Clang->getDiagnosticClient().finish(); |
244 | 121 | return 1; |
245 | 121 | } |
246 | | |
247 | | // Execute the frontend actions. |
248 | 41.4k | { |
249 | 41.4k | llvm::TimeTraceScope TimeScope("ExecuteCompiler"); |
250 | 41.4k | Success = ExecuteCompilerInvocation(Clang.get()); |
251 | 41.4k | } |
252 | | |
253 | | // If any timers were active but haven't been destroyed yet, print their |
254 | | // results now. This happens in -disable-free mode. |
255 | 41.4k | llvm::TimerGroup::printAll(llvm::errs()); |
256 | 41.4k | llvm::TimerGroup::clearAll(); |
257 | | |
258 | 41.4k | if (llvm::timeTraceProfilerEnabled()) { |
259 | 5 | SmallString<128> Path(Clang->getFrontendOpts().OutputFile); |
260 | 5 | llvm::sys::path::replace_extension(Path, "json"); |
261 | 5 | if (!Clang->getFrontendOpts().TimeTracePath.empty()) { |
262 | | // replace the suffix to '.json' directly |
263 | 3 | SmallString<128> TracePath(Clang->getFrontendOpts().TimeTracePath); |
264 | 3 | if (llvm::sys::fs::is_directory(TracePath)) |
265 | 2 | llvm::sys::path::append(TracePath, llvm::sys::path::filename(Path)); |
266 | 3 | Path.assign(TracePath); |
267 | 3 | } |
268 | 5 | if (auto profilerOutput = Clang->createOutputFile( |
269 | 5 | Path.str(), /*Binary=*/false, /*RemoveFileOnSignal=*/false, |
270 | 5 | /*useTemporary=*/false)) { |
271 | 5 | llvm::timeTraceProfilerWrite(*profilerOutput); |
272 | 5 | profilerOutput.reset(); |
273 | 5 | llvm::timeTraceProfilerCleanup(); |
274 | 5 | Clang->clearOutputFiles(false); |
275 | 5 | } |
276 | 5 | } |
277 | | |
278 | | // Our error handler depends on the Diagnostics object, which we're |
279 | | // potentially about to delete. Uninstall the handler now so that any |
280 | | // later errors use the default handling behavior instead. |
281 | 41.4k | llvm::remove_fatal_error_handler(); |
282 | | |
283 | | // When running with -disable-free, don't do any destruction or shutdown. |
284 | 41.4k | if (Clang->getFrontendOpts().DisableFree) { |
285 | 6.14k | llvm::BuryPointer(std::move(Clang)); |
286 | 6.14k | return !Success; |
287 | 6.14k | } |
288 | | |
289 | 35.3k | return !Success; |
290 | 41.4k | } |