Coverage Report

Created: 2022-01-15 10:30

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- BreakpadRecords.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
#include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
10
#include "llvm/ADT/StringExtras.h"
11
#include "llvm/ADT/StringSwitch.h"
12
#include "llvm/Support/Endian.h"
13
#include "llvm/Support/FormatVariadic.h"
14
15
using namespace lldb_private;
16
using namespace lldb_private::breakpad;
17
18
namespace {
19
enum class Token {
20
  Unknown,
21
  Module,
22
  Info,
23
  CodeID,
24
  File,
25
  Func,
26
  Inline,
27
  InlineOrigin,
28
  Public,
29
  Stack,
30
  CFI,
31
  Init,
32
  Win,
33
};
34
}
35
36
template<typename T>
37
static T stringTo(llvm::StringRef Str);
38
39
286k
template <> Token stringTo<Token>(llvm::StringRef Str) {
40
286k
  return llvm::StringSwitch<Token>(Str)
41
286k
      .Case("MODULE", Token::Module)
42
286k
      .Case("INFO", Token::Info)
43
286k
      .Case("CODE_ID", Token::CodeID)
44
286k
      .Case("FILE", Token::File)
45
286k
      .Case("FUNC", Token::Func)
46
286k
      .Case("INLINE", Token::Inline)
47
286k
      .Case("INLINE_ORIGIN", Token::InlineOrigin)
48
286k
      .Case("PUBLIC", Token::Public)
49
286k
      .Case("STACK", Token::Stack)
50
286k
      .Case("CFI", Token::CFI)
51
286k
      .Case("INIT", Token::Init)
52
286k
      .Case("WIN", Token::Win)
53
286k
      .Default(Token::Unknown);
54
286k
}
55
56
template <>
57
56
llvm::Triple::OSType stringTo<llvm::Triple::OSType>(llvm::StringRef Str) {
58
56
  using llvm::Triple;
59
56
  return llvm::StringSwitch<Triple::OSType>(Str)
60
56
      .Case("Linux", Triple::Linux)
61
56
      .Case("mac", Triple::MacOSX)
62
56
      .Case("windows", Triple::Win32)
63
56
      .Default(Triple::UnknownOS);
64
56
}
65
66
template <>
67
55
llvm::Triple::ArchType stringTo<llvm::Triple::ArchType>(llvm::StringRef Str) {
68
55
  using llvm::Triple;
69
55
  return llvm::StringSwitch<Triple::ArchType>(Str)
70
55
      .Case("arm", Triple::arm)
71
55
      .Cases("arm64", "arm64e", Triple::aarch64)
72
55
      .Case("mips", Triple::mips)
73
55
      .Case("ppc", Triple::ppc)
74
55
      .Case("ppc64", Triple::ppc64)
75
55
      .Case("s390", Triple::systemz)
76
55
      .Case("sparc", Triple::sparc)
77
55
      .Case("sparcv9", Triple::sparcv9)
78
55
      .Case("x86", Triple::x86)
79
55
      .Cases("x86_64", "x86_64h", Triple::x86_64)
80
55
      .Default(Triple::UnknownArch);
81
55
}
82
83
template<typename T>
84
286k
static T consume(llvm::StringRef &Str) {
85
286k
  llvm::StringRef Token;
86
286k
  std::tie(Token, Str) = getToken(Str);
87
286k
  return stringTo<T>(Token);
88
286k
}
BreakpadRecords.cpp:(anonymous namespace)::Token consume<(anonymous namespace)::Token>(llvm::StringRef&)
Line
Count
Source
84
286k
static T consume(llvm::StringRef &Str) {
85
286k
  llvm::StringRef Token;
86
286k
  std::tie(Token, Str) = getToken(Str);
87
286k
  return stringTo<T>(Token);
88
286k
}
BreakpadRecords.cpp:llvm::Triple::OSType consume<llvm::Triple::OSType>(llvm::StringRef&)
Line
Count
Source
84
56
static T consume(llvm::StringRef &Str) {
85
56
  llvm::StringRef Token;
86
56
  std::tie(Token, Str) = getToken(Str);
87
56
  return stringTo<T>(Token);
88
56
}
BreakpadRecords.cpp:llvm::Triple::ArchType consume<llvm::Triple::ArchType>(llvm::StringRef&)
Line
Count
Source
84
55
static T consume(llvm::StringRef &Str) {
85
55
  llvm::StringRef Token;
86
55
  std::tie(Token, Str) = getToken(Str);
87
55
  return stringTo<T>(Token);
88
55
}
89
90
/// Return the number of hex digits needed to encode an (POD) object of a given
91
/// type.
92
203
template <typename T> static constexpr size_t hex_digits() {
93
203
  return 2 * sizeof(T);
94
203
}
BreakpadRecords.cpp:unsigned long hex_digits<unsigned char [16]>()
Line
Count
Source
92
152
template <typename T> static constexpr size_t hex_digits() {
93
152
  return 2 * sizeof(T);
94
152
}
BreakpadRecords.cpp:unsigned long hex_digits<parseModuleId(llvm::Triple::OSType, llvm::StringRef)::data_t>()
Line
Count
Source
92
51
template <typename T> static constexpr size_t hex_digits() {
93
51
  return 2 * sizeof(T);
94
51
}
95
96
54
static UUID parseModuleId(llvm::Triple::OSType os, llvm::StringRef str) {
97
54
  struct data_t {
98
54
    using uuid_t = uint8_t[16];
99
54
    uuid_t uuid;
100
54
    llvm::support::ubig32_t age;
101
54
  } data;
102
54
  static_assert(sizeof(data) == 20, "");
103
  // The textual module id encoding should be between 33 and 40 bytes long,
104
  // depending on the size of the age field, which is of variable length.
105
  // The first three chunks of the id are encoded in big endian, so we need to
106
  // byte-swap those.
107
54
  if (str.size() <= hex_digits<data_t::uuid_t>() ||
108
54
      
str.size() > hex_digits<data_t>()51
)
109
3
    return UUID();
110
51
  if (!all_of(str, llvm::isHexDigit))
111
2
    return UUID();
112
113
49
  llvm::StringRef uuid_str = str.take_front(hex_digits<data_t::uuid_t>());
114
49
  llvm::StringRef age_str = str.drop_front(hex_digits<data_t::uuid_t>());
115
116
49
  llvm::copy(fromHex(uuid_str), data.uuid);
117
49
  uint32_t age;
118
49
  bool success = to_integer(age_str, age, 16);
119
49
  assert(success);
120
0
  (void)success;
121
49
  data.age = age;
122
123
  // On non-windows, the age field should always be zero, so we don't include to
124
  // match the native uuid format of these platforms.
125
49
  return UUID::fromData(&data, os == llvm::Triple::Win32 ? 
sizeof(data)10
126
49
                                                         : 
sizeof(data.uuid)39
);
127
51
}
128
129
343
llvm::Optional<Record::Kind> Record::classify(llvm::StringRef Line) {
130
343
  Token Tok = consume<Token>(Line);
131
343
  switch (Tok) {
132
25
  case Token::Module:
133
25
    return Record::Module;
134
20
  case Token::Info:
135
20
    return Record::Info;
136
19
  case Token::File:
137
19
    return Record::File;
138
100
  case Token::Func:
139
100
    return Record::Func;
140
42
  case Token::Public:
141
42
    return Record::Public;
142
46
  case Token::Stack:
143
46
    Tok = consume<Token>(Line);
144
46
    switch (Tok) {
145
23
    case Token::CFI:
146
23
      return Record::StackCFI;
147
20
    case Token::Win:
148
20
      return Record::StackWin;
149
3
    default:
150
3
      return llvm::None;
151
46
    }
152
21
  case Token::Inline:
153
21
    return Record::Inline;
154
3
  case Token::InlineOrigin:
155
3
    return Record::InlineOrigin;
156
66
  case Token::Unknown:
157
    // Optimistically assume that any unrecognised token means this is a line
158
    // record, those don't have a special keyword and start directly with a
159
    // hex number.
160
66
    return Record::Line;
161
162
1
  case Token::CodeID:
163
1
  case Token::CFI:
164
1
  case Token::Init:
165
1
  case Token::Win:
166
    // These should never appear at the start of a valid record.
167
1
    return llvm::None;
168
343
  }
169
0
  llvm_unreachable("Fully covered switch above!");
170
0
}
171
172
285k
llvm::Optional<ModuleRecord> ModuleRecord::parse(llvm::StringRef Line) {
173
  // MODULE Linux x86_64 E5894855C35DCCCCCCCCCCCCCCCCCCCC0 a.out
174
285k
  if (consume<Token>(Line) != Token::Module)
175
285k
    return llvm::None;
176
177
56
  llvm::Triple::OSType OS = consume<llvm::Triple::OSType>(Line);
178
56
  if (OS == llvm::Triple::UnknownOS)
179
1
    return llvm::None;
180
181
55
  llvm::Triple::ArchType Arch = consume<llvm::Triple::ArchType>(Line);
182
55
  if (Arch == llvm::Triple::UnknownArch)
183
1
    return llvm::None;
184
185
54
  llvm::StringRef Str;
186
54
  std::tie(Str, Line) = getToken(Line);
187
54
  UUID ID = parseModuleId(OS, Str);
188
54
  if (!ID)
189
5
    return llvm::None;
190
191
49
  return ModuleRecord(OS, Arch, std::move(ID));
192
54
}
193
194
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
195
0
                                        const ModuleRecord &R) {
196
0
  return OS << "MODULE " << llvm::Triple::getOSTypeName(R.OS) << " "
197
0
            << llvm::Triple::getArchTypeName(R.Arch) << " "
198
0
            << R.ID.GetAsString();
199
0
}
200
201
52
llvm::Optional<InfoRecord> InfoRecord::parse(llvm::StringRef Line) {
202
  // INFO CODE_ID 554889E55DC3CCCCCCCCCCCCCCCCCCCC [a.exe]
203
52
  if (consume<Token>(Line) != Token::Info)
204
10
    return llvm::None;
205
206
42
  if (consume<Token>(Line) != Token::CodeID)
207
1
    return llvm::None;
208
209
41
  llvm::StringRef Str;
210
41
  std::tie(Str, Line) = getToken(Line);
211
  // If we don't have any text following the code ID (e.g. on linux), we should
212
  // use this as the UUID. Otherwise, we should revert back to the module ID.
213
41
  UUID ID;
214
41
  if (Line.trim().empty()) {
215
32
    if (Str.empty() || 
!ID.SetFromStringRef(Str)31
)
216
1
      return llvm::None;
217
32
  }
218
40
  return InfoRecord(std::move(ID));
219
41
}
220
221
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
222
0
                                        const InfoRecord &R) {
223
0
  return OS << "INFO CODE_ID " << R.ID.GetAsString();
224
0
}
225
226
template <typename T>
227
static llvm::Optional<T> parseNumberName(llvm::StringRef Line,
228
22
                                         Token TokenType) {
229
  // TOKEN number name
230
22
  if (consume<Token>(Line) != TokenType)
231
2
    return llvm::None;
232
233
20
  llvm::StringRef Str;
234
20
  size_t Number;
235
20
  std::tie(Str, Line) = getToken(Line);
236
20
  if (!to_integer(Str, Number))
237
2
    return llvm::None;
238
239
18
  llvm::StringRef Name = Line.trim();
240
18
  if (Name.empty())
241
2
    return llvm::None;
242
243
16
  return T(Number, Name);
244
18
}
BreakpadRecords.cpp:llvm::Optional<lldb_private::breakpad::FileRecord> parseNumberName<lldb_private::breakpad::FileRecord>(llvm::StringRef, (anonymous namespace)::Token)
Line
Count
Source
228
16
                                         Token TokenType) {
229
  // TOKEN number name
230
16
  if (consume<Token>(Line) != TokenType)
231
1
    return llvm::None;
232
233
15
  llvm::StringRef Str;
234
15
  size_t Number;
235
15
  std::tie(Str, Line) = getToken(Line);
236
15
  if (!to_integer(Str, Number))
237
1
    return llvm::None;
238
239
14
  llvm::StringRef Name = Line.trim();
240
14
  if (Name.empty())
241
1
    return llvm::None;
242
243
13
  return T(Number, Name);
244
14
}
BreakpadRecords.cpp:llvm::Optional<lldb_private::breakpad::InlineOriginRecord> parseNumberName<lldb_private::breakpad::InlineOriginRecord>(llvm::StringRef, (anonymous namespace)::Token)
Line
Count
Source
228
6
                                         Token TokenType) {
229
  // TOKEN number name
230
6
  if (consume<Token>(Line) != TokenType)
231
1
    return llvm::None;
232
233
5
  llvm::StringRef Str;
234
5
  size_t Number;
235
5
  std::tie(Str, Line) = getToken(Line);
236
5
  if (!to_integer(Str, Number))
237
1
    return llvm::None;
238
239
4
  llvm::StringRef Name = Line.trim();
240
4
  if (Name.empty())
241
1
    return llvm::None;
242
243
3
  return T(Number, Name);
244
4
}
245
246
16
llvm::Optional<FileRecord> FileRecord::parse(llvm::StringRef Line) {
247
  // FILE number name
248
16
  return parseNumberName<FileRecord>(Line, Token::File);
249
16
}
250
251
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
252
0
                                        const FileRecord &R) {
253
0
  return OS << "FILE " << R.Number << " " << R.Name;
254
0
}
255
256
llvm::Optional<InlineOriginRecord>
257
6
InlineOriginRecord::parse(llvm::StringRef Line) {
258
  // INLINE_ORIGIN number name
259
6
  return parseNumberName<InlineOriginRecord>(Line, Token::InlineOrigin);
260
6
}
261
262
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
263
0
                                        const InlineOriginRecord &R) {
264
0
  return OS << "INLINE_ORIGIN " << R.Number << " " << R.Name;
265
0
}
266
267
static bool parsePublicOrFunc(llvm::StringRef Line, bool &Multiple,
268
                              lldb::addr_t &Address, lldb::addr_t *Size,
269
115
                              lldb::addr_t &ParamSize, llvm::StringRef &Name) {
270
  // PUBLIC [m] address param_size name
271
  // or
272
  // FUNC [m] address size param_size name
273
274
115
  Token Tok = Size ? 
Token::Func75
:
Token::Public40
;
275
276
115
  if (consume<Token>(Line) != Tok)
277
28
    return false;
278
279
87
  llvm::StringRef Str;
280
87
  std::tie(Str, Line) = getToken(Line);
281
87
  Multiple = Str == "m";
282
283
87
  if (Multiple)
284
7
    std::tie(Str, Line) = getToken(Line);
285
87
  if (!to_integer(Str, Address, 16))
286
4
    return false;
287
288
83
  if (Tok == Token::Func) {
289
46
    std::tie(Str, Line) = getToken(Line);
290
46
    if (!to_integer(Str, *Size, 16))
291
1
      return false;
292
46
  }
293
294
82
  std::tie(Str, Line) = getToken(Line);
295
82
  if (!to_integer(Str, ParamSize, 16))
296
2
    return false;
297
298
80
  Name = Line.trim();
299
80
  if (Name.empty())
300
2
    return false;
301
302
78
  return true;
303
80
}
304
305
75
llvm::Optional<FuncRecord> FuncRecord::parse(llvm::StringRef Line) {
306
75
  bool Multiple;
307
75
  lldb::addr_t Address, Size, ParamSize;
308
75
  llvm::StringRef Name;
309
310
75
  if (parsePublicOrFunc(Line, Multiple, Address, &Size, ParamSize, Name))
311
43
    return FuncRecord(Multiple, Address, Size, ParamSize, Name);
312
313
32
  return llvm::None;
314
75
}
315
316
2
bool breakpad::operator==(const FuncRecord &L, const FuncRecord &R) {
317
2
  return L.Multiple == R.Multiple && L.Address == R.Address &&
318
2
         L.Size == R.Size && L.ParamSize == R.ParamSize && L.Name == R.Name;
319
2
}
320
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
321
0
                                        const FuncRecord &R) {
322
0
  return OS << llvm::formatv("FUNC {0}{1:x-} {2:x-} {3:x-} {4}",
323
0
                             R.Multiple ? "m " : "", R.Address, R.Size,
324
0
                             R.ParamSize, R.Name);
325
0
}
326
327
12
llvm::Optional<InlineRecord> InlineRecord::parse(llvm::StringRef Line) {
328
  // INLINE inline_nest_level call_site_line call_site_file_num origin_num
329
  // [address size]+
330
12
  if (consume<Token>(Line) != Token::Inline)
331
3
    return llvm::None;
332
333
9
  llvm::SmallVector<llvm::StringRef> Tokens;
334
9
  SplitString(Line, Tokens, " ");
335
9
  if (Tokens.size() < 6 || 
Tokens.size() % 2 == 18
)
336
2
    return llvm::None;
337
338
7
  size_t InlineNestLevel;
339
7
  uint32_t CallSiteLineNum;
340
7
  size_t CallSiteFileNum;
341
7
  size_t OriginNum;
342
7
  if (!(to_integer(Tokens[0], InlineNestLevel) &&
343
7
        to_integer(Tokens[1], CallSiteLineNum) &&
344
7
        to_integer(Tokens[2], CallSiteFileNum) &&
345
7
        to_integer(Tokens[3], OriginNum)))
346
0
    return llvm::None;
347
348
7
  InlineRecord Record = InlineRecord(InlineNestLevel, CallSiteLineNum,
349
7
                                     CallSiteFileNum, OriginNum);
350
16
  for (size_t i = 4; i < Tokens.size(); 
i += 29
) {
351
9
    lldb::addr_t Address;
352
9
    if (!to_integer(Tokens[i], Address, 16))
353
0
      return llvm::None;
354
9
    lldb::addr_t Size;
355
9
    if (!to_integer(Tokens[i + 1].trim(), Size, 16))
356
0
      return llvm::None;
357
9
    Record.Ranges.emplace_back(Address, Size);
358
9
  }
359
7
  return Record;
360
7
}
361
362
2
bool breakpad::operator==(const InlineRecord &L, const InlineRecord &R) {
363
2
  return L.InlineNestLevel == R.InlineNestLevel &&
364
2
         L.CallSiteLineNum == R.CallSiteLineNum &&
365
2
         L.CallSiteFileNum == R.CallSiteFileNum && L.OriginNum == R.OriginNum &&
366
2
         L.Ranges == R.Ranges;
367
2
}
368
369
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
370
0
                                        const InlineRecord &R) {
371
0
  OS << llvm::formatv("INLINE {0} {1} {2} {3}", R.InlineNestLevel,
372
0
                      R.CallSiteLineNum, R.CallSiteFileNum, R.OriginNum);
373
0
  for (const auto &range : R.Ranges) {
374
0
    OS << llvm::formatv(" {0:x-} {1:x-}", range.first, range.second);
375
0
  }
376
0
  return OS;
377
0
}
378
379
53
llvm::Optional<LineRecord> LineRecord::parse(llvm::StringRef Line) {
380
53
  lldb::addr_t Address;
381
53
  llvm::StringRef Str;
382
53
  std::tie(Str, Line) = getToken(Line);
383
53
  if (!to_integer(Str, Address, 16))
384
18
    return llvm::None;
385
386
35
  lldb::addr_t Size;
387
35
  std::tie(Str, Line) = getToken(Line);
388
35
  if (!to_integer(Str, Size, 16))
389
1
    return llvm::None;
390
391
34
  uint32_t LineNum;
392
34
  std::tie(Str, Line) = getToken(Line);
393
34
  if (!to_integer(Str, LineNum))
394
1
    return llvm::None;
395
396
33
  size_t FileNum;
397
33
  std::tie(Str, Line) = getToken(Line);
398
33
  if (!to_integer(Str, FileNum))
399
1
    return llvm::None;
400
401
32
  return LineRecord(Address, Size, LineNum, FileNum);
402
33
}
403
404
1
bool breakpad::operator==(const LineRecord &L, const LineRecord &R) {
405
1
  return L.Address == R.Address && L.Size == R.Size && L.LineNum == R.LineNum &&
406
1
         L.FileNum == R.FileNum;
407
1
}
408
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
409
0
                                        const LineRecord &R) {
410
0
  return OS << llvm::formatv("{0:x-} {1:x-} {2} {3}", R.Address, R.Size,
411
0
                             R.LineNum, R.FileNum);
412
0
}
413
414
40
llvm::Optional<PublicRecord> PublicRecord::parse(llvm::StringRef Line) {
415
40
  bool Multiple;
416
40
  lldb::addr_t Address, ParamSize;
417
40
  llvm::StringRef Name;
418
419
40
  if (parsePublicOrFunc(Line, Multiple, Address, nullptr, ParamSize, Name))
420
35
    return PublicRecord(Multiple, Address, ParamSize, Name);
421
422
5
  return llvm::None;
423
40
}
424
425
2
bool breakpad::operator==(const PublicRecord &L, const PublicRecord &R) {
426
2
  return L.Multiple == R.Multiple && L.Address == R.Address &&
427
2
         L.ParamSize == R.ParamSize && L.Name == R.Name;
428
2
}
429
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
430
0
                                        const PublicRecord &R) {
431
0
  return OS << llvm::formatv("PUBLIC {0}{1:x-} {2:x-} {3}",
432
0
                             R.Multiple ? "m " : "", R.Address, R.ParamSize,
433
0
                             R.Name);
434
0
}
435
436
40
llvm::Optional<StackCFIRecord> StackCFIRecord::parse(llvm::StringRef Line) {
437
  // STACK CFI INIT address size reg1: expr1 reg2: expr2 ...
438
  // or
439
  // STACK CFI address reg1: expr1 reg2: expr2 ...
440
  // No token in exprN ends with a colon.
441
442
40
  if (consume<Token>(Line) != Token::Stack)
443
4
    return llvm::None;
444
36
  if (consume<Token>(Line) != Token::CFI)
445
1
    return llvm::None;
446
447
35
  llvm::StringRef Str;
448
35
  std::tie(Str, Line) = getToken(Line);
449
450
35
  bool IsInitRecord = stringTo<Token>(Str) == Token::Init;
451
35
  if (IsInitRecord)
452
27
    std::tie(Str, Line) = getToken(Line);
453
454
35
  lldb::addr_t Address;
455
35
  if (!to_integer(Str, Address, 16))
456
4
    return llvm::None;
457
458
31
  llvm::Optional<lldb::addr_t> Size;
459
31
  if (IsInitRecord) {
460
26
    Size.emplace();
461
26
    std::tie(Str, Line) = getToken(Line);
462
26
    if (!to_integer(Str, *Size, 16))
463
1
      return llvm::None;
464
26
  }
465
466
30
  return StackCFIRecord(Address, Size, Line.trim());
467
31
}
468
469
4
bool breakpad::operator==(const StackCFIRecord &L, const StackCFIRecord &R) {
470
4
  return L.Address == R.Address && L.Size == R.Size &&
471
4
         L.UnwindRules == R.UnwindRules;
472
4
}
473
474
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
475
0
                                        const StackCFIRecord &R) {
476
0
  OS << "STACK CFI ";
477
0
  if (R.Size)
478
0
    OS << "INIT ";
479
0
  OS << llvm::formatv("{0:x-} ", R.Address);
480
0
  if (R.Size)
481
0
    OS << llvm::formatv("{0:x-} ", *R.Size);
482
0
  return OS << " " << R.UnwindRules;
483
0
}
484
485
63
llvm::Optional<StackWinRecord> StackWinRecord::parse(llvm::StringRef Line) {
486
  // STACK WIN type rva code_size prologue_size epilogue_size parameter_size
487
  //     saved_register_size local_size max_stack_size has_program_string
488
  //     program_string_OR_allocates_base_pointer
489
490
63
  if (consume<Token>(Line) != Token::Stack)
491
1
    return llvm::None;
492
62
  if (consume<Token>(Line) != Token::Win)
493
1
    return llvm::None;
494
495
61
  llvm::StringRef Str;
496
61
  uint8_t Type;
497
61
  std::tie(Str, Line) = getToken(Line);
498
  // Right now we only support the "FrameData" frame type.
499
61
  if (!to_integer(Str, Type) || 
FrameType(Type) != FrameType::FrameData60
)
500
4
    return llvm::None;
501
502
57
  lldb::addr_t RVA;
503
57
  std::tie(Str, Line) = getToken(Line);
504
57
  if (!to_integer(Str, RVA, 16))
505
1
    return llvm::None;
506
507
56
  lldb::addr_t CodeSize;
508
56
  std::tie(Str, Line) = getToken(Line);
509
56
  if (!to_integer(Str, CodeSize, 16))
510
1
    return llvm::None;
511
512
  // Skip fields which we aren't using right now.
513
55
  std::tie(Str, Line) = getToken(Line); // prologue_size
514
55
  std::tie(Str, Line) = getToken(Line); // epilogue_size
515
516
55
  lldb::addr_t ParameterSize;
517
55
  std::tie(Str, Line) = getToken(Line);
518
55
  if (!to_integer(Str, ParameterSize, 16))
519
3
    return llvm::None;
520
521
52
  lldb::addr_t SavedRegisterSize;
522
52
  std::tie(Str, Line) = getToken(Line);
523
52
  if (!to_integer(Str, SavedRegisterSize, 16))
524
1
    return llvm::None;
525
526
51
  lldb::addr_t LocalSize;
527
51
  std::tie(Str, Line) = getToken(Line);
528
51
  if (!to_integer(Str, LocalSize, 16))
529
1
    return llvm::None;
530
531
50
  std::tie(Str, Line) = getToken(Line); // max_stack_size
532
533
50
  uint8_t HasProgramString;
534
50
  std::tie(Str, Line) = getToken(Line);
535
50
  if (!to_integer(Str, HasProgramString))
536
3
    return llvm::None;
537
  // FrameData records should always have a program string.
538
47
  if (!HasProgramString)
539
1
    return llvm::None;
540
541
46
  return StackWinRecord(RVA, CodeSize, ParameterSize, SavedRegisterSize,
542
46
                        LocalSize, Line.trim());
543
47
}
544
545
1
bool breakpad::operator==(const StackWinRecord &L, const StackWinRecord &R) {
546
1
  return L.RVA == R.RVA && L.CodeSize == R.CodeSize &&
547
1
         L.ParameterSize == R.ParameterSize &&
548
1
         L.SavedRegisterSize == R.SavedRegisterSize &&
549
1
         L.LocalSize == R.LocalSize && L.ProgramString == R.ProgramString;
550
1
}
551
552
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
553
0
                                        const StackWinRecord &R) {
554
0
  return OS << llvm::formatv(
555
0
             "STACK WIN 4 {0:x-} {1:x-} ? ? {2} {3} {4} ? 1 {5}", R.RVA,
556
0
             R.CodeSize, R.ParameterSize, R.SavedRegisterSize, R.LocalSize,
557
0
             R.ProgramString);
558
0
}
559
560
248
llvm::StringRef breakpad::toString(Record::Kind K) {
561
248
  switch (K) {
562
24
  case Record::Module:
563
24
    return "MODULE";
564
19
  case Record::Info:
565
19
    return "INFO";
566
23
  case Record::File:
567
23
    return "FILE";
568
90
  case Record::Func:
569
90
    return "FUNC";
570
0
  case Record::Inline:
571
0
    return "INLINE";
572
6
  case Record::InlineOrigin:
573
6
    return "INLINE_ORIGIN";
574
0
  case Record::Line:
575
0
    return "LINE";
576
28
  case Record::Public:
577
28
    return "PUBLIC";
578
23
  case Record::StackCFI:
579
23
    return "STACK CFI";
580
35
  case Record::StackWin:
581
35
    return "STACK WIN";
582
248
  }
583
0
  llvm_unreachable("Unknown record kind!");
584
0
}