diff options
Diffstat (limited to 'src/common/linux')
28 files changed, 6 insertions, 7504 deletions
diff --git a/src/common/linux/dump_stabs.cc b/src/common/linux/dump_stabs.cc deleted file mode 100644 index 6842eae6..00000000 --- a/src/common/linux/dump_stabs.cc +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dump_stabs.cc --- implement the DumpStabsHandler class. - -#include <cstdarg> -#include <cxxabi.h> - -#include <algorithm> -#include <cassert> - -#include "common/linux/dump_stabs.h" - -namespace google_breakpad { - -using std::string; - -// Demangle using abi call. -// Older GCC may not support it. -static string Demangle(const string &mangled) { - int status = 0; - char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); - if (status == 0 && demangled != NULL) { - string str(demangled); - free(demangled); - return str; - } - return string(mangled); -} - -bool DumpStabsHandler::StartCompilationUnit(const char *name, uint64_t address, - const char *build_directory) { - assert(!in_compilation_unit_); - in_compilation_unit_ = true; - current_source_file_name_ = name; - current_source_file_ = module_->FindFile(name); - comp_unit_base_address_ = address; - boundaries_.push_back(static_cast<Module::Address>(address)); - return true; -} - -bool DumpStabsHandler::EndCompilationUnit(uint64_t address) { - assert(in_compilation_unit_); - in_compilation_unit_ = false; - comp_unit_base_address_ = 0; - current_source_file_ = NULL; - current_source_file_name_ = NULL; - if (address) - boundaries_.push_back(static_cast<Module::Address>(address)); - return true; -} - -bool DumpStabsHandler::StartFunction(const string &name, - uint64_t address) { - assert(!current_function_); - Module::Function *f = new Module::Function; - f->name = Demangle(name); - f->address = address; - f->size = 0; // We compute this in DumpStabsHandler::Finalize(). - f->parameter_size = 0; // We don't provide this information. - current_function_ = f; - boundaries_.push_back(static_cast<Module::Address>(address)); - return true; -} - -bool DumpStabsHandler::EndFunction(uint64_t address) { - assert(current_function_); - // Functions in this compilation unit should have address bigger - // than the compilation unit's starting address. There may be a lot - // of duplicated entries for functions in the STABS data; only one - // entry can meet this requirement. - // - // (I don't really understand the above comment; just bringing it - // along from the previous code, and leaving the behaivor unchanged. - // If you know the whole story, please patch this comment. --jimb) - if (current_function_->address >= comp_unit_base_address_) - functions_.push_back(current_function_); - else - delete current_function_; - current_function_ = NULL; - if (address) - boundaries_.push_back(static_cast<Module::Address>(address)); - return true; -} - -bool DumpStabsHandler::Line(uint64_t address, const char *name, int number) { - assert(current_function_); - assert(current_source_file_); - if (name != current_source_file_name_) { - current_source_file_ = module_->FindFile(name); - current_source_file_name_ = name; - } - Module::Line line; - line.address = address; - line.size = 0; // We compute this in DumpStabsHandler::Finalize(). - line.file = current_source_file_; - line.number = number; - current_function_->lines.push_back(line); - return true; -} - -void DumpStabsHandler::Warning(const char *format, ...) { - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} - -void DumpStabsHandler::Finalize() { - // Sort our boundary list, so we can search it quickly. - sort(boundaries_.begin(), boundaries_.end()); - // Sort all functions by address, just for neatness. - sort(functions_.begin(), functions_.end(), - Module::Function::CompareByAddress); - for (vector<Module::Function *>::iterator func_it = functions_.begin(); - func_it != functions_.end(); - func_it++) { - Module::Function *f = *func_it; - // Compute the function f's size. - vector<Module::Address>::iterator boundary - = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address); - if (boundary != boundaries_.end()) - f->size = *boundary - f->address; - else - // If this is the last function in the module, and the STABS - // reader was unable to give us its ending address, then assign - // it a bogus, very large value. This will happen at most once - // per module: since we've added all functions' addresses to the - // boundary table, only one can be the last. - f->size = kFallbackSize; - - // Compute sizes for each of the function f's lines --- if it has any. - if (!f->lines.empty()) { - stable_sort(f->lines.begin(), f->lines.end(), - Module::Line::CompareByAddress); - vector<Module::Line>::iterator last_line = f->lines.end() - 1; - for (vector<Module::Line>::iterator line_it = f->lines.begin(); - line_it != last_line; line_it++) - line_it[0].size = line_it[1].address - line_it[0].address; - // Compute the size of the last line from f's end address. - last_line->size = (f->address + f->size) - last_line->address; - } - } - // Now that everything has a size, add our functions to the module, and - // dispose of our private list. - module_->AddFunctions(functions_.begin(), functions_.end()); - functions_.clear(); -} - -} // namespace google_breakpad diff --git a/src/common/linux/dump_stabs.h b/src/common/linux/dump_stabs.h deleted file mode 100644 index e6ea1d54..00000000 --- a/src/common/linux/dump_stabs.h +++ /dev/null @@ -1,139 +0,0 @@ -// -*- mode: C++ -*- - -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dump_stabs.h: Define the DumpStabsHandler class, which receives -// STABS debugging information from a parser and adds it to a Breakpad -// symbol file. - -#ifndef COMMON_LINUX_DUMP_STABS_H__ -#define COMMON_LINUX_DUMP_STABS_H__ - -#include <stdint.h> - -#include <string> -#include <vector> - -#include "common/linux/module.h" -#include "common/linux/stabs_reader.h" - -namespace google_breakpad { - -using std::string; -using std::vector; - -// A DumpStabsHandler is a handler that receives parsed STABS -// debugging information from a StabsReader, and uses that to populate -// a Module. (All classes are in the google_breakpad namespace.) A -// Module represents the contents of a Breakpad symbol file, and knows -// how to write itself out as such. A DumpStabsHandler thus acts as -// the bridge between STABS and Breakpad data. -class DumpStabsHandler: public google_breakpad::StabsHandler { - public: - // Receive parsed debugging information from a StabsReader, and - // store it all in MODULE. - DumpStabsHandler(Module *module) : - module_(module), - in_compilation_unit_(false), - comp_unit_base_address_(0), - current_function_(NULL), - current_source_file_(NULL), - current_source_file_name_(NULL) { } - - // The standard StabsHandler virtual member functions. - bool StartCompilationUnit(const char *name, uint64_t address, - const char *build_directory); - bool EndCompilationUnit(uint64_t address); - bool StartFunction(const string &name, uint64_t address); - bool EndFunction(uint64_t address); - bool Line(uint64_t address, const char *name, int number); - void Warning(const char *format, ...); - - // Do any final processing necessary to make module_ contain all the - // data provided by the STABS reader. - // - // Because STABS does not provide reliable size information for - // functions and lines, we need to make a pass over the data after - // processing all the STABS to compute those sizes. We take care of - // that here. - void Finalize(); - - private: - - // An arbitrary, but very large, size to use for functions whose - // size we can't compute properly. - static const uint64_t kFallbackSize = 0x10000000; - - // The module we're contributing debugging info to. - Module *module_; - - // The functions we've generated so far. We don't add these to - // module_ as we parse them. Instead, we wait until we've computed - // their ending address, and their lines' ending addresses. - // - // We could just stick them in module_ from the outset, but if - // module_ already contains data gathered from other debugging - // formats, that would complicate the size computation. - vector<Module::Function *> functions_; - - // Boundary addresses. STABS doesn't necessarily supply sizes for - // functions and lines, so we need to compute them ourselves by - // finding the next object. - vector<Module::Address> boundaries_; - - // True if we are currently within a compilation unit: we have gotten a - // StartCompilationUnit call, but no matching EndCompilationUnit call - // yet. We use this for sanity checks. - bool in_compilation_unit_; - - // The base address of the current compilation unit. We use this to - // recognize functions we should omit from the symbol file. (If you - // know the details of why we omit these, please patch this - // comment.) - Module::Address comp_unit_base_address_; - - // The function we're currently contributing lines to. - Module::Function *current_function_; - - // The last Module::File we got a line number in. - Module::File *current_source_file_; - - // The pointer in the .stabstr section of the name that - // current_source_file_ is built from. This allows us to quickly - // recognize when the current line is in the same file as the - // previous one (which it usually is). - const char *current_source_file_name_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_DUMP_STABS_H__ diff --git a/src/common/linux/dump_stabs_unittest.cc b/src/common/linux/dump_stabs_unittest.cc deleted file mode 100644 index 382c4f5f..00000000 --- a/src/common/linux/dump_stabs_unittest.cc +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dump_stabs_unittest.cc: Unit tests for DumpStabsHandler. - -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/linux/dump_stabs.h" - -using google_breakpad::DumpStabsHandler; -using google_breakpad::Module; -using std::vector; - -TEST(DumpStabsHandler, SimpleCU) { - Module m("name", "os", "arch", "id"); - DumpStabsHandler h(&m); - - // Feed in a simple compilation unit that defines a function with - // one line. - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0x9f4d1271e50db93bLL, - "build-directory")); - EXPECT_TRUE(h.StartFunction("function", 0xfde4abbed390c394LL)); - EXPECT_TRUE(h.Line(0xfde4abbed390c394LL, "source-file-name", 174823314)); - EXPECT_TRUE(h.EndFunction(0xfde4abbed390c3a4LL)); - EXPECT_TRUE(h.EndCompilationUnit(0xfee4abbed390c3a4LL)); - h.Finalize(); - - // Now check to see what has been added to the Module. - Module::File *file = m.FindExistingFile("source-file-name"); - ASSERT_TRUE(file != NULL); - - vector<Module::Function *> functions; - m.GetFunctions(&functions, functions.end()); - ASSERT_EQ((size_t) 1, functions.size()); - Module::Function *function = functions[0]; - EXPECT_STREQ("function", function->name.c_str()); - EXPECT_EQ(0xfde4abbed390c394LL, function->address); - EXPECT_EQ(0x10U, function->size); - EXPECT_EQ(0U, function->parameter_size); - ASSERT_EQ((size_t) 1, function->lines.size()); - Module::Line *line = &function->lines[0]; - EXPECT_EQ(0xfde4abbed390c394LL, line->address); - EXPECT_EQ(0x10U, line->size); // derived from EndFunction - EXPECT_TRUE(line->file == file); - EXPECT_EQ(174823314, line->number); -} - -TEST(InferSizes, LineSize) { - Module m("name", "os", "arch", "id"); - DumpStabsHandler h(&m); - - // Feed in a simple compilation unit that defines a function with - // one line. - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xb4513962eff94e92LL, - "build-directory")); - EXPECT_TRUE(h.StartFunction("function", 0xb4513962eff94e92LL)); - EXPECT_TRUE(h.Line(0xb4513962eff94e92LL, "source-file-name-1", 77396614)); - EXPECT_TRUE(h.Line(0xb4513963eff94e92LL, "source-file-name-2", 87660088)); - EXPECT_TRUE(h.EndFunction(0)); // unknown function end address - EXPECT_TRUE(h.EndCompilationUnit(0)); // unknown CU end address - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit-2", 0xb4523963eff94e92LL, - "build-directory-2")); // next boundary - EXPECT_TRUE(h.EndCompilationUnit(0)); - h.Finalize(); - - // Now check to see what has been added to the Module. - Module::File *file1 = m.FindExistingFile("source-file-name-1"); - ASSERT_TRUE(file1 != NULL); - Module::File *file2 = m.FindExistingFile("source-file-name-2"); - ASSERT_TRUE(file2 != NULL); - - vector<Module::Function *> functions; - m.GetFunctions(&functions, functions.end()); - ASSERT_EQ((size_t) 1, functions.size()); - - Module::Function *function = functions[0]; - EXPECT_STREQ("function", function->name.c_str()); - EXPECT_EQ(0xb4513962eff94e92LL, function->address); - EXPECT_EQ(0x1000100000000ULL, function->size); // inferred from CU end - EXPECT_EQ(0U, function->parameter_size); - ASSERT_EQ((size_t) 2, function->lines.size()); - - Module::Line *line1 = &function->lines[0]; - EXPECT_EQ(0xb4513962eff94e92LL, line1->address); - EXPECT_EQ(0x100000000ULL, line1->size); // derived from EndFunction - EXPECT_TRUE(line1->file == file1); - EXPECT_EQ(77396614, line1->number); - - Module::Line *line2 = &function->lines[1]; - EXPECT_EQ(0xb4513963eff94e92LL, line2->address); - EXPECT_EQ(0x1000000000000ULL, line2->size); // derived from EndFunction - EXPECT_TRUE(line2->file == file2); - EXPECT_EQ(87660088, line2->number); -} - -TEST(FunctionNames, Mangled) { - Module m("name", "os", "arch", "id"); - DumpStabsHandler h(&m); - - // Compilation unit with one function, mangled name. - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xf2cfda63cef7f46cLL, - "build-directory")); - EXPECT_TRUE(h.StartFunction("_ZNSt6vectorIySaIyEE9push_backERKy", - 0xf2cfda63cef7f46dLL)); - EXPECT_TRUE(h.EndFunction(0)); - EXPECT_TRUE(h.EndCompilationUnit(0)); - - h.Finalize(); - - // Now check to see what has been added to the Module. - Module::File *file = m.FindExistingFile("compilation-unit"); - ASSERT_TRUE(file != NULL); - - vector<Module::Function *> functions; - m.GetFunctions(&functions, functions.end()); - ASSERT_EQ(1U, functions.size()); - - Module::Function *function = functions[0]; - // This is GCC-specific, but we shouldn't be seeing STABS data anywhere - // but Linux. - EXPECT_STREQ("std::vector<unsigned long long, " - "std::allocator<unsigned long long> >::" - "push_back(unsigned long long const&)", - function->name.c_str()); - EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address); - EXPECT_LT(0U, function->size); // should have used dummy size - EXPECT_EQ(0U, function->parameter_size); - ASSERT_EQ(0U, function->lines.size()); -} - -// The GNU toolchain can omit functions that are not used; however, -// when it does so, it doesn't clean up the debugging information that -// refers to them. In STABS, this results in compilation units whose -// SO addresses are zero. -TEST(Omitted, Function) { - Module m("name", "os", "arch", "id"); - DumpStabsHandler h(&m); - - // The StartCompilationUnit and EndCompilationUnit calls may both have an - // address of zero if the compilation unit has had sections removed. - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0, "build-directory")); - EXPECT_TRUE(h.StartFunction("function", 0x2a133596)); - EXPECT_TRUE(h.EndFunction(0)); - EXPECT_TRUE(h.EndCompilationUnit(0)); -} - -// TODO --- if we actually cared about STABS. Even without these we've -// got full coverage of non-failure source lines in dump_stabs.cc. - -// Line size from next line -// Line size from function end -// Line size from next function start -// line size from cu end -// line size from next cu start -// fallback size is something plausible - -// function size from function end -// function size from next function start -// function size from cu end -// function size from next cu start -// fallback size is something plausible - -// omitting functions outside the compilation unit's address range -// zero-line, one-line, many-line functions diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index eecacd59..ea55cc7b 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -48,14 +48,14 @@ #include "common/dwarf/bytereader-inl.h" #include "common/dwarf/dwarf2diehandler.h" -#include "common/linux/dump_stabs.h" +#include "common/dump_stabs.h" #include "common/linux/dump_symbols.h" -#include "common/linux/dwarf_cfi_to_module.h" -#include "common/linux/dwarf_cu_to_module.h" -#include "common/linux/dwarf_line_to_module.h" +#include "common/dwarf_cfi_to_module.h" +#include "common/dwarf_cu_to_module.h" +#include "common/dwarf_line_to_module.h" #include "common/linux/file_id.h" -#include "common/linux/module.h" -#include "common/linux/stabs_reader.h" +#include "common/module.h" +#include "common/stabs_reader.h" // This namespace contains helper functions. namespace { diff --git a/src/common/linux/dwarf_cfi_to_module.cc b/src/common/linux/dwarf_cfi_to_module.cc deleted file mode 100644 index 603acc0e..00000000 --- a/src/common/linux/dwarf_cfi_to_module.cc +++ /dev/null @@ -1,185 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Implementation of google_breakpad::DwarfCFIToModule. -// See dwarf_cfi_to_module.h for details. - -#include <sstream> - -#include "common/linux/dwarf_cfi_to_module.h" - -namespace google_breakpad { - -using std::ostringstream; - -bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length, - uint8 version, const string &augmentation, - unsigned return_address) { - assert(!entry_); - - // If dwarf2reader::CallFrameInfo can handle this version and - // augmentation, then we should be okay with that, so there's no - // need to check them here. - - // Get ready to collect entries. - entry_ = new Module::StackFrameEntry; - entry_->address = address; - entry_->size = length; - entry_offset_ = offset; - return_address_ = return_address; - - // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI - // may not establish any rule for .ra if the return address column - // is an ordinary register, and that register holds the return - // address on entry to the function. So establish an initial .ra - // rule citing the return address register. - if (return_address_ < register_names_.size()) - entry_->initial_rules[".ra"] = register_names_[return_address_]; - - return true; -} - -string DwarfCFIToModule::RegisterName(int i) { - assert(entry_); - if (i < 0) { - assert(i == kCFARegister); - return ".cfa"; - } - unsigned reg = i; - if (reg == return_address_) - return ".ra"; - - if (0 <= reg && reg < register_names_.size()) - return register_names_[reg]; - - reporter_->UnnamedRegister(entry_offset_, reg); - char buf[30]; - sprintf(buf, "unnamed_register%u", reg); - return buf; -} - -void DwarfCFIToModule::Record(Module::Address address, int reg, - const string &rule) { - assert(entry_); - // Is this one of this entry's initial rules? - if (address == entry_->address) - entry_->initial_rules[RegisterName(reg)] = rule; - // File it under the appropriate address. - else - entry_->rule_changes[address][RegisterName(reg)] = rule; -} - -bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) { - reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg)); - // Treat this as a non-fatal error. - return true; -} - -bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) { - ostringstream s; - s << RegisterName(reg); - Record(address, reg, s.str()); - return true; -} - -bool DwarfCFIToModule::OffsetRule(uint64 address, int reg, - int base_register, long offset) { - ostringstream s; - s << RegisterName(base_register) << " " << offset << " + ^"; - Record(address, reg, s.str()); - return true; -} - -bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg, - int base_register, long offset) { - ostringstream s; - s << RegisterName(base_register) << " " << offset << " +"; - Record(address, reg, s.str()); - return true; -} - -bool DwarfCFIToModule::RegisterRule(uint64 address, int reg, - int base_register) { - ostringstream s; - s << RegisterName(base_register); - Record(address, reg, s.str()); - return true; -} - -bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg, - const string &expression) { - reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); - // Treat this as a non-fatal error. - return true; -} - -bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg, - const string &expression) { - reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); - // Treat this as a non-fatal error. - return true; -} - -bool DwarfCFIToModule::End() { - module_->AddStackFrameEntry(entry_); - entry_ = NULL; - return true; -} - -void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { - fprintf(stderr, "%s, section '%s': " - "the call frame entry at offset 0x%zx refers to register %d," - " whose name we don't know\n", - file_.c_str(), section_.c_str(), offset, reg); -} - -void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset, - const string ®) { - fprintf(stderr, "%s, section '%s': " - "the call frame entry at offset 0x%zx sets the rule for " - "register '%s' to 'undefined', but the Breakpad symbol file format" - " cannot express this\n", - file_.c_str(), section_.c_str(), offset, reg.c_str()); -} - -void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset, - const string ®) { - fprintf(stderr, "%s, section '%s': " - "the call frame entry at offset 0x%zx uses a DWARF expression to" - " describe how to recover register '%s', " - " but this translator cannot yet translate DWARF expressions to" - " Breakpad postfix expressions\n", - file_.c_str(), section_.c_str(), offset, reg.c_str()); -} - -} // namespace google_breakpad diff --git a/src/common/linux/dwarf_cfi_to_module.h b/src/common/linux/dwarf_cfi_to_module.h deleted file mode 100644 index 9df796f5..00000000 --- a/src/common/linux/dwarf_cfi_to_module.h +++ /dev/null @@ -1,154 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_cfi_to_module.h: Define the DwarfCFIToModule class, which -// accepts parsed DWARF call frame info and adds it to a -// google_breakpad::Module object, which can write that information to -// a Breakpad symbol file. - -#ifndef COMMON_LINUX_DWARF_CFI_TO_MODULE_H -#define COMMON_LINUX_DWARF_CFI_TO_MODULE_H - -#include <cassert> -#include <string> -#include <vector> - -#include "common/linux/module.h" -#include "common/dwarf/dwarf2reader.h" - -namespace google_breakpad { - -using dwarf2reader::CallFrameInfo; -using google_breakpad::Module; -using std::string; -using std::vector; - -// A class that accepts parsed call frame information from the DWARF -// CFI parser and populates a google_breakpad::Module object with the -// contents. -class DwarfCFIToModule: public CallFrameInfo::Handler { - public: - - // DwarfCFIToModule uses an instance of this class to report errors - // detected while converting DWARF CFI to Breakpad STACK CFI records. - class Reporter { - public: - // Create a reporter that writes messages to the standard error - // stream. FILE is the name of the file we're processing, and - // SECTION is the name of the section within that file that we're - // looking at (.debug_frame, .eh_frame, etc.). - Reporter(const string &file, const string §ion) - : file_(file), section_(section) { } - virtual ~Reporter() { } - - // The DWARF CFI entry at OFFSET cites register REG, but REG is not - // covered by the vector of register names passed to the - // DwarfCFIToModule constructor, nor does it match the return - // address column number for this entry. - virtual void UnnamedRegister(size_t offset, int reg); - - // The DWARF CFI entry at OFFSET says that REG is undefined, but the - // Breakpad symbol file format cannot express this. - virtual void UndefinedNotSupported(size_t offset, const string ®); - - // The DWARF CFI entry at OFFSET says that REG uses a DWARF - // expression to find its value, but DwarfCFIToModule is not - // capable of translating DWARF expressions to Breakpad postfix - // expressions. - virtual void ExpressionsNotSupported(size_t offset, const string ®); - - protected: - string file_, section_; - }; - - // Create a handler for the dwarf2reader::CallFrameInfo parser that - // records the stack unwinding information it receives in MODULE. - // - // Use REGISTER_NAMES[I] as the name of register number I; *this - // keeps a reference to the vector, so the vector should remain - // alive for as long as the DwarfCFIToModule does. - // - // Use REPORTER for reporting problems encountered in the conversion - // process. - DwarfCFIToModule(Module *module, const vector<string> ®ister_names, - Reporter *reporter) - : module_(module), register_names_(register_names), reporter_(reporter), - entry_(NULL), return_address_(-1) { } - virtual ~DwarfCFIToModule() { delete entry_; } - - virtual bool Entry(size_t offset, uint64 address, uint64 length, - uint8 version, const string &augmentation, - unsigned return_address); - virtual bool UndefinedRule(uint64 address, int reg); - virtual bool SameValueRule(uint64 address, int reg); - virtual bool OffsetRule(uint64 address, int reg, - int base_register, long offset); - virtual bool ValOffsetRule(uint64 address, int reg, - int base_register, long offset); - virtual bool RegisterRule(uint64 address, int reg, int base_register); - virtual bool ExpressionRule(uint64 address, int reg, - const string &expression); - virtual bool ValExpressionRule(uint64 address, int reg, - const string &expression); - virtual bool End(); - - private: - // Return the name to use for register REG. - string RegisterName(int i); - - // Record RULE for register REG at ADDRESS. - void Record(Module::Address address, int reg, const string &rule); - - // The module to which we should add entries. - Module *module_; - - // Map from register numbers to register names. - const vector<string> ®ister_names_; - - // The reporter to use to report problems. - Reporter *reporter_; - - // The current entry we're constructing. - Module::StackFrameEntry *entry_; - - // The section offset of the current frame description entry, for - // use in error messages. - size_t entry_offset_; - - // The return address column for that entry. - unsigned return_address_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_DWARF_CFI_TO_MODULE_H diff --git a/src/common/linux/dwarf_cfi_to_module_unittest.cc b/src/common/linux/dwarf_cfi_to_module_unittest.cc deleted file mode 100644 index d7b08aef..00000000 --- a/src/common/linux/dwarf_cfi_to_module_unittest.cc +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule. - -#include "breakpad_googletest_includes.h" -#include "common/linux/dwarf_cfi_to_module.h" - -using google_breakpad::Module; -using google_breakpad::DwarfCFIToModule; -using testing::ContainerEq; -using testing::Test; -using testing::_; - -struct MockCFIReporter: public DwarfCFIToModule::Reporter { - MockCFIReporter(const string &file, const string §ion) - : Reporter(file, section) { } - MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg)); - MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string ®)); - MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string ®)); -}; - -struct DwarfCFIToModuleFixture { - DwarfCFIToModuleFixture() - : module("module name", "module os", "module arch", "module id"), - reporter("reporter file", "reporter section"), - handler(&module, register_names, &reporter) { - register_names.push_back("reg0"); - register_names.push_back("reg1"); - register_names.push_back("reg2"); - register_names.push_back("reg3"); - register_names.push_back("reg4"); - register_names.push_back("reg5"); - register_names.push_back("reg6"); - register_names.push_back("reg7"); - register_names.push_back("sp"); - register_names.push_back("pc"); - - EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0); - EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0); - EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0); - } - - Module module; - vector<string> register_names; - MockCFIReporter reporter; - DwarfCFIToModule handler; - vector<Module::StackFrameEntry *> entries; -}; - -class Entry: public DwarfCFIToModuleFixture, public Test { }; - -TEST_F(Entry, Accept) { - ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL, - 0xb440ce248169c8d6ULL, 3, "", 0xea93c106)); - ASSERT_TRUE(handler.End()); - module.GetStackFrameEntries(&entries); - EXPECT_EQ(1U, entries.size()); - EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address); - EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Entry, AcceptOldVersion) { - ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL, - 0xc771f44958d40bbcULL, 1, "", 0x093c945e)); - ASSERT_TRUE(handler.End()); - module.GetStackFrameEntries(&entries); - EXPECT_EQ(1U, entries.size()); - EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address); - EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -struct RuleFixture: public DwarfCFIToModuleFixture { - RuleFixture() : DwarfCFIToModuleFixture() { - entry_address = 0x89327ebf86b47492ULL; - entry_size = 0x2f8cd573072fe02aULL; - return_reg = 0x7886a346; - } - void StartEntry() { - ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size, - 3, "", return_reg)); - } - void CheckEntry() { - module.GetStackFrameEntries(&entries); - EXPECT_EQ(1U, entries.size()); - EXPECT_EQ(entry_address, entries[0]->address); - EXPECT_EQ(entry_size, entries[0]->size); - } - uint64 entry_address, entry_size; - unsigned return_reg; -}; - -class Rule: public RuleFixture, public Test { }; - -TEST_F(Rule, UndefinedRule) { - EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7")); - StartEntry(); - ASSERT_TRUE(handler.UndefinedRule(entry_address, 7)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, SameValueRule) { - StartEntry(); - ASSERT_TRUE(handler.SameValueRule(entry_address, 6)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial["reg6"] = "reg6"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, OffsetRule) { - StartEntry(); - ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg, - DwarfCFIToModule::kCFARegister, - 16927065)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^"; - EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); -} - -TEST_F(Rule, OffsetRuleNegative) { - StartEntry(); - ASSERT_TRUE(handler.OffsetRule(entry_address + 1, - DwarfCFIToModule::kCFARegister, 4, -34530721)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^"; - EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); -} - -TEST_F(Rule, ValOffsetRule) { - // Use an unnamed register number, to exercise that branch of RegisterName. - EXPECT_CALL(reporter, UnnamedRegister(_, 10)); - StartEntry(); - ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7, - DwarfCFIToModule::kCFARegister, - 10, 61812979)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 0x5ab7][".cfa"] = - "unnamed_register10 61812979 +"; - EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); -} - -TEST_F(Rule, RegisterRule) { - StartEntry(); - ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial[".ra"] = "reg3"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, ExpressionRule) { - EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2")); - StartEntry(); - ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2, - "it takes two to tango")); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, ValExpressionRule) { - EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0")); - StartEntry(); - ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0, - "bit off more than he could chew")); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, DefaultReturnAddressRule) { - return_reg = 2; - StartEntry(); - ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial[".ra"] = "reg2"; - expected_initial["reg0"] = "reg1"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, DefaultReturnAddressRuleOverride) { - return_reg = 2; - StartEntry(); - ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial[".ra"] = "reg1"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, DefaultReturnAddressRuleLater) { - return_reg = 2; - StartEntry(); - ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial[".ra"] = "reg2"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 1][".ra"] = "reg1"; - EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); -} - diff --git a/src/common/linux/dwarf_cu_to_module.cc b/src/common/linux/dwarf_cu_to_module.cc deleted file mode 100644 index 59efebc4..00000000 --- a/src/common/linux/dwarf_cu_to_module.cc +++ /dev/null @@ -1,881 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Implement the DwarfCUToModule class; see dwarf_cu_to_module.h. - -#include <algorithm> -#include <cassert> - -#include "common/linux/dwarf_cu_to_module.h" -#include "common/linux/dwarf_line_to_module.h" - -namespace google_breakpad { - -using std::map; -using std::vector; - -// Data provided by a DWARF specification DIE. -// -// In DWARF, the DIE for a definition may contain a DW_AT_specification -// attribute giving the offset of the corresponding declaration DIE, and -// the definition DIE may omit information given in the declaration. For -// example, it's common for a function's address range to appear only in -// its definition DIE, but its name to appear only in its declaration -// DIE. -// -// The dumper needs to be able to follow DW_AT_specification links to -// bring all this information together in a FUNC record. Conveniently, -// DIEs that are the target of such links have a DW_AT_declaration flag -// set, so we can identify them when we first see them, and record their -// contents for later reference. -// -// A Specification holds information gathered from a declaration DIE that -// we may need if we find a DW_AT_specification link pointing to it. -struct DwarfCUToModule::Specification { - // The name of the enclosing scope, or the empty string if there is none. - string enclosing_name; - - // The name for the specification DIE itself, without any enclosing - // name components. - string unqualified_name; -}; - -// An abstract origin -- base definition of an inline function. -struct AbstractOrigin { - AbstractOrigin() : name() {} - AbstractOrigin(const string& name) : name(name) {} - - string name; -}; - -typedef map<uint64, AbstractOrigin> AbstractOriginByOffset; - -// Data global to the DWARF-bearing file that is private to the -// DWARF-to-Module process. -struct DwarfCUToModule::FilePrivate { - // A map from offsets of DIEs within the .debug_info section to - // Specifications describing those DIEs. Specification references can - // cross compilation unit boundaries. - SpecificationByOffset specifications; - - AbstractOriginByOffset origins; -}; - -DwarfCUToModule::FileContext::FileContext(const string &filename_arg, - Module *module_arg) - : filename(filename_arg), module(module_arg) { - file_private = new FilePrivate(); -} - -DwarfCUToModule::FileContext::~FileContext() { - delete file_private; -} - -// Information global to the particular compilation unit we're -// parsing. This is for data shared across the CU's entire DIE tree, -// and parameters from the code invoking the CU parser. -struct DwarfCUToModule::CUContext { - CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg) - : file_context(file_context_arg), - reporter(reporter_arg), - language(Language::CPlusPlus) { } - ~CUContext() { - for (vector<Module::Function *>::iterator it = functions.begin(); - it != functions.end(); it++) - delete *it; - }; - - // The DWARF-bearing file into which this CU was incorporated. - FileContext *file_context; - - // For printing error messages. - WarningReporter *reporter; - - // The source language of this compilation unit. - const Language *language; - - // The functions defined in this compilation unit. We accumulate - // them here during parsing. Then, in DwarfCUToModule::Finish, we - // assign them lines and add them to file_context->module. - // - // Destroying this destroys all the functions this vector points to. - vector<Module::Function *> functions; -}; - -// Information about the context of a particular DIE. This is for -// information that changes as we descend the tree towards the leaves: -// the containing classes/namespaces, etc. -struct DwarfCUToModule::DIEContext { - // The fully-qualified name of the context. For example, for a - // tree like: - // - // DW_TAG_namespace Foo - // DW_TAG_class Bar - // DW_TAG_subprogram Baz - // - // in a C++ compilation unit, the DIEContext's name for the - // DW_TAG_subprogram DIE would be "Foo::Bar". The DIEContext's - // name for the DW_TAG_namespace DIE would be "". - string name; -}; - -// An abstract base class for all the dumper's DIE handlers. -class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { - public: - // Create a handler for the DIE at OFFSET whose compilation unit is - // described by CU_CONTEXT, and whose immediate context is described - // by PARENT_CONTEXT. - GenericDIEHandler(CUContext *cu_context, DIEContext *parent_context, - uint64 offset) - : cu_context_(cu_context), - parent_context_(parent_context), - offset_(offset), - declaration_(false), - specification_(NULL) { } - - // Derived classes' ProcessAttributeUnsigned can defer to this to - // handle DW_AT_declaration, or simply not override it. - void ProcessAttributeUnsigned(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - - // Derived classes' ProcessAttributeReference can defer to this to - // handle DW_AT_specification, or simply not override it. - void ProcessAttributeReference(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - - // Derived classes' ProcessAttributeReference can defer to this to - // handle DW_AT_specification, or simply not override it. - void ProcessAttributeString(enum DwarfAttribute attr, - enum DwarfForm form, - const string &data); - - protected: - // Compute and return the fully-qualified name of the DIE. If this - // DIE is a declaration DIE, to be cited by other DIEs' - // DW_AT_specification attributes, record its enclosing name and - // unqualified name in the specification table. - // - // Use this from EndAttributes member functions, not ProcessAttribute* - // functions; only the former can be sure that all the DIE's attributes - // have been seen. - string ComputeQualifiedName(); - - CUContext *cu_context_; - DIEContext *parent_context_; - uint64 offset_; - - // If this DIE has a DW_AT_declaration attribute, this is its value. - // It is false on DIEs with no DW_AT_declaration attribute. - bool declaration_; - - // If this DIE has a DW_AT_specification attribute, this is the - // Specification structure for the DIE the attribute refers to. - // Otherwise, this is NULL. - Specification *specification_; - - // The value of the DW_AT_name attribute, or the empty string if the - // DIE has no such attribute. - string name_attribute_; -}; - -void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned( - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch (attr) { - case dwarf2reader::DW_AT_declaration: declaration_ = (data != 0); break; - default: break; - } -} - -void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch (attr) { - case dwarf2reader::DW_AT_specification: { - // Find the Specification to which this attribute refers, and - // set specification_ appropriately. We could do more processing - // here, but it's better to leave the real work to our - // EndAttribute member function, at which point we know we have - // seen all the DIE's attributes. - FileContext *file_context = cu_context_->file_context; - SpecificationByOffset *specifications - = &file_context->file_private->specifications; - SpecificationByOffset::iterator spec = specifications->find(data); - if (spec != specifications->end()) { - specification_ = &spec->second; - } else { - // Technically, there's no reason a DW_AT_specification - // couldn't be a forward reference, but supporting that would - // be a lot of work (changing to a two-pass structure), and I - // don't think any producers we care about ever emit such - // things. - cu_context_->reporter->UnknownSpecification(offset_, data); - } - break; - } - default: break; - } -} - -void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( - enum DwarfAttribute attr, - enum DwarfForm form, - const string &data) { - switch (attr) { - case dwarf2reader::DW_AT_name: name_attribute_ = data; break; - default: break; - } -} - -string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { - // Find our unqualified name. If the DIE has its own DW_AT_name - // attribute, then use that; otherwise, check our specification. - const string *unqualified_name; - if (name_attribute_.empty() && specification_) - unqualified_name = &specification_->unqualified_name; - else - unqualified_name = &name_attribute_; - - // Find the name of our enclosing context. If we have a - // specification, it's the specification's enclosing context that - // counts; otherwise, use this DIE's context. - const string *enclosing_name; - if (specification_) - enclosing_name = &specification_->enclosing_name; - else - enclosing_name = &parent_context_->name; - - // If this DIE was marked as a declaration, record its names in the - // specification table. - if (declaration_) { - FileContext *file_context = cu_context_->file_context; - Specification spec; - spec.enclosing_name = *enclosing_name; - spec.unqualified_name = *unqualified_name; - file_context->file_private->specifications[offset_] = spec; - } - - // Combine the enclosing name and unqualified name to produce our - // own fully-qualified name. - return cu_context_->language->MakeQualifiedName(*enclosing_name, - *unqualified_name); -} - -// A handler class for DW_TAG_subprogram DIEs. -class DwarfCUToModule::FuncHandler: public GenericDIEHandler { - public: - FuncHandler(CUContext *cu_context, DIEContext *parent_context, - uint64 offset) - : GenericDIEHandler(cu_context, parent_context, offset), - low_pc_(0), high_pc_(0), abstract_origin_(NULL), inline_(false) { } - void ProcessAttributeUnsigned(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - void ProcessAttributeSigned(enum DwarfAttribute attr, - enum DwarfForm form, - int64 data); - void ProcessAttributeReference(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - - bool EndAttributes(); - void Finish(); - - private: - // The fully-qualified name, as derived from name_attribute_, - // specification_, parent_context_. Computed in EndAttributes. - string name_; - uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc - const AbstractOrigin* abstract_origin_; - bool inline_; -}; - -void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch (attr) { - // If this attribute is present at all --- even if its value is - // DW_INL_not_inlined --- then GCC may cite it as someone else's - // DW_AT_abstract_origin attribute. - case dwarf2reader::DW_AT_inline: inline_ = true; break; - - case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break; - case dwarf2reader::DW_AT_high_pc: high_pc_ = data; break; - default: - GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); - break; - } -} - -void DwarfCUToModule::FuncHandler::ProcessAttributeSigned( - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { - switch (attr) { - // If this attribute is present at all --- even if its value is - // DW_INL_not_inlined --- then GCC may cite it as someone else's - // DW_AT_abstract_origin attribute. - case dwarf2reader::DW_AT_inline: inline_ = true; break; - - default: - break; - } -} - -void DwarfCUToModule::FuncHandler::ProcessAttributeReference( - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch(attr) { - case dwarf2reader::DW_AT_abstract_origin: { - const AbstractOriginByOffset& origins = - cu_context_->file_context->file_private->origins; - AbstractOriginByOffset::const_iterator origin = origins.find(data); - if (origin != origins.end()) { - abstract_origin_ = &(origin->second); - } else { - cu_context_->reporter->UnknownAbstractOrigin(offset_, data); - } - break; - } - default: - GenericDIEHandler::ProcessAttributeReference(attr, form, data); - break; - } -} - -bool DwarfCUToModule::FuncHandler::EndAttributes() { - // Compute our name, and record a specification, if appropriate. - name_ = ComputeQualifiedName(); - if (name_.empty() && abstract_origin_) { - name_ = abstract_origin_->name; - } - return true; -} - -void DwarfCUToModule::FuncHandler::Finish() { - // Did we collect the information we need? Not all DWARF function - // entries have low and high addresses (for example, inlined - // functions that were never used), but all the ones we're - // interested in cover a non-empty range of bytes. - if (low_pc_ < high_pc_) { - // Create a Module::Function based on the data we've gathered, and - // add it to the functions_ list. - Module::Function *func = new Module::Function; - func->name = name_; - func->address = low_pc_; - func->size = high_pc_ - low_pc_; - func->parameter_size = 0; - cu_context_->functions.push_back(func); - } else if (inline_) { - AbstractOrigin origin(name_); - cu_context_->file_context->file_private->origins[offset_] = origin; - } -} - -// A handler for DIEs that contain functions and contribute a -// component to their names: namespaces, classes, etc. -class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler { - public: - NamedScopeHandler(CUContext *cu_context, DIEContext *parent_context, - uint64 offset) - : GenericDIEHandler(cu_context, parent_context, offset) { } - bool EndAttributes(); - DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag, - const AttributeList &attrs); - - private: - DIEContext child_context_; // A context for our children. -}; - -bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { - child_context_.name = ComputeQualifiedName(); - return true; -} - -dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler( - uint64 offset, - enum DwarfTag tag, - const AttributeList &attrs) { - switch (tag) { - case dwarf2reader::DW_TAG_subprogram: - return new FuncHandler(cu_context_, &child_context_, offset); - case dwarf2reader::DW_TAG_namespace: - case dwarf2reader::DW_TAG_class_type: - case dwarf2reader::DW_TAG_structure_type: - case dwarf2reader::DW_TAG_union_type: - return new NamedScopeHandler(cu_context_, &child_context_, offset); - default: - return NULL; - } -}; - -void DwarfCUToModule::WarningReporter::CUHeading() { - if (printed_cu_header_) - return; - fprintf(stderr, "%s: in compilation unit '%s' (offset 0x%llx):\n", - filename_.c_str(), cu_name_.c_str(), cu_offset_); - printed_cu_header_ = true; -} - -void DwarfCUToModule::WarningReporter::UnknownSpecification(uint64 offset, - uint64 target) { - CUHeading(); - fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_specification" - " attribute referring to the die at offset 0x%llx, which either" - " was not marked as a declaration, or comes later in the file\n", - filename_.c_str(), offset, target); -} - -void DwarfCUToModule::WarningReporter::UnknownAbstractOrigin(uint64 offset, - uint64 target) { - CUHeading(); - fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_abstract_origin" - " attribute referring to the die at offset 0x%llx, which either" - " was not marked as an inline, or comes later in the file\n", - filename_.c_str(), offset, target); -} - -void DwarfCUToModule::WarningReporter::MissingSection(const string &name) { - CUHeading(); - fprintf(stderr, "%s: warning: couldn't find DWARF '%s' section\n", - filename_.c_str(), name.c_str()); -} - -void DwarfCUToModule::WarningReporter::BadLineInfoOffset(uint64 offset) { - CUHeading(); - fprintf(stderr, "%s: warning: line number data offset beyond end" - " of '.debug_line' section\n", - filename_.c_str()); -} - -void DwarfCUToModule::WarningReporter::UncoveredHeading() { - if (printed_unpaired_header_) - return; - CUHeading(); - fprintf(stderr, "%s: warning: skipping unpaired lines/functions:\n", - filename_.c_str()); - printed_unpaired_header_ = true; -} - -void DwarfCUToModule::WarningReporter::UncoveredFunction( - const Module::Function &function) { - if (!uncovered_warnings_enabled_) - return; - UncoveredHeading(); - fprintf(stderr, " function%s: %s\n", - function.size == 0 ? " (zero-length)" : "", - function.name.c_str()); -} - -void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) { - if (!uncovered_warnings_enabled_) - return; - UncoveredHeading(); - fprintf(stderr, " line%s: %s:%d at 0x%llx\n", - (line.size == 0 ? " (zero-length)" : ""), - line.file->name.c_str(), line.number, line.address); -} - -DwarfCUToModule::DwarfCUToModule(FileContext *file_context, - LineToModuleFunctor *line_reader, - WarningReporter *reporter) - : line_reader_(line_reader), has_source_line_info_(false) { - cu_context_ = new CUContext(file_context, reporter); - child_context_ = new DIEContext(); -} - -DwarfCUToModule::~DwarfCUToModule() { - delete cu_context_; - delete child_context_; -} - -void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { - switch (attr) { - case dwarf2reader::DW_AT_language: // source language of this CU - SetLanguage(static_cast<DwarfLanguage>(data)); - break; - default: - break; - } -} - -void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch (attr) { - case dwarf2reader::DW_AT_stmt_list: // Line number information. - has_source_line_info_ = true; - source_line_offset_ = data; - break; - case dwarf2reader::DW_AT_language: // source language of this CU - SetLanguage(static_cast<DwarfLanguage>(data)); - break; - default: - break; - } -} - -void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr, - enum DwarfForm form, - const string &data) { - if (attr == dwarf2reader::DW_AT_name) - cu_context_->reporter->SetCUName(data); -} - -bool DwarfCUToModule::EndAttributes() { - return true; -} - -dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler( - uint64 offset, - enum DwarfTag tag, - const AttributeList &attrs) { - switch (tag) { - case dwarf2reader::DW_TAG_subprogram: - return new FuncHandler(cu_context_, child_context_, offset); - case dwarf2reader::DW_TAG_namespace: - case dwarf2reader::DW_TAG_class_type: - case dwarf2reader::DW_TAG_structure_type: - case dwarf2reader::DW_TAG_union_type: - return new NamedScopeHandler(cu_context_, child_context_, offset); - default: - return NULL; - } -} - -void DwarfCUToModule::SetLanguage(DwarfLanguage language) { - switch (language) { - case dwarf2reader::DW_LANG_Java: - cu_context_->language = Language::Java; - break; - - // DWARF has no generic language code for assembly language; this is - // what the GNU toolchain uses. - case dwarf2reader::DW_LANG_Mips_Assembler: - cu_context_->language = Language::Assembler; - break; - - // C++ covers so many cases that it probably has some way to cope - // with whatever the other languages throw at us. So make it the - // default. - // - // Objective C and Objective C++ seem to create entries for - // methods whose DW_AT_name values are already fully-qualified: - // "-[Classname method:]". These appear at the top level. - // - // DWARF data for C should never include namespaces or functions - // nested in struct types, but if it ever does, then C++'s - // notation is probably not a bad choice for that. - default: - case dwarf2reader::DW_LANG_ObjC: - case dwarf2reader::DW_LANG_ObjC_plus_plus: - case dwarf2reader::DW_LANG_C: - case dwarf2reader::DW_LANG_C89: - case dwarf2reader::DW_LANG_C99: - case dwarf2reader::DW_LANG_C_plus_plus: - cu_context_->language = Language::CPlusPlus; - break; - } -} - -void DwarfCUToModule::ReadSourceLines(uint64 offset) { - const dwarf2reader::SectionMap §ion_map - = cu_context_->file_context->section_map; - dwarf2reader::SectionMap::const_iterator map_entry - = section_map.find(".debug_line"); - if (map_entry == section_map.end()) { - cu_context_->reporter->MissingSection(".debug_line"); - return; - } - const char *section_start = map_entry->second.first; - uint64 section_length = map_entry->second.second; - if (offset >= section_length) { - cu_context_->reporter->BadLineInfoOffset(offset); - return; - } - (*line_reader_)(section_start + offset, section_length - offset, - cu_context_->file_context->module, &lines_); -} - -namespace { -// Return true if ADDRESS falls within the range of ITEM. -template <class T> -inline bool within(const T &item, Module::Address address) { - // Because Module::Address is unsigned, and unsigned arithmetic - // wraps around, this will be false if ADDRESS falls before the - // start of ITEM, or if it falls after ITEM's end. - return address - item.address < item.size; -} -} - -void DwarfCUToModule::AssignLinesToFunctions() { - vector<Module::Function *> *functions = &cu_context_->functions; - WarningReporter *reporter = cu_context_->reporter; - - // This would be simpler if we assumed that source line entries - // don't cross function boundaries. However, there's no real reason - // to assume that (say) a series of function definitions on the same - // line wouldn't get coalesced into one line number entry. The - // DWARF spec certainly makes no such promises. - // - // So treat the functions and lines as peers, and take the trouble - // to compute their ranges' intersections precisely. In any case, - // the hair here is a constant factor for performance; the - // complexity from here on out is linear. - - // Put both our functions and lines in order by address. - sort(functions->begin(), functions->end(), - Module::Function::CompareByAddress); - sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress); - - // The last line that we used any piece of. We use this only for - // generating warnings. - const Module::Line *last_line_used = NULL; - - // The last function and line we warned about --- so we can avoid - // doing so more than once. - const Module::Function *last_function_cited = NULL; - const Module::Line *last_line_cited = NULL; - - // Make a single pass through both vectors from lower to higher - // addresses, populating each Function's lines vector with lines - // from our lines_ vector that fall within the function's address - // range. - vector<Module::Function *>::iterator func_it = functions->begin(); - vector<Module::Line>::const_iterator line_it = lines_.begin(); - - Module::Address current; - - // Pointers to the referents of func_it and line_it, or NULL if the - // iterator is at the end of the sequence. - Module::Function *func; - const Module::Line *line; - - // Start current at the beginning of the first line or function, - // whichever is earlier. - if (func_it != functions->end() && line_it != lines_.end()) { - func = *func_it; - line = &*line_it; - current = std::min(func->address, line->address); - } else if (line_it != lines_.end()) { - func = NULL; - line = &*line_it; - current = line->address; - } else if (func_it != functions->end()) { - func = *func_it; - line = NULL; - current = (*func_it)->address; - } else { - return; - } - - while (func || line) { - // This loop has two invariants that hold at the top. - // - // First, at least one of the iterators is not at the end of its - // sequence, and those that are not refer to the earliest - // function or line that contains or starts after CURRENT. - // - // Note that every byte is in one of four states: it is covered - // or not covered by a function, and, independently, it is - // covered or not covered by a line. - // - // The second invariant is that CURRENT refers to a byte whose - // state is different from its predecessor, or it refers to the - // first byte in the address space. In other words, CURRENT is - // always the address of a transition. - // - // Note that, although each iteration advances CURRENT from one - // transition address to the next in each iteration, it might - // not advance the iterators. Suppose we have a function that - // starts with a line, has a gap, and then a second line, and - // suppose that we enter an iteration with CURRENT at the end of - // the first line. The next transition address is the start of - // the second line, after the gap, so the iteration should - // advance CURRENT to that point. At the head of that iteration, - // the invariants require that the line iterator be pointing at - // the second line. But this is also true at the head of the - // next. And clearly, the iteration must not change the function - // iterator. So neither iterator moves. - - // Assert the first invariant (see above). - assert(!func || current < func->address || within(*func, current)); - assert(!line || current < line->address || within(*line, current)); - - // The next transition after CURRENT. - Module::Address next_transition; - - // Figure out which state we're in, add lines or warn, and compute - // the next transition address. - if (func && current >= func->address) { - if (line && current >= line->address) { - // Covered by both a line and a function. - Module::Address func_left = func->size - (current - func->address); - Module::Address line_left = line->size - (current - line->address); - // This may overflow, but things work out. - next_transition = current + std::min(func_left, line_left); - Module::Line l = *line; - l.address = current; - l.size = next_transition - current; - func->lines.push_back(l); - last_line_used = line; - } else { - // Covered by a function, but no line. - if (func != last_function_cited) { - reporter->UncoveredFunction(*func); - last_function_cited = func; - } - if (line && within(*func, line->address)) - next_transition = line->address; - else - // If this overflows, we'll catch it below. - next_transition = func->address + func->size; - } - } else { - if (line && current >= line->address) { - // Covered by a line, but no function. - // - // If GCC emits padding after one function to align the start - // of the next, then it will attribute the padding - // instructions to the last source line of function (to reduce - // the size of the line number info), but omit it from the - // DW_AT_{low,high}_pc range given in .debug_info (since it - // costs nothing to be precise there). If we did use at least - // some of the line we're about to skip, and it ends at the - // start of the next function, then assume this is what - // happened, and don't warn. - if (line != last_line_cited - && !(func - && line == last_line_used - && func->address - line->address == line->size)) { - reporter->UncoveredLine(*line); - last_line_cited = line; - } - if (func && within(*line, func->address)) - next_transition = func->address; - else - // If this overflows, we'll catch it below. - next_transition = line->address + line->size; - } else { - // Covered by neither a function nor a line. By the invariant, - // both func and line begin after CURRENT. The next transition - // is the start of the next function or next line, whichever - // is earliest. - assert (func || line); - if (func && line) - next_transition = std::min(func->address, line->address); - else if (func) - next_transition = func->address; - else - next_transition = line->address; - } - } - - // If a function or line abuts the end of the address space, then - // next_transition may end up being zero, in which case we've completed - // our pass. Handle that here, instead of trying to deal with it in - // each place we compute next_transition. - if (!next_transition) - break; - - // Advance iterators as needed. If lines overlap or functions overlap, - // then we could go around more than once. We don't worry too much - // about what result we produce in that case, just as long as we don't - // hang or crash. - while (func_it != functions->end() - && current >= (*func_it)->address - && !within(**func_it, next_transition)) - func_it++; - func = (func_it != functions->end()) ? *func_it : NULL; - while (line_it != lines_.end() - && current >= line_it->address - && !within(*line_it, next_transition)) - line_it++; - line = (line_it != lines_.end()) ? &*line_it : NULL; - - // We must make progress. - assert(next_transition > current); - current = next_transition; - } -} - -void DwarfCUToModule::Finish() { - // Assembly language files have no function data, and that gives us - // no place to store our line numbers (even though the GNU toolchain - // will happily produce source line info for assembly language - // files). To avoid spurious warnings about lines we can't assign - // to functions, skip CUs in languages that lack functions. - if (!cu_context_->language->HasFunctions()) - return; - - // Read source line info, if we have any. - if (has_source_line_info_) - ReadSourceLines(source_line_offset_); - - vector<Module::Function *> *functions = &cu_context_->functions; - - // Dole out lines to the appropriate functions. - AssignLinesToFunctions(); - - // Add our functions, which now have source lines assigned to them, - // to module_. - cu_context_->file_context->module->AddFunctions(functions->begin(), - functions->end()); - - // Ownership of the function objects has shifted from cu_context to - // the Module. - functions->clear(); -} - -bool DwarfCUToModule::StartCompilationUnit(uint64 offset, - uint8 address_size, - uint8 offset_size, - uint64 cu_length, - uint8 dwarf_version) { - return dwarf_version >= 2; -} - -bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag, - const AttributeList& attrs) { - // We don't deal with partial compilation units (the only other tag - // likely to be used for root DIE). - return tag == dwarf2reader::DW_TAG_compile_unit; -} - -} // namespace google_breakpad diff --git a/src/common/linux/dwarf_cu_to_module.h b/src/common/linux/dwarf_cu_to_module.h deleted file mode 100644 index 8d8a0b2c..00000000 --- a/src/common/linux/dwarf_cu_to_module.h +++ /dev/null @@ -1,272 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Add DWARF debugging information to a Breakpad symbol file. This -// file defines the DwarfCUToModule class, which accepts parsed DWARF -// data and populates a google_breakpad::Module with the results; the -// Module can then write its contents as a Breakpad symbol file. - -#ifndef COMMON_LINUX_DWARF_CU_TO_MODULE_H__ -#define COMMON_LINUX_DWARF_CU_TO_MODULE_H__ - -#include <string> - -#include <elf.h> -#include <link.h> -#include "common/linux/language.h" -#include "common/linux/module.h" -#include "common/dwarf/bytereader.h" -#include "common/dwarf/dwarf2diehandler.h" -#include "common/dwarf/dwarf2reader.h" - -namespace google_breakpad { - -using dwarf2reader::AttributeList; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfLanguage; -using dwarf2reader::DwarfTag; - -// Populate a google_breakpad::Module with DWARF debugging information. -// -// An instance of this class can be provided as a handler to a -// dwarf2reader::CompilationUnit DWARF parser. The handler uses the -// results of parsing to populate a google_breakpad::Module with -// source file, function, and source line information. -class DwarfCUToModule: public dwarf2reader::RootDIEHandler { - struct FilePrivate; - public: - - // Information global to the DWARF-bearing file we are processing, - // for use by DwarfCUToModule. Each DwarfCUToModule instance deals - // with a single compilation unit within the file, but information - // global to the whole file is held here. The client is responsible - // for filling it in appropriately (except for the 'file_private' - // field, which the constructor and destructor take care of), and - // then providing it to the DwarfCUToModule instance for each - // compilation unit we process in that file. - struct FileContext { - FileContext(const string &filename_arg, Module *module_arg); - ~FileContext(); - - // The name of this file, for use in error messages. - string filename; - - // A map of this file's sections, used for finding other DWARF - // sections that the .debug_info section may refer to. - dwarf2reader::SectionMap section_map; - - // The Module to which we're contributing definitions. - Module *module; - - // Inter-compilation unit data used internally by the handlers. - FilePrivate *file_private; - }; - - // An abstract base class for functors that handle DWARF line data - // for DwarfCUToModule. DwarfCUToModule could certainly just use - // dwarf2reader::LineInfo itself directly, but decoupling things - // this way makes unit testing a little easier. - class LineToModuleFunctor { - public: - LineToModuleFunctor() { } - virtual ~LineToModuleFunctor() { } - - // Populate MODULE and LINES with source file names and code/line - // mappings, given a pointer to some DWARF line number data - // PROGRAM, and an overestimate of its size. Add no zero-length - // lines to LINES. - virtual void operator()(const char *program, uint64 length, - Module *module, vector<Module::Line> *lines) = 0; - }; - - // The interface DwarfCUToModule uses to report warnings. The member - // function definitions for this class write messages to stderr, but - // you can override them if you'd like to detect or report these - // conditions yourself. - class WarningReporter { - public: - // Warn about problems in the DWARF file FILENAME, in the - // compilation unit at OFFSET. - WarningReporter(const string &filename, uint64 cu_offset) - : filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false), - printed_unpaired_header_(false), - uncovered_warnings_enabled_(false) { } - virtual ~WarningReporter() { } - - // Set the name of the compilation unit we're processing to NAME. - virtual void SetCUName(const string &name) { cu_name_ = name; } - - // Accessor and setter for uncovered_warnings_enabled_. - // UncoveredFunction and UncoveredLine only report a problem if that is - // true. By default, these warnings are disabled, because those - // conditions occur occasionally in healthy code. - virtual bool uncovered_warnings_enabled() const { - return uncovered_warnings_enabled_; - } - virtual void set_uncovered_warnings_enabled(bool value) { - uncovered_warnings_enabled_ = value; - } - - // A DW_AT_specification in the DIE at OFFSET refers to a DIE we - // haven't processed yet, or that wasn't marked as a declaration, - // at TARGET. - virtual void UnknownSpecification(uint64 offset, uint64 target); - - // A DW_AT_abstract_origin in the DIE at OFFSET refers to a DIE we - // haven't processed yet, or that wasn't marked as inline, at TARGET. - virtual void UnknownAbstractOrigin(uint64 offset, uint64 target); - - // We were unable to find the DWARF section named SECTION_NAME. - virtual void MissingSection(const string §ion_name); - - // The CU's DW_AT_stmt_list offset OFFSET is bogus. - virtual void BadLineInfoOffset(uint64 offset); - - // FUNCTION includes code covered by no line number data. - virtual void UncoveredFunction(const Module::Function &function); - - // Line number NUMBER in LINE_FILE, of length LENGTH, includes code - // covered by no function. - virtual void UncoveredLine(const Module::Line &line); - - protected: - string filename_; - uint64 cu_offset_; - string cu_name_; - bool printed_cu_header_; - bool printed_unpaired_header_; - bool uncovered_warnings_enabled_; - - private: - // Print a per-CU heading, once. - void CUHeading(); - // Print an unpaired function/line heading, once. - void UncoveredHeading(); - }; - - // Create a DWARF debugging info handler for a compilation unit - // within FILE_CONTEXT. This uses information received from the - // dwarf2reader::CompilationUnit DWARF parser to populate - // FILE_CONTEXT->module. Use LINE_READER to handle the compilation - // unit's line number data. Use REPORTER to report problems with the - // data we find. - DwarfCUToModule(FileContext *file_context, - LineToModuleFunctor *line_reader, - WarningReporter *reporter); - ~DwarfCUToModule(); - - void ProcessAttributeSigned(enum DwarfAttribute attr, - enum DwarfForm form, - int64 data); - void ProcessAttributeUnsigned(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - void ProcessAttributeString(enum DwarfAttribute attr, - enum DwarfForm form, - const string &data); - bool EndAttributes(); - DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag, - const AttributeList &attrs); - - // Assign all our source Lines to the Functions that cover their - // addresses, and then add them to module_. - void Finish(); - - bool StartCompilationUnit(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version); - bool StartRootDIE(uint64 offset, enum DwarfTag tag, - const AttributeList& attrs); - - private: - - // Used internally by the handler. Full definitions are in - // dwarf_cu_to_module.cc. - struct FilePrivate; - struct Specification; - struct CUContext; - struct DIEContext; - class GenericDIEHandler; - class FuncHandler; - class NamedScopeHandler; - - // A map from section offsets to specifications. - typedef map<uint64, Specification> SpecificationByOffset; - - // Set this compilation unit's source language to LANGUAGE. - void SetLanguage(DwarfLanguage language); - - // Read source line information at OFFSET in the .debug_line - // section. Record source files in module_, but record source lines - // in lines_; we apportion them to functions in - // AssignLinesToFunctions. - void ReadSourceLines(uint64 offset); - - // Assign the lines in lines_ to the individual line lists of the - // functions in functions_. (DWARF line information maps an entire - // compilation unit at a time, and gives no indication of which - // lines belong to which functions, beyond their addresses.) - void AssignLinesToFunctions(); - - // The only reason cu_context_ and child_context_ are pointers is - // that we want to keep their definitions private to - // dwarf_cu_to_module.cc, instead of listing them all here. They are - // owned by this DwarfCUToModule: the constructor sets them, and the - // destructor deletes them. - - // The functor to use to handle line number data. - LineToModuleFunctor *line_reader_; - - // This compilation unit's context. - CUContext *cu_context_; - - // A context for our children. - DIEContext *child_context_; - - // True if this compilation unit has source line information. - bool has_source_line_info_; - - // The offset of this compilation unit's line number information in - // the .debug_line section. - uint64 source_line_offset_; - - // The line numbers we have seen thus far. We accumulate these here - // during parsing. Then, in Finish, we call AssignLinesToFunctions - // to dole them out to the appropriate functions. - vector<Module::Line> lines_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_DWARF_CU_TO_MODULE_H__ diff --git a/src/common/linux/dwarf_cu_to_module_unittest.cc b/src/common/linux/dwarf_cu_to_module_unittest.cc deleted file mode 100644 index 1cfbee69..00000000 --- a/src/common/linux/dwarf_cu_to_module_unittest.cc +++ /dev/null @@ -1,1701 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule. - -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/linux/dwarf_cu_to_module.h" - -using std::vector; - -using dwarf2reader::AttributeList; -using dwarf2reader::DIEHandler; -using dwarf2reader::DwarfTag; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfInline; -using dwarf2reader::RootDIEHandler; -using google_breakpad::DwarfCUToModule; -using google_breakpad::Module; - -using ::testing::_; -using ::testing::AtMost; -using ::testing::Invoke; -using ::testing::Return; -using ::testing::Test; -using ::testing::TestWithParam; -using ::testing::Values; -using ::testing::ValuesIn; - -// Mock classes. - -class MockLineToModuleFunctor: public DwarfCUToModule::LineToModuleFunctor { - public: - MOCK_METHOD4(mock_apply, void(const char *program, uint64 length, - Module *module, vector<Module::Line> *lines)); - void operator()(const char *program, uint64 length, - Module *module, vector<Module::Line> *lines) { - mock_apply(program, length, module, lines); - } -}; - -class MockWarningReporter: public DwarfCUToModule::WarningReporter { - public: - MockWarningReporter(const string &filename, uint64 cu_offset) - : DwarfCUToModule::WarningReporter(filename, cu_offset) { } - MOCK_METHOD1(SetCUName, void(const string &name)); - MOCK_METHOD2(UnknownSpecification, void(uint64 offset, uint64 target)); - MOCK_METHOD2(UnknownAbstractOrigin, void(uint64 offset, uint64 target)); - MOCK_METHOD1(MissingSection, void(const string §ion_name)); - MOCK_METHOD1(BadLineInfoOffset, void(uint64 offset)); - MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function)); - MOCK_METHOD1(UncoveredLine, void(const Module::Line &line)); -}; - -// A fixture class including all the objects needed to handle a -// compilation unit, and their entourage. It includes member functions -// for doing common kinds of setup and tests. -class CUFixtureBase { - public: - - // If we have: - // - // vector<Module::Line> lines; - // AppendLinesFunctor appender(lines); - // - // then doing: - // - // appender(line_program, length, module, line_vector); - // - // will append lines to the end of line_vector. We can use this with - // MockLineToModuleFunctor like this: - // - // MockLineToModuleFunctor l2m; - // EXPECT_CALL(l2m, mock_apply(_,_,_,_)) - // .WillOnce(DoAll(Invoke(appender), Return())); - // - // in which case calling l2m with some line vector will append lines. - class AppendLinesFunctor { - public: - AppendLinesFunctor(const vector<Module::Line> *lines) : lines_(lines) { } - void operator()(const char *program, uint64 length, - Module *module, vector<Module::Line> *lines) { - lines->insert(lines->end(), lines_->begin(), lines_->end()); - } - private: - const vector<Module::Line> *lines_; - }; - - CUFixtureBase() - : module_("module-name", "module-os", "module-arch", "module-id"), - file_context_("dwarf-filename", &module_), - language_(dwarf2reader::DW_LANG_none), - language_signed_(false), - appender_(&lines_), - reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL), - root_handler_(&file_context_, &line_reader_, &reporter_), - functions_filled_(false) { - // By default, expect no warnings to be reported, and expect the - // compilation unit's name to be provided. The test can override - // these expectations. - EXPECT_CALL(reporter_, SetCUName("compilation-unit-name")).Times(1); - EXPECT_CALL(reporter_, UnknownSpecification(_, _)).Times(0); - EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, _)).Times(0); - EXPECT_CALL(reporter_, MissingSection(_)).Times(0); - EXPECT_CALL(reporter_, BadLineInfoOffset(_)).Times(0); - EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0); - EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0); - - // By default, expect the line program reader not to be invoked. We - // may override this in StartCU. - EXPECT_CALL(line_reader_, mock_apply(_,_,_,_)).Times(0); - - // The handler will consult this section map to decide what to - // pass to our line reader. - file_context_.section_map[".debug_line"] = std::make_pair(dummy_line_program_, - dummy_line_size_); - } - - // Add a line with the given address, size, filename, and line - // number to the end of the statement list the handler will receive - // when it invokes its LineToModuleFunctor. Call this before calling - // StartCU. - void PushLine(Module::Address address, Module::Address size, - const string &filename, int line_number); - - // Use LANGUAGE for the compilation unit. More precisely, arrange - // for StartCU to pass the compilation unit's root DIE a - // DW_AT_language attribute whose value is LANGUAGE. - void SetLanguage(dwarf2reader::DwarfLanguage language) { - language_ = language; - } - - // If SIGNED true, have StartCU report DW_AT_language as a signed - // attribute; if false, have it report it as unsigned. - void SetLanguageSigned(bool is_signed) { language_signed_ = is_signed; } - - // Call the handler this.root_handler_'s StartCompilationUnit and - // StartRootDIE member functions, passing it appropriate attributes as - // determined by prior calls to PushLine and SetLanguage. Leave - // this.root_handler_ ready to hear about children: call - // this.root_handler_.EndAttributes, but not this.root_handler_.Finish. - void StartCU(); - - // Add some strange attributes/form pairs to the end of ATTRS. - void PushBackStrangeAttributes(dwarf2reader::AttributeList *attrs); - - // Have HANDLER process some strange attribute/form/value triples. - // These will match those promised by PushBackStrangeAttributes. - void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler); - - // Start a child DIE of PARENT with the given tag and name. Leave - // the handler ready to hear about children: call EndAttributes, but - // not Finish. - DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag, - const string &name); - - // Start a child DIE of PARENT with the given tag and a - // DW_AT_specification attribute whose value is SPECIFICATION. Leave - // the handler ready to hear about children: call EndAttributes, but - // not Finish. If NAME is non-zero, use it as the DW_AT_name - // attribute. - DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag, - uint64 offset, const char *name = NULL); - - // Define a function as a child of PARENT with the given name, - // address, and size. Call EndAttributes and Finish; one cannot - // define children of the defined function's DIE. - void DefineFunction(DIEHandler *parent, const string &name, - Module::Address address, Module::Address size); - - // Create a declaration DIE as a child of PARENT with the given - // offset, tag and name. If NAME is the empty string, don't provide - // a DW_AT_name attribute. Call EndAttributes and Finish. - void DeclarationDIE(DIEHandler *parent, uint64 offset, - DwarfTag tag, const string &name); - - // Create a definition DIE as a child of PARENT with the given tag - // that refers to the declaration DIE at offset SPECIFICATION as its - // specification. If NAME is non-empty, pass it as the DW_AT_name - // attribute. If SIZE is non-zero, record ADDRESS and SIZE as - // low_pc/high_pc attributes. - void DefinitionDIE(DIEHandler *parent, DwarfTag tag, - uint64 specification, const string &name, - Module::Address address = 0, Module::Address size = 0); - - // Create an inline DW_TAG_subprogram DIE as a child of PARENT. If - // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at - // offset SPECIFICATION as its specification. If Name is non-empty, pass it - // as the DW_AT_name attribute. - void AbstractInstanceDIE(DIEHandler *parent, uint64 offset, - DwarfInline type, uint64 specification, - const string &name, - DwarfForm form = dwarf2reader::DW_FORM_data1); - - // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to - // ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty - // string, don't provide a DW_AT_name attribute. - void DefineInlineInstanceDIE(DIEHandler *parent, const string &name, - uint64 origin, Module::Address address, - Module::Address size); - - // The following Test* functions should be called after calling - // this.root_handler_.Finish. After that point, no further calls - // should be made on the handler. - - // Test that the number of functions defined in the module this.module_ is - // equal to EXPECTED. - void TestFunctionCount(size_t expected); - - // Test that the I'th function (ordered by address) in the module - // this.module_ has the given name, address, and size, and that its - // parameter size is zero. - void TestFunction(int i, const string &name, - Module::Address address, Module::Address size); - - // Test that the number of source lines owned by the I'th function - // in the module this.module_ is equal to EXPECTED. - void TestLineCount(int i, size_t expected); - - // Test that the J'th line (ordered by address) of the I'th function - // (again, by address) has the given address, size, filename, and - // line number. - void TestLine(int i, int j, Module::Address address, Module::Address size, - const string &filename, int number); - - // Actual objects under test. - Module module_; - DwarfCUToModule::FileContext file_context_; - - // If this is not DW_LANG_none, we'll pass it as a DW_AT_language - // attribute to the compilation unit. This defaults to DW_LANG_none. - dwarf2reader::DwarfLanguage language_; - - // If this is true, report DW_AT_language as a signed value; if false, - // report it as an unsigned value. - bool language_signed_; - - // If this is not empty, we'll give the CU a DW_AT_stmt_list - // attribute that, when passed to line_reader_, adds these lines to the - // provided lines array. - vector<Module::Line> lines_; - - // Mock line program reader. - MockLineToModuleFunctor line_reader_; - AppendLinesFunctor appender_; - static const char dummy_line_program_[]; - static const size_t dummy_line_size_; - - MockWarningReporter reporter_; - DwarfCUToModule root_handler_; - - private: - // Fill functions_, if we haven't already. - void FillFunctions(); - - // If functions_filled_ is true, this is a table of functions we've - // extracted from module_, sorted by address. - vector<Module::Function *> functions_; - // True if we have filled the above vector with this.module_'s function list. - bool functions_filled_; -}; - -const char CUFixtureBase::dummy_line_program_[] = "lots of fun data"; -const size_t CUFixtureBase::dummy_line_size_ = - sizeof (CUFixtureBase::dummy_line_program_); - -void CUFixtureBase::PushLine(Module::Address address, Module::Address size, - const string &filename, int line_number) { - Module::Line l; - l.address = address; - l.size = size; - l.file = module_.FindFile(filename); - l.number = line_number; - lines_.push_back(l); -} - -void CUFixtureBase::StartCU() { - // If we have lines, make the line reader expect to be invoked at - // most once. (Hey, if the handler can pass its tests without - // bothering to read the line number data, that's great.) - // Have it add the lines passed to PushLine. Otherwise, leave the - // initial expectation (no calls) in force. - if (!lines_.empty()) - EXPECT_CALL(line_reader_, - mock_apply(&dummy_line_program_[0], dummy_line_size_, - &module_, _)) - .Times(AtMost(1)) - .WillOnce(DoAll(Invoke(appender_), Return())); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44, - 0x4241b4f33720dd5cULL, 3)); - { - dwarf2reader::AttributeList attrs; - attrs.push_back(make_pair(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp)); - if (!lines_.empty()) - attrs.push_back(make_pair(dwarf2reader::DW_AT_stmt_list, - dwarf2reader::DW_FORM_ref4)); - if (language_ != dwarf2reader::DW_LANG_none) - attrs.push_back(make_pair(dwarf2reader::DW_AT_language, - language_signed_ - ? dwarf2reader::DW_FORM_sdata - : dwarf2reader::DW_FORM_udata)); - ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, - dwarf2reader::DW_TAG_compile_unit, - attrs)); - } - root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - "compilation-unit-name"); - if (!lines_.empty()) - root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, - dwarf2reader::DW_FORM_ref4, - 0); - if (language_ != dwarf2reader::DW_LANG_none) { - if (language_signed_) - root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language, - dwarf2reader::DW_FORM_sdata, - language_); - else - root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language, - dwarf2reader::DW_FORM_udata, - language_); - } - ASSERT_TRUE(root_handler_.EndAttributes()); -} - -void CUFixtureBase::PushBackStrangeAttributes( - dwarf2reader::AttributeList *attrs) { - attrs->push_back(make_pair((DwarfAttribute) 0xf560dead, - (DwarfForm) 0x4106e4db)); - attrs->push_back(make_pair((DwarfAttribute) 0x85380095, - (DwarfForm) 0x0f16fe87)); - attrs->push_back(make_pair((DwarfAttribute) 0xf7f7480f, - (DwarfForm) 0x829e038a)); - attrs->push_back(make_pair((DwarfAttribute) 0xa55ffb51, - (DwarfForm) 0x2f43b041)); - attrs->push_back(make_pair((DwarfAttribute) 0x2fde304a, - (DwarfForm) 0x895ffa23)); -} - -void CUFixtureBase::ProcessStrangeAttributes( - dwarf2reader::DIEHandler *handler) { - handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead, - (DwarfForm) 0x4106e4db, - 0xa592571997facda1ULL); - handler->ProcessAttributeSigned((DwarfAttribute) 0x85380095, - (DwarfForm) 0x0f16fe87, - 0x12602a4e3bf1f446LL); - handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f, - (DwarfForm) 0x829e038a, - 0x50fddef44734fdecULL); - static const char buffer[10] = "frobynode"; - handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51, - (DwarfForm) 0x2f43b041, - buffer, sizeof(buffer)); - handler->ProcessAttributeString((DwarfAttribute) 0x2f43b041, - (DwarfForm) 0x895ffa23, - "strange string"); -} - -DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent, - DwarfTag tag, - const string &name) { - dwarf2reader::AttributeList attrs; - attrs.push_back(make_pair(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp)); - PushBackStrangeAttributes(&attrs); - dwarf2reader::DIEHandler *handler - = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag, attrs); - if (!handler) - return NULL; - handler->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - ProcessStrangeAttributes(handler); - if (!handler->EndAttributes()) { - handler->Finish(); - delete handler; - return NULL; - } - - return handler; -} - -DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent, - DwarfTag tag, - uint64 specification, - const char *name) { - dwarf2reader::AttributeList attrs; - if (name) - attrs.push_back(make_pair(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp)); - attrs.push_back(make_pair(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4)); - dwarf2reader::DIEHandler *handler - = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag, attrs); - if (!handler) - return NULL; - if (name) - handler->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4, - specification); - if (!handler->EndAttributes()) { - handler->Finish(); - delete handler; - return NULL; - } - - return handler; -} - -void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent, - const string &name, Module::Address address, - Module::Address size) { - dwarf2reader::AttributeList func_attrs; - func_attrs.push_back(make_pair(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp)); - func_attrs.push_back(make_pair(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr)); - func_attrs.push_back(make_pair(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr)); - PushBackStrangeAttributes(&func_attrs); - dwarf2reader::DIEHandler *func - = parent->FindChildHandler(0xe34797c7e68590a8LL, - dwarf2reader::DW_TAG_subprogram, - func_attrs); - ASSERT_TRUE(func != NULL); - func->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, - address); - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr, - address + size); - ProcessStrangeAttributes(func); - EXPECT_TRUE(func->EndAttributes()); - func->Finish(); - delete func; -} - -void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset, - DwarfTag tag, - const string &name) { - dwarf2reader::AttributeList attrs; - if (!name.empty()) - attrs.push_back(make_pair(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp)); - attrs.push_back(make_pair(dwarf2reader::DW_AT_declaration, - dwarf2reader::DW_FORM_flag)); - dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag, attrs); - ASSERT_TRUE(die != NULL); - if (!name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration, - dwarf2reader::DW_FORM_flag, - 1); - EXPECT_TRUE(die->EndAttributes()); - die->Finish(); - delete die; -} - -void CUFixtureBase::DefinitionDIE(DIEHandler *parent, - DwarfTag tag, - uint64 specification, - const string &name, - Module::Address address, - Module::Address size) { - dwarf2reader::AttributeList attrs; - attrs.push_back(make_pair(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4)); - if (!name.empty()) - attrs.push_back(make_pair(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp)); - if (size) { - attrs.push_back(make_pair(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr)); - attrs.push_back(make_pair(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr)); - } - dwarf2reader::DIEHandler *die - = parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag, attrs); - ASSERT_TRUE(die != NULL); - die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4, - specification); - if (!name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - if (size) { - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, - address); - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr, - address + size); - } - EXPECT_TRUE(die->EndAttributes()); - die->Finish(); - delete die; -} - -void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent, - uint64 offset, - DwarfInline type, - uint64 specification, - const string &name, - DwarfForm form) { - dwarf2reader::AttributeList attrs; - if (specification != 0ULL) - attrs.push_back(make_pair(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4)); - attrs.push_back(make_pair(dwarf2reader::DW_AT_inline, form)); - if (!name.empty()) - attrs.push_back(make_pair(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp)); - dwarf2reader::DIEHandler *die - = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram, attrs); - ASSERT_TRUE(die != NULL); - if (specification != 0ULL) - die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4, - specification); - if (form == dwarf2reader::DW_FORM_sdata) { - die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type); - } else { - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type); - } - if (!name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - - EXPECT_TRUE(die->EndAttributes()); - die->Finish(); - delete die; -} - -void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent, - const string &name, - uint64 origin, - Module::Address address, - Module::Address size) { - dwarf2reader::AttributeList func_attrs; - if (!name.empty()) - func_attrs.push_back(make_pair(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp)); - func_attrs.push_back(make_pair(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr)); - func_attrs.push_back(make_pair(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr)); - func_attrs.push_back(make_pair(dwarf2reader::DW_AT_abstract_origin, - dwarf2reader::DW_FORM_ref4)); - PushBackStrangeAttributes(&func_attrs); - dwarf2reader::DIEHandler *func - = parent->FindChildHandler(0x11c70f94c6e87ccdLL, - dwarf2reader::DW_TAG_subprogram, - func_attrs); - ASSERT_TRUE(func != NULL); - if (!name.empty()) { - func->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - } - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, - address); - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr, - address + size); - func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin, - dwarf2reader::DW_FORM_ref4, - origin); - ProcessStrangeAttributes(func); - EXPECT_TRUE(func->EndAttributes()); - func->Finish(); - delete func; -} - -void CUFixtureBase::FillFunctions() { - if (functions_filled_) - return; - module_.GetFunctions(&functions_, functions_.end()); - sort(functions_.begin(), functions_.end(), - Module::Function::CompareByAddress); - functions_filled_ = true; -} - -void CUFixtureBase::TestFunctionCount(size_t expected) { - FillFunctions(); - ASSERT_EQ(expected, functions_.size()); -} - -void CUFixtureBase::TestFunction(int i, const string &name, - Module::Address address, - Module::Address size) { - FillFunctions(); - ASSERT_LT((size_t) i, functions_.size()); - - Module::Function *function = functions_[i]; - EXPECT_EQ(name, function->name); - EXPECT_EQ(address, function->address); - EXPECT_EQ(size, function->size); - EXPECT_EQ(0U, function->parameter_size); -} - -void CUFixtureBase::TestLineCount(int i, size_t expected) { - FillFunctions(); - ASSERT_LT((size_t) i, functions_.size()); - - ASSERT_EQ(expected, functions_[i]->lines.size()); -} - -void CUFixtureBase::TestLine(int i, int j, - Module::Address address, Module::Address size, - const string &filename, int number) { - FillFunctions(); - ASSERT_LT((size_t) i, functions_.size()); - ASSERT_LT((size_t) j, functions_[i]->lines.size()); - - Module::Line *line = &functions_[i]->lines[j]; - EXPECT_EQ(address, line->address); - EXPECT_EQ(size, line->size); - EXPECT_EQ(filename, line->file->name.c_str()); - EXPECT_EQ(number, line->number); -} - -// Include caller locations for our test subroutines. -#define TRACE(call) do { SCOPED_TRACE("called from here"); call; } while (0) -#define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d))) -#define SetLanguage(a) TRACE(SetLanguage(a)) -#define StartCU() TRACE(StartCU()) -#define DefineFunction(a,b,c,d) TRACE(DefineFunction((a),(b),(c),(d))) -#define DeclarationDIE(a,b,c,d) TRACE(DeclarationDIE((a),(b),(c),(d))) -#define DefinitionDIE(a,b,c,d,e,f) TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f))) -#define TestFunctionCount(a) TRACE(TestFunctionCount(a)) -#define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d))) -#define TestLineCount(a,b) TRACE(TestLineCount((a),(b))) -#define TestLine(a,b,c,d,e,f) TRACE(TestLine((a),(b),(c),(d),(e),(f))) - -class Simple: public CUFixtureBase, public Test { -}; - -TEST_F(Simple, OneFunc) { - PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); - - StartCU(); - DefineFunction(&root_handler_, "function1", - 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); - TestLineCount(0, 1); - TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", - 246571772); -} - -TEST_F(Simple, IrrelevantRootChildren) { - StartCU(); - dwarf2reader::AttributeList no_attrs; - EXPECT_FALSE(root_handler_ - .FindChildHandler(0x7db32bff4e2dcfb1ULL, - dwarf2reader::DW_TAG_lexical_block, no_attrs)); -} - -TEST_F(Simple, IrrelevantNamedScopeChildren) { - StartCU(); - dwarf2reader::AttributeList no_attrs; - DIEHandler *class_A_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); - EXPECT_TRUE(class_A_handler != NULL); - EXPECT_FALSE(class_A_handler - ->FindChildHandler(0x02e55999b865e4e9ULL, - dwarf2reader::DW_TAG_lexical_block, - no_attrs)); - delete class_A_handler; -} - -// Verify that FileContexts can safely be deleted unused. -TEST_F(Simple, UnusedFileContext) { - Module m("module-name", "module-os", "module-arch", "module-id"); - DwarfCUToModule::FileContext fc("dwarf-filename", &m); - - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); -} - -TEST_F(Simple, InlineFunction) { - PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); - - StartCU(); - AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0, "inline-name"); - DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "inline-name", - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); -} - -TEST_F(Simple, InlineFunctionSignedAttribute) { - PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); - - StartCU(); - AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0, "inline-name", - dwarf2reader::DW_FORM_sdata); - DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "inline-name", - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); -} - -// Any DIE with an DW_AT_inline attribute can be cited by -// DW_AT_abstract_origin attributes --- even if the value of the -// DW_AT_inline attribute is DW_INL_not_inlined. -TEST_F(Simple, AbstractOriginNotInlined) { - PushLine(0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL, "line-file", 6111581); - - StartCU(); - AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL, - dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance"); - DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL, - 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "abstract-instance", - 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); -} - -TEST_F(Simple, UnknownAbstractOrigin) { - EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return()); - PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); - - StartCU(); - AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0, "inline-name"); - DefineInlineInstanceDIE(&root_handler_, "", 1ULL, - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "", - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); -} - -// An address range. -struct Range { - Module::Address start, end; -}; - -// Test data for pairing functions and lines. -struct Situation { - // Two function intervals, and two line intervals. - Range functions[2], lines[2]; - - // The number of lines we expect to be assigned to each of the - // functions, and the address ranges. - int paired_count[2]; - Range paired[2][2]; - - // The number of functions that are not entirely covered by lines, - // and vice versa. - int uncovered_functions, uncovered_lines; -}; - -#define PAIRING(func1_start, func1_end, func2_start, func2_end, \ - line1_start, line1_end, line2_start, line2_end, \ - func1_num_lines, func2_num_lines, \ - func1_line1_start, func1_line1_end, \ - func1_line2_start, func1_line2_end, \ - func2_line1_start, func2_line1_end, \ - func2_line2_start, func2_line2_end, \ - uncovered_functions, uncovered_lines) \ - { { { func1_start, func1_end }, { func2_start, func2_end } }, \ - { { line1_start, line1_end }, { line2_start, line2_end } }, \ - { func1_num_lines, func2_num_lines }, \ - { { { func1_line1_start, func1_line1_end }, \ - { func1_line2_start, func1_line2_end } }, \ - { { func2_line1_start, func2_line1_end }, \ - { func2_line2_start, func2_line2_end } } }, \ - uncovered_functions, uncovered_lines }, - -Situation situations[] = { -#include "common/linux/testdata/func-line-pairing.h" -}; - -#undef PAIRING - -class FuncLinePairing: public CUFixtureBase, - public TestWithParam<Situation> { }; - -INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing, - ValuesIn(situations)); - -TEST_P(FuncLinePairing, Pairing) { - const Situation &s = GetParam(); - PushLine(s.lines[0].start, - s.lines[0].end - s.lines[0].start, - "line-file", 67636963); - PushLine(s.lines[1].start, - s.lines[1].end - s.lines[1].start, - "line-file", 67636963); - if (s.uncovered_functions) - EXPECT_CALL(reporter_, UncoveredFunction(_)) - .Times(s.uncovered_functions) - .WillRepeatedly(Return()); - if (s.uncovered_lines) - EXPECT_CALL(reporter_, UncoveredLine(_)) - .Times(s.uncovered_lines) - .WillRepeatedly(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function1", - s.functions[0].start, - s.functions[0].end - s.functions[0].start); - DefineFunction(&root_handler_, "function2", - s.functions[1].start, - s.functions[1].end - s.functions[1].start); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", - s.functions[0].start, - s.functions[0].end - s.functions[0].start); - TestLineCount(0, s.paired_count[0]); - for (int i = 0; i < s.paired_count[0]; i++) - TestLine(0, i, s.paired[0][i].start, - s.paired[0][i].end - s.paired[0][i].start, - "line-file", 67636963); - TestFunction(1, "function2", - s.functions[1].start, - s.functions[1].end - s.functions[1].start); - TestLineCount(1, s.paired_count[1]); - for (int i = 0; i < s.paired_count[1]; i++) - TestLine(1, i, s.paired[1][i].start, - s.paired[1][i].end - s.paired[1][i].start, - "line-file", 67636963); -} - -TEST_F(FuncLinePairing, EmptyCU) { - - StartCU(); - root_handler_.Finish(); - - TestFunctionCount(0); -} - -TEST_F(FuncLinePairing, LinesNoFuncs) { - PushLine(40, 2, "line-file", 82485646); - EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); - - StartCU(); - root_handler_.Finish(); - - TestFunctionCount(0); -} - -TEST_F(FuncLinePairing, FuncsNoLines) { - EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "function1", 0x127da12ffcf5c51fULL, 0x1000U); -} - -TEST_F(FuncLinePairing, GapThenFunction) { - PushLine(20, 2, "line-file-2", 174314698); - PushLine(10, 2, "line-file-1", 263008005); - - StartCU(); - DefineFunction(&root_handler_, "function1", 10, 2); - DefineFunction(&root_handler_, "function2", 20, 2); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", 10, 2); - TestLineCount(0, 1); - TestLine(0, 0, 10, 2, "line-file-1", 263008005); - TestFunction(1, "function2", 20, 2); - TestLineCount(1, 1); - TestLine(1, 0, 20, 2, "line-file-2", 174314698); -} - -// If GCC emits padding after one function to align the start of -// the next, then it will attribute the padding instructions to -// the last source line of function (to reduce the size of the -// line number info), but omit it from the DW_AT_{low,high}_pc -// range given in .debug_info (since it costs nothing to be -// precise there). If we did use at least some of the line -// we're about to skip, then assume this is what happened, and -// don't warn. -TEST_F(FuncLinePairing, GCCAlignmentStretch) { - PushLine(10, 10, "line-file", 63351048); - PushLine(20, 10, "line-file", 61661044); - - StartCU(); - DefineFunction(&root_handler_, "function1", 10, 5); - // five-byte gap between functions, covered by line 63351048. - // This should not elicit a warning. - DefineFunction(&root_handler_, "function2", 20, 10); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", 10, 5); - TestLineCount(0, 1); - TestLine(0, 0, 10, 5, "line-file", 63351048); - TestFunction(1, "function2", 20, 10); - TestLineCount(1, 1); - TestLine(1, 0, 20, 10, "line-file", 61661044); -} - -// Unfortunately, neither the DWARF parser's handler interface nor the -// DIEHandler interface is capable of expressing a function that abuts -// the end of the address space: the high_pc value looks like zero. - -TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) { - PushLine(0xfffffffffffffff0ULL, 16, "line-file", 63351048); - EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6); - DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", 0xfffffffffffffff0ULL, 6); - TestLineCount(0, 1); - TestLine(0, 0, 0xfffffffffffffff0ULL, 6, "line-file", 63351048); - TestFunction(1, "function2", 0xfffffffffffffffaULL, 5); - TestLineCount(1, 1); - TestLine(1, 0, 0xfffffffffffffffaULL, 5, "line-file", 63351048); -} - -// A function with more than one uncovered area should only be warned -// about once. -TEST_F(FuncLinePairing, WarnOnceFunc) { - PushLine(20, 1, "line-file-2", 262951329); - PushLine(11, 1, "line-file-1", 219964021); - EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function", 10, 11); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "function", 10, 11); - TestLineCount(0, 2); - TestLine(0, 0, 11, 1, "line-file-1", 219964021); - TestLine(0, 1, 20, 1, "line-file-2", 262951329); -} - -// A line with more than one uncovered area should only be warned -// about once. -TEST_F(FuncLinePairing, WarnOnceLine) { - PushLine(10, 20, "filename1", 118581871); - EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function1", 11, 1); - DefineFunction(&root_handler_, "function2", 13, 1); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", 11, 1); - TestLineCount(0, 1); - TestLine(0, 0, 11, 1, "filename1", 118581871); - TestFunction(1, "function2", 13, 1); - TestLineCount(1, 1); - TestLine(1, 0, 13, 1, "filename1", 118581871); -} - -class CXXQualifiedNames: public CUFixtureBase, - public TestWithParam<DwarfTag> { }; - -INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames, - Values(dwarf2reader::DW_TAG_class_type, - dwarf2reader::DW_TAG_structure_type, - dwarf2reader::DW_TAG_union_type, - dwarf2reader::DW_TAG_namespace)); - -TEST_P(CXXQualifiedNames, TwoFunctions) { - DwarfTag tag = GetParam(); - - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); - PushLine(10, 1, "filename1", 69819327); - PushLine(20, 1, "filename2", 95115701); - - StartCU(); - DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag, - "Enclosure"); - EXPECT_TRUE(enclosure_handler != NULL); - DefineFunction(enclosure_handler, "func_B", 10, 1); - DefineFunction(enclosure_handler, "func_C", 20, 1); - enclosure_handler->Finish(); - delete enclosure_handler; - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "Enclosure::func_B", 10, 1); - TestFunction(1, "Enclosure::func_C", 20, 1); -} - -TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) { - DwarfTag tag = GetParam(); - - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); - PushLine(10, 1, "line-file", 69819327); - - StartCU(); - DIEHandler *namespace_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - "Namespace"); - EXPECT_TRUE(namespace_handler != NULL); - DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag, - "Enclosure"); - EXPECT_TRUE(enclosure_handler != NULL); - DefineFunction(enclosure_handler, "function", 10, 1); - enclosure_handler->Finish(); - delete enclosure_handler; - namespace_handler->Finish(); - delete namespace_handler; - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "Namespace::Enclosure::function", 10, 1); -} - -TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) { - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); - PushLine(10, 1, "filename1", 69819327); - - StartCU(); - DIEHandler *namespace_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - "namespace_A"); - EXPECT_TRUE(namespace_handler != NULL); - DIEHandler *struct_handler - = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type, - "struct_B"); - EXPECT_TRUE(struct_handler != NULL); - DIEHandler *class_handler - = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type, - "class_C"); - DefineFunction(class_handler, "function_D", 10, 1); - class_handler->Finish(); - delete class_handler; - struct_handler->Finish(); - delete struct_handler; - namespace_handler->Finish(); - delete namespace_handler; - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "namespace_A::struct_B::class_C::function_D", 10, 1); -} - -struct LanguageAndQualifiedName { - dwarf2reader::DwarfLanguage language; - const char *name; -}; - -const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = { - { dwarf2reader::DW_LANG_none, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C89, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C99, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C_plus_plus, "class_A::function_B" }, - { dwarf2reader::DW_LANG_Java, "class_A.function_B" }, - { dwarf2reader::DW_LANG_Cobol74, "class_A::function_B" }, - { dwarf2reader::DW_LANG_Mips_Assembler, NULL } -}; - -class QualifiedForLanguage: - public CUFixtureBase, - public TestWithParam<LanguageAndQualifiedName> { }; - -INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage, - ValuesIn(LanguageAndQualifiedNameCases)); - -TEST_P(QualifiedForLanguage, MemberFunction) { - const LanguageAndQualifiedName ¶m = GetParam(); - - PushLine(10, 1, "line-file", 212966758); - SetLanguage(param.language); - - StartCU(); - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - "class_A"); - DefineFunction(class_handler, "function_B", 10, 1); - class_handler->Finish(); - delete class_handler; - root_handler_.Finish(); - - if (param.name) { - TestFunctionCount(1); - TestFunction(0, param.name, 10, 1); - } else { - TestFunctionCount(0); - } -} - -TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) { - const LanguageAndQualifiedName ¶m = GetParam(); - - PushLine(10, 1, "line-file", 212966758); - SetLanguage(param.language); - SetLanguageSigned(true); - - StartCU(); - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - "class_A"); - DefineFunction(class_handler, "function_B", 10, 1); - class_handler->Finish(); - delete class_handler; - root_handler_.Finish(); - - if (param.name) { - TestFunctionCount(1); - TestFunction(0, param.name, 10, 1); - } else { - TestFunctionCount(0); - } -} - -class Specifications: public CUFixtureBase, public Test { }; - -TEST_F(Specifications, Function) { - PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); - - StartCU(); - DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "declaration-name"); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0xcd3c51b946fb1eeeLL, "", - 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "declaration-name", - 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); -} - -TEST_F(Specifications, MemberFunction) { - PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691); - - StartCU(); - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); - DeclarationDIE(class_handler, 0x7d83028c431406e8ULL, - dwarf2reader::DW_TAG_subprogram, "declaration-name"); - class_handler->Finish(); - delete class_handler; - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x7d83028c431406e8ULL, "", - 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "class_A::declaration-name", - 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); -} - -// This case should gather the name from both the definition and the -// declaration's parent. -TEST_F(Specifications, FunctionDeclarationParent) { - PushLine(0x463c9ddf405be227ULL, 0x6a47774af5049680ULL, "line-file", 70254922); - - StartCU(); - { - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - "class_A"); - ASSERT_TRUE(class_handler != NULL); - DeclarationDIE(class_handler, 0x0e0e877c8404544aULL, - dwarf2reader::DW_TAG_subprogram, "declaration-name"); - class_handler->Finish(); - delete class_handler; - } - - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x0e0e877c8404544aULL, "definition-name", - 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); - - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "class_A::definition-name", - 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); -} - -// Named scopes should also gather enclosing name components from -// their declarations. -TEST_F(Specifications, NamedScopeDeclarationParent) { - PushLine(0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, "line-file", 77392604); - - StartCU(); - { - DIEHandler *space_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - "space_A"); - ASSERT_TRUE(space_handler != NULL); - DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL, - dwarf2reader::DW_TAG_class_type, "class-declaration-name"); - space_handler->Finish(); - delete space_handler; - } - - { - DIEHandler *class_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - 0x419bb1d12f9a73a2ULL, "class-definition-name"); - ASSERT_TRUE(class_handler != NULL); - DefineFunction(class_handler, "function", - 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL); - class_handler->Finish(); - delete class_handler; - } - - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "space_A::class-definition-name::function", - 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL); -} - -// This test recreates bug 364. -TEST_F(Specifications, InlineFunction) { - PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); - - StartCU(); - DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "inline-name"); - AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, ""); - DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "inline-name", - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); -} - -// Check name construction for a long chain containing each combination of: -// - struct, union, class, namespace -// - direct and definition -TEST_F(Specifications, LongChain) { - PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926); - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); - - StartCU(); - // The structure we're building here is: - // space_A full definition - // space_B declaration - // space_B definition - // struct_C full definition - // struct_D declaration - // struct_D definition - // union_E full definition - // union_F declaration - // union_F definition - // class_G full definition - // class_H declaration - // class_H definition - // func_I declaration - // func_I definition - // - // So: - // - space_A, struct_C, union_E, and class_G don't use specifications; - // - space_B, struct_D, union_F, and class_H do. - // - func_I uses a specification. - // - // The full name for func_I is thus: - // - // space_A::space_B::struct_C::struct_D::union_E::union_F:: - // class_G::class_H::func_I - { - DIEHandler *space_A_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - "space_A"); - DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL, - dwarf2reader::DW_TAG_namespace, "space_B"); - space_A_handler->Finish(); - delete space_A_handler; - } - - { - DIEHandler *space_B_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - 0x2e111126496596e2ULL); - DIEHandler *struct_C_handler - = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type, - "struct_C"); - DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL, - dwarf2reader::DW_TAG_structure_type, "struct_D"); - struct_C_handler->Finish(); - delete struct_C_handler; - space_B_handler->Finish(); - delete space_B_handler; - } - - { - DIEHandler *struct_D_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type, - 0x20cd423bf2a25a4cULL); - DIEHandler *union_E_handler - = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type, - "union_E"); - DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL, - dwarf2reader::DW_TAG_union_type, "union_F"); - union_E_handler->Finish(); - delete union_E_handler; - struct_D_handler->Finish(); - delete struct_D_handler; - } - - { - DIEHandler *union_F_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type, - 0xe25c84805aa58c32ULL); - DIEHandler *class_G_handler - = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type, - "class_G"); - DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL, - dwarf2reader::DW_TAG_class_type, "class_H"); - class_G_handler->Finish(); - delete class_G_handler; - union_F_handler->Finish(); - delete union_F_handler; - } - - { - DIEHandler *class_H_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - 0xb70d960dcc173b6eULL); - DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL, - dwarf2reader::DW_TAG_subprogram, "func_I"); - class_H_handler->Finish(); - delete class_H_handler; - } - - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x27ff829e3bf69f37ULL, "", - 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "space_A::space_B::struct_C::struct_D::union_E::union_F" - "::class_G::class_H::func_I", - 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); -} - -TEST_F(Specifications, InterCU) { - Module m("module-name", "module-os", "module-arch", "module-id"); - DwarfCUToModule::FileContext fc("dwarf-filename", &m); - EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); - MockLineToModuleFunctor lr; - EXPECT_CALL(lr, mock_apply(_,_,_,_)).Times(0); - dwarf2reader::AttributeList no_attrs; - - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - // First CU. Declares class_A. - { - DwarfCUToModule root1_handler(&fc, &lr, &reporter_); - ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); - dwarf2reader::AttributeList attrs; - PushBackStrangeAttributes(&attrs); - ASSERT_TRUE(root1_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit, - attrs)); - ProcessStrangeAttributes(&root1_handler); - ASSERT_TRUE(root1_handler.EndAttributes()); - DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, - dwarf2reader::DW_TAG_class_type, "class_A"); - root1_handler.Finish(); - } - - // Second CU. Defines class_A, declares member_func_B. - { - DwarfCUToModule root2_handler(&fc, &lr, &reporter_); - ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); - ASSERT_TRUE(root2_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit, - no_attrs)); - ASSERT_TRUE(root2_handler.EndAttributes()); - DIEHandler *class_A_handler - = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, - 0xb8fbfdd5f0b26fceULL); - DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, - dwarf2reader::DW_TAG_subprogram, "member_func_B"); - class_A_handler->Finish(); - delete class_A_handler; - root2_handler.Finish(); - } - - // Third CU. Defines member_func_B. - { - DwarfCUToModule root3_handler(&fc, &lr, &reporter_); - ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); - ASSERT_TRUE(root3_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit, - no_attrs)); - ASSERT_TRUE(root3_handler.EndAttributes()); - DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, - 0xb01fef8b380bd1a2ULL, "", - 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); - root3_handler.Finish(); - } - - vector<Module::Function *> functions; - m.GetFunctions(&functions, functions.end()); - EXPECT_EQ(1U, functions.size()); - EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str()); -} - -TEST_F(Specifications, BadOffset) { - PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272); - EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL)) - .WillOnce(Return()); - - StartCU(); - DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL, - dwarf2reader::DW_TAG_subprogram, "function"); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x2be953efa6f9a996ULL, "", - 0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL); - root_handler_.Finish(); -} - -TEST_F(Specifications, FunctionDefinitionHasOwnName) { - PushLine(0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL, "line-file", 56792403); - - StartCU(); - DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL, - dwarf2reader::DW_TAG_subprogram, "declaration-name"); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0xc34ff4786cae78bdULL, "definition-name", - 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "definition-name", - 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); -} - -TEST_F(Specifications, ClassDefinitionHasOwnName) { - PushLine(0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL, "line-file", 57119241); - - StartCU(); - DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL, - dwarf2reader::DW_TAG_class_type, "class-declaration-name"); - - dwarf2reader::DIEHandler *class_definition - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - 0xd0fe467ec2f1a58cULL, "class-definition-name"); - ASSERT_TRUE(class_definition); - DeclarationDIE(class_definition, 0x6d028229c15623dbULL, - dwarf2reader::DW_TAG_subprogram, - "function-declaration-name"); - class_definition->Finish(); - delete class_definition; - - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x6d028229c15623dbULL, "function-definition-name", - 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); - - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "class-definition-name::function-definition-name", - 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); -} - -// DIEs that cite a specification should prefer the specification's -// parents over their own when choosing qualified names. In this test, -// we take the name from our definition but the enclosing scope name -// from our declaration. I don't see why they'd ever be different, but -// we want to verify what DwarfCUToModule is looking at. -TEST_F(Specifications, PreferSpecificationParents) { - PushLine(0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL, "line-file", 79488694); - - StartCU(); - { - dwarf2reader::DIEHandler *declaration_class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "declaration-class"); - DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL, - dwarf2reader::DW_TAG_subprogram, "function-declaration"); - declaration_class_handler->Finish(); - delete declaration_class_handler; - } - { - dwarf2reader::DIEHandler *definition_class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - "definition-class"); - DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram, - 0x9ddb35517455ef7aULL, "function-definition", - 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); - definition_class_handler->Finish(); - delete definition_class_handler; - } - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "declaration-class::function-definition", - 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); -} - -class Errors: public CUFixtureBase, public Test { }; - -TEST_F(Errors, BadStmtList) { - EXPECT_CALL(reporter_, BadLineInfoOffset(dummy_line_size_ + 10)).Times(1); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd, - 0x2d7d19546cf6590cULL, 3)); - dwarf2reader::AttributeList attrs; - attrs.push_back(make_pair(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp)); - attrs.push_back(make_pair(dwarf2reader::DW_AT_stmt_list, - dwarf2reader::DW_FORM_ref4)); - ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL, - dwarf2reader::DW_TAG_compile_unit, - attrs)); - root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - "compilation-unit-name"); - root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, - dwarf2reader::DW_FORM_ref4, - dummy_line_size_ + 10); - root_handler_.EndAttributes(); - root_handler_.Finish(); -} - -TEST_F(Errors, NoLineSection) { - EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1); - PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290); - // Delete the entry for .debug_line added by the fixture class's constructor. - file_context_.section_map.clear(); - - StartCU(); - root_handler_.Finish(); -} - -TEST_F(Errors, BadDwarfVersion1) { - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - ASSERT_FALSE(root_handler_ - .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, - 0xc9de224ccb99ac3eULL, 1)); -} - -TEST_F(Errors, GoodDwarfVersion2) { - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, - 0xc9de224ccb99ac3eULL, 2)); -} - -TEST_F(Errors, GoodDwarfVersion3) { - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, - 0xc9de224ccb99ac3eULL, 3)); -} - -TEST_F(Errors, BadCURootDIETag) { - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, - 0xc9de224ccb99ac3eULL, 3)); - - dwarf2reader::AttributeList no_attrs; - ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, - dwarf2reader::DW_TAG_subprogram, - no_attrs)); -} - -// Tests for DwarfCUToModule::Reporter. These just produce (or fail to -// produce) output, so their results need to be checked by hand. -struct Reporter: public Test { - Reporter() - : reporter("filename", 0x123456789abcdef0ULL) { - reporter.SetCUName("compilation-unit-name"); - - function.name = "function name"; - function.address = 0x19c45c30770c1eb0ULL; - function.size = 0x89808a5bdfa0a6a3ULL; - function.parameter_size = 0x6a329f18683dcd51ULL; - - file.name = "source file name"; - - line.address = 0x3606ac6267aebeccULL; - line.size = 0x5de482229f32556aULL; - line.file = &file; - line.number = 93400201; - } - - DwarfCUToModule::WarningReporter reporter; - Module::Function function; - Module::File file; - Module::Line line; -}; - -TEST_F(Reporter, UnknownSpecification) { - reporter.UnknownSpecification(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); -} - -TEST_F(Reporter, UnknownAbstractOrigin) { - reporter.UnknownAbstractOrigin(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); -} - -TEST_F(Reporter, MissingSection) { - reporter.MissingSection("section name"); -} - -TEST_F(Reporter, BadLineInfoOffset) { - reporter.BadLineInfoOffset(0x123456789abcdef1ULL); -} - -TEST_F(Reporter, UncoveredFunctionDisabled) { - reporter.UncoveredFunction(function); - EXPECT_FALSE(reporter.uncovered_warnings_enabled()); -} - -TEST_F(Reporter, UncoveredFunctionEnabled) { - reporter.set_uncovered_warnings_enabled(true); - reporter.UncoveredFunction(function); - EXPECT_TRUE(reporter.uncovered_warnings_enabled()); -} - -TEST_F(Reporter, UncoveredLineDisabled) { - reporter.UncoveredLine(line); - EXPECT_FALSE(reporter.uncovered_warnings_enabled()); -} - -TEST_F(Reporter, UncoveredLineEnabled) { - reporter.set_uncovered_warnings_enabled(true); - reporter.UncoveredLine(line); - EXPECT_TRUE(reporter.uncovered_warnings_enabled()); -} - -// Would be nice to also test: -// - overlapping lines, functions diff --git a/src/common/linux/dwarf_line_to_module.cc b/src/common/linux/dwarf_line_to_module.cc deleted file mode 100644 index c740fa30..00000000 --- a/src/common/linux/dwarf_line_to_module.cc +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_line_to_module.cc: Implementation of DwarfLineToModule class. -// See dwarf_line_to_module.h for details. - -#include "common/linux/dwarf_line_to_module.h" - -// Trying to support Windows paths in a reasonable way adds a lot of -// variations to test; it would be better to just put off dealing with -// it until we actually have to deal with DWARF on Windows. - -// Return true if PATH is an absolute path, false if it is relative. -static bool PathIsAbsolute(const string &path) { - return (path.size() >= 1 && path[0] == '/'); -} - -// If PATH is an absolute path, return PATH. If PATH is a relative path, -// treat it as relative to BASE and return the combined path. -static string ExpandPath(const string &path, const string &base) { - if (PathIsAbsolute(path)) - return path; - return base + "/" + path; -} - -namespace google_breakpad { - -void DwarfLineToModule::DefineDir(const string &name, uint32 dir_num) { - // Directory number zero is reserved to mean the compilation - // directory. Silently ignore attempts to redefine it. - if (dir_num != 0) - directories_[dir_num] = name; -} - -void DwarfLineToModule::DefineFile(const string &name, int32 file_num, - uint32 dir_num, uint64 mod_time, - uint64 length) { - if (file_num == -1) - file_num = ++highest_file_number_; - else if (file_num > highest_file_number_) - highest_file_number_ = file_num; - - std::string full_name; - if (dir_num != 0) { - DirectoryTable::const_iterator directory_it = directories_.find(dir_num); - if (directory_it != directories_.end()) { - full_name = ExpandPath(name, directory_it->second); - } else { - if (!warned_bad_directory_number_) { - fprintf(stderr, "warning: DWARF line number data refers to undefined" - " directory numbers\n"); - warned_bad_directory_number_ = true; - } - full_name = name; // just treat name as relative - } - } else { - // Directory number zero is the compilation directory; we just report - // relative paths in that case. - full_name = name; - } - - // Find a Module::File object of the given name, and add it to the - // file table. - files_[file_num] = module_->FindFile(full_name); -} - -void DwarfLineToModule::AddLine(uint64 address, uint64 length, - uint32 file_num, uint32 line_num, - uint32 column_num) { - if (length == 0) - return; - - // Clip lines not to extend beyond the end of the address space. - if (address + length < address) - length = -address; - - // Should we omit this line? (See the comments for omitted_line_end_.) - if (address == 0 || address == omitted_line_end_) { - omitted_line_end_ = address + length; - return; - } else { - omitted_line_end_ = 0; - } - - // Find the source file being referred to. - Module::File *file = files_[file_num]; - if (!file) { - if (!warned_bad_file_number_) { - fprintf(stderr, "warning: DWARF line number data refers to " - "undefined file numbers\n"); - warned_bad_file_number_ = true; - } - return; - } - Module::Line line; - line.address = address; - // We set the size when we get the next line or the EndSequence call. - line.size = length; - line.file = file; - line.number = line_num; - lines_->push_back(line); -} - -} // namespace google_breakpad diff --git a/src/common/linux/dwarf_line_to_module.h b/src/common/linux/dwarf_line_to_module.h deleted file mode 100644 index 7ff466d7..00000000 --- a/src/common/linux/dwarf_line_to_module.h +++ /dev/null @@ -1,179 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// The DwarfLineToModule class accepts line number information from a -// DWARF parser and adds it to a google_breakpad::Module. The Module -// can write that data out as a Breakpad symbol file. - -#ifndef COMMON_LINUX_DWARF_LINE_TO_MODULE_H -#define COMMON_LINUX_DWARF_LINE_TO_MODULE_H - -#include "common/linux/module.h" -#include "common/dwarf/dwarf2reader.h" - -namespace google_breakpad { - -// A class for producing a vector of google_breakpad::Module::Line -// instances from parsed DWARF line number data. -// -// An instance of this class can be provided as a handler to a -// dwarf2reader::LineInfo DWARF line number information parser. The -// handler accepts source location information from the parser and -// uses it to produce a vector of google_breakpad::Module::Line -// objects, referring to google_breakpad::Module::File objects added -// to a particular google_breakpad::Module. -// -// GNU toolchain omitted sections support: -// ====================================== -// -// Given the right options, the GNU toolchain will omit unreferenced -// functions from the final executable. Unfortunately, when it does so, it -// does not remove the associated portions of the DWARF line number -// program; instead, it gives the DW_LNE_set_address instructions referring -// to the now-deleted code addresses of zero. Given this input, the DWARF -// line parser will call AddLine with a series of lines starting at address -// zero. For example, here is the output from 'readelf -wl' for a program -// with four functions, the first three of which have been omitted: -// -// Line Number Statements: -// Extended opcode 2: set Address to 0x0 -// Advance Line by 14 to 15 -// Copy -// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16 -// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18 -// Advance PC by 2 to 0xd -// Extended opcode 1: End of Sequence -// -// Extended opcode 2: set Address to 0x0 -// Advance Line by 14 to 15 -// Copy -// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16 -// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18 -// Advance PC by 2 to 0xd -// Extended opcode 1: End of Sequence -// -// Extended opcode 2: set Address to 0x0 -// Advance Line by 19 to 20 -// Copy -// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 21 -// Special opcode 76: advance Address by 5 to 0x8 and Line by 1 to 22 -// Advance PC by 2 to 0xa -// Extended opcode 1: End of Sequence -// -// Extended opcode 2: set Address to 0x80483a4 -// Advance Line by 23 to 24 -// Copy -// Special opcode 202: advance Address by 14 to 0x80483b2 and Line by 1 to 25 -// Special opcode 76: advance Address by 5 to 0x80483b7 and Line by 1 to 26 -// Advance PC by 6 to 0x80483bd -// Extended opcode 1: End of Sequence -// -// Instead of collecting runs of lines describing code that is not there, -// we try to recognize and drop them. Since the linker doesn't explicitly -// distinguish references to dropped sections from genuine references to -// code at address zero, we must use a heuristic. We have chosen: -// -// - If a line starts at address zero, omit it. (On the platforms -// breakpad targets, it is extremely unlikely that there will be code -// at address zero.) -// -// - If a line starts immediately after an omitted line, omit it too. -class DwarfLineToModule: public dwarf2reader::LineInfoHandler { - public: - // As the DWARF line info parser passes us line records, add source - // files to MODULE, and add all lines to the end of LINES. LINES - // need not be empty. If the parser hands us a zero-length line, we - // omit it. If the parser hands us a line that extends beyond the - // end of the address space, we clip it. It's up to our client to - // sort out which lines belong to which functions; we don't add them - // to any particular function in MODULE ourselves. - DwarfLineToModule(Module *module, vector<Module::Line> *lines) - : module_(module), - lines_(lines), - highest_file_number_(-1), - omitted_line_end_(0), - warned_bad_file_number_(false), - warned_bad_directory_number_(false) { } - - ~DwarfLineToModule() { } - - void DefineDir(const std::string &name, uint32 dir_num); - void DefineFile(const std::string &name, int32 file_num, - uint32 dir_num, uint64 mod_time, - uint64 length); - void AddLine(uint64 address, uint64 length, - uint32 file_num, uint32 line_num, uint32 column_num); - - private: - - typedef std::map<uint32, std::string> DirectoryTable; - typedef std::map<uint32, Module::File *> FileTable; - - // The module we're contributing debugging info to. Owned by our - // client. - Module *module_; - - // The vector of lines we're accumulating. Owned by our client. - // - // In a Module, as in a breakpad symbol file, lines belong to - // specific functions, but DWARF simply assigns lines to addresses; - // one must infer the line/function relationship using the - // functions' beginning and ending addresses. So we can't add these - // to the appropriate function from module_ until we've read the - // function info as well. Instead, we accumulate lines here, and let - // whoever constructed this sort it all out. - vector<Module::Line> *lines_; - - // A table mapping directory numbers to paths. - DirectoryTable directories_; - - // A table mapping file numbers to Module::File pointers. - FileTable files_; - - // The highest file number we've seen so far, or -1 if we've seen - // none. Used for dynamically defined file numbers. - int32 highest_file_number_; - - // This is the ending address of the last line we omitted, or zero if we - // didn't omit the previous line. It is zero before we have received any - // AddLine calls. - uint64 omitted_line_end_; - - // True if we've warned about: - bool warned_bad_file_number_; // bad file numbers - bool warned_bad_directory_number_; // bad directory numbers -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_DWARF_LINE_TO_MODULE_H diff --git a/src/common/linux/dwarf_line_to_module_unittest.cc b/src/common/linux/dwarf_line_to_module_unittest.cc deleted file mode 100644 index 54411591..00000000 --- a/src/common/linux/dwarf_line_to_module_unittest.cc +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule. - -#include "breakpad_googletest_includes.h" -#include "common/linux/dwarf_line_to_module.h" - -using google_breakpad::DwarfLineToModule; -using google_breakpad::Module; -using google_breakpad::Module; - -TEST(Simple, One) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineFile("file1", 0x30bf0f27, 0, 0, 0); - h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27, - 0x4c090cbf, 0x1cf9fe0d); - - vector<Module::File *> files; - m.GetFiles(&files); - EXPECT_EQ(1U, files.size()); - EXPECT_STREQ("file1", files[0]->name.c_str()); - - EXPECT_EQ(1U, lines.size()); - EXPECT_EQ(0x6fd126fbf74f2680ULL, lines[0].address); - EXPECT_EQ(0x63c9a14cf556712bULL, lines[0].size); - EXPECT_TRUE(lines[0].file == files[0]); - EXPECT_EQ(0x4c090cbf, lines[0].number); -} - -TEST(Simple, Many) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineDir("directory1", 0x838299ab); - h.DefineDir("directory2", 0xf85de023); - h.DefineFile("file1", 0x2b80377a, 0x838299ab, 0, 0); - h.DefineFile("file1", 0x63beb4a4, 0xf85de023, 0, 0); - h.DefineFile("file2", 0x1d161d56, 0x838299ab, 0, 0); - h.DefineFile("file2", 0x1e7a667c, 0xf85de023, 0, 0); - h.AddLine(0x69900c5d553b7274ULL, 0x90fded183f0d0d3cULL, 0x2b80377a, - 0x15b0f0a9U, 0x3ff5abd6U); - h.AddLine(0x45811219a39b7101ULL, 0x25a5e6a924afc41fULL, 0x63beb4a4, - 0x4d259ce9U, 0x41c5ee32U); - h.AddLine(0xfa90514c1dc9704bULL, 0x0063efeabc02f313ULL, 0x1d161d56, - 0x1ee9fa4fU, 0xbf70e46aU); - h.AddLine(0x556b55fb6a647b10ULL, 0x3f3089ca2bfd80f5ULL, 0x1e7a667c, - 0x77fc280eU, 0x2c4a728cU); - h.DefineFile("file3", -1, 0, 0, 0); - h.AddLine(0xe2d72a37f8d9403aULL, 0x034dfab5b0d4d236ULL, 0x63beb4a5, - 0x75047044U, 0xb6a0016cU); - - vector<Module::File *> files; - m.GetFiles(&files); - ASSERT_EQ(5U, files.size()); - EXPECT_STREQ("directory1/file1", files[0]->name.c_str()); - EXPECT_STREQ("directory1/file2", files[1]->name.c_str()); - EXPECT_STREQ("directory2/file1", files[2]->name.c_str()); - EXPECT_STREQ("directory2/file2", files[3]->name.c_str()); - EXPECT_STREQ("file3", files[4]->name.c_str()); - - ASSERT_EQ(5U, lines.size()); - - EXPECT_EQ(0x69900c5d553b7274ULL, lines[0].address); - EXPECT_EQ(0x90fded183f0d0d3cULL, lines[0].size); - EXPECT_TRUE(lines[0].file == files[0]); - EXPECT_EQ(0x15b0f0a9, lines[0].number); - - EXPECT_EQ(0x45811219a39b7101ULL, lines[1].address); - EXPECT_EQ(0x25a5e6a924afc41fULL, lines[1].size); - EXPECT_TRUE(lines[1].file == files[2]); - EXPECT_EQ(0x4d259ce9, lines[1].number); - - EXPECT_EQ(0xfa90514c1dc9704bULL, lines[2].address); - EXPECT_EQ(0x0063efeabc02f313ULL, lines[2].size); - EXPECT_TRUE(lines[2].file == files[1]); - EXPECT_EQ(0x1ee9fa4f, lines[2].number); - - EXPECT_EQ(0x556b55fb6a647b10ULL, lines[3].address); - EXPECT_EQ(0x3f3089ca2bfd80f5ULL, lines[3].size); - EXPECT_TRUE(lines[3].file == files[3]); - EXPECT_EQ(0x77fc280e, lines[3].number); - - EXPECT_EQ(0xe2d72a37f8d9403aULL, lines[4].address); - EXPECT_EQ(0x034dfab5b0d4d236ULL, lines[4].size); - EXPECT_TRUE(lines[4].file == files[4]); - EXPECT_EQ(0x75047044, lines[4].number); -} - -TEST(Filenames, Absolute) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineDir("directory1", 1); - h.DefineFile("/absolute", 1, 1, 0, 0); - - h.AddLine(1, 1, 1, 0, 0); - - vector<Module::File *> files; - m.GetFiles(&files); - ASSERT_EQ(1U, files.size()); - EXPECT_STREQ("/absolute", files[0]->name.c_str()); - ASSERT_EQ(1U, lines.size()); - EXPECT_TRUE(lines[0].file == files[0]); -} - -TEST(Filenames, Relative) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineDir("directory1", 1); - h.DefineFile("relative", 1, 1, 0, 0); - - h.AddLine(1, 1, 1, 0, 0); - - vector<Module::File *> files; - m.GetFiles(&files); - ASSERT_EQ(1U, files.size()); - EXPECT_STREQ("directory1/relative", files[0]->name.c_str()); - ASSERT_EQ(1U, lines.size()); - EXPECT_TRUE(lines[0].file == files[0]); -} - -TEST(Filenames, StrangeFile) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineDir("directory1", 1); - h.DefineFile("", 1, 1, 0, 0); - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("directory1/", lines[0].file->name.c_str()); -} - -TEST(Filenames, StrangeDirectory) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineDir("", 1); - h.DefineFile("file1", 1, 1, 0, 0); - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("/file1", lines[0].file->name.c_str()); -} - -TEST(Filenames, StrangeDirectoryAndFile) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineDir("", 1); - h.DefineFile("", 1, 1, 0, 0); - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("/", lines[0].file->name.c_str()); -} - -// We should silently ignore attempts to define directory number zero, -// since that is always the compilation directory. -TEST(Errors, DirectoryZero) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineDir("directory0", 0); // should be ignored - h.DefineFile("relative", 1, 0, 0, 0); - - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("relative", lines[0].file->name.c_str()); -} - -// We should refuse to add lines with bogus file numbers. We should -// produce only one warning, however. -TEST(Errors, BadFileNumber) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineFile("relative", 1, 0, 0, 0); - h.AddLine(1, 1, 2, 0, 0); // bad file number - h.AddLine(2, 1, 2, 0, 0); // bad file number (no duplicate warning) - - EXPECT_EQ(0U, lines.size()); -} - -// We should treat files with bogus directory numbers as relative to -// the compilation unit. -TEST(Errors, BadDirectoryNumber) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineDir("directory1", 1); - h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number - h.DefineFile("baddirnumber2", 2, 2, 0, 0); // bad dir number (no warning) - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("baddirnumber1", lines[0].file->name.c_str()); -} - -// We promise not to report empty lines. -TEST(Errors, EmptyLine) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(1, 0, 1, 0, 0); - - ASSERT_EQ(0U, lines.size()); -} - -// We are supposed to clip lines that extend beyond the end of the -// address space. -TEST(Errors, BigLine) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_EQ(1U, lines[0].size); -} - -// The 'Omitted' tests verify that we correctly omit line information -// for code in sections that the linker has dropped. See "GNU -// toolchain omitted sections support" at the top of the -// DwarfLineToModule class. - -TEST(Omitted, DroppedThenGood) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0, 10, 1, 83816211, 0); // should be omitted - h.AddLine(20, 10, 1, 13059195, 0); // should be recorded - - ASSERT_EQ(1U, lines.size()); - EXPECT_EQ(13059195, lines[0].number); -} - -TEST(Omitted, GoodThenDropped) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0x9dd6a372, 10, 1, 41454594, 0); // should be recorded - h.AddLine(0, 10, 1, 44793413, 0); // should be omitted - - ASSERT_EQ(1U, lines.size()); - EXPECT_EQ(41454594, lines[0].number); -} - -TEST(Omitted, Mix1) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0x679ed72f, 10, 1, 58932642, 0); // should be recorded - h.AddLine(0xdfb5a72d, 10, 1, 39847385, 0); // should be recorded - h.AddLine(0, 0x78, 1, 23053829, 0); // should be omitted - h.AddLine(0x78, 0x6a, 1, 65317783, 0); // should be omitted - h.AddLine(0x78 + 0x6a, 0x2a, 1, 77601423, 0); // should be omitted - h.AddLine(0x9fe0cea5, 10, 1, 91806582, 0); // should be recorded - h.AddLine(0x7e41a109, 10, 1, 56169221, 0); // should be recorded - - ASSERT_EQ(4U, lines.size()); - EXPECT_EQ(58932642, lines[0].number); - EXPECT_EQ(39847385, lines[1].number); - EXPECT_EQ(91806582, lines[2].number); - EXPECT_EQ(56169221, lines[3].number); -} - -TEST(Omitted, Mix2) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0, 0xf2, 1, 58802211, 0); // should be omitted - h.AddLine(0xf2, 0xb9, 1, 78958222, 0); // should be omitted - h.AddLine(0xf2 + 0xb9, 0xf7, 1, 64861892, 0); // should be omitted - h.AddLine(0x4e4d271e, 9, 1, 67355743, 0); // should be recorded - h.AddLine(0xdfb5a72d, 30, 1, 23365776, 0); // should be recorded - h.AddLine(0, 0x64, 1, 76196762, 0); // should be omitted - h.AddLine(0x64, 0x33, 1, 71066611, 0); // should be omitted - h.AddLine(0x64 + 0x33, 0xe3, 1, 61749337, 0); // should be omitted - - ASSERT_EQ(2U, lines.size()); - EXPECT_EQ(67355743, lines[0].number); - EXPECT_EQ(23365776, lines[1].number); -} diff --git a/src/common/linux/language.cc b/src/common/linux/language.cc deleted file mode 100644 index 5e6473a1..00000000 --- a/src/common/linux/language.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// language.cc: Subclasses and singletons for google_breakpad::Language. -// See language.h for details. - -#include "common/linux/language.h" - -namespace google_breakpad { - -// C++ language-specific operations. -class CPPLanguage: public Language { - public: - string MakeQualifiedName(const string &parent_name, - const string &name) const { - if (parent_name.empty()) - return name; - else - return parent_name + "::" + name; - } -}; - -const CPPLanguage CPPLanguageSingleton; - -// Java language-specific operations. -class JavaLanguage: public Language { - public: - string MakeQualifiedName(const string &parent_name, - const string &name) const { - if (parent_name.empty()) - return name; - else - return parent_name + "." + name; - } -}; - -JavaLanguage JavaLanguageSingleton; - -// Assembler language-specific operations. -class AssemblerLanguage: public Language { - bool HasFunctions() const { return false; } - string MakeQualifiedName(const string &parent_name, - const string &name) const { - return name; - } -}; - -AssemblerLanguage AssemblerLanguageSingleton; - -const Language * const Language::CPlusPlus = &CPPLanguageSingleton; -const Language * const Language::Java = &JavaLanguageSingleton; -const Language * const Language::Assembler = &AssemblerLanguageSingleton; - -} // namespace google_breakpad diff --git a/src/common/linux/language.h b/src/common/linux/language.h deleted file mode 100644 index 03bdf7f0..00000000 --- a/src/common/linux/language.h +++ /dev/null @@ -1,84 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// language.h: Define google_breakpad::Language. Instances of -// subclasses of this class provide language-appropriate operations -// for the Breakpad symbol dumper. - -#ifndef COMMON_LINUX_LANGUAGE_H__ -#define COMMON_LINUX_LANGUAGE_H__ - -#include <string> - -namespace google_breakpad { - -using std::string; - -// An abstract base class for language-specific operations. We choose -// an instance of a subclass of this when we find the CU's language. -// This class's definitions are appropriate for CUs with no specified -// language. -class Language { - public: - // Return true if this language has functions to which we can assign - // line numbers. (Debugging info for assembly language, for example, - // can have source location information, but does not have functions - // recorded using DW_TAG_subprogram DIEs.) - virtual bool HasFunctions() const { return true; } - - // Construct a fully-qualified, language-appropriate form of NAME, - // given that PARENT_NAME is the name of the construct enclosing - // NAME. If PARENT_NAME is the empty string, then NAME is a - // top-level name. - // - // This API sort of assumes that a fully-qualified name is always - // some simple textual composition of the unqualified name and its - // parent's name, and that we don't need to know anything else about - // the parent or the child (say, their DIEs' tags) to do the job. - // This is true for the languages we support at the moment, and - // keeps things concrete. Perhaps a more refined operation would - // take into account the parent and child DIE types, allow languages - // to use their own data type for complex parent names, etc. But if - // C++ doesn't need all that, who would? - virtual string MakeQualifiedName (const string &parent_name, - const string &name) const = 0; - - // Instances for specific languages. - static const Language * const CPlusPlus, - * const Java, - * const Assembler; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_LANGUAGE_H__ diff --git a/src/common/linux/module.cc b/src/common/linux/module.cc deleted file mode 100644 index f6373895..00000000 --- a/src/common/linux/module.cc +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// module.cc: Implement google_breakpad::Module. See module.h. - -#include <cerrno> -#include <cstring> - -#include "common/linux/module.h" - -namespace google_breakpad { - -Module::Module(const string &name, const string &os, - const string &architecture, const string &id) : - name_(name), - os_(os), - architecture_(architecture), - id_(id), - load_address_(0) { } - -Module::~Module() { - for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); it++) - delete it->second; - for (vector<Function *>::iterator it = functions_.begin(); - it != functions_.end(); it++) - delete *it; - for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin(); - it != stack_frame_entries_.end(); it++) - delete *it; -} - -void Module::SetLoadAddress(Address address) { - load_address_ = address; -} - -void Module::AddFunction(Function *function) { - functions_.push_back(function); -} - -void Module::AddFunctions(vector<Function *>::iterator begin, - vector<Function *>::iterator end) { - functions_.insert(functions_.end(), begin, end); -} - -void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) { - stack_frame_entries_.push_back(stack_frame_entry); -} - -void Module::GetFunctions(vector<Function *> *vec, - vector<Function *>::iterator i) { - vec->insert(i, functions_.begin(), functions_.end()); -} - -Module::File *Module::FindFile(const string &name) { - // A tricky bit here. The key of each map entry needs to be a - // pointer to the entry's File's name string. This means that we - // can't do the initial lookup with any operation that would create - // an empty entry for us if the name isn't found (like, say, - // operator[] or insert do), because such a created entry's key will - // be a pointer the string passed as our argument. Since the key of - // a map's value type is const, we can't fix it up once we've - // created our file. lower_bound does the lookup without doing an - // insertion, and returns a good hint iterator to pass to insert. - // Our "destiny" is where we belong, whether we're there or not now. - FileByNameMap::iterator destiny = files_.lower_bound(&name); - if (destiny == files_.end() - || *destiny->first != name) { // Repeated string comparison, boo hoo. - File *file = new File; - file->name = name; - file->source_id = -1; - destiny = files_.insert(destiny, - FileByNameMap::value_type(&file->name, file)); - } - return destiny->second; -} - -Module::File *Module::FindFile(const char *name) { - string name_string = name; - return FindFile(name_string); -} - -Module::File *Module::FindExistingFile(const string &name) { - FileByNameMap::iterator it = files_.find(&name); - return (it == files_.end()) ? NULL : it->second; -} - -void Module::GetFiles(vector<File *> *vec) { - vec->clear(); - for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); it++) - vec->push_back(it->second); -} - -void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) { - *vec = stack_frame_entries_; -} - -void Module::AssignSourceIds() { - // First, give every source file an id of -1. - for (FileByNameMap::iterator file_it = files_.begin(); - file_it != files_.end(); file_it++) - file_it->second->source_id = -1; - - // Next, mark all files actually cited by our functions' line number - // info, by setting each one's source id to zero. - for (vector<Function *>::const_iterator func_it = functions_.begin(); - func_it != functions_.end(); func_it++) { - Function *func = *func_it; - for (vector<Line>::iterator line_it = func->lines.begin(); - line_it != func->lines.end(); line_it++) - line_it->file->source_id = 0; - } - - // Finally, assign source ids to those files that have been marked. - // We could have just assigned source id numbers while traversing - // the line numbers, but doing it this way numbers the files in - // lexicographical order by name, which is neat. - int next_source_id = 0; - for (FileByNameMap::iterator file_it = files_.begin(); - file_it != files_.end(); file_it++) - if (! file_it->second->source_id) - file_it->second->source_id = next_source_id++; -} - -bool Module::ReportError() { - fprintf(stderr, "error writing symbol file: %s\n", - strerror (errno)); - return false; -} - -bool Module::WriteRuleMap(const RuleMap &rule_map, FILE *stream) { - for (RuleMap::const_iterator it = rule_map.begin(); - it != rule_map.end(); it++) { - if (it != rule_map.begin() && - 0 > putc(' ', stream)) - return false; - if (0 > fprintf(stream, "%s: %s", it->first.c_str(), it->second.c_str())) - return false; - } - return true; -} - -bool Module::Write(FILE *stream) { - if (0 > fprintf(stream, "MODULE %s %s %s %s\n", - os_.c_str(), architecture_.c_str(), id_.c_str(), - name_.c_str())) - return ReportError(); - - AssignSourceIds(); - - // Write out files. - for (FileByNameMap::iterator file_it = files_.begin(); - file_it != files_.end(); file_it++) { - File *file = file_it->second; - if (file->source_id >= 0) { - if (0 > fprintf(stream, "FILE %d %s\n", - file->source_id, file->name.c_str())) - return ReportError(); - } - } - - // Write out functions and their lines. - for (vector<Function *>::const_iterator func_it = functions_.begin(); - func_it != functions_.end(); func_it++) { - Function *func = *func_it; - if (0 > fprintf(stream, "FUNC %llx %llx %llx %s\n", - (unsigned long long) (func->address - load_address_), - (unsigned long long) func->size, - (unsigned long long) func->parameter_size, - func->name.c_str())) - return ReportError(); - for (vector<Line>::iterator line_it = func->lines.begin(); - line_it != func->lines.end(); line_it++) - if (0 > fprintf(stream, "%llx %llx %d %d\n", - (unsigned long long) (line_it->address - load_address_), - (unsigned long long) line_it->size, - line_it->number, - line_it->file->source_id)) - return ReportError(); - } - - // Write out 'STACK CFI INIT' and 'STACK CFI' records. - vector<StackFrameEntry *>::const_iterator frame_it; - for (frame_it = stack_frame_entries_.begin(); - frame_it != stack_frame_entries_.end(); frame_it++) { - StackFrameEntry *entry = *frame_it; - if (0 > fprintf(stream, "STACK CFI INIT %llx %llx ", - (unsigned long long) entry->address - load_address_, - (unsigned long long) entry->size) - || !WriteRuleMap(entry->initial_rules, stream) - || 0 > putc('\n', stream)) - return ReportError(); - - // Write out this entry's delta rules as 'STACK CFI' records. - for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin(); - delta_it != entry->rule_changes.end(); delta_it++) { - if (0 > fprintf(stream, "STACK CFI %llx ", - (unsigned long long) delta_it->first - load_address_) - || !WriteRuleMap(delta_it->second, stream) - || 0 > putc('\n', stream)) - return ReportError(); - } - } - - return true; -} - -} // namespace google_breakpad diff --git a/src/common/linux/module.h b/src/common/linux/module.h deleted file mode 100644 index 7a44d4ab..00000000 --- a/src/common/linux/module.h +++ /dev/null @@ -1,268 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// module.h: Define google_breakpad::Module. A Module holds debugging -// information, and can write that information out as a Breakpad -// symbol file. - -#ifndef COMMON_LINUX_MODULE_H__ -#define COMMON_LINUX_MODULE_H__ - -#include <map> -#include <string> -#include <vector> -#include <cstdio> - -#include "google_breakpad/common/breakpad_types.h" - -namespace google_breakpad { - -using std::string; -using std::vector; -using std::map; - -// A Module represents the contents of a module, and supports methods -// for adding information produced by parsing STABS or DWARF data -// --- possibly both from the same file --- and then writing out the -// unified contents as a Breakpad-format symbol file. -class Module { - public: - // The type of addresses and sizes in a symbol table. - typedef u_int64_t Address; - struct File; - struct Function; - struct Line; - - // Addresses appearing in File, Function, and Line structures are - // absolute, not relative to the the module's load address. That - // is, if the module were loaded at its nominal load address, the - // addresses would be correct. - - // A source file. - struct File { - // The name of the source file. - string name; - - // The file's source id. The Write member function clears this - // field and assigns source ids a fresh, so any value placed here - // before calling Write will be lost. - int source_id; - }; - - // A function. - struct Function { - // For sorting by address. (Not style-guide compliant, but it's - // stupid not to put this in the struct.) - static bool CompareByAddress(const Function *x, const Function *y) { - return x->address < y->address; - } - - // The function's name. - string name; - - // The start address and length of the function's code. - Address address, size; - - // The function's parameter size. - Address parameter_size; - - // Source lines belonging to this function, sorted by increasing - // address. - vector<Line> lines; - }; - - // A source line. - struct Line { - // For sorting by address. (Not style-guide compliant, but it's - // stupid not to put this in the struct.) - static bool CompareByAddress(const Module::Line &x, const Module::Line &y) { - return x.address < y.address; - } - - Address address, size; // The address and size of the line's code. - File *file; // The source file. - int number; // The source line number. - }; - - // A map from register names to postfix expressions that recover - // their their values. This can represent a complete set of rules to - // follow at some address, or a set of changes to be applied to an - // extant set of rules. - typedef map<string, string> RuleMap; - - // A map from addresses to RuleMaps, representing changes that take - // effect at given addresses. - typedef map<Address, RuleMap> RuleChangeMap; - - // A range of 'STACK CFI' stack walking information. An instance of - // this structure corresponds to a 'STACK CFI INIT' record and the - // subsequent 'STACK CFI' records that fall within its range. - struct StackFrameEntry { - // The starting address and number of bytes of machine code this - // entry covers. - Address address, size; - - // The initial register recovery rules, in force at the starting - // address. - RuleMap initial_rules; - - // A map from addresses to rule changes. To find the rules in - // force at a given address, start with initial_rules, and then - // apply the changes given in this map for all addresses up to and - // including the address you're interested in. - RuleChangeMap rule_changes; - }; - - // Create a new module with the given name, operating system, - // architecture, and ID string. - Module(const string &name, const string &os, const string &architecture, - const string &id); - ~Module(); - - // Set the module's load address to LOAD_ADDRESS; addresses given - // for functions and lines will be written to the Breakpad symbol - // file as offsets from this address. Construction initializes this - // module's load address to zero: addresses written to the symbol - // file will be the same as they appear in the File and Line - // structures. - void SetLoadAddress(Address load_address); - - // Add FUNCTION to the module. - // This module owns all Function objects added with this function: - // destroying the module destroys them as well. - void AddFunction(Function *function); - - // Add all the functions in [BEGIN,END) to the module. - // This module owns all Function objects added with this function: - // destroying the module destroys them as well. - void AddFunctions(vector<Function *>::iterator begin, - vector<Function *>::iterator end); - - // Add STACK_FRAME_ENTRY to the module. - // - // This module owns all StackFrameEntry objects added with this - // function: destroying the module destroys them as well. - void AddStackFrameEntry(StackFrameEntry *stack_frame_entry); - - // If this module has a file named NAME, return a pointer to it. If - // it has none, then create one and return a pointer to the new - // file. This module owns all File objects created using these - // functions; destroying the module destroys them as well. - File *FindFile(const string &name); - File *FindFile(const char *name); - - // If this module has a file named NAME, return a pointer to it. - // Otherwise, return NULL. - File *FindExistingFile(const string &name); - - // Insert pointers to the functions added to this module at I in - // VEC. The pointed-to Functions are still owned by this module. - // (Since this is effectively a copy of the function list, this is - // mostly useful for testing; other uses should probably get a more - // appropriate interface.) - void GetFunctions(vector<Function *> *vec, vector<Function *>::iterator i); - - // Clear VEC and fill it with pointers to the Files added to this - // module, sorted by name. The pointed-to Files are still owned by - // this module. (Since this is effectively a copy of the file list, - // this is mostly useful for testing; other uses should probably get - // a more appropriate interface.) - void GetFiles(vector<File *> *vec); - - // Clear VEC and fill it with pointers to the StackFrameEntry - // objects that have been added to this module. (Since this is - // effectively a copy of the stack frame entry list, this is mostly - // useful for testing; other uses should probably get - // a more appropriate interface.) - void GetStackFrameEntries(vector<StackFrameEntry *> *vec); - - // Find those files in this module that are actually referred to by - // functions' line number data, and assign them source id numbers. - // Set the source id numbers for all other files --- unused by the - // source line data --- to -1. We do this before writing out the - // symbol file, at which point we omit any unused files. - void AssignSourceIds(); - - // Call AssignSourceIds, and write this module to STREAM in the - // breakpad symbol format. Return true if all goes well, or false if - // an error occurs. This method writes out: - // - a header based on the values given to the constructor, - // - the source files added via FindFile, and finally - // - the functions added via AddFunctions, each with its lines. - // Addresses in the output are all relative to the load address - // established by SetLoadAddress. - bool Write(FILE *stream); - -private: - - // Report an error that has occurred writing the symbol file, using - // errno to find the appropriate cause. Return false. - static bool ReportError(); - - // Write RULE_MAP to STREAM, in the form appropriate for 'STACK CFI' - // records, without a final newline. Return true if all goes well; - // if an error occurs, return false, and leave errno set. - static bool WriteRuleMap(const RuleMap &rule_map, FILE *stream); - - // Module header entries. - string name_, os_, architecture_, id_; - - // The module's nominal load address. Addresses for functions and - // lines are absolute, assuming the module is loaded at this - // address. - Address load_address_; - - // Relation for maps whose keys are strings shared with some other - // structure. - struct CompareStringPtrs { - bool operator()(const string *x, const string *y) { return *x < *y; }; - }; - - // A map from filenames to File structures. The map's keys are - // pointers to the Files' names. - typedef map<const string *, File *, CompareStringPtrs> FileByNameMap; - - // The module owns all the files and functions that have been added - // to it; destroying the module frees the Files and Functions these - // point to. - FileByNameMap files_; // This module's source files. - vector<Function *> functions_; // This module's functions. - - // The module owns all the call frame info entries that have been - // added to it. - vector<StackFrameEntry *> stack_frame_entries_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_MODULE_H__ diff --git a/src/common/linux/module_unittest.cc b/src/common/linux/module_unittest.cc deleted file mode 100644 index 771d91e5..00000000 --- a/src/common/linux/module_unittest.cc +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// module_unittest.cc: Unit tests for google_breakpad::Module. - -#include <cerrno> -#include <cstdio> -#include <cstdlib> -#include <cstring> - -#include <algorithm> -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/linux/module.h" - -using google_breakpad::Module; -using std::string; -using std::vector; -using testing::ContainerEq; - -// Return a FILE * referring to a temporary file that will be deleted -// automatically when the stream is closed or the program exits. -FILE *checked_tmpfile() { - FILE *f = tmpfile(); - if (!f) { - fprintf(stderr, "error creating temporary file: %s\n", strerror(errno)); - exit(1); - } - return f; -} - -// Read from STREAM until end of file, and return the contents as a -// string. -string checked_read(FILE *stream) { - string contents; - int c; - while ((c = getc(stream)) != EOF) - contents.push_back(c); - if (ferror(stream)) { - fprintf(stderr, "error reading temporary file contents: %s\n", - strerror(errno)); - exit(1); - } - return contents; -} - -// Apply 'fflush' to STREAM, and check for errors. -void checked_fflush(FILE *stream) { - if (fflush(stream) == EOF) { - fprintf(stderr, "error flushing temporary file stream: %s\n", - strerror(errno)); - exit(1); - } -} - -// Apply 'fclose' to STREAM, and check for errors. -void checked_fclose(FILE *stream) { - if (fclose(stream) == EOF) { - fprintf(stderr, "error closing temporary file stream: %s\n", - strerror(errno)); - exit(1); - } -} - -#define MODULE_NAME "name with spaces" -#define MODULE_OS "os-name" -#define MODULE_ARCH "architecture" -#define MODULE_ID "id-string" - -TEST(Write, Header) { - FILE *f = checked_tmpfile(); - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - m.Write(f); - checked_fflush(f); - rewind(f); - string contents = checked_read(f); - checked_fclose(f); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", - contents.c_str()); -} - -TEST(Write, OneLineFunc) { - FILE *f = checked_tmpfile(); - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - Module::File *file = m.FindFile("file_name.cc"); - Module::Function *function = new(Module::Function); - function->name = "function_name"; - function->address = 0xe165bf8023b9d9abLL; - function->size = 0x1e4bb0eb1cbf5b09LL; - function->parameter_size = 0x772beee89114358aLL; - Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL, - file, 67519080 }; - function->lines.push_back(line); - m.AddFunction(function); - - m.Write(f); - checked_fflush(f); - rewind(f); - string contents = checked_read(f); - checked_fclose(f); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FILE 0 file_name.cc\n" - "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a" - " function_name\n" - "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n", - contents.c_str()); -} - -TEST(Write, RelativeLoadAddress) { - FILE *f = checked_tmpfile(); - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - m.SetLoadAddress(0x2ab698b0b6407073LL); - - // Some source files. We will expect to see them in lexicographic order. - Module::File *file1 = m.FindFile("filename-b.cc"); - Module::File *file2 = m.FindFile("filename-a.cc"); - - // A function. - Module::Function *function = new(Module::Function); - function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)"; - function->address = 0xbec774ea5dd935f3LL; - function->size = 0x2922088f98d3f6fcLL; - function->parameter_size = 0xe5e9aa008bd5f0d0LL; - - // Some source lines. The module should not sort these. - Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, - file1, 41676901 }; - Module::Line line2 = { 0xdaf35bc123885c04LL, 0xcf621b8d324d0ebLL, - file2, 67519080 }; - function->lines.push_back(line2); - function->lines.push_back(line1); - - m.AddFunction(function); - - // Some stack information. - Module::StackFrameEntry *entry = new Module::StackFrameEntry(); - entry->address = 0x30f9e5c83323973dULL; - entry->size = 0x49fc9ca7c7c13dc2ULL; - entry->initial_rules[".cfa"] = "he was a handsome man"; - entry->initial_rules["and"] = "what i want to know is"; - entry->rule_changes[0x30f9e5c83323973eULL]["how"] = - "do you like your blueeyed boy"; - entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; - m.AddStackFrameEntry(entry); - - m.Write(f); - checked_fflush(f); - rewind(f); - string contents = checked_read(f); - checked_fclose(f); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FILE 0 filename-a.cc\n" - "FILE 1 filename-b.cc\n" - "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" - " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" - "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n" - "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n" - "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2" - " .cfa: he was a handsome man" - " and: what i want to know is\n" - "STACK CFI 6434d177ce326cb" - " Mister: Death" - " how: do you like your blueeyed boy\n", - contents.c_str()); -} - -TEST(Write, OmitUnusedFiles) { - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Create some source files. - Module::File *file1 = m.FindFile("filename1"); - m.FindFile("filename2"); // not used by any line - Module::File *file3 = m.FindFile("filename3"); - - // Create a function. - Module::Function *function = new(Module::Function); - function->name = "function_name"; - function->address = 0x9b926d464f0b9384LL; - function->size = 0x4f524a4ba795e6a6LL; - function->parameter_size = 0xbbe8133a6641c9b7LL; - - // Source files that refer to some files, but not others. - Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL, - file1, 137850127 }; - Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL, - file3, 28113549 }; - function->lines.push_back(line1); - function->lines.push_back(line2); - m.AddFunction(function); - - m.AssignSourceIds(); - - vector<Module::File *> vec; - m.GetFiles(&vec); - EXPECT_EQ((size_t) 3, vec.size()); - EXPECT_STREQ("filename1", vec[0]->name.c_str()); - EXPECT_NE(-1, vec[0]->source_id); - // Expect filename2 not to be used. - EXPECT_STREQ("filename2", vec[1]->name.c_str()); - EXPECT_EQ(-1, vec[1]->source_id); - EXPECT_STREQ("filename3", vec[2]->name.c_str()); - EXPECT_NE(-1, vec[2]->source_id); - - FILE *f = checked_tmpfile(); - m.Write(f); - checked_fflush(f); - rewind(f); - string contents = checked_read(f); - checked_fclose(f); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FILE 0 filename1\n" - "FILE 1 filename3\n" - "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" - " function_name\n" - "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n" - "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n", - contents.c_str()); -} - -TEST(Construct, AddFunctions) { - FILE *f = checked_tmpfile(); - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Two functions. - Module::Function *function1 = new(Module::Function); - function1->name = "_without_form"; - function1->address = 0xd35024aa7ca7da5cLL; - function1->size = 0x200b26e605f99071LL; - function1->parameter_size = 0xf14ac4fed48c4a99LL; - - Module::Function *function2 = new(Module::Function); - function2->name = "_and_void"; - function2->address = 0x2987743d0b35b13fLL; - function2->size = 0xb369db048deb3010LL; - function2->parameter_size = 0x938e556cb5a79988LL; - - // Put them in a vector. - vector<Module::Function *> vec; - vec.push_back(function1); - vec.push_back(function2); - - m.AddFunctions(vec.begin(), vec.end()); - - m.Write(f); - checked_fflush(f); - rewind(f); - string contents = checked_read(f); - checked_fclose(f); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99" - " _without_form\n" - "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" - " _and_void\n", - contents.c_str()); - - // Check that m.GetFunctions returns the functions we expect. - vec.clear(); - m.GetFunctions(&vec, vec.end()); - EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1)); - EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2)); - EXPECT_EQ((size_t) 2, vec.size()); -} - -TEST(Construct, AddFrames) { - FILE *f = checked_tmpfile(); - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // First STACK CFI entry, with no initial rules or deltas. - Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); - entry1->address = 0xddb5f41285aa7757ULL; - entry1->size = 0x1486493370dc5073ULL; - m.AddStackFrameEntry(entry1); - - // Second STACK CFI entry, with initial rules but no deltas. - Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); - entry2->address = 0x8064f3af5e067e38ULL; - entry2->size = 0x0de2a5ee55509407ULL; - entry2->initial_rules[".cfa"] = "I think that I shall never see"; - entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; - entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; - m.AddStackFrameEntry(entry2); - - // Third STACK CFI entry, with initial rules and deltas. - Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); - entry3->address = 0x5e8d0db0a7075c6cULL; - entry3->size = 0x1c7edb12a7aea229ULL; - entry3->initial_rules[".cfa"] = "Whose woods are these"; - entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = - "the village though"; - entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = - "he will not see me stopping here"; - entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = - "his house is in"; - entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = - "I think I know"; - m.AddStackFrameEntry(entry3); - - // Check that Write writes STACK CFI records properly. - m.Write(f); - checked_fflush(f); - rewind(f); - string contents = checked_read(f); - checked_fclose(f); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n" - "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" - " .cfa: I think that I shall never see" - " cannoli: a tree whose hungry mouth is prest" - " stromboli: a poem lovely as a tree\n" - "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" - " .cfa: Whose woods are these\n" - "STACK CFI 36682fad3763ffff" - " .cfa: I think I know" - " stromboli: his house is in\n" - "STACK CFI 47ceb0f63c269d7f" - " calzone: the village though" - " cannoli: he will not see me stopping here\n", - contents.c_str()); - - // Check that GetStackFrameEntries works. - vector<Module::StackFrameEntry *> entries; - m.GetStackFrameEntries(&entries); - ASSERT_EQ(3U, entries.size()); - // Check first entry. - EXPECT_EQ(0xddb5f41285aa7757ULL, entries[0]->address); - EXPECT_EQ(0x1486493370dc5073ULL, entries[0]->size); - ASSERT_EQ(0U, entries[0]->initial_rules.size()); - ASSERT_EQ(0U, entries[0]->rule_changes.size()); - // Check second entry. - EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); - EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); - ASSERT_EQ(3U, entries[1]->initial_rules.size()); - Module::RuleMap entry2_initial; - entry2_initial[".cfa"] = "I think that I shall never see"; - entry2_initial["stromboli"] = "a poem lovely as a tree"; - entry2_initial["cannoli"] = "a tree whose hungry mouth is prest"; - EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); - ASSERT_EQ(0U, entries[1]->rule_changes.size()); - // Check third entry. - EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[2]->address); - EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[2]->size); - Module::RuleMap entry3_initial; - entry3_initial[".cfa"] = "Whose woods are these"; - EXPECT_THAT(entries[2]->initial_rules, ContainerEq(entry3_initial)); - Module::RuleChangeMap entry3_changes; - entry3_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; - entry3_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; - entry3_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; - entry3_changes[0x47ceb0f63c269d7fULL]["cannoli"] = - "he will not see me stopping here"; - EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes)); -} - -TEST(Construct, UniqueFiles) { - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - Module::File *file1 = m.FindFile("foo"); - Module::File *file2 = m.FindFile(string("bar")); - Module::File *file3 = m.FindFile(string("foo")); - Module::File *file4 = m.FindFile("bar"); - EXPECT_NE(file1, file2); - EXPECT_EQ(file1, file3); - EXPECT_EQ(file2, file4); - EXPECT_EQ(file1, m.FindExistingFile("foo")); - EXPECT_TRUE(m.FindExistingFile("baz") == NULL); -} diff --git a/src/common/linux/stabs_reader.cc b/src/common/linux/stabs_reader.cc deleted file mode 100644 index a536144f..00000000 --- a/src/common/linux/stabs_reader.cc +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// This file implements the google_breakpad::StabsReader class. -// See stabs_reader.h. - -#include <a.out.h> -#include <stab.h> -#include <cstring> -#include <cassert> - -#include "common/linux/stabs_reader.h" - -namespace google_breakpad { - -StabsReader::StabsReader(const uint8_t *stab, size_t stab_size, - const uint8_t *stabstr, size_t stabstr_size, - StabsHandler *handler) : - stabstr_(stabstr), - stabstr_size_(stabstr_size), - handler_(handler), - string_offset_(0), - next_cu_string_offset_(0), - symbol_(NULL), - current_source_file_(NULL) { - symbols_ = reinterpret_cast<const struct nlist *>(stab); - symbols_end_ = symbols_ + (stab_size / sizeof (*symbols_)); -} - -const char *StabsReader::SymbolString() { - ptrdiff_t offset = string_offset_ + symbol_->n_un.n_strx; - if (offset < 0 || (size_t) offset >= stabstr_size_) { - handler_->Warning("symbol %d: name offset outside the string section\n", - symbol_ - symbols_); - // Return our null string, to keep our promise about all names being - // taken from the string section. - offset = 0; - } - return reinterpret_cast<const char *>(stabstr_ + offset); -} - -bool StabsReader::Process() { - symbol_ = symbols_; - while (symbol_ < symbols_end_) { - if (symbol_->n_type == N_SO) { - if (! ProcessCompilationUnit()) - return false; - } else if (symbol_->n_type == N_UNDF) { - // At the head of each compilation unit's entries there is an - // N_UNDF stab giving the number of symbols in the compilation - // unit, and the number of bytes that compilation unit's strings - // take up in the .stabstr section. Each CU's strings are - // separate; the n_strx values are offsets within the current - // CU's portion of the .stabstr section. - // - // As an optimization, the GNU linker combines all the - // compilation units into one, with a single N_UNDF at the - // beginning. However, other linkers, like Gold, do not perform - // this optimization. - string_offset_ = next_cu_string_offset_; - next_cu_string_offset_ = SymbolValue(); - symbol_++; - } else - symbol_++; - } - return true; -} - -bool StabsReader::ProcessCompilationUnit() { - assert(symbol_ < symbols_end_ && symbol_->n_type == N_SO); - - // There may be an N_SO entry whose name ends with a slash, - // indicating the directory in which the compilation occurred. - // The build directory defaults to NULL. - const char *build_directory = NULL; - { - const char *name = SymbolString(); - if (name[0] && name[strlen(name) - 1] == '/') { - build_directory = name; - symbol_++; - } - } - - // We expect to see an N_SO entry with a filename next, indicating - // the start of the compilation unit. - { - if (symbol_ >= symbols_end_ || symbol_->n_type != N_SO) - return true; - const char *name = SymbolString(); - if (name[0] == '\0') { - // This seems to be a stray end-of-compilation-unit marker; - // consume it, but don't report the end, since we didn't see a - // beginning. - symbol_++; - return true; - } - current_source_file_ = name; - } - - if (! handler_->StartCompilationUnit(current_source_file_, - SymbolValue(), - build_directory)) - return false; - - symbol_++; - - // The STABS documentation says that some compilers may emit - // additional N_SO entries with names immediately following the - // first, and that they should be ignored. However, the original - // Breakpad STABS reader doesn't ignore them, so we won't either. - - // Process the body of the compilation unit, up to the next N_SO. - while (symbol_ < symbols_end_ && symbol_->n_type != N_SO) { - if (symbol_->n_type == N_FUN) { - if (! ProcessFunction()) - return false; - } else - // Ignore anything else. - symbol_++; - } - - // An N_SO with an empty name indicates the end of the compilation - // unit. Default to zero. - uint64_t ending_address = 0; - if (symbol_ < symbols_end_) { - assert(symbol_->n_type == N_SO); - const char *name = SymbolString(); - if (name[0] == '\0') { - ending_address = SymbolValue(); - symbol_++; - } - } - - if (! handler_->EndCompilationUnit(ending_address)) - return false; - - return true; -} - -bool StabsReader::ProcessFunction() { - assert(symbol_ < symbols_end_ && symbol_->n_type == N_FUN); - - uint64_t function_address = SymbolValue(); - // The STABS string for an N_FUN entry is the name of the function, - // followed by a colon, followed by type information for the - // function. We want to pass the name alone to StartFunction. - const char *stab_string = SymbolString(); - const char *name_end = strchr(stab_string, ':'); - if (! name_end) - name_end = stab_string + strlen(stab_string); - std::string name(stab_string, name_end - stab_string); - if (! handler_->StartFunction(name, function_address)) - return false; - symbol_++; - - while (symbol_ < symbols_end_) { - if (symbol_->n_type == N_SO || symbol_->n_type == N_FUN) - break; - else if (symbol_->n_type == N_SLINE) { - // The value of an N_SLINE entry is the offset of the line from - // the function's start address. - uint64_t line_address = function_address + SymbolValue(); - // The n_desc of a N_SLINE entry is the line number. It's a - // signed 16-bit field; line numbers from 32768 to 65535 are - // stored as n-65536. - uint16_t line_number = symbol_->n_desc; - if (! handler_->Line(line_address, current_source_file_, line_number)) - return false; - symbol_++; - } else if (symbol_->n_type == N_SOL) { - current_source_file_ = SymbolString(); - symbol_++; - } else - // Ignore anything else. - symbol_++; - } - - // If there is a subsequent N_SO or N_FUN entry, its address is our - // end address. - uint64_t ending_address = 0; - if (symbol_ < symbols_end_) { - assert(symbol_->n_type == N_SO || symbol_->n_type == N_FUN); - ending_address = SymbolValue(); - // Note: we do not increment symbol_ here, since we haven't consumed it. - } - - if (! handler_->EndFunction(ending_address)) - return false; - - return true; -} - -} // namespace google_breakpad diff --git a/src/common/linux/stabs_reader.h b/src/common/linux/stabs_reader.h deleted file mode 100644 index 5cfcdfb5..00000000 --- a/src/common/linux/stabs_reader.h +++ /dev/null @@ -1,206 +0,0 @@ -// -*- mode: c++ -*- - -// Copyright (c) 2010 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// stabs_reader.h: Define StabsReader, a parser for STABS debugging -// information. A description of the STABS debugging format can be -// found at: -// -// http://sourceware.org/gdb/current/onlinedocs/stabs_toc.html -// -// The comments here assume you understand the format. -// -// This parser assumes that the system's <a.out.h> and <stab.h> -// headers accurately describe the layout of the STABS data; this code -// will not parse STABS data for a system with a different address -// size or endianness. - -#ifndef COMMON_LINUX_STABS_READER_H__ -#define COMMON_LINUX_STABS_READER_H__ - -#include <stdint.h> -#include <cstddef> -#include <a.out.h> - -#include <string> - -namespace google_breakpad { - -class StabsHandler; - -class StabsReader { - public: - // Create a reader for the STABS debug information whose .stab - // section is the STAB_SIZE bytes at STAB, and whose .stabstr - // section is the STABSTR_SIZE bytes at STABSTR. The reader will - // call the member functions of HANDLER to report the information it - // finds, when the reader's 'Process' member function is called. - // - // Note that, in ELF, the .stabstr section should be found using the - // 'sh_link' field of the .stab section header, not by name. - StabsReader(const uint8_t *stab, size_t stab_size, - const uint8_t *stabstr, size_t stabstr_size, - StabsHandler *handler); - - // Process the STABS data, calling the handler's member functions to - // report what we find. While the handler functions return true, - // continue to process until we reach the end of the section. If we - // processed the entire section and all handlers returned true, - // return true. If any handler returned false, return false. - bool Process(); - - private: - // Return the name of the current symbol. - const char *SymbolString(); - - // Return the value of the current symbol. - const uint64_t SymbolValue() { - return symbol_->n_value; - } - - // Process a compilation unit starting at symbol_. Return true - // to continue processing, or false to abort. - bool ProcessCompilationUnit(); - - // Process a function in current_source_file_ starting at symbol_. - // Return true to continue processing, or false to abort. - bool ProcessFunction(); - - // The debugging information we're reading. - const struct nlist *symbols_, *symbols_end_; - const uint8_t *stabstr_; - size_t stabstr_size_; - - StabsHandler *handler_; - - // The offset of the current compilation unit's strings within stabstr_. - size_t string_offset_; - - // The value string_offset_ should have for the next compilation unit, - // as established by N_UNDF entries. - size_t next_cu_string_offset_; - - // The current symbol we're processing. - const struct nlist *symbol_; - - // The current source file name. - const char *current_source_file_; -}; - -// Consumer-provided callback structure for the STABS reader. Clients -// of the STABS reader provide an instance of this structure. The -// reader then invokes the member functions of that instance to report -// the information it finds. -// -// The default definitions of the member functions do nothing, and return -// true so processing will continue. -class StabsHandler { - public: - StabsHandler() { } - virtual ~StabsHandler() { } - - // Some general notes about the handler callback functions: - - // Processing proceeds until the end of the .stabs section, or until - // one of these functions returns false. - - // The addresses given are as reported in the STABS info, without - // regard for whether the module may be loaded at different - // addresses at different times (a shared library, say). When - // processing STABS from an ELF shared library, the addresses given - // all assume the library is loaded at its nominal load address. - // They are *not* offsets from the nominal load address. If you - // want offsets, you must subtract off the library's nominal load - // address. - - // The arguments to these functions named FILENAME are all - // references to strings stored in the .stabstr section. Because - // both the Linux and Solaris linkers factor out duplicate strings - // from the .stabstr section, the consumer can assume that if two - // FILENAME values are different addresses, they represent different - // file names. - // - // Thus, it's safe to use (say) std::map<char *, ...>, which does - // string address comparisons, not string content comparisons. - // Since all the strings are in same array of characters --- the - // .stabstr section --- comparing their addresses produces - // predictable, if not lexicographically meaningful, results. - - // Begin processing a compilation unit whose main source file is - // named FILENAME, and whose base address is ADDRESS. If - // BUILD_DIRECTORY is non-NULL, it is the name of the build - // directory in which the compilation occurred. - virtual bool StartCompilationUnit(const char *filename, uint64_t address, - const char *build_directory) { - return true; - } - - // Finish processing the compilation unit. If ADDRESS is non-zero, - // it is the ending address of the compilation unit. If ADDRESS is - // zero, then the compilation unit's ending address is not - // available, and the consumer must infer it by other means. - virtual bool EndCompilationUnit(uint64_t address) { return true; } - - // Begin processing a function named NAME, whose starting address is - // ADDRESS. This function belongs to the compilation unit that was - // most recently started but not ended. - // - // Note that, unlike filenames, NAME is not a pointer into the - // .stabstr section; this is because the name as it appears in the - // STABS data is followed by type information. The value passed to - // StartFunction is the function name alone. - // - // In languages that use name mangling, like C++, NAME is mangled. - virtual bool StartFunction(const std::string &name, uint64_t address) { - return true; - } - - // Finish processing the function. If ADDRESS is non-zero, it is - // the ending address for the function. If ADDRESS is zero, then - // the function's ending address is not available, and the consumer - // must infer it by other means. - virtual bool EndFunction(uint64_t address) { return true; } - - // Report that the code at ADDRESS is attributable to line NUMBER of - // the source file named FILENAME. The caller must infer the ending - // address of the line. - virtual bool Line(uint64_t address, const char *filename, int number) { - return true; - } - - // Report a warning. FORMAT is a printf-like format string, - // specifying how to format the subsequent arguments. - virtual void Warning(const char *format, ...) = 0; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_STABS_READER_H__ diff --git a/src/common/linux/stabs_reader_unittest.cc b/src/common/linux/stabs_reader_unittest.cc deleted file mode 100644 index 88fcfe67..00000000 --- a/src/common/linux/stabs_reader_unittest.cc +++ /dev/null @@ -1,685 +0,0 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader. - -#include <a.out.h> -#include <cassert> -#include <cerrno> -#include <cstdarg> -#include <cstdlib> -#include <cstring> -#include <fstream> -#include <iomanip> -#include <iostream> -#include <map> -#include <sstream> -#include <stab.h> - -#include "breakpad_googletest_includes.h" -#include "common/linux/stabs_reader.h" - -using std::istream; -using std::istringstream; -using std::map; -using std::ostream; -using std::ostringstream; -using std::string; - -using ::testing::_; -using ::testing::Eq; -using ::testing::InSequence; -using ::testing::Return; -using ::testing::Sequence; -using ::testing::StrEq; - -using google_breakpad::StabsHandler; -using google_breakpad::StabsReader; - -namespace { - -// Mock stabs file parser -// -// In order to test StabsReader, we parse a human-readable input file -// describing STABS entries into in-memory .stab and .stabstr -// sections, and then pass those to StabsReader to look at. The -// human-readable file is called a "mock stabs file". -// -// Except for compilation unit boundary lines (described below), each -// line of a mock stabs file should have the following form: -// -// TYPE OTHER DESC VALUE NAME -// -// where all data is Latin-1 bytes and fields are separated by single -// space characters, except for NAME, which may contain spaces and -// continues to the end of the line. The fields have the following -// meanings: -// -// - TYPE: the name of the stabs symbol type; like SO or FUN. These are -// the names from /usr/include/bits/stab.def, without the leading N_. -// -// - OTHER, DESC, VALUE: numeric values for the n_other, n_desc, and -// n_value fields of the stab. These can be decimal or hex, -// using C++ notation (10, 0x10) -// -// - NAME: textual data for the entry. STABS packs all kinds of -// interesting data into entries' NAME fields, so calling it a NAME -// is misleading, but that's how it is. For SO, this may be a -// filename; for FUN, this is the function name, plus type data; and -// so on. -// -// A compilation unit boundary line has the form: -// -// cu-boundary FILENAME - -// I don't know if the whole parser/handler pattern is really worth -// the bureaucracy in this case. But just writing it out as -// old-fashioned functions wasn't astonishingly clear either, so it -// seemed worth a try. - -// A handler class for mock stabs data. -class MockStabsHandler { - public: - MockStabsHandler() { } - virtual ~MockStabsHandler() { } - // The mock stabs parser calls this member function for each entry - // it parses, passing it the contents of the entry. If this function - // returns true, the parser continues; if it returns false, the parser - // stops, and its Process member function returns false. - virtual bool Entry(enum __stab_debug_code type, char other, short desc, - unsigned long value, const string &name) { return true; } - // Report a compilation unit boundary whose filename is FILENAME. As - // for the Entry function, this should return true to continue - // parsing, or false to stop processing. - virtual bool CUBoundary(const string &filename) { return true; } - - // Report an error in parsing the mock stabs data. If this returns true, - // the parser continues; if it returns false, the parser stops and - // its Process member function returns false. - virtual bool Error(const char *format, ...) = 0; -}; - -// A class for parsing mock stabs files. -class MockStabsParser { - public: - // Create a parser reading input from STREAM and passing data to HANDLER. - // Use FILENAME when reporting errors. - MockStabsParser(const string &filename, istream *stream, - MockStabsHandler *handler); - // Parse data from the STREAM, invoking HANDLER->Entry for each - // entry we get. Return true if we parsed all the data succesfully, - // or false if we stopped early because Entry returned false, or if - // there were any errors during parsing. - bool Process(); - private: - // A type for maps from stab type names ("SO", "SLINE", etc.) to - // n_type values. - typedef map<string, unsigned char> StabTypeNameTable; - - // Initialize the table mapping STAB type names to n_type values. - void InitializeTypeNames(); - - // Parse LINE, one line of input from a mock stabs file, and pass - // its contents to handler_->Entry and return the boolean value that - // returns. If we encounter an error parsing the line, report it - // using handler->Error. - bool ParseLine(const string &line); - - const string &filename_; - istream *stream_; - MockStabsHandler *handler_; - int line_number_; - StabTypeNameTable type_names_; -}; - -MockStabsParser::MockStabsParser(const string &filename, istream *stream, - MockStabsHandler *handler): - filename_(filename), stream_(stream), handler_(handler), - line_number_(0) { - InitializeTypeNames(); -} - -bool MockStabsParser::Process() { - // Iterate once per line, including a line at EOF without a - // terminating newline. - for(;;) { - string line; - getline(*stream_, line, '\n'); - if (line.empty() && stream_->eof()) - break; - line_number_++; - if (! ParseLine(line)) - return false; - } - return true; -} - -void MockStabsParser::InitializeTypeNames() { - // On GLIBC-based systems, <bits/stab.def> is a file containing a - // call to an unspecified macro __define_stab for each stab type. - // <stab.h> uses it to define the __stab_debug_code enum type. We - // use it here to initialize our mapping from type names to enum - // values. - // - // This isn't portable to non-GLIBC systems. Feel free to just - // hard-code the values if this becomes a problem. -# define __define_stab(name, code, str) type_names_[string(str)] = code; -# include <bits/stab.def> -# undef __define_stab -} - -bool MockStabsParser::ParseLine(const string &line) { - istringstream linestream(line); - // Allow "0x" prefix for hex, and so on. - linestream.unsetf(istringstream::basefield); - // Parse and validate the stabs type. - string typeName; - linestream >> typeName; - if (typeName == "cu-boundary") { - if (linestream.peek() == ' ') - linestream.get(); - string filename; - getline(linestream, filename, '\n'); - return handler_->CUBoundary(filename); - } else { - StabTypeNameTable::const_iterator typeIt = type_names_.find(typeName); - if (typeIt == type_names_.end()) - return handler_->Error("%s:%d: unrecognized stab type: %s\n", - filename_.c_str(), line_number_, typeName.c_str()); - // These are int, not char and unsigned char, to ensure they're parsed - // as decimal numbers, not characters. - int otherInt, descInt; - unsigned long value; - linestream >> otherInt >> descInt >> value; - if (linestream.fail()) - return handler_->Error("%s:%d: malformed mock stabs input line\n", - filename_.c_str(), line_number_); - if (linestream.peek() == ' ') - linestream.get(); - string name; - getline(linestream, name, '\n'); - return handler_->Entry(static_cast<__stab_debug_code>(typeIt->second), - otherInt, descInt, value, name); - } -} - -// A class for constructing .stab sections. -// -// A .stab section is an array of struct nlist entries. These -// entries' n_un.n_strx fields are indices into an accompanying -// .stabstr section. -class StabSection { - public: - StabSection(): used_(0), size_(1) { - entries_ = (struct nlist *) malloc(sizeof(*entries_) * size_); - } - ~StabSection() { free(entries_); } - - // Append a new 'struct nlist' entry to the end of the section, and - // return a pointer to it. This pointer is valid until the next - // call to Append. The caller should initialize the returned entry - // as needed. - struct nlist *Append(); - // Set the first entry's n_desc field to COUNT, and set its n_value field - // to STRING_SIZE. - void SetHeader(short count, unsigned long string_size); - // Set SECTION to the contents of a .stab section holding the - // accumulated list of entries added with Append. - void GetSection(string *section); - // Clear the array, and prepare this StabSection to accumulate a fresh - // set of entries. - void Clear(); - - private: - // The array of stabs entries, - struct nlist *entries_; - // The number of elements of entries_ that are used, and the allocated size - // of the array. - size_t used_, size_; -}; - -struct nlist *StabSection::Append() { - if (used_ == size_) { - size_ *= 2; - entries_ = (struct nlist *) realloc(entries_, sizeof(*entries_) * size_); - } - assert(used_ < size_); - return &entries_[used_++]; -} - -void StabSection::SetHeader(short count, unsigned long string_size) { - assert(used_ >= 1); - entries_[0].n_desc = count; - entries_[0].n_value = string_size; -} - -void StabSection::GetSection(string *section) { - section->assign(reinterpret_cast<char *>(entries_), - sizeof(*entries_) * used_); -} - -void StabSection::Clear() { - used_ = 0; - size_ = 1; - entries_ = (struct nlist *) realloc(entries_, sizeof(*entries_) * size_); -} - -// A class for building .stabstr sections. -// -// A .stabstr section is an array of characters containing a bunch of -// null-terminated strings. A string is identified by the index of -// its initial character in the array. The array always starts with a -// null byte, so that an index of zero refers to the empty string. -// -// This implementation also ensures that if two strings are equal, we -// assign them the same indices; most linkers do this, and some -// clients may rely upon it. (Note that this is not quite the same as -// ensuring that a string only appears once in the section; you could -// share space when one string is a suffix of another, but we don't.) -class StabstrSection { - public: - StabstrSection(): next_byte_(1) { string_indices_[""] = 0; } - // Ensure STR is present in the string section, and return its index. - size_t Insert(const string &str); - // Set SECTION to the contents of a .stabstr section in which the - // strings passed to Insert appear at the indices we promised. - void GetSection(string *section); - // Clear the contents of this StabstrSection, and prepare it to - // accumulate a new set of strings. - void Clear(); - private: - // Maps from strings to .stabstr indices and back. - typedef map<string, size_t> StringToIndex; - typedef map<size_t, const string *> IndexToString; - - // A map from strings to the indices we've assigned them. - StringToIndex string_indices_; - - // The next unused byte in the section. The next string we add - // will get this index. - size_t next_byte_; -}; - -size_t StabstrSection::Insert(const string &str) { - StringToIndex::iterator it = string_indices_.find(str); - size_t index; - if (it != string_indices_.end()) { - index = it->second; - } else { - // This is the first time we've seen STR; add it to the table. - string_indices_[str] = next_byte_; - index = next_byte_; - next_byte_ += str.size() + 1; - } - return index; -} - -void StabstrSection::GetSection(string *section) { - // First we have to invert the map. - IndexToString byIndex; - for (StringToIndex::const_iterator it = string_indices_.begin(); - it != string_indices_.end(); it++) - byIndex[it->second] = &it->first; - // Now we build the .stabstr section. - section->clear(); - for (IndexToString::const_iterator it = byIndex.begin(); - it != byIndex.end(); it++) { - // Make sure we're actually assigning it the index we claim to be. - assert(it->first == section->size()); - *section += *(it->second); - *section += '\0'; - } -} - -void StabstrSection::Clear() { - string_indices_.clear(); - string_indices_[""] = 0; - next_byte_ = 1; -} - -// A mock stabs parser handler class that builds .stab and .stabstr -// sections. -class StabsSectionsBuilder: public MockStabsHandler { - public: - // Construct a handler that will receive data from a MockStabsParser - // and construct .stab and .stabstr sections. FILENAME should be - // the name of the mock stabs input file; we use it in error - // messages. - StabsSectionsBuilder(const string &filename) - : filename_(filename), error_count_(0), has_header_(false), - entry_count_(0) { } - - // Overridden virtual member functions. - bool Entry(enum __stab_debug_code type, char other, short desc, - unsigned long value, const string &name); - bool CUBoundary(const string &filename); - bool Error(const char *format, ...); - - // Set SECTION to the contents of a .stab or .stabstr section - // reflecting the entries that have been passed to us via Entry. - void GetStab(string *section); - void GetStabstr(string *section); - - private: - // Finish a compilation unit. If there are any entries accumulated in - // stab_ and stabstr_, add them as a new compilation unit to - // finished_cu_stabs_ and finished_cu_stabstr_, and then clear stab_ and - // stabstr_. - void FinishCU(); - - const string &filename_; // input filename, for error messages - int error_count_; // number of errors we've seen so far - - // The following members accumulate the contents of a single compilation - // unit, possibly headed by an N_UNDF stab. - bool has_header_; // true if we have an N_UNDF header - int entry_count_; // the number of entries we've seen - StabSection stab_; // 'struct nlist' entries - StabstrSection stabstr_; // and the strings they love - - // Accumulated .stab and .stabstr content for all compilation units. - string finished_cu_stab_, finished_cu_stabstr_; -}; - -bool StabsSectionsBuilder::Entry(enum __stab_debug_code type, char other, - short desc, unsigned long value, - const string &name) { - struct nlist *entry = stab_.Append(); - entry->n_type = type; - entry->n_other = other; - entry->n_desc = desc; - entry->n_value = value; - entry->n_un.n_strx = stabstr_.Insert(name); - entry_count_++; - return true; -} - -bool StabsSectionsBuilder::CUBoundary(const string &filename) { - FinishCU(); - // Add a header for the compilation unit. - assert(!has_header_); - assert(entry_count_ == 0); - struct nlist *entry = stab_.Append(); - entry->n_type = N_UNDF; - entry->n_other = 0; - entry->n_desc = 0; // will be set to number of entries - entry->n_value = 0; // will be set to size of .stabstr data - entry->n_un.n_strx = stabstr_.Insert(filename); - has_header_ = true; - // The N_UNDF header isn't included in the symbol count, so we - // shouldn't bump entry_count_ here. - return true; -} - -void StabsSectionsBuilder::FinishCU() { - if (entry_count_ > 0) { - // Get the strings first, so we can record their size in the header. - string stabstr; - stabstr_.GetSection(&stabstr); - finished_cu_stabstr_ += stabstr; - - // Initialize our header, if we have one, and extract the .stab data. - if (has_header_) - stab_.SetHeader(entry_count_, stabstr.size()); - string stab; - stab_.GetSection(&stab); - finished_cu_stab_ += stab; - } - - stab_.Clear(); - stabstr_.Clear(); - has_header_ = false; - entry_count_ = 0; -} - -bool StabsSectionsBuilder::Error(const char *format, ...) { - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - error_count_++; - if (error_count_ >= 20) { - fprintf(stderr, - "%s: lots of errors; is this really a mock stabs file?\n", - filename_.c_str()); - return false; - } - return true; -} - -void StabsSectionsBuilder::GetStab(string *section) { - FinishCU(); - *section = finished_cu_stab_; -} - -void StabsSectionsBuilder::GetStabstr(string *section) { - FinishCU(); - *section = finished_cu_stabstr_; -} - -class MockStabsReaderHandler: public StabsHandler { - public: - MOCK_METHOD3(StartCompilationUnit, - bool(const char *, uint64_t, const char *)); - MOCK_METHOD1(EndCompilationUnit, bool(uint64_t)); - MOCK_METHOD2(StartFunction, bool(const std::string &, uint64_t)); - MOCK_METHOD1(EndFunction, bool(uint64_t)); - MOCK_METHOD3(Line, bool(uint64_t, const char *, int)); - void Warning(const char *format, ...) { MockWarning(format); } - MOCK_METHOD1(MockWarning, void(const char *)); -}; - -// Create a StabsReader to parse the mock stabs data in INPUT_FILE, -// passing the parsed information to HANDLER. If all goes well, return -// the result of calling the reader's Process member function. -// Otherwise, return false. INPUT_FILE should be relative to the top -// of the source tree. -static bool ApplyHandlerToMockStabsData(StabsHandler *handler, - const string &input_file) { - string full_input_file - = string(getenv("srcdir") ? getenv("srcdir") : ".") + "/" + input_file; - - // Open the input file. - std::ifstream stream(full_input_file.c_str()); - if (stream.fail()) { - fprintf(stderr, "error opening mock stabs input file %s: %s\n", - full_input_file.c_str(), strerror(errno)); - return false; - } - - // Parse the mock stabs data, and produce stabs sections to use as - // test input to the reader. - StabsSectionsBuilder builder(full_input_file); - MockStabsParser mock_parser(full_input_file, &stream, &builder); - if (!mock_parser.Process()) - return false; - string stab, stabstr; - builder.GetStab(&stab); - builder.GetStabstr(&stabstr); - - // Run the parser on the test input, passing whatever we find to HANDLER. - StabsReader reader( - reinterpret_cast<const uint8_t *>(stab.data()), stab.size(), - reinterpret_cast<const uint8_t *>(stabstr.data()), stabstr.size(), - handler); - return reader.Process(); -} - -TEST(StabsReader, MockStabsInput) { - MockStabsReaderHandler mock_handler; - - { - InSequence s; - - EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file1.c"), - 0x42, StrEq("builddir1/"))) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(StrEq("fun1"), 0x62)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, Line(0xe4, StrEq("file1.c"), 91)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, Line(0x164, StrEq("header.h"), 111)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0x112)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(StrEq("fun2"), 0x112)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, Line(0x234, StrEq("header.h"), 131)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, Line(0x254, StrEq("file1.c"), 151)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0x152)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0x152)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"), - 0x182, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0x192)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData( - &mock_handler, - "common/linux/testdata/stabs_reader_unittest.input1")); -} - -TEST(StabsReader, AbruptCU) { - MockStabsReaderHandler mock_handler; - - { - InSequence s; - - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file2-1.c"), 0x12, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(NULL)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData( - &mock_handler, - "common/linux/testdata/stabs_reader_unittest.input2")); -} - -TEST(StabsReader, AbruptFunction) { - MockStabsReaderHandler mock_handler; - - { - InSequence s; - - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file3-1.c"), 0x12, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0x22)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(NULL)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData( - &mock_handler, - "common/linux/testdata/stabs_reader_unittest.input3")); -} - -TEST(StabsReader, NoCU) { - MockStabsReaderHandler mock_handler; - - EXPECT_CALL(mock_handler, StartCompilationUnit(_, _, _)) - .Times(0); - EXPECT_CALL(mock_handler, StartFunction(_, _)) - .Times(0); - - ASSERT_TRUE(ApplyHandlerToMockStabsData( - &mock_handler, - "common/linux/testdata/stabs_reader_unittest.input4")); - -} - -TEST(StabsReader, NoCUEnd) { - MockStabsReaderHandler mock_handler; - - { - InSequence s; - - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file5-1.c"), 0x12, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file5-2.c"), 0x22, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(NULL)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData( - &mock_handler, - "common/linux/testdata/stabs_reader_unittest.input5")); - -} - -TEST(StabsReader, MultipleCUs) { - MockStabsReaderHandler mock_handler; - - { - InSequence s; - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("antimony"), 0x12, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x22)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0x32)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0x32)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("aluminum"), 0x42, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0x52)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0x62)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0x62)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData( - &mock_handler, - "common/linux/testdata/stabs_reader_unittest.input6")); -} - -// name duplication - -} // anonymous namespace diff --git a/src/common/linux/testdata/func-line-pairing.h b/src/common/linux/testdata/func-line-pairing.h deleted file mode 100644 index 05538f96..00000000 --- a/src/common/linux/testdata/func-line-pairing.h +++ /dev/null @@ -1,676 +0,0 @@ -// -*- mode: c++ -*- - -// Test data for pairing functions and lines. -// -// For a pair of functions that are adjacent (10,20),(20,25) and a -// pair that are not (10,15),(20,25), we include a test case for every -// possible arrangement of two lines relative to those functions. We -// include cases only for non-empty ranges, since empty functions and -// lines are dropped before we do any pairing. -// -// Each test case is represented by a macro call of the form: -// -// PAIRING(func1_start, func1_end, func2_start, func2_end, -// line1_start, line1_end, line2_start, line2_end, -// func1_num_lines, func2_num_lines, -// func1_line1_start, func1_line1_end, -// func1_line2_start, func1_line2_end, -// func2_line1_start, func2_line1_end, -// func2_line2_start, func2_line2_end, -// uncovered_funcs, uncovered_lines) -// -// where: -// - funcN_{start,end} is the range of the N'th function -// - lineN_{start,end} is the range of the N'th function -// - funcN_num_lines is the number of source lines that should be -// paired with the N'th function -// - funcN_lineM_{start,end} is the range of the M'th line -// paired with the N'th function, where 0,0 indicates that -// there should be no such line paired -// - uncovered_funcs is the number of functions with area that is -// uncovered by any line, and -// - uncovered_lines is the reverse. - -// func1 func2 line1 line2 num pairing1 pairing2 uncovered -PAIRING(10, 20, 20, 25, 6, 7, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #0 -PAIRING(10, 20, 20, 25, 6, 7, 7, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #1 -PAIRING(10, 20, 20, 25, 6, 7, 7, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #2 -PAIRING(10, 20, 20, 25, 6, 7, 7, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #3 -PAIRING(10, 20, 20, 25, 6, 7, 7, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #4 -PAIRING(10, 20, 20, 25, 6, 7, 7, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #5 -PAIRING(10, 20, 20, 25, 6, 7, 7, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #6 -PAIRING(10, 20, 20, 25, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #7 -PAIRING(10, 20, 20, 25, 6, 7, 8, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #8 -PAIRING(10, 20, 20, 25, 6, 7, 8, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #9 -PAIRING(10, 20, 20, 25, 6, 7, 8, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #10 -PAIRING(10, 20, 20, 25, 6, 7, 8, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #11 -PAIRING(10, 20, 20, 25, 6, 7, 8, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #12 -PAIRING(10, 20, 20, 25, 6, 7, 8, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #13 -PAIRING(10, 20, 20, 25, 6, 7, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #14 -PAIRING(10, 20, 20, 25, 6, 7, 10, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #15 -PAIRING(10, 20, 20, 25, 6, 7, 10, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #16 -PAIRING(10, 20, 20, 25, 6, 7, 10, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #17 -PAIRING(10, 20, 20, 25, 6, 7, 10, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #18 -PAIRING(10, 20, 20, 25, 6, 7, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #19 -PAIRING(10, 20, 20, 25, 6, 7, 11, 20, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #20 -PAIRING(10, 20, 20, 25, 6, 7, 11, 21, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #21 -PAIRING(10, 20, 20, 25, 6, 7, 11, 25, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #22 -PAIRING(10, 20, 20, 25, 6, 7, 11, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #23 -PAIRING(10, 20, 20, 25, 6, 7, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #24 -PAIRING(10, 20, 20, 25, 6, 7, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #25 -PAIRING(10, 20, 20, 25, 6, 7, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #26 -PAIRING(10, 20, 20, 25, 6, 7, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #27 -PAIRING(10, 20, 20, 25, 6, 7, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #28 -PAIRING(10, 20, 20, 25, 6, 7, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #29 -PAIRING(10, 20, 20, 25, 6, 7, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #30 -PAIRING(10, 20, 20, 25, 6, 7, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #31 -PAIRING(10, 20, 20, 25, 6, 10, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #32 -PAIRING(10, 20, 20, 25, 6, 10, 10, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #33 -PAIRING(10, 20, 20, 25, 6, 10, 10, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #34 -PAIRING(10, 20, 20, 25, 6, 10, 10, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #35 -PAIRING(10, 20, 20, 25, 6, 10, 10, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #36 -PAIRING(10, 20, 20, 25, 6, 10, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #37 -PAIRING(10, 20, 20, 25, 6, 10, 11, 20, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #38 -PAIRING(10, 20, 20, 25, 6, 10, 11, 21, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #39 -PAIRING(10, 20, 20, 25, 6, 10, 11, 25, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #40 -PAIRING(10, 20, 20, 25, 6, 10, 11, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #41 -PAIRING(10, 20, 20, 25, 6, 10, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #42 -PAIRING(10, 20, 20, 25, 6, 10, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #43 -PAIRING(10, 20, 20, 25, 6, 10, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #44 -PAIRING(10, 20, 20, 25, 6, 10, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #45 -PAIRING(10, 20, 20, 25, 6, 10, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #46 -PAIRING(10, 20, 20, 25, 6, 10, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #47 -PAIRING(10, 20, 20, 25, 6, 10, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #48 -PAIRING(10, 20, 20, 25, 6, 10, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #49 -PAIRING(10, 20, 20, 25, 6, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 1) // #50 -PAIRING(10, 20, 20, 25, 6, 11, 11, 20, 2, 0, 10, 11, 11, 20, 0, 0, 0, 0, 1, 1) // #51 -PAIRING(10, 20, 20, 25, 6, 11, 11, 21, 2, 1, 10, 11, 11, 20, 20, 21, 0, 0, 1, 1) // #52 -PAIRING(10, 20, 20, 25, 6, 11, 11, 25, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 1) // #53 -PAIRING(10, 20, 20, 25, 6, 11, 11, 26, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 2) // #54 -PAIRING(10, 20, 20, 25, 6, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 1) // #55 -PAIRING(10, 20, 20, 25, 6, 11, 12, 20, 2, 0, 10, 11, 12, 20, 0, 0, 0, 0, 2, 1) // #56 -PAIRING(10, 20, 20, 25, 6, 11, 12, 21, 2, 1, 10, 11, 12, 20, 20, 21, 0, 0, 2, 1) // #57 -PAIRING(10, 20, 20, 25, 6, 11, 12, 25, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 1) // #58 -PAIRING(10, 20, 20, 25, 6, 11, 12, 26, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 2) // #59 -PAIRING(10, 20, 20, 25, 6, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #60 -PAIRING(10, 20, 20, 25, 6, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #61 -PAIRING(10, 20, 20, 25, 6, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #62 -PAIRING(10, 20, 20, 25, 6, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 1) // #63 -PAIRING(10, 20, 20, 25, 6, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #64 -PAIRING(10, 20, 20, 25, 6, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 2) // #65 -PAIRING(10, 20, 20, 25, 6, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #66 -PAIRING(10, 20, 20, 25, 6, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #67 -PAIRING(10, 20, 20, 25, 6, 20, 20, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #68 -PAIRING(10, 20, 20, 25, 6, 20, 20, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #69 -PAIRING(10, 20, 20, 25, 6, 20, 20, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #70 -PAIRING(10, 20, 20, 25, 6, 20, 21, 22, 1, 1, 10, 20, 0, 0, 21, 22, 0, 0, 1, 1) // #71 -PAIRING(10, 20, 20, 25, 6, 20, 21, 25, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 1) // #72 -PAIRING(10, 20, 20, 25, 6, 20, 21, 26, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 2) // #73 -PAIRING(10, 20, 20, 25, 6, 20, 25, 26, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #74 -PAIRING(10, 20, 20, 25, 6, 20, 26, 27, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #75 -PAIRING(10, 20, 20, 25, 6, 21, 21, 22, 1, 2, 10, 20, 0, 0, 20, 21, 21, 22, 1, 1) // #76 -PAIRING(10, 20, 20, 25, 6, 21, 21, 25, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 1) // #77 -PAIRING(10, 20, 20, 25, 6, 21, 21, 26, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 2) // #78 -PAIRING(10, 20, 20, 25, 6, 21, 22, 23, 1, 2, 10, 20, 0, 0, 20, 21, 22, 23, 1, 1) // #79 -PAIRING(10, 20, 20, 25, 6, 21, 22, 25, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 1) // #80 -PAIRING(10, 20, 20, 25, 6, 21, 22, 26, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 2) // #81 -PAIRING(10, 20, 20, 25, 6, 21, 25, 26, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #82 -PAIRING(10, 20, 20, 25, 6, 21, 26, 27, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #83 -PAIRING(10, 20, 20, 25, 6, 25, 25, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #84 -PAIRING(10, 20, 20, 25, 6, 25, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #85 -PAIRING(10, 20, 20, 25, 6, 26, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #86 -PAIRING(10, 20, 20, 25, 6, 26, 27, 28, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #87 -PAIRING(10, 20, 20, 25, 10, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 0) // #88 -PAIRING(10, 20, 20, 25, 10, 11, 11, 20, 2, 0, 10, 11, 11, 20, 0, 0, 0, 0, 1, 0) // #89 -PAIRING(10, 20, 20, 25, 10, 11, 11, 21, 2, 1, 10, 11, 11, 20, 20, 21, 0, 0, 1, 0) // #90 -PAIRING(10, 20, 20, 25, 10, 11, 11, 25, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 0) // #91 -PAIRING(10, 20, 20, 25, 10, 11, 11, 26, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 1) // #92 -PAIRING(10, 20, 20, 25, 10, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 0) // #93 -PAIRING(10, 20, 20, 25, 10, 11, 12, 20, 2, 0, 10, 11, 12, 20, 0, 0, 0, 0, 2, 0) // #94 -PAIRING(10, 20, 20, 25, 10, 11, 12, 21, 2, 1, 10, 11, 12, 20, 20, 21, 0, 0, 2, 0) // #95 -PAIRING(10, 20, 20, 25, 10, 11, 12, 25, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 0) // #96 -PAIRING(10, 20, 20, 25, 10, 11, 12, 26, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 1) // #97 -PAIRING(10, 20, 20, 25, 10, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 0) // #98 -PAIRING(10, 20, 20, 25, 10, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 0) // #99 -PAIRING(10, 20, 20, 25, 10, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #100 -PAIRING(10, 20, 20, 25, 10, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 0) // #101 -PAIRING(10, 20, 20, 25, 10, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 0) // #102 -PAIRING(10, 20, 20, 25, 10, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #103 -PAIRING(10, 20, 20, 25, 10, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #104 -PAIRING(10, 20, 20, 25, 10, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #105 -PAIRING(10, 20, 20, 25, 10, 20, 20, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 0) // #106 -PAIRING(10, 20, 20, 25, 10, 20, 20, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 0) // #107 -PAIRING(10, 20, 20, 25, 10, 20, 20, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #108 -PAIRING(10, 20, 20, 25, 10, 20, 21, 22, 1, 1, 10, 20, 0, 0, 21, 22, 0, 0, 1, 0) // #109 -PAIRING(10, 20, 20, 25, 10, 20, 21, 25, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 0) // #110 -PAIRING(10, 20, 20, 25, 10, 20, 21, 26, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 1) // #111 -PAIRING(10, 20, 20, 25, 10, 20, 25, 26, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #112 -PAIRING(10, 20, 20, 25, 10, 20, 26, 27, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #113 -PAIRING(10, 20, 20, 25, 10, 21, 21, 22, 1, 2, 10, 20, 0, 0, 20, 21, 21, 22, 1, 0) // #114 -PAIRING(10, 20, 20, 25, 10, 21, 21, 25, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 0) // #115 -PAIRING(10, 20, 20, 25, 10, 21, 21, 26, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 1) // #116 -PAIRING(10, 20, 20, 25, 10, 21, 22, 23, 1, 2, 10, 20, 0, 0, 20, 21, 22, 23, 1, 0) // #117 -PAIRING(10, 20, 20, 25, 10, 21, 22, 25, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 0) // #118 -PAIRING(10, 20, 20, 25, 10, 21, 22, 26, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 1) // #119 -PAIRING(10, 20, 20, 25, 10, 21, 25, 26, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #120 -PAIRING(10, 20, 20, 25, 10, 21, 26, 27, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #121 -PAIRING(10, 20, 20, 25, 10, 25, 25, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #122 -PAIRING(10, 20, 20, 25, 10, 25, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #123 -PAIRING(10, 20, 20, 25, 10, 26, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #124 -PAIRING(10, 20, 20, 25, 10, 26, 27, 28, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #125 -PAIRING(10, 20, 20, 25, 11, 12, 12, 13, 2, 0, 11, 12, 12, 13, 0, 0, 0, 0, 2, 0) // #126 -PAIRING(10, 20, 20, 25, 11, 12, 12, 20, 2, 0, 11, 12, 12, 20, 0, 0, 0, 0, 2, 0) // #127 -PAIRING(10, 20, 20, 25, 11, 12, 12, 21, 2, 1, 11, 12, 12, 20, 20, 21, 0, 0, 2, 0) // #128 -PAIRING(10, 20, 20, 25, 11, 12, 12, 25, 2, 1, 11, 12, 12, 20, 20, 25, 0, 0, 1, 0) // #129 -PAIRING(10, 20, 20, 25, 11, 12, 12, 26, 2, 1, 11, 12, 12, 20, 20, 25, 0, 0, 1, 1) // #130 -PAIRING(10, 20, 20, 25, 11, 12, 13, 14, 2, 0, 11, 12, 13, 14, 0, 0, 0, 0, 2, 0) // #131 -PAIRING(10, 20, 20, 25, 11, 12, 13, 20, 2, 0, 11, 12, 13, 20, 0, 0, 0, 0, 2, 0) // #132 -PAIRING(10, 20, 20, 25, 11, 12, 13, 21, 2, 1, 11, 12, 13, 20, 20, 21, 0, 0, 2, 0) // #133 -PAIRING(10, 20, 20, 25, 11, 12, 13, 25, 2, 1, 11, 12, 13, 20, 20, 25, 0, 0, 1, 0) // #134 -PAIRING(10, 20, 20, 25, 11, 12, 13, 26, 2, 1, 11, 12, 13, 20, 20, 25, 0, 0, 1, 1) // #135 -PAIRING(10, 20, 20, 25, 11, 12, 20, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 0) // #136 -PAIRING(10, 20, 20, 25, 11, 12, 20, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 0) // #137 -PAIRING(10, 20, 20, 25, 11, 12, 20, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #138 -PAIRING(10, 20, 20, 25, 11, 12, 21, 22, 1, 1, 11, 12, 0, 0, 21, 22, 0, 0, 2, 0) // #139 -PAIRING(10, 20, 20, 25, 11, 12, 21, 25, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 0) // #140 -PAIRING(10, 20, 20, 25, 11, 12, 21, 26, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 1) // #141 -PAIRING(10, 20, 20, 25, 11, 12, 25, 26, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #142 -PAIRING(10, 20, 20, 25, 11, 12, 26, 27, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #143 -PAIRING(10, 20, 20, 25, 11, 20, 20, 21, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 0) // #144 -PAIRING(10, 20, 20, 25, 11, 20, 20, 25, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 0) // #145 -PAIRING(10, 20, 20, 25, 11, 20, 20, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #146 -PAIRING(10, 20, 20, 25, 11, 20, 21, 22, 1, 1, 11, 20, 0, 0, 21, 22, 0, 0, 2, 0) // #147 -PAIRING(10, 20, 20, 25, 11, 20, 21, 25, 1, 1, 11, 20, 0, 0, 21, 25, 0, 0, 2, 0) // #148 -PAIRING(10, 20, 20, 25, 11, 20, 21, 26, 1, 1, 11, 20, 0, 0, 21, 25, 0, 0, 2, 1) // #149 -PAIRING(10, 20, 20, 25, 11, 20, 25, 26, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #150 -PAIRING(10, 20, 20, 25, 11, 20, 26, 27, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #151 -PAIRING(10, 20, 20, 25, 11, 21, 21, 22, 1, 2, 11, 20, 0, 0, 20, 21, 21, 22, 2, 0) // #152 -PAIRING(10, 20, 20, 25, 11, 21, 21, 25, 1, 2, 11, 20, 0, 0, 20, 21, 21, 25, 1, 0) // #153 -PAIRING(10, 20, 20, 25, 11, 21, 21, 26, 1, 2, 11, 20, 0, 0, 20, 21, 21, 25, 1, 1) // #154 -PAIRING(10, 20, 20, 25, 11, 21, 22, 23, 1, 2, 11, 20, 0, 0, 20, 21, 22, 23, 2, 0) // #155 -PAIRING(10, 20, 20, 25, 11, 21, 22, 25, 1, 2, 11, 20, 0, 0, 20, 21, 22, 25, 2, 0) // #156 -PAIRING(10, 20, 20, 25, 11, 21, 22, 26, 1, 2, 11, 20, 0, 0, 20, 21, 22, 25, 2, 1) // #157 -PAIRING(10, 20, 20, 25, 11, 21, 25, 26, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #158 -PAIRING(10, 20, 20, 25, 11, 21, 26, 27, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #159 -PAIRING(10, 20, 20, 25, 11, 25, 25, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #160 -PAIRING(10, 20, 20, 25, 11, 25, 26, 27, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #161 -PAIRING(10, 20, 20, 25, 11, 26, 26, 27, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #162 -PAIRING(10, 20, 20, 25, 11, 26, 27, 28, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #163 -PAIRING(10, 20, 20, 25, 20, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 0) // #164 -PAIRING(10, 20, 20, 25, 20, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 0) // #165 -PAIRING(10, 20, 20, 25, 20, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #166 -PAIRING(10, 20, 20, 25, 20, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 0) // #167 -PAIRING(10, 20, 20, 25, 20, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 0) // #168 -PAIRING(10, 20, 20, 25, 20, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #169 -PAIRING(10, 20, 20, 25, 20, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #170 -PAIRING(10, 20, 20, 25, 20, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #171 -PAIRING(10, 20, 20, 25, 20, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #172 -PAIRING(10, 20, 20, 25, 20, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #173 -PAIRING(10, 20, 20, 25, 20, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #174 -PAIRING(10, 20, 20, 25, 20, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #175 -PAIRING(10, 20, 20, 25, 21, 22, 22, 23, 0, 2, 0, 0, 0, 0, 21, 22, 22, 23, 2, 0) // #176 -PAIRING(10, 20, 20, 25, 21, 22, 22, 25, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 0) // #177 -PAIRING(10, 20, 20, 25, 21, 22, 22, 26, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 1) // #178 -PAIRING(10, 20, 20, 25, 21, 22, 23, 24, 0, 2, 0, 0, 0, 0, 21, 22, 23, 24, 2, 0) // #179 -PAIRING(10, 20, 20, 25, 21, 22, 23, 25, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 0) // #180 -PAIRING(10, 20, 20, 25, 21, 22, 23, 26, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 1) // #181 -PAIRING(10, 20, 20, 25, 21, 22, 25, 26, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #182 -PAIRING(10, 20, 20, 25, 21, 22, 26, 27, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #183 -PAIRING(10, 20, 20, 25, 21, 25, 25, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #184 -PAIRING(10, 20, 20, 25, 21, 25, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #185 -PAIRING(10, 20, 20, 25, 21, 26, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #186 -PAIRING(10, 20, 20, 25, 21, 26, 27, 28, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #187 -PAIRING(10, 20, 20, 25, 25, 26, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #188 -PAIRING(10, 20, 20, 25, 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #189 -PAIRING(10, 20, 20, 25, 26, 27, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #190 -PAIRING(10, 20, 20, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #191 -PAIRING(10, 15, 20, 25, 6, 7, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #192 -PAIRING(10, 15, 20, 25, 6, 7, 7, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #193 -PAIRING(10, 15, 20, 25, 6, 7, 7, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #194 -PAIRING(10, 15, 20, 25, 6, 7, 7, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #195 -PAIRING(10, 15, 20, 25, 6, 7, 7, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #196 -PAIRING(10, 15, 20, 25, 6, 7, 7, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #197 -PAIRING(10, 15, 20, 25, 6, 7, 7, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #198 -PAIRING(10, 15, 20, 25, 6, 7, 7, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #199 -PAIRING(10, 15, 20, 25, 6, 7, 7, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #200 -PAIRING(10, 15, 20, 25, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #201 -PAIRING(10, 15, 20, 25, 6, 7, 8, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #202 -PAIRING(10, 15, 20, 25, 6, 7, 8, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #203 -PAIRING(10, 15, 20, 25, 6, 7, 8, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #204 -PAIRING(10, 15, 20, 25, 6, 7, 8, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #205 -PAIRING(10, 15, 20, 25, 6, 7, 8, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #206 -PAIRING(10, 15, 20, 25, 6, 7, 8, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #207 -PAIRING(10, 15, 20, 25, 6, 7, 8, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #208 -PAIRING(10, 15, 20, 25, 6, 7, 8, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #209 -PAIRING(10, 15, 20, 25, 6, 7, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #210 -PAIRING(10, 15, 20, 25, 6, 7, 10, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #211 -PAIRING(10, 15, 20, 25, 6, 7, 10, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #212 -PAIRING(10, 15, 20, 25, 6, 7, 10, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #213 -PAIRING(10, 15, 20, 25, 6, 7, 10, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #214 -PAIRING(10, 15, 20, 25, 6, 7, 10, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #215 -PAIRING(10, 15, 20, 25, 6, 7, 10, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #216 -PAIRING(10, 15, 20, 25, 6, 7, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #217 -PAIRING(10, 15, 20, 25, 6, 7, 11, 15, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #218 -PAIRING(10, 15, 20, 25, 6, 7, 11, 16, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #219 -PAIRING(10, 15, 20, 25, 6, 7, 11, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #220 -PAIRING(10, 15, 20, 25, 6, 7, 11, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #221 -PAIRING(10, 15, 20, 25, 6, 7, 11, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #222 -PAIRING(10, 15, 20, 25, 6, 7, 11, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #223 -PAIRING(10, 15, 20, 25, 6, 7, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #224 -PAIRING(10, 15, 20, 25, 6, 7, 15, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #225 -PAIRING(10, 15, 20, 25, 6, 7, 15, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #226 -PAIRING(10, 15, 20, 25, 6, 7, 15, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #227 -PAIRING(10, 15, 20, 25, 6, 7, 15, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #228 -PAIRING(10, 15, 20, 25, 6, 7, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #229 -PAIRING(10, 15, 20, 25, 6, 7, 16, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #230 -PAIRING(10, 15, 20, 25, 6, 7, 16, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #231 -PAIRING(10, 15, 20, 25, 6, 7, 16, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #232 -PAIRING(10, 15, 20, 25, 6, 7, 16, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #233 -PAIRING(10, 15, 20, 25, 6, 7, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #234 -PAIRING(10, 15, 20, 25, 6, 7, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #235 -PAIRING(10, 15, 20, 25, 6, 7, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #236 -PAIRING(10, 15, 20, 25, 6, 7, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #237 -PAIRING(10, 15, 20, 25, 6, 7, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #238 -PAIRING(10, 15, 20, 25, 6, 7, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #239 -PAIRING(10, 15, 20, 25, 6, 7, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #240 -PAIRING(10, 15, 20, 25, 6, 7, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #241 -PAIRING(10, 15, 20, 25, 6, 10, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #242 -PAIRING(10, 15, 20, 25, 6, 10, 10, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #243 -PAIRING(10, 15, 20, 25, 6, 10, 10, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #244 -PAIRING(10, 15, 20, 25, 6, 10, 10, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #245 -PAIRING(10, 15, 20, 25, 6, 10, 10, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #246 -PAIRING(10, 15, 20, 25, 6, 10, 10, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #247 -PAIRING(10, 15, 20, 25, 6, 10, 10, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #248 -PAIRING(10, 15, 20, 25, 6, 10, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #249 -PAIRING(10, 15, 20, 25, 6, 10, 11, 15, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #250 -PAIRING(10, 15, 20, 25, 6, 10, 11, 16, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #251 -PAIRING(10, 15, 20, 25, 6, 10, 11, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #252 -PAIRING(10, 15, 20, 25, 6, 10, 11, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #253 -PAIRING(10, 15, 20, 25, 6, 10, 11, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #254 -PAIRING(10, 15, 20, 25, 6, 10, 11, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #255 -PAIRING(10, 15, 20, 25, 6, 10, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #256 -PAIRING(10, 15, 20, 25, 6, 10, 15, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #257 -PAIRING(10, 15, 20, 25, 6, 10, 15, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #258 -PAIRING(10, 15, 20, 25, 6, 10, 15, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #259 -PAIRING(10, 15, 20, 25, 6, 10, 15, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #260 -PAIRING(10, 15, 20, 25, 6, 10, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #261 -PAIRING(10, 15, 20, 25, 6, 10, 16, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #262 -PAIRING(10, 15, 20, 25, 6, 10, 16, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #263 -PAIRING(10, 15, 20, 25, 6, 10, 16, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #264 -PAIRING(10, 15, 20, 25, 6, 10, 16, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #265 -PAIRING(10, 15, 20, 25, 6, 10, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #266 -PAIRING(10, 15, 20, 25, 6, 10, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #267 -PAIRING(10, 15, 20, 25, 6, 10, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #268 -PAIRING(10, 15, 20, 25, 6, 10, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #269 -PAIRING(10, 15, 20, 25, 6, 10, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #270 -PAIRING(10, 15, 20, 25, 6, 10, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #271 -PAIRING(10, 15, 20, 25, 6, 10, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #272 -PAIRING(10, 15, 20, 25, 6, 10, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #273 -PAIRING(10, 15, 20, 25, 6, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 1) // #274 -PAIRING(10, 15, 20, 25, 6, 11, 11, 15, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 1) // #275 -PAIRING(10, 15, 20, 25, 6, 11, 11, 16, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 2) // #276 -PAIRING(10, 15, 20, 25, 6, 11, 11, 20, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 1) // #277 -PAIRING(10, 15, 20, 25, 6, 11, 11, 21, 2, 1, 10, 11, 11, 15, 20, 21, 0, 0, 1, 2) // #278 -PAIRING(10, 15, 20, 25, 6, 11, 11, 25, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 2) // #279 -PAIRING(10, 15, 20, 25, 6, 11, 11, 26, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 2) // #280 -PAIRING(10, 15, 20, 25, 6, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 1) // #281 -PAIRING(10, 15, 20, 25, 6, 11, 12, 15, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 1) // #282 -PAIRING(10, 15, 20, 25, 6, 11, 12, 16, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 2) // #283 -PAIRING(10, 15, 20, 25, 6, 11, 12, 20, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 1) // #284 -PAIRING(10, 15, 20, 25, 6, 11, 12, 21, 2, 1, 10, 11, 12, 15, 20, 21, 0, 0, 2, 2) // #285 -PAIRING(10, 15, 20, 25, 6, 11, 12, 25, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 2) // #286 -PAIRING(10, 15, 20, 25, 6, 11, 12, 26, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 2) // #287 -PAIRING(10, 15, 20, 25, 6, 11, 15, 16, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #288 -PAIRING(10, 15, 20, 25, 6, 11, 15, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #289 -PAIRING(10, 15, 20, 25, 6, 11, 15, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 2) // #290 -PAIRING(10, 15, 20, 25, 6, 11, 15, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #291 -PAIRING(10, 15, 20, 25, 6, 11, 15, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #292 -PAIRING(10, 15, 20, 25, 6, 11, 16, 17, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #293 -PAIRING(10, 15, 20, 25, 6, 11, 16, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #294 -PAIRING(10, 15, 20, 25, 6, 11, 16, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 2) // #295 -PAIRING(10, 15, 20, 25, 6, 11, 16, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #296 -PAIRING(10, 15, 20, 25, 6, 11, 16, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #297 -PAIRING(10, 15, 20, 25, 6, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #298 -PAIRING(10, 15, 20, 25, 6, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #299 -PAIRING(10, 15, 20, 25, 6, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #300 -PAIRING(10, 15, 20, 25, 6, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 1) // #301 -PAIRING(10, 15, 20, 25, 6, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #302 -PAIRING(10, 15, 20, 25, 6, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 2) // #303 -PAIRING(10, 15, 20, 25, 6, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #304 -PAIRING(10, 15, 20, 25, 6, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #305 -PAIRING(10, 15, 20, 25, 6, 15, 15, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #306 -PAIRING(10, 15, 20, 25, 6, 15, 15, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #307 -PAIRING(10, 15, 20, 25, 6, 15, 15, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #308 -PAIRING(10, 15, 20, 25, 6, 15, 15, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #309 -PAIRING(10, 15, 20, 25, 6, 15, 15, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #310 -PAIRING(10, 15, 20, 25, 6, 15, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #311 -PAIRING(10, 15, 20, 25, 6, 15, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #312 -PAIRING(10, 15, 20, 25, 6, 15, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #313 -PAIRING(10, 15, 20, 25, 6, 15, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #314 -PAIRING(10, 15, 20, 25, 6, 15, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #315 -PAIRING(10, 15, 20, 25, 6, 15, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #316 -PAIRING(10, 15, 20, 25, 6, 15, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #317 -PAIRING(10, 15, 20, 25, 6, 15, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #318 -PAIRING(10, 15, 20, 25, 6, 15, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #319 -PAIRING(10, 15, 20, 25, 6, 15, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #320 -PAIRING(10, 15, 20, 25, 6, 15, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #321 -PAIRING(10, 15, 20, 25, 6, 15, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #322 -PAIRING(10, 15, 20, 25, 6, 15, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #323 -PAIRING(10, 15, 20, 25, 6, 16, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #324 -PAIRING(10, 15, 20, 25, 6, 16, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #325 -PAIRING(10, 15, 20, 25, 6, 16, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #326 -PAIRING(10, 15, 20, 25, 6, 16, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #327 -PAIRING(10, 15, 20, 25, 6, 16, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #328 -PAIRING(10, 15, 20, 25, 6, 16, 17, 18, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #329 -PAIRING(10, 15, 20, 25, 6, 16, 17, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #330 -PAIRING(10, 15, 20, 25, 6, 16, 17, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #331 -PAIRING(10, 15, 20, 25, 6, 16, 17, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #332 -PAIRING(10, 15, 20, 25, 6, 16, 17, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #333 -PAIRING(10, 15, 20, 25, 6, 16, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #334 -PAIRING(10, 15, 20, 25, 6, 16, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #335 -PAIRING(10, 15, 20, 25, 6, 16, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #336 -PAIRING(10, 15, 20, 25, 6, 16, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #337 -PAIRING(10, 15, 20, 25, 6, 16, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #338 -PAIRING(10, 15, 20, 25, 6, 16, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #339 -PAIRING(10, 15, 20, 25, 6, 16, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #340 -PAIRING(10, 15, 20, 25, 6, 16, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #341 -PAIRING(10, 15, 20, 25, 6, 20, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #342 -PAIRING(10, 15, 20, 25, 6, 20, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #343 -PAIRING(10, 15, 20, 25, 6, 20, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #344 -PAIRING(10, 15, 20, 25, 6, 20, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #345 -PAIRING(10, 15, 20, 25, 6, 20, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #346 -PAIRING(10, 15, 20, 25, 6, 20, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #347 -PAIRING(10, 15, 20, 25, 6, 20, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #348 -PAIRING(10, 15, 20, 25, 6, 20, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #349 -PAIRING(10, 15, 20, 25, 6, 21, 21, 22, 1, 2, 10, 15, 0, 0, 20, 21, 21, 22, 1, 1) // #350 -PAIRING(10, 15, 20, 25, 6, 21, 21, 25, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 1) // #351 -PAIRING(10, 15, 20, 25, 6, 21, 21, 26, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 2) // #352 -PAIRING(10, 15, 20, 25, 6, 21, 22, 23, 1, 2, 10, 15, 0, 0, 20, 21, 22, 23, 1, 1) // #353 -PAIRING(10, 15, 20, 25, 6, 21, 22, 25, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 1) // #354 -PAIRING(10, 15, 20, 25, 6, 21, 22, 26, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 2) // #355 -PAIRING(10, 15, 20, 25, 6, 21, 25, 26, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #356 -PAIRING(10, 15, 20, 25, 6, 21, 26, 27, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #357 -PAIRING(10, 15, 20, 25, 6, 25, 25, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #358 -PAIRING(10, 15, 20, 25, 6, 25, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #359 -PAIRING(10, 15, 20, 25, 6, 26, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #360 -PAIRING(10, 15, 20, 25, 6, 26, 27, 28, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #361 -PAIRING(10, 15, 20, 25, 10, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 0) // #362 -PAIRING(10, 15, 20, 25, 10, 11, 11, 15, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 0) // #363 -PAIRING(10, 15, 20, 25, 10, 11, 11, 16, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 1) // #364 -PAIRING(10, 15, 20, 25, 10, 11, 11, 20, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 0) // #365 -PAIRING(10, 15, 20, 25, 10, 11, 11, 21, 2, 1, 10, 11, 11, 15, 20, 21, 0, 0, 1, 1) // #366 -PAIRING(10, 15, 20, 25, 10, 11, 11, 25, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 1) // #367 -PAIRING(10, 15, 20, 25, 10, 11, 11, 26, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 1) // #368 -PAIRING(10, 15, 20, 25, 10, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 0) // #369 -PAIRING(10, 15, 20, 25, 10, 11, 12, 15, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 0) // #370 -PAIRING(10, 15, 20, 25, 10, 11, 12, 16, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 1) // #371 -PAIRING(10, 15, 20, 25, 10, 11, 12, 20, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 0) // #372 -PAIRING(10, 15, 20, 25, 10, 11, 12, 21, 2, 1, 10, 11, 12, 15, 20, 21, 0, 0, 2, 1) // #373 -PAIRING(10, 15, 20, 25, 10, 11, 12, 25, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 1) // #374 -PAIRING(10, 15, 20, 25, 10, 11, 12, 26, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 1) // #375 -PAIRING(10, 15, 20, 25, 10, 11, 15, 16, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #376 -PAIRING(10, 15, 20, 25, 10, 11, 15, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #377 -PAIRING(10, 15, 20, 25, 10, 11, 15, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #378 -PAIRING(10, 15, 20, 25, 10, 11, 15, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #379 -PAIRING(10, 15, 20, 25, 10, 11, 15, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #380 -PAIRING(10, 15, 20, 25, 10, 11, 16, 17, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #381 -PAIRING(10, 15, 20, 25, 10, 11, 16, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #382 -PAIRING(10, 15, 20, 25, 10, 11, 16, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #383 -PAIRING(10, 15, 20, 25, 10, 11, 16, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #384 -PAIRING(10, 15, 20, 25, 10, 11, 16, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #385 -PAIRING(10, 15, 20, 25, 10, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 0) // #386 -PAIRING(10, 15, 20, 25, 10, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 0) // #387 -PAIRING(10, 15, 20, 25, 10, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #388 -PAIRING(10, 15, 20, 25, 10, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 0) // #389 -PAIRING(10, 15, 20, 25, 10, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 0) // #390 -PAIRING(10, 15, 20, 25, 10, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #391 -PAIRING(10, 15, 20, 25, 10, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #392 -PAIRING(10, 15, 20, 25, 10, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #393 -PAIRING(10, 15, 20, 25, 10, 15, 15, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #394 -PAIRING(10, 15, 20, 25, 10, 15, 15, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #395 -PAIRING(10, 15, 20, 25, 10, 15, 15, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #396 -PAIRING(10, 15, 20, 25, 10, 15, 15, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #397 -PAIRING(10, 15, 20, 25, 10, 15, 15, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #398 -PAIRING(10, 15, 20, 25, 10, 15, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #399 -PAIRING(10, 15, 20, 25, 10, 15, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #400 -PAIRING(10, 15, 20, 25, 10, 15, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #401 -PAIRING(10, 15, 20, 25, 10, 15, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #402 -PAIRING(10, 15, 20, 25, 10, 15, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #403 -PAIRING(10, 15, 20, 25, 10, 15, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 0) // #404 -PAIRING(10, 15, 20, 25, 10, 15, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 0) // #405 -PAIRING(10, 15, 20, 25, 10, 15, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #406 -PAIRING(10, 15, 20, 25, 10, 15, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 0) // #407 -PAIRING(10, 15, 20, 25, 10, 15, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 0) // #408 -PAIRING(10, 15, 20, 25, 10, 15, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #409 -PAIRING(10, 15, 20, 25, 10, 15, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #410 -PAIRING(10, 15, 20, 25, 10, 15, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #411 -PAIRING(10, 15, 20, 25, 10, 16, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #412 -PAIRING(10, 15, 20, 25, 10, 16, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #413 -PAIRING(10, 15, 20, 25, 10, 16, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #414 -PAIRING(10, 15, 20, 25, 10, 16, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #415 -PAIRING(10, 15, 20, 25, 10, 16, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #416 -PAIRING(10, 15, 20, 25, 10, 16, 17, 18, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #417 -PAIRING(10, 15, 20, 25, 10, 16, 17, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #418 -PAIRING(10, 15, 20, 25, 10, 16, 17, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #419 -PAIRING(10, 15, 20, 25, 10, 16, 17, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #420 -PAIRING(10, 15, 20, 25, 10, 16, 17, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #421 -PAIRING(10, 15, 20, 25, 10, 16, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #422 -PAIRING(10, 15, 20, 25, 10, 16, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #423 -PAIRING(10, 15, 20, 25, 10, 16, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #424 -PAIRING(10, 15, 20, 25, 10, 16, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #425 -PAIRING(10, 15, 20, 25, 10, 16, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #426 -PAIRING(10, 15, 20, 25, 10, 16, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #427 -PAIRING(10, 15, 20, 25, 10, 16, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #428 -PAIRING(10, 15, 20, 25, 10, 16, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #429 -PAIRING(10, 15, 20, 25, 10, 20, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 0) // #430 -PAIRING(10, 15, 20, 25, 10, 20, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 0) // #431 -PAIRING(10, 15, 20, 25, 10, 20, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #432 -PAIRING(10, 15, 20, 25, 10, 20, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 0) // #433 -PAIRING(10, 15, 20, 25, 10, 20, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 0) // #434 -PAIRING(10, 15, 20, 25, 10, 20, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #435 -PAIRING(10, 15, 20, 25, 10, 20, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #436 -PAIRING(10, 15, 20, 25, 10, 20, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #437 -PAIRING(10, 15, 20, 25, 10, 21, 21, 22, 1, 2, 10, 15, 0, 0, 20, 21, 21, 22, 1, 1) // #438 -PAIRING(10, 15, 20, 25, 10, 21, 21, 25, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 1) // #439 -PAIRING(10, 15, 20, 25, 10, 21, 21, 26, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 2) // #440 -PAIRING(10, 15, 20, 25, 10, 21, 22, 23, 1, 2, 10, 15, 0, 0, 20, 21, 22, 23, 1, 1) // #441 -PAIRING(10, 15, 20, 25, 10, 21, 22, 25, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 1) // #442 -PAIRING(10, 15, 20, 25, 10, 21, 22, 26, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 2) // #443 -PAIRING(10, 15, 20, 25, 10, 21, 25, 26, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #444 -PAIRING(10, 15, 20, 25, 10, 21, 26, 27, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #445 -PAIRING(10, 15, 20, 25, 10, 25, 25, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #446 -PAIRING(10, 15, 20, 25, 10, 25, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #447 -PAIRING(10, 15, 20, 25, 10, 26, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #448 -PAIRING(10, 15, 20, 25, 10, 26, 27, 28, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #449 -PAIRING(10, 15, 20, 25, 11, 12, 12, 13, 2, 0, 11, 12, 12, 13, 0, 0, 0, 0, 2, 0) // #450 -PAIRING(10, 15, 20, 25, 11, 12, 12, 15, 2, 0, 11, 12, 12, 15, 0, 0, 0, 0, 2, 0) // #451 -PAIRING(10, 15, 20, 25, 11, 12, 12, 16, 2, 0, 11, 12, 12, 15, 0, 0, 0, 0, 2, 1) // #452 -PAIRING(10, 15, 20, 25, 11, 12, 12, 20, 2, 0, 11, 12, 12, 15, 0, 0, 0, 0, 2, 0) // #453 -PAIRING(10, 15, 20, 25, 11, 12, 12, 21, 2, 1, 11, 12, 12, 15, 20, 21, 0, 0, 2, 1) // #454 -PAIRING(10, 15, 20, 25, 11, 12, 12, 25, 2, 1, 11, 12, 12, 15, 20, 25, 0, 0, 1, 1) // #455 -PAIRING(10, 15, 20, 25, 11, 12, 12, 26, 2, 1, 11, 12, 12, 15, 20, 25, 0, 0, 1, 1) // #456 -PAIRING(10, 15, 20, 25, 11, 12, 13, 14, 2, 0, 11, 12, 13, 14, 0, 0, 0, 0, 2, 0) // #457 -PAIRING(10, 15, 20, 25, 11, 12, 13, 15, 2, 0, 11, 12, 13, 15, 0, 0, 0, 0, 2, 0) // #458 -PAIRING(10, 15, 20, 25, 11, 12, 13, 16, 2, 0, 11, 12, 13, 15, 0, 0, 0, 0, 2, 1) // #459 -PAIRING(10, 15, 20, 25, 11, 12, 13, 20, 2, 0, 11, 12, 13, 15, 0, 0, 0, 0, 2, 0) // #460 -PAIRING(10, 15, 20, 25, 11, 12, 13, 21, 2, 1, 11, 12, 13, 15, 20, 21, 0, 0, 2, 1) // #461 -PAIRING(10, 15, 20, 25, 11, 12, 13, 25, 2, 1, 11, 12, 13, 15, 20, 25, 0, 0, 1, 1) // #462 -PAIRING(10, 15, 20, 25, 11, 12, 13, 26, 2, 1, 11, 12, 13, 15, 20, 25, 0, 0, 1, 1) // #463 -PAIRING(10, 15, 20, 25, 11, 12, 15, 16, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #464 -PAIRING(10, 15, 20, 25, 11, 12, 15, 20, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #465 -PAIRING(10, 15, 20, 25, 11, 12, 15, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 1) // #466 -PAIRING(10, 15, 20, 25, 11, 12, 15, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #467 -PAIRING(10, 15, 20, 25, 11, 12, 15, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #468 -PAIRING(10, 15, 20, 25, 11, 12, 16, 17, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #469 -PAIRING(10, 15, 20, 25, 11, 12, 16, 20, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #470 -PAIRING(10, 15, 20, 25, 11, 12, 16, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 1) // #471 -PAIRING(10, 15, 20, 25, 11, 12, 16, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #472 -PAIRING(10, 15, 20, 25, 11, 12, 16, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #473 -PAIRING(10, 15, 20, 25, 11, 12, 20, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 0) // #474 -PAIRING(10, 15, 20, 25, 11, 12, 20, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 0) // #475 -PAIRING(10, 15, 20, 25, 11, 12, 20, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #476 -PAIRING(10, 15, 20, 25, 11, 12, 21, 22, 1, 1, 11, 12, 0, 0, 21, 22, 0, 0, 2, 0) // #477 -PAIRING(10, 15, 20, 25, 11, 12, 21, 25, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 0) // #478 -PAIRING(10, 15, 20, 25, 11, 12, 21, 26, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 1) // #479 -PAIRING(10, 15, 20, 25, 11, 12, 25, 26, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #480 -PAIRING(10, 15, 20, 25, 11, 12, 26, 27, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #481 -PAIRING(10, 15, 20, 25, 11, 15, 15, 16, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #482 -PAIRING(10, 15, 20, 25, 11, 15, 15, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #483 -PAIRING(10, 15, 20, 25, 11, 15, 15, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 1) // #484 -PAIRING(10, 15, 20, 25, 11, 15, 15, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #485 -PAIRING(10, 15, 20, 25, 11, 15, 15, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #486 -PAIRING(10, 15, 20, 25, 11, 15, 16, 17, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #487 -PAIRING(10, 15, 20, 25, 11, 15, 16, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #488 -PAIRING(10, 15, 20, 25, 11, 15, 16, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 1) // #489 -PAIRING(10, 15, 20, 25, 11, 15, 16, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #490 -PAIRING(10, 15, 20, 25, 11, 15, 16, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #491 -PAIRING(10, 15, 20, 25, 11, 15, 20, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 0) // #492 -PAIRING(10, 15, 20, 25, 11, 15, 20, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 0) // #493 -PAIRING(10, 15, 20, 25, 11, 15, 20, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #494 -PAIRING(10, 15, 20, 25, 11, 15, 21, 22, 1, 1, 11, 15, 0, 0, 21, 22, 0, 0, 2, 0) // #495 -PAIRING(10, 15, 20, 25, 11, 15, 21, 25, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 0) // #496 -PAIRING(10, 15, 20, 25, 11, 15, 21, 26, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 1) // #497 -PAIRING(10, 15, 20, 25, 11, 15, 25, 26, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #498 -PAIRING(10, 15, 20, 25, 11, 15, 26, 27, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #499 -PAIRING(10, 15, 20, 25, 11, 16, 16, 17, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #500 -PAIRING(10, 15, 20, 25, 11, 16, 16, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #501 -PAIRING(10, 15, 20, 25, 11, 16, 16, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #502 -PAIRING(10, 15, 20, 25, 11, 16, 16, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #503 -PAIRING(10, 15, 20, 25, 11, 16, 16, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #504 -PAIRING(10, 15, 20, 25, 11, 16, 17, 18, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #505 -PAIRING(10, 15, 20, 25, 11, 16, 17, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #506 -PAIRING(10, 15, 20, 25, 11, 16, 17, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #507 -PAIRING(10, 15, 20, 25, 11, 16, 17, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #508 -PAIRING(10, 15, 20, 25, 11, 16, 17, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #509 -PAIRING(10, 15, 20, 25, 11, 16, 20, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 1) // #510 -PAIRING(10, 15, 20, 25, 11, 16, 20, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #511 -PAIRING(10, 15, 20, 25, 11, 16, 20, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #512 -PAIRING(10, 15, 20, 25, 11, 16, 21, 22, 1, 1, 11, 15, 0, 0, 21, 22, 0, 0, 2, 1) // #513 -PAIRING(10, 15, 20, 25, 11, 16, 21, 25, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 1) // #514 -PAIRING(10, 15, 20, 25, 11, 16, 21, 26, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 2) // #515 -PAIRING(10, 15, 20, 25, 11, 16, 25, 26, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #516 -PAIRING(10, 15, 20, 25, 11, 16, 26, 27, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #517 -PAIRING(10, 15, 20, 25, 11, 20, 20, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 0) // #518 -PAIRING(10, 15, 20, 25, 11, 20, 20, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 0) // #519 -PAIRING(10, 15, 20, 25, 11, 20, 20, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #520 -PAIRING(10, 15, 20, 25, 11, 20, 21, 22, 1, 1, 11, 15, 0, 0, 21, 22, 0, 0, 2, 0) // #521 -PAIRING(10, 15, 20, 25, 11, 20, 21, 25, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 0) // #522 -PAIRING(10, 15, 20, 25, 11, 20, 21, 26, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 1) // #523 -PAIRING(10, 15, 20, 25, 11, 20, 25, 26, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #524 -PAIRING(10, 15, 20, 25, 11, 20, 26, 27, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #525 -PAIRING(10, 15, 20, 25, 11, 21, 21, 22, 1, 2, 11, 15, 0, 0, 20, 21, 21, 22, 2, 1) // #526 -PAIRING(10, 15, 20, 25, 11, 21, 21, 25, 1, 2, 11, 15, 0, 0, 20, 21, 21, 25, 1, 1) // #527 -PAIRING(10, 15, 20, 25, 11, 21, 21, 26, 1, 2, 11, 15, 0, 0, 20, 21, 21, 25, 1, 2) // #528 -PAIRING(10, 15, 20, 25, 11, 21, 22, 23, 1, 2, 11, 15, 0, 0, 20, 21, 22, 23, 2, 1) // #529 -PAIRING(10, 15, 20, 25, 11, 21, 22, 25, 1, 2, 11, 15, 0, 0, 20, 21, 22, 25, 2, 1) // #530 -PAIRING(10, 15, 20, 25, 11, 21, 22, 26, 1, 2, 11, 15, 0, 0, 20, 21, 22, 25, 2, 2) // #531 -PAIRING(10, 15, 20, 25, 11, 21, 25, 26, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #532 -PAIRING(10, 15, 20, 25, 11, 21, 26, 27, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #533 -PAIRING(10, 15, 20, 25, 11, 25, 25, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #534 -PAIRING(10, 15, 20, 25, 11, 25, 26, 27, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #535 -PAIRING(10, 15, 20, 25, 11, 26, 26, 27, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #536 -PAIRING(10, 15, 20, 25, 11, 26, 27, 28, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #537 -PAIRING(10, 15, 20, 25, 15, 16, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #538 -PAIRING(10, 15, 20, 25, 15, 16, 16, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #539 -PAIRING(10, 15, 20, 25, 15, 16, 16, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #540 -PAIRING(10, 15, 20, 25, 15, 16, 16, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #541 -PAIRING(10, 15, 20, 25, 15, 16, 16, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #542 -PAIRING(10, 15, 20, 25, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #543 -PAIRING(10, 15, 20, 25, 15, 16, 17, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #544 -PAIRING(10, 15, 20, 25, 15, 16, 17, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #545 -PAIRING(10, 15, 20, 25, 15, 16, 17, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #546 -PAIRING(10, 15, 20, 25, 15, 16, 17, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #547 -PAIRING(10, 15, 20, 25, 15, 16, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #548 -PAIRING(10, 15, 20, 25, 15, 16, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #549 -PAIRING(10, 15, 20, 25, 15, 16, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #550 -PAIRING(10, 15, 20, 25, 15, 16, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #551 -PAIRING(10, 15, 20, 25, 15, 16, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #552 -PAIRING(10, 15, 20, 25, 15, 16, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #553 -PAIRING(10, 15, 20, 25, 15, 16, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #554 -PAIRING(10, 15, 20, 25, 15, 16, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #555 -PAIRING(10, 15, 20, 25, 15, 20, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #556 -PAIRING(10, 15, 20, 25, 15, 20, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #557 -PAIRING(10, 15, 20, 25, 15, 20, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #558 -PAIRING(10, 15, 20, 25, 15, 20, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #559 -PAIRING(10, 15, 20, 25, 15, 20, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #560 -PAIRING(10, 15, 20, 25, 15, 20, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #561 -PAIRING(10, 15, 20, 25, 15, 20, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #562 -PAIRING(10, 15, 20, 25, 15, 20, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #563 -PAIRING(10, 15, 20, 25, 15, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 1) // #564 -PAIRING(10, 15, 20, 25, 15, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #565 -PAIRING(10, 15, 20, 25, 15, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 2) // #566 -PAIRING(10, 15, 20, 25, 15, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 1) // #567 -PAIRING(10, 15, 20, 25, 15, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #568 -PAIRING(10, 15, 20, 25, 15, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 2) // #569 -PAIRING(10, 15, 20, 25, 15, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #570 -PAIRING(10, 15, 20, 25, 15, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #571 -PAIRING(10, 15, 20, 25, 15, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #572 -PAIRING(10, 15, 20, 25, 15, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #573 -PAIRING(10, 15, 20, 25, 15, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #574 -PAIRING(10, 15, 20, 25, 15, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #575 -PAIRING(10, 15, 20, 25, 16, 17, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #576 -PAIRING(10, 15, 20, 25, 16, 17, 17, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #577 -PAIRING(10, 15, 20, 25, 16, 17, 17, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #578 -PAIRING(10, 15, 20, 25, 16, 17, 17, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #579 -PAIRING(10, 15, 20, 25, 16, 17, 17, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #580 -PAIRING(10, 15, 20, 25, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #581 -PAIRING(10, 15, 20, 25, 16, 17, 18, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #582 -PAIRING(10, 15, 20, 25, 16, 17, 18, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #583 -PAIRING(10, 15, 20, 25, 16, 17, 18, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #584 -PAIRING(10, 15, 20, 25, 16, 17, 18, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #585 -PAIRING(10, 15, 20, 25, 16, 17, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #586 -PAIRING(10, 15, 20, 25, 16, 17, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #587 -PAIRING(10, 15, 20, 25, 16, 17, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #588 -PAIRING(10, 15, 20, 25, 16, 17, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #589 -PAIRING(10, 15, 20, 25, 16, 17, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #590 -PAIRING(10, 15, 20, 25, 16, 17, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #591 -PAIRING(10, 15, 20, 25, 16, 17, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #592 -PAIRING(10, 15, 20, 25, 16, 17, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #593 -PAIRING(10, 15, 20, 25, 16, 20, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #594 -PAIRING(10, 15, 20, 25, 16, 20, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #595 -PAIRING(10, 15, 20, 25, 16, 20, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #596 -PAIRING(10, 15, 20, 25, 16, 20, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #597 -PAIRING(10, 15, 20, 25, 16, 20, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #598 -PAIRING(10, 15, 20, 25, 16, 20, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #599 -PAIRING(10, 15, 20, 25, 16, 20, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #600 -PAIRING(10, 15, 20, 25, 16, 20, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #601 -PAIRING(10, 15, 20, 25, 16, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 1) // #602 -PAIRING(10, 15, 20, 25, 16, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #603 -PAIRING(10, 15, 20, 25, 16, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 2) // #604 -PAIRING(10, 15, 20, 25, 16, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 1) // #605 -PAIRING(10, 15, 20, 25, 16, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #606 -PAIRING(10, 15, 20, 25, 16, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 2) // #607 -PAIRING(10, 15, 20, 25, 16, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #608 -PAIRING(10, 15, 20, 25, 16, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #609 -PAIRING(10, 15, 20, 25, 16, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #610 -PAIRING(10, 15, 20, 25, 16, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #611 -PAIRING(10, 15, 20, 25, 16, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #612 -PAIRING(10, 15, 20, 25, 16, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #613 -PAIRING(10, 15, 20, 25, 20, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 0) // #614 -PAIRING(10, 15, 20, 25, 20, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 0) // #615 -PAIRING(10, 15, 20, 25, 20, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #616 -PAIRING(10, 15, 20, 25, 20, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 0) // #617 -PAIRING(10, 15, 20, 25, 20, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 0) // #618 -PAIRING(10, 15, 20, 25, 20, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #619 -PAIRING(10, 15, 20, 25, 20, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #620 -PAIRING(10, 15, 20, 25, 20, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #621 -PAIRING(10, 15, 20, 25, 20, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #622 -PAIRING(10, 15, 20, 25, 20, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #623 -PAIRING(10, 15, 20, 25, 20, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #624 -PAIRING(10, 15, 20, 25, 20, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #625 -PAIRING(10, 15, 20, 25, 21, 22, 22, 23, 0, 2, 0, 0, 0, 0, 21, 22, 22, 23, 2, 0) // #626 -PAIRING(10, 15, 20, 25, 21, 22, 22, 25, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 0) // #627 -PAIRING(10, 15, 20, 25, 21, 22, 22, 26, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 1) // #628 -PAIRING(10, 15, 20, 25, 21, 22, 23, 24, 0, 2, 0, 0, 0, 0, 21, 22, 23, 24, 2, 0) // #629 -PAIRING(10, 15, 20, 25, 21, 22, 23, 25, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 0) // #630 -PAIRING(10, 15, 20, 25, 21, 22, 23, 26, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 1) // #631 -PAIRING(10, 15, 20, 25, 21, 22, 25, 26, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #632 -PAIRING(10, 15, 20, 25, 21, 22, 26, 27, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #633 -PAIRING(10, 15, 20, 25, 21, 25, 25, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #634 -PAIRING(10, 15, 20, 25, 21, 25, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #635 -PAIRING(10, 15, 20, 25, 21, 26, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #636 -PAIRING(10, 15, 20, 25, 21, 26, 27, 28, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #637 -PAIRING(10, 15, 20, 25, 25, 26, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #638 -PAIRING(10, 15, 20, 25, 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #639 -PAIRING(10, 15, 20, 25, 26, 27, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #640 -PAIRING(10, 15, 20, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #641 diff --git a/src/common/linux/testdata/stabs_reader_unittest.input1 b/src/common/linux/testdata/stabs_reader_unittest.input1 deleted file mode 100644 index 44b3d0a3..00000000 --- a/src/common/linux/testdata/stabs_reader_unittest.input1 +++ /dev/null @@ -1,19 +0,0 @@ -SO 10 11 0x02 builddir/ -FUN 20 21 0x12 not the SO with source file name we expected -SO 30 31 0x22 -SO 40 41 0x32 builddir1/ -SO 50 51 0x42 file1.c -LSYM 60 61 0x52 not the FUN we're looking for -FUN 70 71 0x62 fun1 -BINCL 80 81 0x72 something to ignore in a FUN body -SLINE 90 91 0x82 -SOL 100 101 0x92 header.h -SLINE 110 111 0x102 -FUN 120 121 0x112 fun2:some stabs type info here, to trim from the name -SLINE 130 131 0x122 -SOL 140 141 0x132 file1.c -SLINE 150 151 0x142 -SO 160 161 0x152 -LSYM 170 171 0x162 -SO 180 181 0x182 file3.c -SO 190 191 0x192 diff --git a/src/common/linux/testdata/stabs_reader_unittest.input2 b/src/common/linux/testdata/stabs_reader_unittest.input2 deleted file mode 100644 index 82efeb92..00000000 --- a/src/common/linux/testdata/stabs_reader_unittest.input2 +++ /dev/null @@ -1 +0,0 @@ -SO 10 11 0x12 file2-1.c diff --git a/src/common/linux/testdata/stabs_reader_unittest.input3 b/src/common/linux/testdata/stabs_reader_unittest.input3 deleted file mode 100644 index 73e6a302..00000000 --- a/src/common/linux/testdata/stabs_reader_unittest.input3 +++ /dev/null @@ -1,2 +0,0 @@ -SO 10 11 0x12 file3-1.c -FUN 20 21 0x22 fun3_1 diff --git a/src/common/linux/testdata/stabs_reader_unittest.input4 b/src/common/linux/testdata/stabs_reader_unittest.input4 deleted file mode 100644 index dfdbf677..00000000 --- a/src/common/linux/testdata/stabs_reader_unittest.input4 +++ /dev/null @@ -1 +0,0 @@ -SO 10 11 0x12 build-directory/ diff --git a/src/common/linux/testdata/stabs_reader_unittest.input5 b/src/common/linux/testdata/stabs_reader_unittest.input5 deleted file mode 100644 index 7a447c88..00000000 --- a/src/common/linux/testdata/stabs_reader_unittest.input5 +++ /dev/null @@ -1,2 +0,0 @@ -SO 10 11 0x12 file5-1.c -SO 20 21 0x22 file5-2.c diff --git a/src/common/linux/testdata/stabs_reader_unittest.input6 b/src/common/linux/testdata/stabs_reader_unittest.input6 deleted file mode 100644 index 54c2c9d4..00000000 --- a/src/common/linux/testdata/stabs_reader_unittest.input6 +++ /dev/null @@ -1,8 +0,0 @@ -cu-boundary antimony -SO 10 11 0x12 antimony -FUN 20 21 0x22 arsenic -SO 30 31 0x32 -cu-boundary aluminum -SO 40 41 0x42 aluminum -FUN 50 51 0x52 selenium -SO 60 61 0x62 |