1 | //===-- LVOptions.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 | // This implements the LVOptions class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" |
14 | #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" |
15 | #include "llvm/Support/Errc.h" |
16 | |
17 | using namespace llvm; |
18 | using namespace llvm::logicalview; |
19 | |
20 | #define DEBUG_TYPE "Options" |
21 | |
22 | //===----------------------------------------------------------------------===// |
23 | // Options extracted from the command line. |
24 | //===----------------------------------------------------------------------===// |
25 | static LVOptions Options; |
26 | LVOptions *LVOptions::getOptions() { return &Options; } |
27 | void LVOptions::setOptions(LVOptions *CmdOptions) { Options = *CmdOptions; } |
28 | |
29 | void LVOptions::resolveDependencies() { |
30 | // Attributes that are classified as standard options. |
31 | auto StandardAttributes = [&]() { |
32 | // Set the 'standard' attribute to indicate its associated attributes. |
33 | setAttributeStandard(); |
34 | |
35 | setAttributeBase(); |
36 | setAttributeCoverage(); |
37 | setAttributeDirectories(); |
38 | setAttributeDiscriminator(); |
39 | setAttributeFilename(); |
40 | setAttributeFiles(); |
41 | setAttributeFormat(); |
42 | setAttributeLanguage(); |
43 | setAttributeLevel(); |
44 | setAttributeProducer(); |
45 | setAttributePublics(); |
46 | setAttributeRange(); |
47 | setAttributeReference(); |
48 | setAttributeZero(); |
49 | }; |
50 | |
51 | // Attributes that are classified as extended options. |
52 | auto ExtendedAttributes = [&]() { |
53 | // Set the 'extended' attribute to indicate its associated attributes. |
54 | setAttributeExtended(); |
55 | |
56 | setAttributeArgument(); |
57 | setAttributeDiscarded(); |
58 | setAttributeEncoded(); |
59 | setAttributeGaps(); |
60 | setAttributeGenerated(); |
61 | setAttributeGlobal(); |
62 | setAttributeInserted(); |
63 | setAttributeLinkage(); |
64 | setAttributeLocal(); |
65 | setAttributeLocation(); |
66 | setAttributeOffset(); |
67 | setAttributePathname(); |
68 | setAttributeQualified(); |
69 | setAttributeQualifier(); |
70 | setAttributeRegister(); |
71 | setAttributeSize(); |
72 | setAttributeSubrange(); |
73 | setAttributeSystem(); |
74 | setAttributeTypename(); |
75 | }; |
76 | |
77 | // '--Attribute=standard' settings. |
78 | if (getAttributeStandard()) |
79 | StandardAttributes(); |
80 | |
81 | // '--Attribute=extended' settings. |
82 | if (getAttributeExtended()) |
83 | ExtendedAttributes(); |
84 | |
85 | // '--Attribute=all' settings. |
86 | if (getAttributeAll()) { |
87 | StandardAttributes(); |
88 | ExtendedAttributes(); |
89 | } |
90 | |
91 | // '--attribute=pathname' supersedes '--attribute=filename'. |
92 | if (getAttributePathname()) |
93 | resetAttributeFilename(); |
94 | |
95 | // Assume '--output=text' as default |
96 | if (!getOutputText() && !getOutputJson()) |
97 | setOutputText(); |
98 | |
99 | // '--output=all' settings. |
100 | if (getOutputAll()) { |
101 | setOutputJson(); |
102 | setOutputSplit(); |
103 | setOutputText(); |
104 | } |
105 | |
106 | // A view split folder was specified. |
107 | if (getOutputFolder().length()) |
108 | setOutputSplit(); |
109 | |
110 | // Always use the full pathname with splitted output. |
111 | if (getOutputSplit()) |
112 | setAttributePathname(); |
113 | |
114 | // '--print=elements' settings. |
115 | if (getPrintElements()) { |
116 | setPrintInstructions(); |
117 | setPrintLines(); |
118 | setPrintScopes(); |
119 | setPrintSymbols(); |
120 | setPrintTypes(); |
121 | } |
122 | |
123 | // '--print=all' settings. |
124 | if (getPrintAll()) { |
125 | setPrintInstructions(); |
126 | setPrintLines(); |
127 | setPrintScopes(); |
128 | setPrintSizes(); |
129 | setPrintSymbols(); |
130 | setPrintSummary(); |
131 | setPrintTypes(); |
132 | setPrintWarnings(); |
133 | } |
134 | |
135 | // '--warning=all' settings. |
136 | if (getWarningAll()) { |
137 | setWarningCoverages(); |
138 | setWarningLines(); |
139 | setWarningLocations(); |
140 | setWarningRanges(); |
141 | } |
142 | |
143 | // '--internal=all' settings. |
144 | if (getInternalAll()) { |
145 | setInternalCmdline(); |
146 | setInternalID(); |
147 | setInternalIntegrity(); |
148 | setInternalNone(); |
149 | setInternalTag(); |
150 | } |
151 | |
152 | // '--compare=all' settings. |
153 | if (getCompareAll()) { |
154 | setCompareLines(); |
155 | setCompareScopes(); |
156 | setCompareSymbols(); |
157 | setCompareTypes(); |
158 | } |
159 | |
160 | // Compare the scopes if a request for compare symbols, types, lines. |
161 | if (getCompareLines() || getCompareSymbols() || getCompareTypes()) |
162 | setCompareScopes(); |
163 | |
164 | // Generic request for comparison. |
165 | if (getCompareScopes()) |
166 | setCompareExecute(); |
167 | |
168 | // Print any logical line (debug or instruction). |
169 | if (getPrintInstructions() || getPrintLines()) |
170 | setPrintAnyLine(); |
171 | |
172 | // Print any logical element (line, scope, symbol or type). |
173 | if (getPrintAnyLine() || getPrintScopes() || getPrintSymbols() || |
174 | getPrintTypes()) |
175 | setPrintAnyElement(); |
176 | |
177 | // Print 'sizes' or 'summary'. |
178 | if (getPrintSizes() && getPrintSummary()) |
179 | setPrintSizesSummary(); |
180 | |
181 | // Generic request for printing. |
182 | if (getPrintAll() || getPrintAnyElement() || getPrintSizesSummary() || |
183 | getPrintWarnings()) |
184 | setPrintExecute(); |
185 | |
186 | // '--reports=all' settings. |
187 | if (getReportAll()) { |
188 | setReportChildren(); |
189 | setReportList(); |
190 | setReportParents(); |
191 | setReportView(); |
192 | } |
193 | |
194 | // '--report=view' is a shortcut for '--report=parents,children'. |
195 | if (getReportView()) { |
196 | setReportChildren(); |
197 | setReportParents(); |
198 | } |
199 | |
200 | // The report will include: Parents or Children. |
201 | if (getReportParents() || getReportChildren() || getReportView()) |
202 | setReportAnyView(); |
203 | |
204 | // The report will include: List or Parents or Children. |
205 | if (getReportList() || getReportAnyView()) |
206 | setReportExecute(); |
207 | |
208 | // If a view or element comparison has been requested, the following options |
209 | // must be set, in order to get a correct compare: |
210 | // 1) Sort the CUs, to get a fast compare. |
211 | // 2) Encode template instantiations, so the names include template |
212 | // parameter information. |
213 | // 3) Include qualified types and their sizes. |
214 | // 4) Include any inserted abstract references. |
215 | // 5) For added/missing elements add the '+' or '-' tags. |
216 | if (getCompareExecute()) { |
217 | resetPrintExecute(); |
218 | setComparePrint(); |
219 | setSortMode(LVSortMode::Line); |
220 | setAttributeAdded(); |
221 | setAttributeArgument(); |
222 | setAttributeEncoded(); |
223 | setAttributeInserted(); |
224 | setAttributeMissing(); |
225 | setAttributeQualified(); |
226 | setAttributeSize(); |
227 | } |
228 | |
229 | // Enable formatting for printing (indentation, print children). |
230 | setPrintFormatting(); |
231 | |
232 | // These attributes are dependent on the capture of location information. |
233 | if (getAttributeCoverage() || getAttributeGaps() || getAttributeRegister()) |
234 | setAttributeLocation(); |
235 | |
236 | // Location information is only relevant when printing symbols. |
237 | if (!getPrintSymbols()) { |
238 | resetAttributeCoverage(); |
239 | resetAttributeGaps(); |
240 | resetAttributeLocation(); |
241 | resetAttributeRegister(); |
242 | } |
243 | |
244 | // Quick check for printing any element source information. |
245 | if (getAttributeFilename() || getAttributePathname()) |
246 | setAttributeAnySource(); |
247 | |
248 | // Quick check for printing any location information. |
249 | if (getAttributeLocation() || getAttributeRange()) |
250 | setAttributeAnyLocation(); |
251 | |
252 | if (getAttributeRange() || getPrintAnyLine()) |
253 | setGeneralCollectRanges(); |
254 | |
255 | calculateIndentationSize(); |
256 | |
257 | // Print collected command line options. |
258 | LLVM_DEBUG({ dump(); }); |
259 | } |
260 | |
261 | void LVOptions::calculateIndentationSize() { |
262 | if (getInternalID()) { |
263 | std::string String = hexSquareString(Value: 0); |
264 | IndentationSize += String.length(); |
265 | } |
266 | if (getCompareExecute() && (getAttributeAdded() || getAttributeMissing())) |
267 | ++IndentationSize; |
268 | if (getAttributeOffset()) { |
269 | std::string String = hexSquareString(Value: 0); |
270 | IndentationSize += String.length(); |
271 | } |
272 | if (getAttributeLevel()) { |
273 | std::stringstream Stream; |
274 | Stream.str(s: std::string()); |
275 | Stream << "[" << std::setfill('0') << std::setw(3) << 0 << "]" ; |
276 | IndentationSize += Stream.tellp(); |
277 | } |
278 | if (getAttributeGlobal()) |
279 | ++IndentationSize; |
280 | } |
281 | |
282 | // Print the current values for all the options, after the dependencies |
283 | // has been resolved. |
284 | void LVOptions::print(raw_ostream &OS) const { |
285 | // --attribute |
286 | OS << "** Attributes **\n" |
287 | << "All: " << getAttributeAll() << ", " |
288 | << "Argument: " << getAttributeArgument() << ", " |
289 | << "Base: " << getAttributeBase() << ", " |
290 | << "Coverage: " << getAttributeCoverage() << "\n" |
291 | << "Directories: " << getAttributeDirectories() << ", " |
292 | << "Discarded: " << getAttributeDiscarded() << ", " |
293 | << "Discriminator: " << getAttributeDiscriminator() << ", " |
294 | << "Encoded: " << getAttributeEncoded() << "\n" |
295 | << "Extended: " << getAttributeExtended() << ", " |
296 | << "Filename: " << getAttributeFilename() << ", " |
297 | << "Files: " << getAttributeFiles() << ", " |
298 | << "Format: " << getAttributeFormat() << "\n" |
299 | << "Gaps: " << getAttributeGaps() << ", " |
300 | << "Generated: " << getAttributeGenerated() << ", " |
301 | << "Global: " << getAttributeGlobal() << ", " |
302 | << "Inserted: " << getAttributeInserted() << "\n" |
303 | << "Level: " << getAttributeLevel() << ", " |
304 | << "Linkage: " << getAttributeLinkage() << ", " |
305 | << "Local: " << getAttributeLocal() << ", " |
306 | << "Location: " << getAttributeLocation() << "\n" |
307 | << "Offset: " << getAttributeOffset() << ", " |
308 | << "Pathname: " << getAttributePathname() << ", " |
309 | << "Producer: " << getAttributeProducer() << ", " |
310 | << "Publics: " << getAttributePublics() << "\n" |
311 | << "Qualified: " << getAttributeQualified() << ", " |
312 | << "Qualifier: " << getAttributeQualifier() << ", " |
313 | << "Range: " << getAttributeRange() << ", " |
314 | << "Reference: " << getAttributeReference() << "\n" |
315 | << "Register: " << getAttributeRegister() << ", " |
316 | << "Size: " << getAttributeSize() << ", " |
317 | << "Standard: " << getAttributeStandard() << ", " |
318 | << "Subrange: " << getAttributeSubrange() << "\n" |
319 | << "System: " << getAttributeSystem() << ", " |
320 | << "Typename: " << getAttributeTypename() << ", " |
321 | << "Underlying: " << getAttributeUnderlying() << ", " |
322 | << "Zero: " << getAttributeZero() << "\n" ; |
323 | OS << "Added: " << getAttributeAdded() << ", " |
324 | << "AnyLocation: " << getAttributeAnyLocation() << ", " |
325 | << "AnySource: " << getAttributeAnySource() << ", " |
326 | << "Missing: " << getAttributeMissing() << "\n" |
327 | << "\n" ; |
328 | |
329 | // --compare |
330 | OS << "** Compare **\n" |
331 | << "All: " << getCompareAll() << ", " |
332 | << "Lines: " << getCompareLines() << ", " |
333 | << "Scopes: " << getCompareScopes() << ", " |
334 | << "Symbols: " << getCompareSymbols() << ", " |
335 | << "Types: " << getCompareTypes() << "\n" ; |
336 | OS << "Context: " << getCompareContext() << ", " |
337 | << "Execute: " << getCompareExecute() << ", " |
338 | << "Print: " << getComparePrint() << "\n" |
339 | << "\n" ; |
340 | |
341 | // --print |
342 | OS << "** Print **\n" |
343 | << "All: " << getPrintAll() << ", " |
344 | << "Elements: " << getPrintElements() << ", " |
345 | << "Instructions: " << getPrintInstructions() << ", " |
346 | << "Lines: " << getPrintLines() << "\n" |
347 | << "Scopes: " << getPrintScopes() << ", " |
348 | << "Sizes: " << getPrintSizes() << ", " |
349 | << "Summary: " << getPrintSummary() << ", " |
350 | << "Symbols: " << getPrintSymbols() << "\n" |
351 | << "Types: " << getPrintTypes() << ", " |
352 | << "Warnings: " << getPrintWarnings() << "\n" ; |
353 | OS << "AnyElemeny: " << getPrintAnyElement() << ", " |
354 | << "AnyLine: " << getPrintAnyLine() << ", " |
355 | << "Execute: " << getPrintExecute() << ", " |
356 | << "Formatting: " << getPrintFormatting() << "\n" |
357 | << "Offset: " << getPrintOffset() << ", " |
358 | << "SizesSummary: " << getPrintSizesSummary() << "\n" |
359 | << "\n" ; |
360 | |
361 | // --report |
362 | OS << "** Report **\n" |
363 | << "All: " << getReportAll() << ", " |
364 | << "Children: " << getReportChildren() << ", " |
365 | << "List: " << getReportList() << ", " |
366 | << "Parents: " << getReportParents() << ", " |
367 | << "View: " << getReportView() << "\n" ; |
368 | OS << "AnyView: " << getReportAnyView() << ", " |
369 | << "Execute: " << getReportExecute() << "\n" |
370 | << "\n" ; |
371 | |
372 | // --select |
373 | OS << "** Select **\n" |
374 | << "IgnoreCase: " << getSelectIgnoreCase() << ", " |
375 | << "UseRegex: " << getSelectUseRegex() << ", " |
376 | << "Execute: " << getSelectExecute() << ", " |
377 | << "GenericKind: " << getSelectGenericKind() << "\n" |
378 | << "GenericPattern: " << getSelectGenericPattern() << ", " |
379 | << "OffsetPattern: " << getSelectOffsetPattern() << "\n" |
380 | << "\n" ; |
381 | |
382 | // --warning |
383 | OS << "** Warning **\n" |
384 | << "All: " << getWarningAll() << ", " |
385 | << "Coverage: " << getWarningCoverages() << ", " |
386 | << "Lines: " << getWarningLines() << ", " |
387 | << "Locations: " << getWarningLocations() << ", " |
388 | << "Ranges: " << getWarningRanges() << "\n" |
389 | << "\n" ; |
390 | |
391 | // --internal |
392 | OS << "** Internal **\n" |
393 | << "All: " << Options.getInternalAll() << ", " |
394 | << "Cmdline: " << Options.getInternalCmdline() << ", " |
395 | << "ID: " << Options.getInternalID() << ", " |
396 | << "Integrity: " << Options.getInternalIntegrity() << ", " |
397 | << "None: " << Options.getInternalNone() << "\n" |
398 | << "Tag: " << Options.getInternalTag() << "\n" |
399 | << "\n" ; |
400 | } |
401 | |
402 | //===----------------------------------------------------------------------===// |
403 | // Logical element selection using patterns. |
404 | //===----------------------------------------------------------------------===// |
405 | LVPatterns *LVPatterns::getPatterns() { |
406 | static LVPatterns Patterns; |
407 | return &Patterns; |
408 | } |
409 | |
410 | Error LVPatterns::createMatchEntry(LVMatchInfo &Filters, StringRef Pattern, |
411 | bool IgnoreCase, bool UseRegex) { |
412 | LVMatch Match; |
413 | // Process pattern as regular expression. |
414 | if (UseRegex) { |
415 | Match.Pattern = std::string(Pattern); |
416 | if (Pattern.size()) { |
417 | Match.RE = std::make_shared<Regex>(args&: Pattern, args: IgnoreCase ? Regex::IgnoreCase |
418 | : Regex::NoFlags); |
419 | std::string Error; |
420 | if (!Match.RE->isValid(Error)) |
421 | return createStringError(EC: errc::invalid_argument, |
422 | Fmt: "Error in regular expression: %s" , |
423 | Vals: Error.c_str()); |
424 | |
425 | Match.Mode = LVMatchMode::Regex; |
426 | Filters.push_back(x: Match); |
427 | return Error::success(); |
428 | } |
429 | } |
430 | |
431 | // Process pattern as an exact string match, depending on the case. |
432 | Match.Pattern = std::string(Pattern); |
433 | if (Match.Pattern.size()) { |
434 | Match.Mode = IgnoreCase ? LVMatchMode::NoCase : LVMatchMode::Match; |
435 | Filters.push_back(x: Match); |
436 | } |
437 | |
438 | return Error::success(); |
439 | } |
440 | |
441 | void LVPatterns::addGenericPatterns(StringSet<> &Patterns) { |
442 | addPatterns(Patterns, Filters&: GenericMatchInfo); |
443 | if (GenericMatchInfo.size()) { |
444 | options().setSelectGenericPattern(); |
445 | options().setSelectExecute(); |
446 | } |
447 | } |
448 | |
449 | void LVPatterns::addOffsetPatterns(const LVOffsetSet &Patterns) { |
450 | llvm::append_range(C&: OffsetMatchInfo, R: Patterns); |
451 | if (OffsetMatchInfo.size()) { |
452 | options().setSelectOffsetPattern(); |
453 | options().setSelectExecute(); |
454 | } |
455 | } |
456 | |
457 | void LVPatterns::addPatterns(StringSet<> &Patterns, LVMatchInfo &Filters) { |
458 | bool IgnoreCase = options().getSelectIgnoreCase(); |
459 | bool UseRegex = options().getSelectUseRegex(); |
460 | for (const StringSet<>::value_type &Entry : Patterns) { |
461 | StringRef Pattern = Entry.first(); |
462 | if (Error Err = createMatchEntry(Filters, Pattern, IgnoreCase, UseRegex)) |
463 | consumeError(Err: std::move(Err)); |
464 | } |
465 | |
466 | LLVM_DEBUG({ |
467 | dbgs() << "\nPattern Information:\n" ; |
468 | for (LVMatch &Match : Filters) |
469 | dbgs() << "Mode: " |
470 | << (Match.Mode == LVMatchMode::Match ? "Match" : "Regex" ) |
471 | << " Pattern: '" << Match.Pattern << "'\n" ; |
472 | }); |
473 | } |
474 | |
475 | void LVPatterns::addElement(LVElement *Element) { |
476 | // Mark any element that matches a given pattern. |
477 | Element->setIsMatched(); |
478 | options().setSelectExecute(); |
479 | if (options().getReportList()) |
480 | getReaderCompileUnit()->addMatched(Element); |
481 | if (options().getReportAnyView()) { |
482 | getReaderCompileUnit()->addMatched(Scope: Element->getIsScope() |
483 | ? static_cast<LVScope *>(Element) |
484 | : Element->getParentScope()); |
485 | // Mark element as matched. |
486 | if (!Element->getIsScope()) |
487 | Element->setHasPattern(); |
488 | } |
489 | } |
490 | |
491 | void LVPatterns::updateReportOptions() { |
492 | if (ElementRequest.size() || LineRequest.size() || ScopeRequest.size() || |
493 | SymbolRequest.size() || TypeRequest.size()) { |
494 | options().setSelectGenericKind(); |
495 | options().setSelectExecute(); |
496 | } |
497 | |
498 | // If we have selected requests and there are no specified report options, |
499 | // assume the 'details' option. |
500 | if (options().getSelectExecute() && !options().getReportExecute()) { |
501 | options().setReportExecute(); |
502 | options().setReportList(); |
503 | } |
504 | } |
505 | |
506 | // Match a general pattern. |
507 | bool LVPatterns::matchPattern(StringRef Input, const LVMatchInfo &MatchInfo) { |
508 | bool Matched = false; |
509 | // Do not match an empty 'Input'. |
510 | if (Input.empty()) |
511 | return Matched; |
512 | // Traverse all match specifications. |
513 | for (const LVMatch &Match : MatchInfo) { |
514 | switch (Match.Mode) { |
515 | case LVMatchMode::Match: |
516 | Matched = Input == Match.Pattern; |
517 | break; |
518 | case LVMatchMode::NoCase: |
519 | Matched = Input.equals_insensitive(RHS: Match.Pattern); |
520 | break; |
521 | case LVMatchMode::Regex: |
522 | Matched = Match.RE->match(String: Input); |
523 | break; |
524 | default: |
525 | break; |
526 | } |
527 | // Return if we have a match. |
528 | if (Matched) |
529 | return true; |
530 | } |
531 | return Matched; |
532 | } |
533 | |
534 | bool LVPatterns::printElement(const LVLine *Line) const { |
535 | return (options().getPrintLines() && Line->getIsLineDebug()) || |
536 | (options().getPrintInstructions() && Line->getIsLineAssembler()); |
537 | } |
538 | |
539 | bool LVPatterns::printObject(const LVLocation *Location) const { |
540 | if (options().getAttributeAll()) |
541 | return true; |
542 | bool DoPrint = options().getAttributeAnyLocation(); |
543 | // Consider the case of filler locations. |
544 | if (DoPrint && Location && Location->getIsGapEntry()) |
545 | DoPrint = options().getAttributeGaps(); |
546 | return DoPrint; |
547 | } |
548 | |
549 | bool LVPatterns::printElement(const LVScope *Scope) const { |
550 | // A scope will be printed depending on the following rules: |
551 | // - Request to print scopes. |
552 | // - Request to print any of its children. |
553 | // - If the scope is Root or CompileUnit: |
554 | // Request to print summary, sizes or warnings. |
555 | return options().getPrintScopes() || |
556 | (options().getPrintSymbols() && Scope->getHasSymbols()) || |
557 | (options().getPrintAnyLine() && Scope->getHasLines()) || |
558 | (options().getPrintTypes() && Scope->getHasTypes()) || |
559 | ((options().getPrintSizesSummary() || options().getPrintWarnings()) && |
560 | (Scope->getIsRoot() || Scope->getIsCompileUnit())); |
561 | } |
562 | |
563 | bool LVPatterns::printElement(const LVSymbol *Symbol) const { |
564 | // Print compiler generated symbols only if command line option. |
565 | if (Symbol->getIsArtificial()) |
566 | return options().getAttributeGenerated() && options().getPrintSymbols(); |
567 | return options().getPrintSymbols(); |
568 | } |
569 | |
570 | bool LVPatterns::printElement(const LVType *Type) const { |
571 | // Print array subranges only if print types is requested. |
572 | if (Type->getIsSubrange()) |
573 | return options().getAttributeSubrange() && options().getPrintTypes(); |
574 | return options().getPrintTypes(); |
575 | } |
576 | |
577 | void LVPatterns::print(raw_ostream &OS) const { |
578 | OS << "LVPatterns\n" ; |
579 | LLVM_DEBUG(dbgs() << "Print Patterns\n" ); |
580 | } |
581 | |