1//===- FormatUtil.cpp ----------------------------------------- *- C++ --*-===//
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#include "FormatUtil.h"
10#include "llvm/ADT/STLExtras.h"
11#include "llvm/ADT/StringExtras.h"
12#include "llvm/BinaryFormat/COFF.h"
13#include "llvm/DebugInfo/CodeView/CodeView.h"
14#include "llvm/Support/FormatAdapters.h"
15#include "llvm/Support/FormatVariadic.h"
16
17using namespace llvm;
18using namespace llvm::codeview;
19using namespace llvm::pdb;
20
21std::string llvm::pdb::truncateStringBack(StringRef S, uint32_t MaxLen) {
22  if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3)
23    return S;
24
25  assert(MaxLen >= 3);
26  uint32_t FinalLen = std::min<size_t>(S.size(), MaxLen - 3);
27  S = S.take_front(FinalLen);
28  return std::string(S) + std::string("...");
29}
30
31std::string llvm::pdb::truncateStringMiddle(StringRef S, uint32_t MaxLen) {
32  if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3)
33    return S;
34
35  assert(MaxLen >= 3);
36  uint32_t FinalLen = std::min<size_t>(S.size(), MaxLen - 3);
37  StringRef Front = S.take_front(FinalLen / 2);
38  StringRef Back = S.take_back(Front.size());
39  return std::string(Front) + std::string("...") + std::string(Back);
40}
41
42std::string llvm::pdb::truncateStringFront(StringRef S, uint32_t MaxLen) {
43  if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3)
44    return S;
45
46  assert(MaxLen >= 3);
47  S = S.take_back(MaxLen - 3);
48  return std::string("...") + std::string(S);
49}
50
51std::string llvm::pdb::truncateQuotedNameFront(StringRef Label, StringRef Name,
52                                               uint32_t MaxLen) {
53  uint32_t RequiredExtraChars = Label.size() + 1 + 2;
54  if (MaxLen == 0 || RequiredExtraChars + Name.size() <= MaxLen)
55    return formatv("{0} \"{1}\"", Label, Name).str();
56
57  assert(MaxLen >= RequiredExtraChars);
58  std::string TN = truncateStringFront(Name, MaxLen - RequiredExtraChars);
59  return formatv("{0} \"{1}\"", Label, TN).str();
60}
61
62std::string llvm::pdb::truncateQuotedNameBack(StringRef Label, StringRef Name,
63                                              uint32_t MaxLen) {
64  uint32_t RequiredExtraChars = Label.size() + 1 + 2;
65  if (MaxLen == 0 || RequiredExtraChars + Name.size() <= MaxLen)
66    return formatv("{0} \"{1}\"", Label, Name).str();
67
68  assert(MaxLen >= RequiredExtraChars);
69  std::string TN = truncateStringBack(Name, MaxLen - RequiredExtraChars);
70  return formatv("{0} \"{1}\"", Label, TN).str();
71}
72
73std::string llvm::pdb::typesetItemList(ArrayRef<std::string> Opts,
74                                       uint32_t IndentLevel, uint32_t GroupSize,
75                                       StringRef Sep) {
76  std::string Result;
77  while (!Opts.empty()) {
78    ArrayRef<std::string> ThisGroup;
79    ThisGroup = Opts.take_front(GroupSize);
80    Opts = Opts.drop_front(ThisGroup.size());
81    Result += join(ThisGroup, Sep);
82    if (!Opts.empty()) {
83      Result += Sep;
84      Result += "\n";
85      Result += formatv("{0}", fmt_repeat(' ', IndentLevel));
86    }
87  }
88  return Result;
89}
90
91std::string llvm::pdb::typesetStringList(uint32_t IndentLevel,
92                                         ArrayRef<StringRef> Strings) {
93  std::string Result = "[";
94  for (const auto &S : Strings) {
95    Result += formatv("\n{0}{1}", fmt_repeat(' ', IndentLevel), S);
96  }
97  Result += "]";
98  return Result;
99}
100
101std::string llvm::pdb::formatChunkKind(DebugSubsectionKind Kind,
102                                       bool Friendly) {
103  if (Friendly) {
104    switch (Kind) {
105      RETURN_CASE(DebugSubsectionKind, None, "none");
106      RETURN_CASE(DebugSubsectionKind, Symbols, "symbols");
107      RETURN_CASE(DebugSubsectionKind, Lines, "lines");
108      RETURN_CASE(DebugSubsectionKind, StringTable, "strings");
109      RETURN_CASE(DebugSubsectionKind, FileChecksums, "checksums");
110      RETURN_CASE(DebugSubsectionKind, FrameData, "frames");
111      RETURN_CASE(DebugSubsectionKind, InlineeLines, "inlinee lines");
112      RETURN_CASE(DebugSubsectionKind, CrossScopeImports, "xmi");
113      RETURN_CASE(DebugSubsectionKind, CrossScopeExports, "xme");
114      RETURN_CASE(DebugSubsectionKind, ILLines, "il lines");
115      RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap, "func md token map");
116      RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap, "type md token map");
117      RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput,
118                  "merged assembly input");
119      RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA, "coff symbol rva");
120    }
121  } else {
122    switch (Kind) {
123      RETURN_CASE(DebugSubsectionKind, None, "none");
124      RETURN_CASE(DebugSubsectionKind, Symbols, "DEBUG_S_SYMBOLS");
125      RETURN_CASE(DebugSubsectionKind, Lines, "DEBUG_S_LINES");
126      RETURN_CASE(DebugSubsectionKind, StringTable, "DEBUG_S_STRINGTABLE");
127      RETURN_CASE(DebugSubsectionKind, FileChecksums, "DEBUG_S_FILECHKSMS");
128      RETURN_CASE(DebugSubsectionKind, FrameData, "DEBUG_S_FRAMEDATA");
129      RETURN_CASE(DebugSubsectionKind, InlineeLines, "DEBUG_S_INLINEELINES");
130      RETURN_CASE(DebugSubsectionKind, CrossScopeImports,
131                  "DEBUG_S_CROSSSCOPEIMPORTS");
132      RETURN_CASE(DebugSubsectionKind, CrossScopeExports,
133                  "DEBUG_S_CROSSSCOPEEXPORTS");
134      RETURN_CASE(DebugSubsectionKind, ILLines, "DEBUG_S_IL_LINES");
135      RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap,
136                  "DEBUG_S_FUNC_MDTOKEN_MAP");
137      RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap,
138                  "DEBUG_S_TYPE_MDTOKEN_MAP");
139      RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput,
140                  "DEBUG_S_MERGED_ASSEMBLYINPUT");
141      RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA,
142                  "DEBUG_S_COFF_SYMBOL_RVA");
143    }
144  }
145  return formatUnknownEnum(Kind);
146}
147
148std::string llvm::pdb::formatSymbolKind(SymbolKind K) {
149  switch (uint32_t(K)) {
150#define SYMBOL_RECORD(EnumName, value, name)                                   \
151  case EnumName:                                                               \
152    return #EnumName;
153#define CV_SYMBOL(EnumName, value) SYMBOL_RECORD(EnumName, value, EnumName)
154#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
155  }
156  return formatUnknownEnum(K);
157}
158
159StringRef llvm::pdb::formatTypeLeafKind(TypeLeafKind K) {
160  switch (K) {
161#define TYPE_RECORD(EnumName, value, name)                                     \
162  case EnumName:                                                               \
163    return #EnumName;
164#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
165  default:
166    llvm_unreachable("Unknown type leaf kind!");
167  }
168  return "";
169}
170
171std::string llvm::pdb::formatSegmentOffset(uint16_t Segment, uint32_t Offset) {
172  return formatv("{0:4}:{1:4}", Segment, Offset);
173}
174
175#define PUSH_CHARACTERISTIC_FLAG(Enum, TheOpt, Value, Style, Descriptive)      \
176  PUSH_FLAG(Enum, TheOpt, Value,                                               \
177            ((Style == CharacteristicStyle::HeaderDefinition) ? #TheOpt        \
178                                                              : Descriptive))
179
180#define PUSH_MASKED_CHARACTERISTIC_FLAG(Enum, Mask, TheOpt, Value, Style,      \
181                                        Descriptive)                           \
182  PUSH_MASKED_FLAG(Enum, Mask, TheOpt, Value,                                  \
183                   ((Style == CharacteristicStyle::HeaderDefinition)           \
184                        ? #TheOpt                                              \
185                        : Descriptive))
186
187std::string llvm::pdb::formatSectionCharacteristics(uint32_t IndentLevel,
188                                                    uint32_t C,
189                                                    uint32_t FlagsPerLine,
190                                                    StringRef Separator,
191                                                    CharacteristicStyle Style) {
192  using SC = COFF::SectionCharacteristics;
193  std::vector<std::string> Opts;
194  if (C == COFF::SC_Invalid)
195    return "invalid";
196  if (C == 0)
197    return "none";
198  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, Style, "noload");
199  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, Style, "no padding");
200  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_CNT_CODE, C, Style, "code");
201  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C, Style,
202                           "initialized data");
203  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C, Style,
204                           "uninitialized data");
205  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, Style, "other");
206  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_INFO, C, Style, "info");
207  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, Style, "remove");
208  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, Style, "comdat");
209  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_GPREL, C, Style, "gp rel");
210  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, Style, "purgeable");
211  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, Style, "16-bit");
212  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, Style, "locked");
213  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, Style, "preload");
214  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C,
215                                  Style, "1 byte align");
216  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C,
217                                  Style, "2 byte align");
218  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C,
219                                  Style, "4 byte align");
220  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C,
221                                  Style, "8 byte align");
222  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C,
223                                  Style, "16 byte align");
224  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C,
225                                  Style, "32 byte align");
226  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C,
227                                  Style, "64 byte align");
228  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C,
229                                  Style, "128 byte align");
230  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C,
231                                  Style, "256 byte align");
232  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C,
233                                  Style, "512 byte align");
234  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C,
235                                  Style, "1024 byte align");
236  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C,
237                                  Style, "2048 byte align");
238  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C,
239                                  Style, "4096 byte align");
240  PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C,
241                                  Style, "8192 byte align");
242  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, Style,
243                           "noreloc overflow");
244  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, Style,
245                           "discardable");
246  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, Style,
247                           "not cached");
248  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, Style, "not paged");
249  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, Style, "shared");
250  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, Style,
251                           "execute permissions");
252  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_READ, C, Style,
253                           "read permissions");
254  PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, Style,
255                           "write permissions");
256  return typesetItemList(Opts, IndentLevel, FlagsPerLine, Separator);
257}
258