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