Index: lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.syms =================================================================== --- lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.syms +++ lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.syms @@ -0,0 +1,17 @@ +MODULE windows x86 897DD83EA8C8411897F3A925EE4BF7411 unwind-via-stack-win.pdb +INFO CODE_ID 5D499B5C5000 unwind-via-stack-win.exe +PUBLIC 0 0 dummy +PUBLIC 10 0 call_many +PUBLIC 80 0 main +PUBLIC 90 0 many_pointer_args +PUBLIC 100 0 bogus_rule +PUBLIC 110 0 bogus_cfa_rhs +PUBLIC 120 0 bogus_esp_rhs +PUBLIC 130 0 temporary_var +STACK WIN 4 10 6d 0 0 0 0 0 0 1 $T0 $esp 80 + = $eip $T0 ^ = $esp $T0 4 + = +STACK WIN 4 80 8 0 0 0 0 0 0 1 $T0 $esp = $eip $T0 ^ = $esp $T0 4 + = +STACK WIN 4 90 5 0 0 50 0 0 0 1 $T0 $esp = $eip $T0 ^ = $esp $T0 4 + = +STACK WIN 4 100 4 0 0 0 0 0 0 1 bogus +STACK WIN 4 110 4 0 0 0 0 0 0 1 $T0 $bogus = $eip $T0 ^ = $esp $T0 4 + = +STACK WIN 4 120 4 0 0 0 0 0 0 1 $T0 $esp = $eip $T0 ^ = $esp $bogus 4 + = +STACK WIN 4 130 4 0 0 0 0 0 0 1 $T0 $esp = $bogus $T0 = $eip $bogus ^ = $esp $T0 4 + = Index: lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.yaml =================================================================== --- lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.yaml +++ lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.yaml @@ -0,0 +1,35 @@ +--- !minidump +Streams: + - Type: ThreadList + Threads: + - Thread Id: 0x0000290C + Priority Class: 0x00000020 + Environment Block: 0x0000000000A98000 + Context: 3F0001000000000000000000000000000000000000000000000000007F02000000000000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002B000000530000002B0000002B00000080100B0080100B000050A90080100B0080100B0000000000E4FECF0092100B0023000000440301007CFECF002B0000007F0200000000000000000000000000000000000000000000801F0000FFFF020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000144E3D6C2000000001000000EA1E00F4C000E50700000000FC0100002CE3C014D8E202010000E507880F401D839DC60100000000400000007F00000000000000880F401D0A000000900F401D0000000000000100EA1E00009808E5077F00000000000000000000009008E507990100006002E5072CABC87708346474B42300000100000044E3C014200000000000000020532777A80F401D4F346474D00F401D6F378CCC5C4CD5010000000000000000000000000000000000000000000000003AFCD72F90E3C01418CE3470B4230000B80F401DC00F401DC80F401DD00F401D + Stack: + Start of Memory Range: 0x0000000000CFFE78 + Content: 0000000079100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0085100B0094842777 + - Type: ModuleList + Modules: + - Base of Image: 0x00000000000B1000 + Size of Image: 0x00004000 + Module Name: 'unwind-via-stack-win.exe' + CodeView Record: 525344533ED87D89C8A8184197F3A925EE4BF74101000000433A5C70726F6A656374735C746573745F6170705C436F6E736F6C654170706C69636174696F6E315C44656275675C436F6E736F6C654170706C69636174696F6E312E70646200 + - Base of Image: 0x0000000077260000 + Size of Image: 0x000E0000 + Module Name: 'C:\Windows\System32\kernel32.dll' + CodeView Record: 5253445300F90A57CF8DED8A463A90390318CD4401000000776B65726E656C33322EFFFFFFFF + - Type: MemoryList + Memory Ranges: + - Start of Memory Range: 0x0000000000CFFE78 + Content: 0000000079100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0085100B0094842777 + - Type: SystemInfo + Processor Arch: X86 + Platform ID: Win32NT + CPU: + Vendor ID: AuthenticAMD + Version Info: 0x00800F82 + Feature Info: 0x178BFBFF + - Type: MiscInfo + Content: 54050000F703000008290000C883495D0000000000000000AC0D000098080000AC0D00000200000002000000002000000D0000000000000002000000C4FFFFFF430065006E007400720061006C0020004500750072006F007000650020005300740061006E0064006100720064002000540069006D006500000000000000000000000A0000000500030000000000000000000000430065006E007400720061006C0020004500750072006F00700065002000530075006D006D00650072002000540069006D00650000000000000000000000000000000300000005000200000000000000C4FFFFFF310037003100330034002E0031002E007800380036006600720065002E007200730034005F00720065006C0065006100730065002E003100380030003400310030002D00310038003000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064006200670063006F00720065002E0069003300380036002C00310030002E0030002E00310037003100330034002E0031000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C816B92 +... Index: lldb/trunk/lit/SymbolFile/Breakpad/unwind-via-stack-win.test =================================================================== --- lldb/trunk/lit/SymbolFile/Breakpad/unwind-via-stack-win.test +++ lldb/trunk/lit/SymbolFile/Breakpad/unwind-via-stack-win.test @@ -0,0 +1,54 @@ +# RUN: yaml2obj %S/Inputs/unwind-via-stack-win.yaml > %t +# RUN: %lldb -c %t \ +# RUN: -o "target symbols add %S/Inputs/unwind-via-stack-win.syms" \ +# RUN: -s %s -b | FileCheck %s + +# First check that unwind plan generation works correctly. +# This function has a "typical" unwind rule. +image show-unwind -n call_many +# CHECK-LABEL: image show-unwind -n call_many +# CHECK: UNWIND PLANS for unwind-via-stack-win.exe`call_many +# CHECK: Symbol file UnwindPlan: +# CHECK: This UnwindPlan originally sourced from breakpad STACK WIN +# CHECK: This UnwindPlan is sourced from the compiler: yes. +# CHECK: This UnwindPlan is valid at all instruction locations: no. +# CHECK: Address range of this UnwindPlan: [unwind-via-stack-win.exe..module_image + 16-0x0000007d) +# CHECK: row[0]: 0: CFA=DW_OP_breg7 +0, DW_OP_consts +80, DW_OP_plus => esp=DW_OP_pick 0x00, DW_OP_consts +4, DW_OP_plus eip=DW_OP_pick 0x00, DW_OP_deref + +# Then, some invalid rules. +image show-unwind -n bogus_rule +# CHECK-LABEL: image show-unwind -n bogus_rule +# CHECK: UNWIND PLANS for unwind-via-stack-win.exe`bogus_rule +# CHECK-NOT: Symbol file + +image show-unwind -n bogus_cfa_rhs +# CHECK-LABEL: image show-unwind -n bogus_cfa_rhs +# CHECK: UNWIND PLANS for unwind-via-stack-win.exe`bogus_cfa_rhs +# CHECK-NOT: Symbol file + +image show-unwind -n bogus_esp_rhs +# CHECK-LABEL: image show-unwind -n bogus_esp_rhs +# CHECK: UNWIND PLANS for unwind-via-stack-win.exe`bogus_esp_rhs +# CHECK-NOT: Symbol file + +# We don't treat unknown lhs as an error, as it can be just a temporary +# variable used in other rules. +image show-unwind -n temporary_var +# CHECK-LABEL: image show-unwind -n temporary_var +# CHECK: UNWIND PLANS for unwind-via-stack-win.exe`temporary_var +# CHECK: Symbol file UnwindPlan: +# CHECK: This UnwindPlan originally sourced from breakpad STACK WIN +# CHECK: This UnwindPlan is sourced from the compiler: yes. +# CHECK: This UnwindPlan is valid at all instruction locations: no. +# CHECK: Address range of this UnwindPlan: [unwind-via-stack-win.exe..module_image + 304-0x00000134) +# CHECK: row[0]: 0: CFA=DW_OP_breg7 +0 => esp=DW_OP_pick 0x00, DW_OP_consts +4, DW_OP_plus eip=DW_OP_pick 0x00, DW_OP_deref + +# And finally, check that backtracing works as a whole by unwinding a simple +# stack. +thread backtrace +# CHECK-LABEL: thread backtrace +# CHECK: frame #0: 0x000b1092 unwind-via-stack-win.exe`many_pointer_args +# CHECK: frame #1: 0x000b1079 unwind-via-stack-win.exe`call_many + 105 +# CHECK: frame #2: 0x000b1085 unwind-via-stack-win.exe`main + 5 +# CHECK: frame #3: 0x77278494 kernel32.dll +# CHECK-NOT: frame Index: lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -12,6 +12,7 @@ #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/PostfixExpression.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/UnwindPlan.h" @@ -204,9 +205,14 @@ void ParseCUData(); void ParseLineTableAndSupportFiles(CompileUnit &cu, CompUnitData &data); void ParseUnwindData(); - bool ParseUnwindRow(llvm::StringRef unwind_rules, - const RegisterInfoResolver &resolver, - UnwindPlan::Row &row); + llvm::ArrayRef SaveAsDWARF(postfix::Node &node); + lldb::UnwindPlanSP ParseCFIUnwindPlan(const Bookmark &bookmark, + const RegisterInfoResolver &resolver); + bool ParseCFIUnwindRow(llvm::StringRef unwind_rules, + const RegisterInfoResolver &resolver, + UnwindPlan::Row &row); + lldb::UnwindPlanSP ParseWinUnwindPlan(const Bookmark &bookmark, + const RegisterInfoResolver &resolver); using CompUnitMap = RangeDataVector; @@ -214,7 +220,11 @@ llvm::Optional m_cu_data; using UnwindMap = RangeDataVector; - llvm::Optional m_unwind_data; + struct UnwindData { + UnwindMap cfi; + UnwindMap win; + }; + llvm::Optional m_unwind_data; llvm::BumpPtrAllocator m_allocator; }; Index: lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -15,7 +15,6 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/PostfixExpression.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TypeMap.h" #include "lldb/Utility/Log.h" @@ -421,7 +420,17 @@ return ResolveRegister(resolver, name); } -bool SymbolFileBreakpad::ParseUnwindRow(llvm::StringRef unwind_rules, +llvm::ArrayRef SymbolFileBreakpad::SaveAsDWARF(postfix::Node &node) { + ArchSpec arch = m_objfile_sp->GetArchitecture(); + StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(), + arch.GetByteOrder()); + ToDWARF(node, dwarf); + uint8_t *saved = m_allocator.Allocate(dwarf.GetSize()); + std::memcpy(saved, dwarf.GetData(), dwarf.GetSize()); + return {saved, dwarf.GetSize()}; +} + +bool SymbolFileBreakpad::ParseCFIUnwindRow(llvm::StringRef unwind_rules, const RegisterInfoResolver &resolver, UnwindPlan::Row &row) { Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); @@ -454,18 +463,12 @@ return false; } - ArchSpec arch = m_objfile_sp->GetArchitecture(); - StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(), - arch.GetByteOrder()); - ToDWARF(*rhs, dwarf); - uint8_t *saved = m_allocator.Allocate(dwarf.GetSize()); - std::memcpy(saved, dwarf.GetData(), dwarf.GetSize()); - + llvm::ArrayRef saved = SaveAsDWARF(*rhs); if (lhs == ".cfa") { - row.GetCFAValue().SetIsDWARFExpression(saved, dwarf.GetSize()); + row.GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size()); } else if (const RegisterInfo *info = ResolveRegisterOrRA(resolver, lhs)) { UnwindPlan::Row::RegisterLocation loc; - loc.SetIsDWARFExpression(saved, dwarf.GetSize()); + loc.SetIsDWARFExpression(saved.data(), saved.size()); row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc); } else LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs); @@ -481,20 +484,27 @@ SymbolFileBreakpad::GetUnwindPlan(const Address &address, const RegisterInfoResolver &resolver) { ParseUnwindData(); - const UnwindMap::Entry *entry = - m_unwind_data->FindEntryThatContains(address.GetFileAddress()); - if (!entry) - return nullptr; + if (auto *entry = + m_unwind_data->cfi.FindEntryThatContains(address.GetFileAddress())) + return ParseCFIUnwindPlan(entry->data, resolver); + if (auto *entry = + m_unwind_data->win.FindEntryThatContains(address.GetFileAddress())) + return ParseWinUnwindPlan(entry->data, resolver); + return nullptr; +} +UnwindPlanSP +SymbolFileBreakpad::ParseCFIUnwindPlan(const Bookmark &bookmark, + const RegisterInfoResolver &resolver) { addr_t base = GetBaseFileAddress(); if (base == LLDB_INVALID_ADDRESS) return nullptr; - LineIterator It(*m_objfile_sp, Record::StackCFI, entry->data), + LineIterator It(*m_objfile_sp, Record::StackCFI, bookmark), End(*m_objfile_sp); llvm::Optional init_record = StackCFIRecord::parse(*It); - assert(init_record.hasValue()); - assert(init_record->Size.hasValue()); + assert(init_record.hasValue() && init_record->Size.hasValue() && + "Record already parsed successfully in ParseUnwindData!"); auto plan_sp = std::make_shared(lldb::eRegisterKindLLDB); plan_sp->SetSourceName("breakpad STACK CFI"); @@ -507,7 +517,7 @@ auto row_sp = std::make_shared(); row_sp->SetOffset(0); - if (!ParseUnwindRow(init_record->UnwindRules, resolver, *row_sp)) + if (!ParseCFIUnwindRow(init_record->UnwindRules, resolver, *row_sp)) return nullptr; plan_sp->AppendRow(row_sp); for (++It; It != End; ++It) { @@ -519,13 +529,98 @@ row_sp = std::make_shared(*row_sp); row_sp->SetOffset(record->Address - init_record->Address); - if (!ParseUnwindRow(record->UnwindRules, resolver, *row_sp)) + if (!ParseCFIUnwindRow(record->UnwindRules, resolver, *row_sp)) return nullptr; plan_sp->AppendRow(row_sp); } return plan_sp; } +UnwindPlanSP +SymbolFileBreakpad::ParseWinUnwindPlan(const Bookmark &bookmark, + const RegisterInfoResolver &resolver) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); + addr_t base = GetBaseFileAddress(); + if (base == LLDB_INVALID_ADDRESS) + return nullptr; + + LineIterator It(*m_objfile_sp, Record::StackWin, bookmark); + llvm::Optional record = StackWinRecord::parse(*It); + assert(record.hasValue() && + "Record already parsed successfully in ParseUnwindData!"); + + auto plan_sp = std::make_shared(lldb::eRegisterKindLLDB); + plan_sp->SetSourceName("breakpad STACK WIN"); + plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo); + plan_sp->SetSourcedFromCompiler(eLazyBoolYes); + plan_sp->SetPlanValidAddressRange( + AddressRange(base + record->RVA, record->CodeSize, + m_objfile_sp->GetModule()->GetSectionList())); + + auto row_sp = std::make_shared(); + row_sp->SetOffset(0); + + llvm::BumpPtrAllocator node_alloc; + std::vector> program = + postfix::ParseFPOProgram(record->ProgramString, node_alloc); + + if (program.empty()) { + LLDB_LOG(log, "Invalid unwind rule: {0}.", record->ProgramString); + return nullptr; + } + auto it = program.begin(); + const auto &symbol_resolver = + [&](postfix::SymbolNode &symbol) -> postfix::Node * { + llvm::StringRef name = symbol.GetName(); + for (const auto &rule : llvm::make_range(program.begin(), it)) { + if (rule.first == name) + return rule.second; + } + if (const RegisterInfo *info = ResolveRegister(resolver, name)) + return postfix::MakeNode( + node_alloc, info->kinds[eRegisterKindLLDB]); + return nullptr; + }; + + // We assume the first value will be the CFA. It is usually called T0, but + // clang will use T1, if it needs to realign the stack. + if (!postfix::ResolveSymbols(it->second, symbol_resolver)) { + LLDB_LOG(log, "Resolving symbols in `{0}` failed.", record->ProgramString); + return nullptr; + } + llvm::ArrayRef saved = SaveAsDWARF(*it->second); + row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size()); + + // Replace the node value with InitialValueNode, so that subsequent + // expressions refer to the CFA value instead of recomputing the whole + // expression. + it->second = postfix::MakeNode(node_alloc); + + + // Now process the rest of the assignments. + for (++it; it != program.end(); ++it) { + const RegisterInfo *info = ResolveRegister(resolver, it->first); + // It is not an error if the resolution fails because the program may + // contain temporary variables. + if (!info) + continue; + if (!postfix::ResolveSymbols(it->second, symbol_resolver)) { + LLDB_LOG(log, "Resolving symbols in `{0}` failed.", + record->ProgramString); + return nullptr; + } + + llvm::ArrayRef saved = SaveAsDWARF(*it->second); + UnwindPlan::Row::RegisterLocation loc; + loc.SetIsDWARFExpression(saved.data(), saved.size()); + row_sp->SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc); + } + + plan_sp->AppendRow(row_sp); + return plan_sp; +} + addr_t SymbolFileBreakpad::GetBaseFileAddress() { return m_objfile_sp->GetModule() ->GetObjectFile() @@ -633,8 +728,8 @@ void SymbolFileBreakpad::ParseUnwindData() { if (m_unwind_data) return; - m_unwind_data.emplace(); + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); addr_t base = GetBaseFileAddress(); if (base == LLDB_INVALID_ADDRESS) { @@ -646,10 +741,20 @@ It != End; ++It) { if (auto record = StackCFIRecord::parse(*It)) { if (record->Size) - m_unwind_data->Append(UnwindMap::Entry( + m_unwind_data->cfi.Append(UnwindMap::Entry( base + record->Address, *record->Size, It.GetBookmark())); } else LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It); } - m_unwind_data->Sort(); + m_unwind_data->cfi.Sort(); + + for (LineIterator It(*m_objfile_sp, Record::StackWin), End(*m_objfile_sp); + It != End; ++It) { + if (auto record = StackWinRecord::parse(*It)) { + m_unwind_data->win.Append(UnwindMap::Entry( + base + record->RVA, record->CodeSize, It.GetBookmark())); + } else + LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It); + } + m_unwind_data->win.Sort(); }