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;
getOptions()26 LVOptions *LVOptions::getOptions() { return &Options; }
setOptions(LVOptions * CmdOptions)27 void LVOptions::setOptions(LVOptions *CmdOptions) { Options = *CmdOptions; }
28 
resolveDependencies()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 
calculateIndentationSize()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(0);
269     IndentationSize += String.length();
270   }
271   if (getAttributeLevel()) {
272     std::stringstream Stream;
273     Stream.str(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.
print(raw_ostream & OS) const283 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 //===----------------------------------------------------------------------===//
getPatterns()403 LVPatterns *LVPatterns::getPatterns() {
404   static LVPatterns Patterns;
405   return &Patterns;
406 }
407 
createMatchEntry(LVMatchInfo & Filters,StringRef Pattern,bool IgnoreCase,bool UseRegex)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>(Pattern, IgnoreCase ? Regex::IgnoreCase
416                                                              : Regex::NoFlags);
417       std::string Error;
418       if (!Match.RE->isValid(Error))
419         return createStringError(errc::invalid_argument,
420                                  "Error in regular expression: %s",
421                                  Error.c_str());
422 
423       Match.Mode = LVMatchMode::Regex;
424       Filters.push_back(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(Match);
434   }
435 
436   return Error::success();
437 }
438 
addGenericPatterns(StringSet<> & Patterns)439 void LVPatterns::addGenericPatterns(StringSet<> &Patterns) {
440   addPatterns(Patterns, GenericMatchInfo);
441   if (GenericMatchInfo.size()) {
442     options().setSelectGenericPattern();
443     options().setSelectExecute();
444   }
445 }
446 
addOffsetPatterns(const LVOffsetSet & Patterns)447 void LVPatterns::addOffsetPatterns(const LVOffsetSet &Patterns) {
448   for (const LVOffset &Entry : Patterns)
449     OffsetMatchInfo.push_back(Entry);
450   if (OffsetMatchInfo.size()) {
451     options().setSelectOffsetPattern();
452     options().setSelectExecute();
453   }
454 }
455 
addPatterns(StringSet<> & Patterns,LVMatchInfo & Filters)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(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 
addElement(LVElement * Element)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(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 
updateReportOptions()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.
matchPattern(StringRef Input,const LVMatchInfo & MatchInfo)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.equals(Match.Pattern);
516       break;
517     case LVMatchMode::NoCase:
518       Matched = Input.equals_insensitive(Match.Pattern);
519       break;
520     case LVMatchMode::Regex:
521       Matched = Match.RE->match(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 
printElement(const LVLine * Line) const533 bool LVPatterns::printElement(const LVLine *Line) const {
534   return (options().getPrintLines() && Line->getIsLineDebug()) ||
535          (options().getPrintInstructions() && Line->getIsLineAssembler());
536 }
537 
printObject(const LVLocation * Location) const538 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 
printElement(const LVScope * Scope) const548 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 
printElement(const LVSymbol * Symbol) const562 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 
printElement(const LVType * Type) const569 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 
print(raw_ostream & OS) const576 void LVPatterns::print(raw_ostream &OS) const {
577   OS << "LVPatterns\n";
578   LLVM_DEBUG(dbgs() << "Print Patterns\n");
579 }
580