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
17using namespace llvm;
18using namespace llvm::logicalview;
19
20#define DEBUG_TYPE "Options"
21
22//===----------------------------------------------------------------------===//
23// Options extracted from the command line.
24//===----------------------------------------------------------------------===//
25static LVOptions Options;
26LVOptions *LVOptions::getOptions() { return &Options; }
27void LVOptions::setOptions(LVOptions *CmdOptions) { Options = *CmdOptions; }
28
29void 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
258void 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.
283void 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//===----------------------------------------------------------------------===//
403LVPatterns *LVPatterns::getPatterns() {
404  static LVPatterns Patterns;
405  return &Patterns;
406}
407
408Error 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
439void LVPatterns::addGenericPatterns(StringSet<> &Patterns) {
440  addPatterns(Patterns, GenericMatchInfo);
441  if (GenericMatchInfo.size()) {
442    options().setSelectGenericPattern();
443    options().setSelectExecute();
444  }
445}
446
447void 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
456void 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
474void 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
490void 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.
506bool 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
533bool LVPatterns::printElement(const LVLine *Line) const {
534  return (options().getPrintLines() && Line->getIsLineDebug()) ||
535         (options().getPrintInstructions() && Line->getIsLineAssembler());
536}
537
538bool 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
548bool 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
562bool 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
569bool 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
576void LVPatterns::print(raw_ostream &OS) const {
577  OS << "LVPatterns\n";
578  LLVM_DEBUG(dbgs() << "Print Patterns\n");
579}
580