aboutsummaryrefslogtreecommitdiff
path: root/src/common/linux
diff options
context:
space:
mode:
authorjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-04-05 19:40:17 +0000
committerjimblandy <jimblandy@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-04-05 19:40:17 +0000
commit87855248f1fab83caf002418196a34051d359f2c (patch)
tree349501494aa76b5f15afc0a105bac2455abd2002 /src/common/linux
parentBreakpad Linux Dumper: Disable warnings about unpaired functions and lines by... (diff)
downloadbreakpad-87855248f1fab83caf002418196a34051d359f2c.tar.xz
Breakpad symbol dumper: Move Linux dumping classes into src/common.
The Linux symbol dumper's classes are reasonably portable, and should be usable for the Mac dumper as well. Move them to src/common, along with their unit tests. Update #include directives and Makefile. a=jimblandy, r=nealsid git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@567 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/common/linux')
-rw-r--r--src/common/linux/dump_stabs.cc178
-rw-r--r--src/common/linux/dump_stabs.h139
-rw-r--r--src/common/linux/dump_stabs_unittest.cc193
-rw-r--r--src/common/linux/dump_symbols.cc12
-rw-r--r--src/common/linux/dwarf_cfi_to_module.cc185
-rw-r--r--src/common/linux/dwarf_cfi_to_module.h154
-rw-r--r--src/common/linux/dwarf_cfi_to_module_unittest.cc260
-rw-r--r--src/common/linux/dwarf_cu_to_module.cc881
-rw-r--r--src/common/linux/dwarf_cu_to_module.h272
-rw-r--r--src/common/linux/dwarf_cu_to_module_unittest.cc1701
-rw-r--r--src/common/linux/dwarf_line_to_module.cc132
-rw-r--r--src/common/linux/dwarf_line_to_module.h179
-rw-r--r--src/common/linux/dwarf_line_to_module_unittest.cc339
-rw-r--r--src/common/linux/language.cc82
-rw-r--r--src/common/linux/language.h84
-rw-r--r--src/common/linux/module.cc235
-rw-r--r--src/common/linux/module.h268
-rw-r--r--src/common/linux/module_unittest.cc396
-rw-r--r--src/common/linux/stabs_reader.cc220
-rw-r--r--src/common/linux/stabs_reader.h206
-rw-r--r--src/common/linux/stabs_reader_unittest.cc685
-rw-r--r--src/common/linux/testdata/func-line-pairing.h676
-rw-r--r--src/common/linux/testdata/stabs_reader_unittest.input119
-rw-r--r--src/common/linux/testdata/stabs_reader_unittest.input21
-rw-r--r--src/common/linux/testdata/stabs_reader_unittest.input32
-rw-r--r--src/common/linux/testdata/stabs_reader_unittest.input41
-rw-r--r--src/common/linux/testdata/stabs_reader_unittest.input52
-rw-r--r--src/common/linux/testdata/stabs_reader_unittest.input68
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 &reg) {
- 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 &reg) {
- 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 &section)
- : 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 &reg);
-
- // 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 &reg);
-
- 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> &register_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> &register_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 &section)
- : Reporter(file, section) { }
- MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg));
- MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string &reg));
- MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string &reg));
-};
-
-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 &section_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 &section_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 &section_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 &param = 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 &param = 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