180814287SRaphael Isemann //===-- BreakpadRecords.cpp -----------------------------------------------===//
22cf5486cSPavel Labath //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62cf5486cSPavel Labath //
72cf5486cSPavel Labath //===----------------------------------------------------------------------===//
82cf5486cSPavel Labath 
92cf5486cSPavel Labath #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
102cf5486cSPavel Labath #include "llvm/ADT/StringExtras.h"
112cf5486cSPavel Labath #include "llvm/ADT/StringSwitch.h"
122cf5486cSPavel Labath #include "llvm/Support/Endian.h"
132cf5486cSPavel Labath #include "llvm/Support/FormatVariadic.h"
142cf5486cSPavel Labath 
152cf5486cSPavel Labath using namespace lldb_private;
162cf5486cSPavel Labath using namespace lldb_private::breakpad;
172cf5486cSPavel Labath 
182cf5486cSPavel Labath namespace {
190a9f47d7SPavel Labath enum class Token {
200a9f47d7SPavel Labath   Unknown,
210a9f47d7SPavel Labath   Module,
220a9f47d7SPavel Labath   Info,
230a9f47d7SPavel Labath   CodeID,
240a9f47d7SPavel Labath   File,
250a9f47d7SPavel Labath   Func,
26*cc9ced0eSZequan Wu   Inline,
27*cc9ced0eSZequan Wu   InlineOrigin,
280a9f47d7SPavel Labath   Public,
290a9f47d7SPavel Labath   Stack,
300a9f47d7SPavel Labath   CFI,
310a9f47d7SPavel Labath   Init,
320a9f47d7SPavel Labath   Win,
330a9f47d7SPavel Labath };
342cf5486cSPavel Labath }
352cf5486cSPavel Labath 
36dfaafbcfSPavel Labath template<typename T>
37dfaafbcfSPavel Labath static T stringTo(llvm::StringRef Str);
38dfaafbcfSPavel Labath 
stringTo(llvm::StringRef Str)39dfaafbcfSPavel Labath template <> Token stringTo<Token>(llvm::StringRef Str) {
40dfaafbcfSPavel Labath   return llvm::StringSwitch<Token>(Str)
412cf5486cSPavel Labath       .Case("MODULE", Token::Module)
422cf5486cSPavel Labath       .Case("INFO", Token::Info)
432cf5486cSPavel Labath       .Case("CODE_ID", Token::CodeID)
442cf5486cSPavel Labath       .Case("FILE", Token::File)
452cf5486cSPavel Labath       .Case("FUNC", Token::Func)
46*cc9ced0eSZequan Wu       .Case("INLINE", Token::Inline)
47*cc9ced0eSZequan Wu       .Case("INLINE_ORIGIN", Token::InlineOrigin)
482cf5486cSPavel Labath       .Case("PUBLIC", Token::Public)
492cf5486cSPavel Labath       .Case("STACK", Token::Stack)
50dfaafbcfSPavel Labath       .Case("CFI", Token::CFI)
51dfaafbcfSPavel Labath       .Case("INIT", Token::Init)
520a9f47d7SPavel Labath       .Case("WIN", Token::Win)
532cf5486cSPavel Labath       .Default(Token::Unknown);
542cf5486cSPavel Labath }
552cf5486cSPavel Labath 
56dfaafbcfSPavel Labath template <>
stringTo(llvm::StringRef Str)57dfaafbcfSPavel Labath llvm::Triple::OSType stringTo<llvm::Triple::OSType>(llvm::StringRef Str) {
582cf5486cSPavel Labath   using llvm::Triple;
59dfaafbcfSPavel Labath   return llvm::StringSwitch<Triple::OSType>(Str)
602cf5486cSPavel Labath       .Case("Linux", Triple::Linux)
612cf5486cSPavel Labath       .Case("mac", Triple::MacOSX)
622cf5486cSPavel Labath       .Case("windows", Triple::Win32)
632cf5486cSPavel Labath       .Default(Triple::UnknownOS);
642cf5486cSPavel Labath }
652cf5486cSPavel Labath 
66dfaafbcfSPavel Labath template <>
stringTo(llvm::StringRef Str)67dfaafbcfSPavel Labath llvm::Triple::ArchType stringTo<llvm::Triple::ArchType>(llvm::StringRef Str) {
682cf5486cSPavel Labath   using llvm::Triple;
69dfaafbcfSPavel Labath   return llvm::StringSwitch<Triple::ArchType>(Str)
702cf5486cSPavel Labath       .Case("arm", Triple::arm)
715e173dc5SPavel Labath       .Cases("arm64", "arm64e", Triple::aarch64)
722cf5486cSPavel Labath       .Case("mips", Triple::mips)
732cf5486cSPavel Labath       .Case("ppc", Triple::ppc)
742cf5486cSPavel Labath       .Case("ppc64", Triple::ppc64)
752cf5486cSPavel Labath       .Case("s390", Triple::systemz)
762cf5486cSPavel Labath       .Case("sparc", Triple::sparc)
772cf5486cSPavel Labath       .Case("sparcv9", Triple::sparcv9)
782cf5486cSPavel Labath       .Case("x86", Triple::x86)
79f71e35dcSPavel Labath       .Cases("x86_64", "x86_64h", Triple::x86_64)
802cf5486cSPavel Labath       .Default(Triple::UnknownArch);
812cf5486cSPavel Labath }
822cf5486cSPavel Labath 
83dfaafbcfSPavel Labath template<typename T>
consume(llvm::StringRef & Str)84dfaafbcfSPavel Labath static T consume(llvm::StringRef &Str) {
85dfaafbcfSPavel Labath   llvm::StringRef Token;
86dfaafbcfSPavel Labath   std::tie(Token, Str) = getToken(Str);
87dfaafbcfSPavel Labath   return stringTo<T>(Token);
88dfaafbcfSPavel Labath }
89dfaafbcfSPavel Labath 
905b18ddb6SPavel Labath /// Return the number of hex digits needed to encode an (POD) object of a given
915b18ddb6SPavel Labath /// type.
hex_digits()925b18ddb6SPavel Labath template <typename T> static constexpr size_t hex_digits() {
935b18ddb6SPavel Labath   return 2 * sizeof(T);
945b18ddb6SPavel Labath }
955b18ddb6SPavel Labath 
parseModuleId(llvm::Triple::OSType os,llvm::StringRef str)962cf5486cSPavel Labath static UUID parseModuleId(llvm::Triple::OSType os, llvm::StringRef str) {
975b18ddb6SPavel Labath   struct data_t {
98025b9d0fSPavel Labath     using uuid_t = uint8_t[16];
99025b9d0fSPavel Labath     uuid_t uuid;
100025b9d0fSPavel Labath     llvm::support::ubig32_t age;
1012cf5486cSPavel Labath   } data;
1022cf5486cSPavel Labath   static_assert(sizeof(data) == 20, "");
1032cf5486cSPavel Labath   // The textual module id encoding should be between 33 and 40 bytes long,
1042cf5486cSPavel Labath   // depending on the size of the age field, which is of variable length.
1052cf5486cSPavel Labath   // The first three chunks of the id are encoded in big endian, so we need to
1062cf5486cSPavel Labath   // byte-swap those.
1075b18ddb6SPavel Labath   if (str.size() <= hex_digits<data_t::uuid_t>() ||
1085b18ddb6SPavel Labath       str.size() > hex_digits<data_t>())
1092cf5486cSPavel Labath     return UUID();
110025b9d0fSPavel Labath   if (!all_of(str, llvm::isHexDigit))
1112cf5486cSPavel Labath     return UUID();
112025b9d0fSPavel Labath 
113025b9d0fSPavel Labath   llvm::StringRef uuid_str = str.take_front(hex_digits<data_t::uuid_t>());
114025b9d0fSPavel Labath   llvm::StringRef age_str = str.drop_front(hex_digits<data_t::uuid_t>());
115025b9d0fSPavel Labath 
116025b9d0fSPavel Labath   llvm::copy(fromHex(uuid_str), data.uuid);
1175b18ddb6SPavel Labath   uint32_t age;
118025b9d0fSPavel Labath   bool success = to_integer(age_str, age, 16);
119025b9d0fSPavel Labath   assert(success);
120025b9d0fSPavel Labath   (void)success;
1215b18ddb6SPavel Labath   data.age = age;
1222cf5486cSPavel Labath 
1232cf5486cSPavel Labath   // On non-windows, the age field should always be zero, so we don't include to
1242cf5486cSPavel Labath   // match the native uuid format of these platforms.
1255b18ddb6SPavel Labath   return UUID::fromData(&data, os == llvm::Triple::Win32 ? sizeof(data)
1265b18ddb6SPavel Labath                                                          : sizeof(data.uuid));
1272cf5486cSPavel Labath }
1282cf5486cSPavel Labath 
classify(llvm::StringRef Line)129dfaafbcfSPavel Labath llvm::Optional<Record::Kind> Record::classify(llvm::StringRef Line) {
130dfaafbcfSPavel Labath   Token Tok = consume<Token>(Line);
1312cf5486cSPavel Labath   switch (Tok) {
1322cf5486cSPavel Labath   case Token::Module:
1332cf5486cSPavel Labath     return Record::Module;
1342cf5486cSPavel Labath   case Token::Info:
1352cf5486cSPavel Labath     return Record::Info;
1362cf5486cSPavel Labath   case Token::File:
1372cf5486cSPavel Labath     return Record::File;
1382cf5486cSPavel Labath   case Token::Func:
1392cf5486cSPavel Labath     return Record::Func;
1402cf5486cSPavel Labath   case Token::Public:
1412cf5486cSPavel Labath     return Record::Public;
1422cf5486cSPavel Labath   case Token::Stack:
143dfaafbcfSPavel Labath     Tok = consume<Token>(Line);
144dfaafbcfSPavel Labath     switch (Tok) {
145dfaafbcfSPavel Labath     case Token::CFI:
1469837f548SPavel Labath       return Record::StackCFI;
1470a9f47d7SPavel Labath     case Token::Win:
1480a9f47d7SPavel Labath       return Record::StackWin;
149dfaafbcfSPavel Labath     default:
150dfaafbcfSPavel Labath       return llvm::None;
151dfaafbcfSPavel Labath     }
152*cc9ced0eSZequan Wu   case Token::Inline:
153*cc9ced0eSZequan Wu     return Record::Inline;
154*cc9ced0eSZequan Wu   case Token::InlineOrigin:
155*cc9ced0eSZequan Wu     return Record::InlineOrigin;
1562cf5486cSPavel Labath   case Token::Unknown:
1572cf5486cSPavel Labath     // Optimistically assume that any unrecognised token means this is a line
1582cf5486cSPavel Labath     // record, those don't have a special keyword and start directly with a
1590a9f47d7SPavel Labath     // hex number.
1602cf5486cSPavel Labath     return Record::Line;
161dfaafbcfSPavel Labath 
162dfaafbcfSPavel Labath   case Token::CodeID:
163dfaafbcfSPavel Labath   case Token::CFI:
164dfaafbcfSPavel Labath   case Token::Init:
1650a9f47d7SPavel Labath   case Token::Win:
166dfaafbcfSPavel Labath     // These should never appear at the start of a valid record.
167dfaafbcfSPavel Labath     return llvm::None;
1682cf5486cSPavel Labath   }
1692cf5486cSPavel Labath   llvm_unreachable("Fully covered switch above!");
1702cf5486cSPavel Labath }
1712cf5486cSPavel Labath 
parse(llvm::StringRef Line)1722cf5486cSPavel Labath llvm::Optional<ModuleRecord> ModuleRecord::parse(llvm::StringRef Line) {
1732cf5486cSPavel Labath   // MODULE Linux x86_64 E5894855C35DCCCCCCCCCCCCCCCCCCCC0 a.out
174dfaafbcfSPavel Labath   if (consume<Token>(Line) != Token::Module)
1752cf5486cSPavel Labath     return llvm::None;
1762cf5486cSPavel Labath 
177dfaafbcfSPavel Labath   llvm::Triple::OSType OS = consume<llvm::Triple::OSType>(Line);
1782cf5486cSPavel Labath   if (OS == llvm::Triple::UnknownOS)
1792cf5486cSPavel Labath     return llvm::None;
1802cf5486cSPavel Labath 
181dfaafbcfSPavel Labath   llvm::Triple::ArchType Arch = consume<llvm::Triple::ArchType>(Line);
1822cf5486cSPavel Labath   if (Arch == llvm::Triple::UnknownArch)
1832cf5486cSPavel Labath     return llvm::None;
1842cf5486cSPavel Labath 
185dfaafbcfSPavel Labath   llvm::StringRef Str;
1862cf5486cSPavel Labath   std::tie(Str, Line) = getToken(Line);
1872cf5486cSPavel Labath   UUID ID = parseModuleId(OS, Str);
1882cf5486cSPavel Labath   if (!ID)
1892cf5486cSPavel Labath     return llvm::None;
1902cf5486cSPavel Labath 
1912cf5486cSPavel Labath   return ModuleRecord(OS, Arch, std::move(ID));
1922cf5486cSPavel Labath }
1932cf5486cSPavel Labath 
operator <<(llvm::raw_ostream & OS,const ModuleRecord & R)1942cf5486cSPavel Labath llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
1952cf5486cSPavel Labath                                         const ModuleRecord &R) {
1965b18ddb6SPavel Labath   return OS << "MODULE " << llvm::Triple::getOSTypeName(R.OS) << " "
1975b18ddb6SPavel Labath             << llvm::Triple::getArchTypeName(R.Arch) << " "
1985b18ddb6SPavel Labath             << R.ID.GetAsString();
1992cf5486cSPavel Labath }
2002cf5486cSPavel Labath 
parse(llvm::StringRef Line)2012cf5486cSPavel Labath llvm::Optional<InfoRecord> InfoRecord::parse(llvm::StringRef Line) {
2022cf5486cSPavel Labath   // INFO CODE_ID 554889E55DC3CCCCCCCCCCCCCCCCCCCC [a.exe]
203dfaafbcfSPavel Labath   if (consume<Token>(Line) != Token::Info)
204dfaafbcfSPavel Labath     return llvm::None;
205dfaafbcfSPavel Labath 
206dfaafbcfSPavel Labath   if (consume<Token>(Line) != Token::CodeID)
207dfaafbcfSPavel Labath     return llvm::None;
208dfaafbcfSPavel Labath 
2092cf5486cSPavel Labath   llvm::StringRef Str;
2102cf5486cSPavel Labath   std::tie(Str, Line) = getToken(Line);
2112cf5486cSPavel Labath   // If we don't have any text following the code ID (e.g. on linux), we should
2122cf5486cSPavel Labath   // use this as the UUID. Otherwise, we should revert back to the module ID.
2132cf5486cSPavel Labath   UUID ID;
2142cf5486cSPavel Labath   if (Line.trim().empty()) {
2151beffc18SJaroslav Sevcik     if (Str.empty() || !ID.SetFromStringRef(Str))
2162cf5486cSPavel Labath       return llvm::None;
2172cf5486cSPavel Labath   }
2182cf5486cSPavel Labath   return InfoRecord(std::move(ID));
2192cf5486cSPavel Labath }
2202cf5486cSPavel Labath 
operator <<(llvm::raw_ostream & OS,const InfoRecord & R)2212cf5486cSPavel Labath llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
2222cf5486cSPavel Labath                                         const InfoRecord &R) {
2235b18ddb6SPavel Labath   return OS << "INFO CODE_ID " << R.ID.GetAsString();
2242cf5486cSPavel Labath }
2252cf5486cSPavel Labath 
226*cc9ced0eSZequan Wu template <typename T>
parseNumberName(llvm::StringRef Line,Token TokenType)227*cc9ced0eSZequan Wu static llvm::Optional<T> parseNumberName(llvm::StringRef Line,
228*cc9ced0eSZequan Wu                                          Token TokenType) {
229*cc9ced0eSZequan Wu   // TOKEN number name
230*cc9ced0eSZequan Wu   if (consume<Token>(Line) != TokenType)
231b1f28579SPavel Labath     return llvm::None;
232b1f28579SPavel Labath 
233dfaafbcfSPavel Labath   llvm::StringRef Str;
234b1f28579SPavel Labath   size_t Number;
235b1f28579SPavel Labath   std::tie(Str, Line) = getToken(Line);
236b1f28579SPavel Labath   if (!to_integer(Str, Number))
237b1f28579SPavel Labath     return llvm::None;
238b1f28579SPavel Labath 
239b1f28579SPavel Labath   llvm::StringRef Name = Line.trim();
240b1f28579SPavel Labath   if (Name.empty())
241b1f28579SPavel Labath     return llvm::None;
242b1f28579SPavel Labath 
243*cc9ced0eSZequan Wu   return T(Number, Name);
244*cc9ced0eSZequan Wu }
245*cc9ced0eSZequan Wu 
parse(llvm::StringRef Line)246*cc9ced0eSZequan Wu llvm::Optional<FileRecord> FileRecord::parse(llvm::StringRef Line) {
247*cc9ced0eSZequan Wu   // FILE number name
248*cc9ced0eSZequan Wu   return parseNumberName<FileRecord>(Line, Token::File);
249b1f28579SPavel Labath }
250b1f28579SPavel Labath 
operator <<(llvm::raw_ostream & OS,const FileRecord & R)251b1f28579SPavel Labath llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
252b1f28579SPavel Labath                                         const FileRecord &R) {
253b1f28579SPavel Labath   return OS << "FILE " << R.Number << " " << R.Name;
254b1f28579SPavel Labath }
255b1f28579SPavel Labath 
256*cc9ced0eSZequan Wu llvm::Optional<InlineOriginRecord>
parse(llvm::StringRef Line)257*cc9ced0eSZequan Wu InlineOriginRecord::parse(llvm::StringRef Line) {
258*cc9ced0eSZequan Wu   // INLINE_ORIGIN number name
259*cc9ced0eSZequan Wu   return parseNumberName<InlineOriginRecord>(Line, Token::InlineOrigin);
260*cc9ced0eSZequan Wu }
261*cc9ced0eSZequan Wu 
operator <<(llvm::raw_ostream & OS,const InlineOriginRecord & R)262*cc9ced0eSZequan Wu llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
263*cc9ced0eSZequan Wu                                         const InlineOriginRecord &R) {
264*cc9ced0eSZequan Wu   return OS << "INLINE_ORIGIN " << R.Number << " " << R.Name;
265*cc9ced0eSZequan Wu }
266*cc9ced0eSZequan Wu 
parsePublicOrFunc(llvm::StringRef Line,bool & Multiple,lldb::addr_t & Address,lldb::addr_t * Size,lldb::addr_t & ParamSize,llvm::StringRef & Name)26706bb3735SPavel Labath static bool parsePublicOrFunc(llvm::StringRef Line, bool &Multiple,
26806bb3735SPavel Labath                               lldb::addr_t &Address, lldb::addr_t *Size,
26906bb3735SPavel Labath                               lldb::addr_t &ParamSize, llvm::StringRef &Name) {
2702cf5486cSPavel Labath   // PUBLIC [m] address param_size name
27106bb3735SPavel Labath   // or
27206bb3735SPavel Labath   // FUNC [m] address size param_size name
27306bb3735SPavel Labath 
27406bb3735SPavel Labath   Token Tok = Size ? Token::Func : Token::Public;
27506bb3735SPavel Labath 
276dfaafbcfSPavel Labath   if (consume<Token>(Line) != Tok)
27706bb3735SPavel Labath     return false;
2782cf5486cSPavel Labath 
279dfaafbcfSPavel Labath   llvm::StringRef Str;
2802cf5486cSPavel Labath   std::tie(Str, Line) = getToken(Line);
28106bb3735SPavel Labath   Multiple = Str == "m";
2822cf5486cSPavel Labath 
2832cf5486cSPavel Labath   if (Multiple)
2842cf5486cSPavel Labath     std::tie(Str, Line) = getToken(Line);
2852cf5486cSPavel Labath   if (!to_integer(Str, Address, 16))
28606bb3735SPavel Labath     return false;
28706bb3735SPavel Labath 
28806bb3735SPavel Labath   if (Tok == Token::Func) {
28906bb3735SPavel Labath     std::tie(Str, Line) = getToken(Line);
29006bb3735SPavel Labath     if (!to_integer(Str, *Size, 16))
29106bb3735SPavel Labath       return false;
29206bb3735SPavel Labath   }
2932cf5486cSPavel Labath 
2942cf5486cSPavel Labath   std::tie(Str, Line) = getToken(Line);
2952cf5486cSPavel Labath   if (!to_integer(Str, ParamSize, 16))
29606bb3735SPavel Labath     return false;
2972cf5486cSPavel Labath 
29806bb3735SPavel Labath   Name = Line.trim();
2992cf5486cSPavel Labath   if (Name.empty())
30006bb3735SPavel Labath     return false;
3012cf5486cSPavel Labath 
30206bb3735SPavel Labath   return true;
30306bb3735SPavel Labath }
30406bb3735SPavel Labath 
parse(llvm::StringRef Line)30506bb3735SPavel Labath llvm::Optional<FuncRecord> FuncRecord::parse(llvm::StringRef Line) {
30606bb3735SPavel Labath   bool Multiple;
30706bb3735SPavel Labath   lldb::addr_t Address, Size, ParamSize;
30806bb3735SPavel Labath   llvm::StringRef Name;
30906bb3735SPavel Labath 
31006bb3735SPavel Labath   if (parsePublicOrFunc(Line, Multiple, Address, &Size, ParamSize, Name))
31106bb3735SPavel Labath     return FuncRecord(Multiple, Address, Size, ParamSize, Name);
31206bb3735SPavel Labath 
31306bb3735SPavel Labath   return llvm::None;
31406bb3735SPavel Labath }
31506bb3735SPavel Labath 
operator ==(const FuncRecord & L,const FuncRecord & R)31606bb3735SPavel Labath bool breakpad::operator==(const FuncRecord &L, const FuncRecord &R) {
3175b18ddb6SPavel Labath   return L.Multiple == R.Multiple && L.Address == R.Address &&
3185b18ddb6SPavel Labath          L.Size == R.Size && L.ParamSize == R.ParamSize && L.Name == R.Name;
31906bb3735SPavel Labath }
operator <<(llvm::raw_ostream & OS,const FuncRecord & R)32006bb3735SPavel Labath llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
32106bb3735SPavel Labath                                         const FuncRecord &R) {
32206bb3735SPavel Labath   return OS << llvm::formatv("FUNC {0}{1:x-} {2:x-} {3:x-} {4}",
3235b18ddb6SPavel Labath                              R.Multiple ? "m " : "", R.Address, R.Size,
3245b18ddb6SPavel Labath                              R.ParamSize, R.Name);
32506bb3735SPavel Labath }
32606bb3735SPavel Labath 
parse(llvm::StringRef Line)327*cc9ced0eSZequan Wu llvm::Optional<InlineRecord> InlineRecord::parse(llvm::StringRef Line) {
328*cc9ced0eSZequan Wu   // INLINE inline_nest_level call_site_line call_site_file_num origin_num
329*cc9ced0eSZequan Wu   // [address size]+
330*cc9ced0eSZequan Wu   if (consume<Token>(Line) != Token::Inline)
331*cc9ced0eSZequan Wu     return llvm::None;
332*cc9ced0eSZequan Wu 
333*cc9ced0eSZequan Wu   llvm::SmallVector<llvm::StringRef> Tokens;
334*cc9ced0eSZequan Wu   SplitString(Line, Tokens, " ");
335*cc9ced0eSZequan Wu   if (Tokens.size() < 6 || Tokens.size() % 2 == 1)
336*cc9ced0eSZequan Wu     return llvm::None;
337*cc9ced0eSZequan Wu 
338*cc9ced0eSZequan Wu   size_t InlineNestLevel;
339*cc9ced0eSZequan Wu   uint32_t CallSiteLineNum;
340*cc9ced0eSZequan Wu   size_t CallSiteFileNum;
341*cc9ced0eSZequan Wu   size_t OriginNum;
342*cc9ced0eSZequan Wu   if (!(to_integer(Tokens[0], InlineNestLevel) &&
343*cc9ced0eSZequan Wu         to_integer(Tokens[1], CallSiteLineNum) &&
344*cc9ced0eSZequan Wu         to_integer(Tokens[2], CallSiteFileNum) &&
345*cc9ced0eSZequan Wu         to_integer(Tokens[3], OriginNum)))
346*cc9ced0eSZequan Wu     return llvm::None;
347*cc9ced0eSZequan Wu 
348*cc9ced0eSZequan Wu   InlineRecord Record = InlineRecord(InlineNestLevel, CallSiteLineNum,
349*cc9ced0eSZequan Wu                                      CallSiteFileNum, OriginNum);
350*cc9ced0eSZequan Wu   for (size_t i = 4; i < Tokens.size(); i += 2) {
351*cc9ced0eSZequan Wu     lldb::addr_t Address;
352*cc9ced0eSZequan Wu     if (!to_integer(Tokens[i], Address, 16))
353*cc9ced0eSZequan Wu       return llvm::None;
354*cc9ced0eSZequan Wu     lldb::addr_t Size;
355*cc9ced0eSZequan Wu     if (!to_integer(Tokens[i + 1].trim(), Size, 16))
356*cc9ced0eSZequan Wu       return llvm::None;
357*cc9ced0eSZequan Wu     Record.Ranges.emplace_back(Address, Size);
358*cc9ced0eSZequan Wu   }
359*cc9ced0eSZequan Wu   return Record;
360*cc9ced0eSZequan Wu }
361*cc9ced0eSZequan Wu 
operator ==(const InlineRecord & L,const InlineRecord & R)362*cc9ced0eSZequan Wu bool breakpad::operator==(const InlineRecord &L, const InlineRecord &R) {
363*cc9ced0eSZequan Wu   return L.InlineNestLevel == R.InlineNestLevel &&
364*cc9ced0eSZequan Wu          L.CallSiteLineNum == R.CallSiteLineNum &&
365*cc9ced0eSZequan Wu          L.CallSiteFileNum == R.CallSiteFileNum && L.OriginNum == R.OriginNum &&
366*cc9ced0eSZequan Wu          L.Ranges == R.Ranges;
367*cc9ced0eSZequan Wu }
368*cc9ced0eSZequan Wu 
operator <<(llvm::raw_ostream & OS,const InlineRecord & R)369*cc9ced0eSZequan Wu llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
370*cc9ced0eSZequan Wu                                         const InlineRecord &R) {
371*cc9ced0eSZequan Wu   OS << llvm::formatv("INLINE {0} {1} {2} {3}", R.InlineNestLevel,
372*cc9ced0eSZequan Wu                       R.CallSiteLineNum, R.CallSiteFileNum, R.OriginNum);
373*cc9ced0eSZequan Wu   for (const auto &range : R.Ranges) {
374*cc9ced0eSZequan Wu     OS << llvm::formatv(" {0:x-} {1:x-}", range.first, range.second);
375*cc9ced0eSZequan Wu   }
376*cc9ced0eSZequan Wu   return OS;
377*cc9ced0eSZequan Wu }
378*cc9ced0eSZequan Wu 
parse(llvm::StringRef Line)379b1f28579SPavel Labath llvm::Optional<LineRecord> LineRecord::parse(llvm::StringRef Line) {
380b1f28579SPavel Labath   lldb::addr_t Address;
381b1f28579SPavel Labath   llvm::StringRef Str;
382b1f28579SPavel Labath   std::tie(Str, Line) = getToken(Line);
383b1f28579SPavel Labath   if (!to_integer(Str, Address, 16))
384b1f28579SPavel Labath     return llvm::None;
385b1f28579SPavel Labath 
386b1f28579SPavel Labath   lldb::addr_t Size;
387b1f28579SPavel Labath   std::tie(Str, Line) = getToken(Line);
388b1f28579SPavel Labath   if (!to_integer(Str, Size, 16))
389b1f28579SPavel Labath     return llvm::None;
390b1f28579SPavel Labath 
391b1f28579SPavel Labath   uint32_t LineNum;
392b1f28579SPavel Labath   std::tie(Str, Line) = getToken(Line);
393b1f28579SPavel Labath   if (!to_integer(Str, LineNum))
394b1f28579SPavel Labath     return llvm::None;
395b1f28579SPavel Labath 
396b1f28579SPavel Labath   size_t FileNum;
397b1f28579SPavel Labath   std::tie(Str, Line) = getToken(Line);
398b1f28579SPavel Labath   if (!to_integer(Str, FileNum))
399b1f28579SPavel Labath     return llvm::None;
400b1f28579SPavel Labath 
401b1f28579SPavel Labath   return LineRecord(Address, Size, LineNum, FileNum);
402b1f28579SPavel Labath }
403b1f28579SPavel Labath 
operator ==(const LineRecord & L,const LineRecord & R)404b1f28579SPavel Labath bool breakpad::operator==(const LineRecord &L, const LineRecord &R) {
405b1f28579SPavel Labath   return L.Address == R.Address && L.Size == R.Size && L.LineNum == R.LineNum &&
406b1f28579SPavel Labath          L.FileNum == R.FileNum;
407b1f28579SPavel Labath }
operator <<(llvm::raw_ostream & OS,const LineRecord & R)408b1f28579SPavel Labath llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
409b1f28579SPavel Labath                                         const LineRecord &R) {
410b1f28579SPavel Labath   return OS << llvm::formatv("{0:x-} {1:x-} {2} {3}", R.Address, R.Size,
411b1f28579SPavel Labath                              R.LineNum, R.FileNum);
412b1f28579SPavel Labath }
413b1f28579SPavel Labath 
parse(llvm::StringRef Line)41406bb3735SPavel Labath llvm::Optional<PublicRecord> PublicRecord::parse(llvm::StringRef Line) {
41506bb3735SPavel Labath   bool Multiple;
41606bb3735SPavel Labath   lldb::addr_t Address, ParamSize;
41706bb3735SPavel Labath   llvm::StringRef Name;
41806bb3735SPavel Labath 
41906bb3735SPavel Labath   if (parsePublicOrFunc(Line, Multiple, Address, nullptr, ParamSize, Name))
4202cf5486cSPavel Labath     return PublicRecord(Multiple, Address, ParamSize, Name);
42106bb3735SPavel Labath 
42206bb3735SPavel Labath   return llvm::None;
4232cf5486cSPavel Labath }
4242cf5486cSPavel Labath 
operator ==(const PublicRecord & L,const PublicRecord & R)4252cf5486cSPavel Labath bool breakpad::operator==(const PublicRecord &L, const PublicRecord &R) {
4265b18ddb6SPavel Labath   return L.Multiple == R.Multiple && L.Address == R.Address &&
4275b18ddb6SPavel Labath          L.ParamSize == R.ParamSize && L.Name == R.Name;
4282cf5486cSPavel Labath }
operator <<(llvm::raw_ostream & OS,const PublicRecord & R)4292cf5486cSPavel Labath llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
4302cf5486cSPavel Labath                                         const PublicRecord &R) {
4312cf5486cSPavel Labath   return OS << llvm::formatv("PUBLIC {0}{1:x-} {2:x-} {3}",
4325b18ddb6SPavel Labath                              R.Multiple ? "m " : "", R.Address, R.ParamSize,
4335b18ddb6SPavel Labath                              R.Name);
4342cf5486cSPavel Labath }
4352cf5486cSPavel Labath 
parse(llvm::StringRef Line)4369837f548SPavel Labath llvm::Optional<StackCFIRecord> StackCFIRecord::parse(llvm::StringRef Line) {
4379837f548SPavel Labath   // STACK CFI INIT address size reg1: expr1 reg2: expr2 ...
4389837f548SPavel Labath   // or
4399837f548SPavel Labath   // STACK CFI address reg1: expr1 reg2: expr2 ...
4409837f548SPavel Labath   // No token in exprN ends with a colon.
4419837f548SPavel Labath 
4429837f548SPavel Labath   if (consume<Token>(Line) != Token::Stack)
4439837f548SPavel Labath     return llvm::None;
4449837f548SPavel Labath   if (consume<Token>(Line) != Token::CFI)
4459837f548SPavel Labath     return llvm::None;
4469837f548SPavel Labath 
4479837f548SPavel Labath   llvm::StringRef Str;
4489837f548SPavel Labath   std::tie(Str, Line) = getToken(Line);
4499837f548SPavel Labath 
4509837f548SPavel Labath   bool IsInitRecord = stringTo<Token>(Str) == Token::Init;
4519837f548SPavel Labath   if (IsInitRecord)
4529837f548SPavel Labath     std::tie(Str, Line) = getToken(Line);
4539837f548SPavel Labath 
4549837f548SPavel Labath   lldb::addr_t Address;
4559837f548SPavel Labath   if (!to_integer(Str, Address, 16))
4569837f548SPavel Labath     return llvm::None;
4579837f548SPavel Labath 
4589837f548SPavel Labath   llvm::Optional<lldb::addr_t> Size;
4599837f548SPavel Labath   if (IsInitRecord) {
4609837f548SPavel Labath     Size.emplace();
4619837f548SPavel Labath     std::tie(Str, Line) = getToken(Line);
4629837f548SPavel Labath     if (!to_integer(Str, *Size, 16))
4639837f548SPavel Labath       return llvm::None;
4649837f548SPavel Labath   }
4659837f548SPavel Labath 
4669837f548SPavel Labath   return StackCFIRecord(Address, Size, Line.trim());
4679837f548SPavel Labath }
4689837f548SPavel Labath 
operator ==(const StackCFIRecord & L,const StackCFIRecord & R)4699837f548SPavel Labath bool breakpad::operator==(const StackCFIRecord &L, const StackCFIRecord &R) {
4709837f548SPavel Labath   return L.Address == R.Address && L.Size == R.Size &&
4719837f548SPavel Labath          L.UnwindRules == R.UnwindRules;
4729837f548SPavel Labath }
4739837f548SPavel Labath 
operator <<(llvm::raw_ostream & OS,const StackCFIRecord & R)4749837f548SPavel Labath llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
4759837f548SPavel Labath                                         const StackCFIRecord &R) {
4769837f548SPavel Labath   OS << "STACK CFI ";
4779837f548SPavel Labath   if (R.Size)
4789837f548SPavel Labath     OS << "INIT ";
4799837f548SPavel Labath   OS << llvm::formatv("{0:x-} ", R.Address);
4809837f548SPavel Labath   if (R.Size)
4819837f548SPavel Labath     OS << llvm::formatv("{0:x-} ", *R.Size);
4829837f548SPavel Labath   return OS << " " << R.UnwindRules;
4839837f548SPavel Labath }
4849837f548SPavel Labath 
parse(llvm::StringRef Line)4850a9f47d7SPavel Labath llvm::Optional<StackWinRecord> StackWinRecord::parse(llvm::StringRef Line) {
4860a9f47d7SPavel Labath   // STACK WIN type rva code_size prologue_size epilogue_size parameter_size
4870a9f47d7SPavel Labath   //     saved_register_size local_size max_stack_size has_program_string
4880a9f47d7SPavel Labath   //     program_string_OR_allocates_base_pointer
4890a9f47d7SPavel Labath 
4900a9f47d7SPavel Labath   if (consume<Token>(Line) != Token::Stack)
4910a9f47d7SPavel Labath     return llvm::None;
4920a9f47d7SPavel Labath   if (consume<Token>(Line) != Token::Win)
4930a9f47d7SPavel Labath     return llvm::None;
4940a9f47d7SPavel Labath 
4950a9f47d7SPavel Labath   llvm::StringRef Str;
4960a9f47d7SPavel Labath   uint8_t Type;
4970a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line);
4980a9f47d7SPavel Labath   // Right now we only support the "FrameData" frame type.
4990a9f47d7SPavel Labath   if (!to_integer(Str, Type) || FrameType(Type) != FrameType::FrameData)
5000a9f47d7SPavel Labath     return llvm::None;
5010a9f47d7SPavel Labath 
5020a9f47d7SPavel Labath   lldb::addr_t RVA;
5030a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line);
5040a9f47d7SPavel Labath   if (!to_integer(Str, RVA, 16))
5050a9f47d7SPavel Labath     return llvm::None;
5060a9f47d7SPavel Labath 
5070a9f47d7SPavel Labath   lldb::addr_t CodeSize;
5080a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line);
5090a9f47d7SPavel Labath   if (!to_integer(Str, CodeSize, 16))
5100a9f47d7SPavel Labath     return llvm::None;
5110a9f47d7SPavel Labath 
5120a9f47d7SPavel Labath   // Skip fields which we aren't using right now.
5130a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line); // prologue_size
5140a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line); // epilogue_size
5150a9f47d7SPavel Labath 
5160a9f47d7SPavel Labath   lldb::addr_t ParameterSize;
5170a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line);
5180a9f47d7SPavel Labath   if (!to_integer(Str, ParameterSize, 16))
5190a9f47d7SPavel Labath     return llvm::None;
5200a9f47d7SPavel Labath 
5210a9f47d7SPavel Labath   lldb::addr_t SavedRegisterSize;
5220a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line);
5230a9f47d7SPavel Labath   if (!to_integer(Str, SavedRegisterSize, 16))
5240a9f47d7SPavel Labath     return llvm::None;
5250a9f47d7SPavel Labath 
5260a9f47d7SPavel Labath   lldb::addr_t LocalSize;
5270a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line);
5280a9f47d7SPavel Labath   if (!to_integer(Str, LocalSize, 16))
5290a9f47d7SPavel Labath     return llvm::None;
5300a9f47d7SPavel Labath 
5310a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line); // max_stack_size
5320a9f47d7SPavel Labath 
5330a9f47d7SPavel Labath   uint8_t HasProgramString;
5340a9f47d7SPavel Labath   std::tie(Str, Line) = getToken(Line);
5350a9f47d7SPavel Labath   if (!to_integer(Str, HasProgramString))
5360a9f47d7SPavel Labath     return llvm::None;
5370a9f47d7SPavel Labath   // FrameData records should always have a program string.
5380a9f47d7SPavel Labath   if (!HasProgramString)
5390a9f47d7SPavel Labath     return llvm::None;
5400a9f47d7SPavel Labath 
5410a9f47d7SPavel Labath   return StackWinRecord(RVA, CodeSize, ParameterSize, SavedRegisterSize,
5420a9f47d7SPavel Labath                         LocalSize, Line.trim());
5430a9f47d7SPavel Labath }
5440a9f47d7SPavel Labath 
operator ==(const StackWinRecord & L,const StackWinRecord & R)5450a9f47d7SPavel Labath bool breakpad::operator==(const StackWinRecord &L, const StackWinRecord &R) {
5460a9f47d7SPavel Labath   return L.RVA == R.RVA && L.CodeSize == R.CodeSize &&
5470a9f47d7SPavel Labath          L.ParameterSize == R.ParameterSize &&
5480a9f47d7SPavel Labath          L.SavedRegisterSize == R.SavedRegisterSize &&
5490a9f47d7SPavel Labath          L.LocalSize == R.LocalSize && L.ProgramString == R.ProgramString;
5500a9f47d7SPavel Labath }
5510a9f47d7SPavel Labath 
operator <<(llvm::raw_ostream & OS,const StackWinRecord & R)5520a9f47d7SPavel Labath llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
5530a9f47d7SPavel Labath                                         const StackWinRecord &R) {
5540a9f47d7SPavel Labath   return OS << llvm::formatv(
5550a9f47d7SPavel Labath              "STACK WIN 4 {0:x-} {1:x-} ? ? {2} {3} {4} ? 1 {5}", R.RVA,
5560a9f47d7SPavel Labath              R.CodeSize, R.ParameterSize, R.SavedRegisterSize, R.LocalSize,
5570a9f47d7SPavel Labath              R.ProgramString);
5580a9f47d7SPavel Labath }
5590a9f47d7SPavel Labath 
toString(Record::Kind K)5602cf5486cSPavel Labath llvm::StringRef breakpad::toString(Record::Kind K) {
5612cf5486cSPavel Labath   switch (K) {
5622cf5486cSPavel Labath   case Record::Module:
5632cf5486cSPavel Labath     return "MODULE";
5642cf5486cSPavel Labath   case Record::Info:
5652cf5486cSPavel Labath     return "INFO";
5662cf5486cSPavel Labath   case Record::File:
5672cf5486cSPavel Labath     return "FILE";
5682cf5486cSPavel Labath   case Record::Func:
5692cf5486cSPavel Labath     return "FUNC";
570*cc9ced0eSZequan Wu   case Record::Inline:
571*cc9ced0eSZequan Wu     return "INLINE";
572*cc9ced0eSZequan Wu   case Record::InlineOrigin:
573*cc9ced0eSZequan Wu     return "INLINE_ORIGIN";
5742cf5486cSPavel Labath   case Record::Line:
5752cf5486cSPavel Labath     return "LINE";
5762cf5486cSPavel Labath   case Record::Public:
5772cf5486cSPavel Labath     return "PUBLIC";
578dfaafbcfSPavel Labath   case Record::StackCFI:
579dfaafbcfSPavel Labath     return "STACK CFI";
5800a9f47d7SPavel Labath   case Record::StackWin:
5810a9f47d7SPavel Labath     return "STACK WIN";
5822cf5486cSPavel Labath   }
5832cf5486cSPavel Labath   llvm_unreachable("Unknown record kind!");
5842cf5486cSPavel Labath }
585