summaryrefslogtreecommitdiffstats
path: root/breakpad
diff options
context:
space:
mode:
authorthestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-02 01:55:06 +0000
committerthestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-02 01:55:06 +0000
commitb07fc5114ccce26011ec2312eee3397134739f9a (patch)
tree1570e3652386e2b314e1be8067e7e44a00f49b75 /breakpad
parent74f34b094a7b21f0c057f493abee5db30b988592 (diff)
downloadchromium_src-b07fc5114ccce26011ec2312eee3397134739f9a.zip
chromium_src-b07fc5114ccce26011ec2312eee3397134739f9a.tar.gz
chromium_src-b07fc5114ccce26011ec2312eee3397134739f9a.tar.bz2
Linux: Use upstream google-breakpad instead of our fork.
BUG=28276 TEST=dump_syms works with ToT Chrome. Review URL: http://codereview.chromium.org/414049 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33534 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'breakpad')
-rw-r--r--breakpad/breakpad.gyp57
-rw-r--r--breakpad/linux/breakpad_googletest_includes.h (renamed from breakpad/linux/dump_symbols.h)23
-rw-r--r--breakpad/linux/directory_reader.h105
-rw-r--r--breakpad/linux/directory_reader_unittest.cc77
-rw-r--r--breakpad/linux/dump_symbols.cc779
-rw-r--r--breakpad/linux/dump_syms.cc50
-rw-r--r--breakpad/linux/exception_handler.cc322
-rw-r--r--breakpad/linux/exception_handler.h198
-rw-r--r--breakpad/linux/exception_handler_unittest.cc246
-rw-r--r--breakpad/linux/file_id.cc115
-rw-r--r--breakpad/linux/file_id.h70
-rw-r--r--breakpad/linux/generate-test-dump.cc6
-rw-r--r--breakpad/linux/line_reader.h125
-rw-r--r--breakpad/linux/line_reader_unittest.cc184
-rw-r--r--breakpad/linux/linux_dumper.cc421
-rw-r--r--breakpad/linux/linux_dumper.h145
-rw-r--r--breakpad/linux/linux_dumper_unittest.cc118
-rw-r--r--breakpad/linux/linux_libc_support.h178
-rw-r--r--breakpad/linux/linux_libc_support_unittest.cc153
-rw-r--r--breakpad/linux/linux_syscall_support.h2800
-rw-r--r--breakpad/linux/memory.h181
-rw-r--r--breakpad/linux/memory_unittest.cc84
-rw-r--r--breakpad/linux/minidump-2-core.cc603
-rw-r--r--breakpad/linux/minidump_file_writer.cc254
-rw-r--r--breakpad/linux/minidump_format_linux.h44
-rw-r--r--breakpad/linux/minidump_writer.cc862
-rw-r--r--breakpad/linux/minidump_writer.h53
-rw-r--r--breakpad/linux/minidump_writer_unittest.cc70
28 files changed, 47 insertions, 8276 deletions
diff --git a/breakpad/breakpad.gyp b/breakpad/breakpad.gyp
index 1fed709..74ed1f1 100644
--- a/breakpad/breakpad.gyp
+++ b/breakpad/breakpad.gyp
@@ -247,6 +247,7 @@
'sources': [
'src/tools/linux/symupload/sym_upload.cc',
'src/common/linux/http_upload.cc',
+ 'src/common/linux/http_upload.h',
],
'include_dirs': [
'src',
@@ -262,11 +263,16 @@
'type': 'executable',
'sources': [
- 'linux/dump_syms.cc',
- 'linux/dump_symbols.cc',
- 'linux/dump_symbols.h',
- 'linux/file_id.cc',
- 'linux/file_id.h',
+ 'src/common/linux/dump_symbols.cc',
+ 'src/common/linux/dump_symbols.h',
+ 'src/common/linux/file_id.cc',
+ 'src/common/linux/file_id.h',
+ 'src/common/linux/guid_creator.h',
+ 'src/common/linux/module.cc',
+ 'src/common/linux/module.h',
+ 'src/common/linux/stabs_reader.cc',
+ 'src/common/linux/stabs_reader.h',
+ 'src/tools/linux/dump_syms/dump_syms.cc',
],
'include_dirs': [
@@ -283,15 +289,25 @@
'type': '<(library)',
'sources': [
- 'linux/exception_handler.cc',
- 'linux/linux_dumper.cc',
- 'linux/minidump_writer.cc',
+ 'src/client/linux/handler/exception_handler.cc',
+ 'src/client/linux/minidump_writer/directory_reader.h',
+ 'src/client/linux/minidump_writer/line_reader.h',
+ 'src/client/linux/minidump_writer/linux_dumper.cc',
+ 'src/client/linux/minidump_writer/linux_dumper.h',
+ 'src/client/linux/minidump_writer/minidump_writer.cc',
+ 'src/client/linux/minidump_writer/minidump_writer.h',
+ 'src/client/minidump_file_writer-inl.h',
+ 'src/client/minidump_file_writer.cc',
+ 'src/client/minidump_file_writer.h',
+ 'src/common/convert_UTF.c',
+ 'src/common/convert_UTF.h',
'src/common/linux/guid_creator.cc',
+ 'src/common/linux/guid_creator.h',
+ 'src/common/linux/linux_libc_support.h',
+ 'src/common/linux/linux_syscall_support.h',
+ 'src/common/linux/memory.h',
'src/common/string_conversion.cc',
- 'src/common/convert_UTF.c',
-
- # TODO(agl): unfork this file
- 'linux/minidump_file_writer.cc',
+ 'src/common/string_conversion.h',
],
'include_dirs': [
@@ -306,20 +322,23 @@
'dependencies': [
'../testing/gtest.gyp:gtest',
'../testing/gtest.gyp:gtestmain',
+ '../testing/gmock.gyp:gmock',
'breakpad_client',
],
'sources': [
- 'linux/directory_reader_unittest.cc',
- 'linux/exception_handler_unittest.cc',
- 'linux/line_reader_unittest.cc',
- 'linux/linux_dumper_unittest.cc',
- 'linux/linux_libc_support_unittest.cc',
- 'linux/memory_unittest.cc',
- 'linux/minidump_writer_unittest.cc',
+ 'src/client/linux/minidump_writer/directory_reader_unittest.cc',
+ 'src/client/linux/handler/exception_handler_unittest.cc',
+ 'src/client/linux/minidump_writer/line_reader_unittest.cc',
+ 'src/client/linux/minidump_writer/linux_dumper_unittest.cc',
+ 'src/common/linux/linux_libc_support_unittest.cc',
+ 'src/common/linux/memory_unittest.cc',
+ 'src/client/linux/minidump_writer/minidump_writer_unittest.cc',
+ 'linux/breakpad_googletest_includes.h',
],
'include_dirs': [
+ 'linux', # Use our copy of breakpad_googletest_includes.h
'src',
'..',
'.',
diff --git a/breakpad/linux/dump_symbols.h b/breakpad/linux/breakpad_googletest_includes.h
index 662b482..aeab315 100644
--- a/breakpad/linux/dump_symbols.h
+++ b/breakpad/linux/breakpad_googletest_includes.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006, 2009, Google Inc.
+// Copyright (c) 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -26,22 +26,11 @@
// 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.
-//
-// dump_symbols.cc: Implements a linux stab debugging format dumper.
-//
-
-#ifndef BREAKPAD_LINUX_DUMP_SYMBOLS_H_
-#define BREAKPAD_LINUX_DUMP_SYMBOLS_H_
-
-#include <string>
-
-namespace google_breakpad {
-class DumpSymbols {
- public:
- static bool WriteSymbolFile(const std::string& obj_file, int sym_fd);
-};
+#ifndef BREAKPAD_GOOGLETEST_INCLUDES_H__
+#define BREAKPAD_GOOGLETEST_INCLUDES_H__
-} // namespace google_breakpad
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
-#endif // BREAKPAD_LINUX_DUMP_SYMBOLS_H_
+#endif // BREAKPAD_GOOGLETEST_INCLUDES_H__
diff --git a/breakpad/linux/directory_reader.h b/breakpad/linux/directory_reader.h
deleted file mode 100644
index 76950ec..0000000
--- a/breakpad/linux/directory_reader.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#ifndef CLIENT_LINUX_HANDLE_DIRECTORY_READER_H_
-#define CLIENT_LINUX_HANDLE_DIRECTORY_READER_H_
-
-#include <stdint.h>
-#include <unistd.h>
-#include <limits.h>
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-
-#include "breakpad/linux/linux_syscall_support.h"
-
-namespace google_breakpad {
-
-// A class for enumerating a directory without using diropen/readdir or other
-// functions which may allocate memory.
-class DirectoryReader {
- public:
- DirectoryReader(int fd)
- : fd_(fd),
- buf_used_(0) {
- }
-
- // Return the next entry from the directory
- // name: (output) the NUL terminated entry name
- //
- // Returns true iff successful (false on EOF).
- //
- // After calling this, one must call |PopEntry| otherwise you'll get the same
- // entry over and over.
- bool GetNextEntry(const char** name) {
- struct kernel_dirent* const dent =
- reinterpret_cast<kernel_dirent*>(buf_);
-
- if (buf_used_ == 0) {
- // need to read more entries.
- const int n = sys_getdents(fd_, dent, sizeof(buf_));
- if (n < 0) {
- return false;
- } else if (n == 0) {
- hit_eof_ = true;
- } else {
- buf_used_ += n;
- }
- }
-
- if (buf_used_ == 0 && hit_eof_)
- return false;
-
- assert(buf_used_ > 0);
-
- *name = dent->d_name;
- return true;
- }
-
- void PopEntry() {
- if (!buf_used_)
- return;
-
- const struct kernel_dirent* const dent =
- reinterpret_cast<kernel_dirent*>(buf_);
-
- buf_used_ -= dent->d_reclen;
- memmove(buf_, buf_ + dent->d_reclen, buf_used_);
- }
-
- private:
- const int fd_;
- bool hit_eof_;
- unsigned buf_used_;
- uint8_t buf_[sizeof(struct kernel_dirent) + NAME_MAX + 1];
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_HANDLE_DIRECTORY_READER_H_
diff --git a/breakpad/linux/directory_reader_unittest.cc b/breakpad/linux/directory_reader_unittest.cc
deleted file mode 100644
index d04cc86..0000000
--- a/breakpad/linux/directory_reader_unittest.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#include <set>
-#include <string>
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/types.h>
-
-#include "breakpad/linux/directory_reader.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using namespace google_breakpad;
-
-namespace {
-typedef testing::Test DirectoryReaderTest;
-}
-
-TEST(DirectoryReaderTest, CompareResults) {
- std::set<std::string> dent_set;
-
- DIR *const dir = opendir("/proc/self");
- ASSERT_TRUE(dir != NULL);
-
- struct dirent* dent;
- while ((dent = readdir(dir)))
- dent_set.insert(dent->d_name);
-
- closedir(dir);
-
- const int fd = open("/proc/self", O_DIRECTORY | O_RDONLY);
- ASSERT_GE(fd, 0);
-
- DirectoryReader dir_reader(fd);
- unsigned seen = 0;
-
- const char* name;
- while (dir_reader.GetNextEntry(&name)) {
- ASSERT_TRUE(dent_set.find(name) != dent_set.end());
- seen++;
- dir_reader.PopEntry();
- }
-
- ASSERT_TRUE(dent_set.find("status") != dent_set.end());
- ASSERT_TRUE(dent_set.find("stat") != dent_set.end());
- ASSERT_TRUE(dent_set.find("cmdline") != dent_set.end());
-
- ASSERT_EQ(dent_set.size(), seen);
- close(fd);
-}
diff --git a/breakpad/linux/dump_symbols.cc b/breakpad/linux/dump_symbols.cc
deleted file mode 100644
index 49b70e5..0000000
--- a/breakpad/linux/dump_symbols.cc
+++ /dev/null
@@ -1,779 +0,0 @@
-// Copyright (c) 2006, 2009, 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.
-
-#include "breakpad/linux/dump_symbols.h"
-
-#include <a.out.h>
-#include <assert.h>
-#include <cxxabi.h>
-#include <elf.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <link.h>
-#include <stab.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
-#include <functional>
-#include <list>
-#include <vector>
-
-#include "breakpad/linux/file_id.h"
-#include "common/linux/guid_creator.h"
-
-// This namespace contains helper functions.
-namespace {
-
-// Infomation of a line.
-struct LineInfo {
- // The index into string table for the name of the source file which
- // this line belongs to.
- // Load from stab symbol.
- uint32_t source_name_index;
- // Offset from start of the function.
- // Load from stab symbol.
- ElfW(Off) rva_to_func;
- // Offset from base of the loading binary.
- ElfW(Off) rva_to_base;
- // Size of the line.
- // It is the difference of the starting address of the line and starting
- // address of the next N_SLINE, N_FUN or N_SO.
- uint32_t size;
- // Line number.
- uint32_t line_num;
- // Id of the source file for this line.
- int source_id;
-};
-
-typedef std::list<struct LineInfo> LineInfoList;
-
-// Information of a function.
-struct FuncInfo {
- // Name of the function.
- const char* name;
- // Offset from the base of the loading address.
- ElfW(Off) rva_to_base;
- // Virtual address of the function.
- // Load from stab symbol.
- ElfW(Addr) addr;
- // Size of the function.
- // It is the difference of the starting address of the function and starting
- // address of the next N_FUN or N_SO.
- uint32_t size;
- // Total size of stack parameters.
- uint32_t stack_param_size;
- // Is there any lines included from other files?
- bool has_sol;
- // Line information array.
- LineInfoList line_info;
-};
-
-typedef std::list<struct FuncInfo> FuncInfoList;
-
-// Information of a source file.
-struct SourceFileInfo {
- // Name string index into the string table.
- uint32_t name_index;
- // Name of the source file.
- const char* name;
- // Starting address of the source file.
- ElfW(Addr) addr;
- // Id of the source file.
- int source_id;
- // Functions information.
- FuncInfoList func_info;
-};
-
-typedef std::list<struct SourceFileInfo> SourceFileInfoList;
-
-// Information of a symbol table.
-// This is the root of all types of symbol.
-struct SymbolInfo {
- SourceFileInfoList source_file_info;
-
- // The next source id for newly found source file.
- int next_source_id;
-};
-
-// Stab section name.
-static const char* kStabName = ".stab";
-
-// Demangle using abi call.
-// Older GCC may not support it.
-static std::string Demangle(const char* mangled) {
- int status = 0;
- char* demangled = abi::__cxa_demangle(mangled, NULL, NULL, &status);
- if (status == 0 && demangled != NULL) {
- std::string str(demangled);
- free(demangled);
- return str;
- }
- return std::string(mangled);
-}
-
-// Fix offset into virtual address by adding the mapped base into offsets.
-// Make life easier when want to find something by offset.
-static void FixAddress(void* obj_base) {
- ElfW(Addr) base = reinterpret_cast<ElfW(Addr)>(obj_base);
- ElfW(Ehdr)* elf_header = static_cast<ElfW(Ehdr)* >(obj_base);
- elf_header->e_phoff += base;
- elf_header->e_shoff += base;
- ElfW(Shdr)* sections = reinterpret_cast<ElfW(Shdr)* >(elf_header->e_shoff);
- for (int i = 0; i < elf_header->e_shnum; ++i)
- sections[i].sh_offset += base;
-}
-
-// Find the prefered loading address of the binary.
-static ElfW(Addr) GetLoadingAddress(const ElfW(Phdr)* program_headers,
- int nheader) {
- for (int i = 0; i < nheader; ++i) {
- const ElfW(Phdr)& header = program_headers[i];
- // For executable, it is the PT_LOAD segment with offset to zero.
- if (header.p_type == PT_LOAD &&
- header.p_offset == 0)
- return header.p_vaddr;
- }
- // For other types of ELF, return 0.
- return 0;
-}
-
-static bool WriteFormat(int fd, const char* fmt, ...) {
- va_list list;
- char buffer[4096];
- ssize_t expected, written;
- va_start(list, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, list);
- expected = strlen(buffer);
- written = write(fd, buffer, strlen(buffer));
- va_end(list);
- return expected == written;
-}
-
-static bool IsValidElf(const ElfW(Ehdr)* elf_header) {
- return memcmp(elf_header, ELFMAG, SELFMAG) == 0;
-}
-
-static const ElfW(Shdr)* FindSectionByName(const char* name,
- const ElfW(Shdr)* sections,
- const ElfW(Shdr)* strtab,
- int nsection) {
- assert(name != NULL);
- assert(sections != NULL);
- assert(nsection > 0);
-
- int name_len = strlen(name);
- if (name_len == 0)
- return NULL;
-
- for (int i = 0; i < nsection; ++i) {
- const char* section_name =
- reinterpret_cast<char*>(strtab->sh_offset + sections[i].sh_name);
- if (!strncmp(name, section_name, name_len))
- return sections + i;
- }
- return NULL;
-}
-
-// TODO(liuli): Computer the stack parameter size.
-// Expect parameter variables are immediately following the N_FUN symbol.
-// Will need to parse the type information to get a correct size.
-static int LoadStackParamSize(struct nlist* list,
- struct nlist* list_end,
- struct FuncInfo* func_info) {
- struct nlist* cur_list = list;
- assert(cur_list->n_type == N_FUN);
- ++cur_list;
- int step = 1;
- while (cur_list < list_end && cur_list->n_type == N_PSYM) {
- ++cur_list;
- ++step;
- }
- func_info->stack_param_size = 0;
- return step;
-}
-
-static int LoadLineInfo(struct nlist* list,
- struct nlist* list_end,
- const struct SourceFileInfo& source_file_info,
- struct FuncInfo* func_info) {
- struct nlist* cur_list = list;
- func_info->has_sol = false;
- // Records which source file the following lines belongs. Default
- // to the file we are handling. This helps us handling inlined source.
- // When encountering N_SOL, we will change this to the source file
- // specified by N_SOL.
- int current_source_name_index = source_file_info.name_index;
- do {
- // Skip non line information.
- while (cur_list < list_end && cur_list->n_type != N_SLINE) {
- // Only exit when got another function, or source file.
- if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO)
- return cur_list - list;
- // N_SOL means source lines following it will be from
- // another source file.
- if (cur_list->n_type == N_SOL) {
- func_info->has_sol = true;
-
- if (cur_list->n_un.n_strx > 0 &&
- cur_list->n_un.n_strx != current_source_name_index) {
- // The following lines will be from this source file.
- current_source_name_index = cur_list->n_un.n_strx;
- }
- }
- ++cur_list;
- }
- struct LineInfo line;
- while (cur_list < list_end && cur_list->n_type == N_SLINE) {
- line.source_name_index = current_source_name_index;
- line.rva_to_func = cur_list->n_value;
- // n_desc is a signed short
- line.line_num = (unsigned short)cur_list->n_desc;
- // Don't set it here.
- // Will be processed in later pass.
- line.source_id = -1;
- func_info->line_info.push_back(line);
- ++cur_list;
- }
- } while (list < list_end);
-
- return cur_list - list;
-}
-
-static int LoadFuncSymbols(struct nlist* list,
- struct nlist* list_end,
- const ElfW(Shdr)* stabstr_section,
- struct SourceFileInfo* source_file_info) {
- struct nlist* cur_list = list;
- assert(cur_list->n_type == N_SO);
- ++cur_list;
- source_file_info->func_info.clear();
- while (cur_list < list_end) {
- // Go until the function symbol.
- while (cur_list < list_end && cur_list->n_type != N_FUN) {
- if (cur_list->n_type == N_SO) {
- return cur_list - list;
- }
- ++cur_list;
- continue;
- }
- if (cur_list->n_type == N_FUN) {
- struct FuncInfo func_info;
- func_info.name =
- reinterpret_cast<char* >(cur_list->n_un.n_strx +
- stabstr_section->sh_offset);
- func_info.addr = cur_list->n_value;
- func_info.rva_to_base = 0;
- func_info.size = 0;
- func_info.stack_param_size = 0;
- func_info.has_sol = 0;
-
- // Stack parameter size.
- cur_list += LoadStackParamSize(cur_list, list_end, &func_info);
- // Line info.
- cur_list += LoadLineInfo(cur_list,
- list_end,
- *source_file_info,
- &func_info);
-
- // Functions in this module should have address bigger than the module
- // startring address.
- // There maybe a lot of duplicated entry for a function in the symbol,
- // only one of them can met this.
- if (func_info.addr >= source_file_info->addr) {
- source_file_info->func_info.push_back(func_info);
- }
- }
- }
- return cur_list - list;
-}
-
-// Comapre the address.
-// The argument should have a memeber named "addr"
-template<class T1, class T2>
-static bool CompareAddress(T1* a, T2* b) {
- return a->addr < b->addr;
-}
-
-// Sort the array into increasing ordered array based on the virtual address.
-// Return vector of pointers to the elements in the incoming array. So caller
-// should make sure the returned vector lives longer than the incoming vector.
-template<class Container>
-static std::vector<typename Container::value_type* > SortByAddress(
- Container* container) {
- typedef typename Container::iterator It;
- typedef typename Container::value_type T;
- std::vector<T* > sorted_array_ptr;
- sorted_array_ptr.reserve(container->size());
- for (It it = container->begin(); it != container->end(); it++)
- sorted_array_ptr.push_back(&(*it));
- std::sort(sorted_array_ptr.begin(),
- sorted_array_ptr.end(),
- std::ptr_fun(CompareAddress<T, T>));
-
- return sorted_array_ptr;
-}
-
-// Find the address of the next function or source file symbol in the symbol
-// table. The address should be bigger than the current function's address.
-static ElfW(Addr) NextAddress(
- std::vector<struct FuncInfo* >* sorted_functions,
- std::vector<struct SourceFileInfo* >* sorted_files,
- const struct FuncInfo& func_info) {
- std::vector<struct FuncInfo* >::iterator next_func_iter =
- std::find_if(sorted_functions->begin(),
- sorted_functions->end(),
- std::bind1st(
- std::ptr_fun(
- CompareAddress<struct FuncInfo,
- struct FuncInfo>),
- &func_info));
- if (next_func_iter != sorted_functions->end())
- return (*next_func_iter)->addr;
-
- std::vector<struct SourceFileInfo* >::iterator next_file_iter =
- std::find_if(sorted_files->begin(),
- sorted_files->end(),
- std::bind1st(
- std::ptr_fun(
- CompareAddress<struct FuncInfo,
- struct SourceFileInfo>),
- &func_info));
- if (next_file_iter != sorted_files->end()) {
- return (*next_file_iter)->addr;
- }
- return 0;
-}
-
-static int FindFileByNameIdx(uint32_t name_index,
- SourceFileInfoList& files) {
- for (SourceFileInfoList::iterator it = files.begin();
- it != files.end(); it++) {
- if (it->name_index == name_index)
- return it->source_id;
- }
-
- return -1;
-}
-
-// Add included file information.
-// Also fix the source id for the line info.
-static void AddIncludedFiles(struct SymbolInfo* symbols,
- const ElfW(Shdr)* stabstr_section) {
- for (SourceFileInfoList::iterator source_file_it =
- symbols->source_file_info.begin();
- source_file_it != symbols->source_file_info.end();
- ++source_file_it) {
- struct SourceFileInfo& source_file = *source_file_it;
-
- for (FuncInfoList::iterator func_info_it = source_file.func_info.begin();
- func_info_it != source_file.func_info.end();
- ++func_info_it) {
- struct FuncInfo& func_info = *func_info_it;
-
- for (LineInfoList::iterator line_info_it = func_info.line_info.begin();
- line_info_it != func_info.line_info.end(); ++line_info_it) {
- struct LineInfo& line_info = *line_info_it;
-
- assert(line_info.source_name_index > 0);
- assert(source_file.name_index > 0);
-
- // Check if the line belongs to the source file by comparing the
- // name index into string table.
- if (line_info.source_name_index != source_file.name_index) {
- // This line is not from the current source file, check if this
- // source file has been added before.
- int found_source_id = FindFileByNameIdx(line_info.source_name_index,
- symbols->source_file_info);
- if (found_source_id < 0) {
- // Got a new included file.
- // Those included files don't have address or line information.
- SourceFileInfo new_file;
- new_file.name_index = line_info.source_name_index;
- new_file.name =
- reinterpret_cast<char* >(new_file.name_index +
- stabstr_section->sh_offset);
- new_file.addr = 0;
- new_file.source_id = symbols->next_source_id++;
- line_info.source_id = new_file.source_id;
- symbols->source_file_info.push_back(new_file);
- } else {
- // The file has been added.
- line_info.source_id = found_source_id;
- }
- } else {
- // The line belongs to the file.
- line_info.source_id = source_file.source_id;
- }
- } // for each line.
- } // for each function.
- } // for each source file.
-}
-
-// Compute size and rva information based on symbols loaded from stab section.
-static bool ComputeSizeAndRVA(ElfW(Addr) loading_addr,
- struct SymbolInfo* symbols) {
- std::vector<struct SourceFileInfo* > sorted_files =
- SortByAddress(&(symbols->source_file_info));
- for (size_t i = 0; i < sorted_files.size(); ++i) {
- struct SourceFileInfo& source_file =* sorted_files[i];
- std::vector<struct FuncInfo* > sorted_functions =
- SortByAddress(&(source_file.func_info));
- for (size_t j = 0; j < sorted_functions.size(); ++j) {
- struct FuncInfo& func_info = *sorted_functions[j];
- assert(func_info.addr >= loading_addr);
- func_info.rva_to_base = func_info.addr - loading_addr;
- func_info.size = 0;
- ElfW(Addr) next_addr = NextAddress(&sorted_functions,
- &sorted_files,
- func_info);
- // I've noticed functions with an address bigger than any other functions
- // and source files modules, this is probably the last function in the
- // module, due to limitions of Linux stab symbol, it is impossible to get
- // the exact size of this kind of function, thus we give it a default
- // very big value. This should be safe since this is the last function.
- // But it is a ugly hack.....
- // The following code can reproduce the case:
- // template<class T>
- // void Foo(T value) {
- // }
- //
- // int main(void) {
- // Foo(10);
- // Foo(std::string("hello"));
- // return 0;
- // }
- // TODO(liuli): Find a better solution.
- static const int kDefaultSize = 0x10000000;
- static int no_next_addr_count = 0;
- if (next_addr != 0) {
- func_info.size = next_addr - func_info.addr;
- } else {
- if (no_next_addr_count > 1) {
- fprintf(stderr, "Got more than one function without the following ");
- fprintf(stderr, "symbol. Ignore this function.\n");
- fprintf(stderr, "The dumped symbol may not correct.\n");
- assert(!"This should not happen!\n");
- func_info.size = 0;
- continue;
- }
-
- no_next_addr_count++;
- func_info.size = kDefaultSize;
- }
- // Compute line size.
- for (LineInfoList::iterator line_info_it = func_info.line_info.begin();
- line_info_it != func_info.line_info.end(); line_info_it++) {
- struct LineInfo& line_info = *line_info_it;
- LineInfoList::iterator next_line_info_it = line_info_it;
- next_line_info_it++;
- line_info.size = 0;
- if (next_line_info_it != func_info.line_info.end()) {
- line_info.size =
- next_line_info_it->rva_to_func - line_info.rva_to_func;
- } else {
- // The last line in the function.
- // If we can find a function or source file symbol immediately
- // following the line, we can get the size of the line by computing
- // the difference of the next address to the starting address of this
- // line.
- // Otherwise, we need to set a default big enough value. This occurs
- // mostly because the this function is the last one in the module.
- if (next_addr != 0) {
- ElfW(Off) next_addr_offset = next_addr - func_info.addr;
- line_info.size = next_addr_offset - line_info.rva_to_func;
- } else {
- line_info.size = kDefaultSize;
- }
- }
- line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base;
- } // for each line.
- } // for each function.
- } // for each source file.
- return true;
-}
-
-static bool LoadSymbols(const ElfW(Shdr)* stab_section,
- const ElfW(Shdr)* stabstr_section,
- ElfW(Addr) loading_addr,
- struct SymbolInfo* symbols) {
- if (stab_section == NULL || stabstr_section == NULL)
- return false;
-
- struct nlist* lists =
- reinterpret_cast<struct nlist* >(stab_section->sh_offset);
- int nstab = stab_section->sh_size / sizeof(struct nlist);
- // First pass, load all symbols from the object file.
- for (int i = 0; i < nstab;) {
- int step = 1;
- struct nlist* cur_list = lists + i;
- if (cur_list->n_type == N_SO) {
- // FUNC <address> <length> <param_stack_size> <function>
- struct SourceFileInfo source_file_info;
- source_file_info.name_index = cur_list->n_un.n_strx;
- source_file_info.name = reinterpret_cast<char* >(cur_list->n_un.n_strx +
- stabstr_section->sh_offset);
- source_file_info.addr = cur_list->n_value;
- if (strchr(source_file_info.name, '.'))
- source_file_info.source_id = symbols->next_source_id++;
- else
- source_file_info.source_id = -1;
- step = LoadFuncSymbols(cur_list, lists + nstab,
- stabstr_section, &source_file_info);
- symbols->source_file_info.push_back(source_file_info);
- }
- i += step;
- }
-
- // Second pass, compute the size of functions and lines.
- if (ComputeSizeAndRVA(loading_addr, symbols)) {
- // Third pass, check for included source code, especially for header files.
- // Until now, we only have compiling unit information, but they can
- // have code from include files, add them here.
- AddIncludedFiles(symbols, stabstr_section);
- return true;
- }
- return false;
-}
-
-static bool LoadSymbols(ElfW(Ehdr)* elf_header, struct SymbolInfo* symbols) {
- // Translate all offsets in section headers into address.
- FixAddress(elf_header);
- ElfW(Addr) loading_addr = GetLoadingAddress(
- reinterpret_cast<ElfW(Phdr)* >(elf_header->e_phoff),
- elf_header->e_phnum);
-
- const ElfW(Shdr)* sections =
- reinterpret_cast<ElfW(Shdr)* >(elf_header->e_shoff);
- const ElfW(Shdr)* strtab = sections + elf_header->e_shstrndx;
- const ElfW(Shdr)* stab_section =
- FindSectionByName(kStabName, sections, strtab, elf_header->e_shnum);
- if (stab_section == NULL) {
- fprintf(stderr, "Stab section not found.\n");
- return false;
- }
- const ElfW(Shdr)* stabstr_section = stab_section->sh_link + sections;
-
- // Load symbols.
- return LoadSymbols(stab_section, stabstr_section, loading_addr, symbols);
-}
-
-static bool WriteModuleInfo(int fd,
- ElfW(Half) arch,
- const std::string& obj_file) {
- const char* arch_name = NULL;
- if (arch == EM_386)
- arch_name = "x86";
- else if (arch == EM_X86_64)
- arch_name = "x86_64";
- else
- return false;
-
- uint8_t identifier[google_breakpad::kMDGUIDSize];
- google_breakpad::FileID file_id(obj_file.c_str());
- if (file_id.ElfFileIdentifier(identifier)) {
- char identifier_str[40];
- file_id.ConvertIdentifierToString(identifier,
- identifier_str, sizeof(identifier_str));
- char id_no_dash[40];
- int id_no_dash_len = 0;
- memset(id_no_dash, 0, sizeof(id_no_dash));
- for (int i = 0; identifier_str[i] != '\0'; ++i)
- if (identifier_str[i] != '-')
- id_no_dash[id_no_dash_len++] = identifier_str[i];
- // Add an extra "0" by the end.
- id_no_dash[id_no_dash_len++] = '0';
- std::string filename = obj_file;
- size_t slash_pos = obj_file.find_last_of("/");
- if (slash_pos != std::string::npos)
- filename = obj_file.substr(slash_pos + 1);
- return WriteFormat(fd, "MODULE Linux %s %s %s\n", arch_name,
- id_no_dash, filename.c_str());
- }
- return false;
-}
-
-static bool WriteSourceFileInfo(int fd, const struct SymbolInfo& symbols) {
- for (SourceFileInfoList::const_iterator it =
- symbols.source_file_info.begin();
- it != symbols.source_file_info.end(); it++) {
- if (it->source_id != -1) {
- const char* name = it->name;
- if (!WriteFormat(fd, "FILE %d %s\n", it->source_id, name))
- return false;
- }
- }
- return true;
-}
-
-static bool WriteOneFunction(int fd,
- const struct FuncInfo& func_info) {
- // Discard the ending part of the name.
- std::string func_name(func_info.name);
- std::string::size_type last_colon = func_name.find_last_of(':');
- if (last_colon != std::string::npos)
- func_name = func_name.substr(0, last_colon);
- func_name = Demangle(func_name.c_str());
-
- if (func_info.size <= 0)
- return true;
-
- if (WriteFormat(fd, "FUNC %lx %lx %d %s\n",
- func_info.rva_to_base,
- func_info.size,
- func_info.stack_param_size,
- func_name.c_str())) {
- for (LineInfoList::const_iterator it = func_info.line_info.begin();
- it != func_info.line_info.end(); it++) {
- const struct LineInfo& line_info =* it;
- if (!WriteFormat(fd, "%lx %lx %d %d\n",
- line_info.rva_to_base,
- line_info.size,
- line_info.line_num,
- line_info.source_id))
- return false;
- }
- return true;
- }
- return false;
-}
-
-static bool WriteFunctionInfo(int fd, const struct SymbolInfo& symbols) {
- for (SourceFileInfoList::const_iterator it =
- symbols.source_file_info.begin();
- it != symbols.source_file_info.end(); it++) {
- const struct SourceFileInfo& file_info =* it;
- for (FuncInfoList::const_iterator fiIt = file_info.func_info.begin();
- fiIt != file_info.func_info.end(); fiIt++) {
- const struct FuncInfo& func_info =* fiIt;
- if (!WriteOneFunction(fd, func_info))
- return false;
- }
- }
- return true;
-}
-
-static bool DumpStabSymbols(int fd, const struct SymbolInfo& symbols) {
- return WriteSourceFileInfo(fd, symbols) &&
- WriteFunctionInfo(fd, symbols);
-}
-
-//
-// FDWrapper
-//
-// Wrapper class to make sure opened file is closed.
-//
-class FDWrapper {
- public:
- explicit FDWrapper(int fd) :
- fd_(fd) {
- }
- ~FDWrapper() {
- if (fd_ != -1)
- close(fd_);
- }
- int get() {
- return fd_;
- }
- int release() {
- int fd = fd_;
- fd_ = -1;
- return fd;
- }
- private:
- int fd_;
-};
-
-//
-// MmapWrapper
-//
-// Wrapper class to make sure mapped regions are unmapped.
-//
-class MmapWrapper {
- public:
- MmapWrapper(void* mapped_address, size_t mapped_size) :
- base_(mapped_address), size_(mapped_size) {
- }
- ~MmapWrapper() {
- if (base_ != NULL) {
- assert(size_ > 0);
- munmap(base_, size_);
- }
- }
- void release() {
- base_ = NULL;
- size_ = 0;
- }
-
- private:
- void* base_;
- size_t size_;
-};
-
-} // namespace
-
-namespace google_breakpad {
-
-bool DumpSymbols::WriteSymbolFile(const std::string& obj_file,
- int sym_fd) {
- int obj_fd = open(obj_file.c_str(), O_RDONLY);
- if (obj_fd < 0)
- return false;
- FDWrapper obj_fd_wrapper(obj_fd);
- struct stat st;
- if (fstat(obj_fd, &st) != 0 && st.st_size <= 0)
- return false;
- void* obj_base = mmap(NULL, st.st_size,
- PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0);
- if (obj_base == MAP_FAILED)
- return false;
- MmapWrapper map_wrapper(obj_base, st.st_size);
- ElfW(Ehdr)* elf_header = reinterpret_cast<ElfW(Ehdr)* >(obj_base);
- if (!IsValidElf(elf_header))
- return false;
- struct SymbolInfo symbols;
- symbols.next_source_id = 0;
-
- if (!LoadSymbols(elf_header, &symbols))
- return false;
- // Write to symbol file.
- if (WriteModuleInfo(sym_fd, elf_header->e_machine, obj_file) &&
- DumpStabSymbols(sym_fd, symbols))
- return true;
-
- return false;
-}
-
-} // namespace google_breakpad
diff --git a/breakpad/linux/dump_syms.cc b/breakpad/linux/dump_syms.cc
deleted file mode 100644
index 2d90acd..0000000
--- a/breakpad/linux/dump_syms.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2006, 2009, 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.
-
-#include <string>
-#include <cstdio>
-
-#include "breakpad/linux/dump_symbols.h"
-
-using google_breakpad::DumpSymbols;
-
-int main(int argc, char** argv) {
- if (argc != 2) {
- fprintf(stderr, "Usage: %s <binary-with-stab-symbol>\n", argv[0]);
- return 1;
- }
-
- DumpSymbols dumper;
- if (!dumper.WriteSymbolFile(argv[1], fileno(stdout))) {
- fprintf(stderr, "Failed to write symbol file.\n");
- return 1;
- }
-
- return 0;
-}
diff --git a/breakpad/linux/exception_handler.cc b/breakpad/linux/exception_handler.cc
deleted file mode 100644
index 4a4955e..0000000
--- a/breakpad/linux/exception_handler.cc
+++ /dev/null
@@ -1,322 +0,0 @@
-// Copyright (c) 2009, 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.
-
-// The ExceptionHandler object installs signal handlers for a number of
-// signals. We rely on the signal handler running on the thread which crashed
-// in order to identify it. This is true of the synchronous signals (SEGV etc),
-// but not true of ABRT. Thus, if you send ABRT to yourself in a program which
-// uses ExceptionHandler, you need to use tgkill to direct it to the current
-// thread.
-//
-// The signal flow looks like this:
-//
-// SignalHandler (uses a global stack of ExceptionHandler objects to find
-// | one to handle the signal. If the first rejects it, try
-// | the second etc...)
-// V
-// HandleSignal ----------------------------| (clones a new process which
-// | | shares an address space with
-// (wait for cloned | the crashed process. This
-// process) | allows us to ptrace the crashed
-// | | process)
-// V V
-// (set signal handler to ThreadEntry (static function to bounce
-// SIG_DFL and rethrow, | back into the object)
-// killing the crashed |
-// process) V
-// DoDump (writes minidump)
-// |
-// V
-// sys_exit
-//
-
-// This code is a little fragmented. Different functions of the ExceptionHandler
-// class run in a number of different contexts. Some of them run in a normal
-// context and are easy to code, others run in a compromised context and the
-// restrictions at the top of minidump_writer.cc apply: no libc and use the
-// alternative malloc. Each function should have comment above it detailing the
-// context which it runs in.
-
-#include "breakpad/linux/exception_handler.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/limits.h>
-#include <sched.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/mman.h>
-#include <sys/signal.h>
-#include <sys/syscall.h>
-#include <sys/ucontext.h>
-#include <sys/user.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "breakpad/linux/linux_libc_support.h"
-#include "breakpad/linux/linux_syscall_support.h"
-#include "breakpad/linux/memory.h"
-#include "breakpad/linux/minidump_writer.h"
-#include "common/linux/guid_creator.h"
-
-// A wrapper for the tgkill syscall: send a signal to a specific thread.
-static int tgkill(pid_t tgid, pid_t tid, int sig) {
- syscall(__NR_tgkill, tgid, tid, sig);
-}
-
-namespace google_breakpad {
-
-// The list of signals which we consider to be crashes. The default action for
-// all these signals must be Core (see man 7 signal) because we rethrow the
-// signal after handling it and expect that it'll be fatal.
-static const int kExceptionSignals[] = {
- SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, -1
-};
-
-// We can stack multiple exception handlers. In that case, this is the global
-// which holds the stack.
-std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
-unsigned ExceptionHandler::handler_stack_index_ = 0;
-pthread_mutex_t ExceptionHandler::handler_stack_mutex_ =
- PTHREAD_MUTEX_INITIALIZER;
-
-// Runs before crashing: normal context.
-ExceptionHandler::ExceptionHandler(const std::string &dump_path,
- FilterCallback filter,
- MinidumpCallback callback,
- void *callback_context,
- bool install_handler)
- : filter_(filter),
- callback_(callback),
- callback_context_(callback_context),
- dump_path_(),
- handler_installed_(install_handler),
- crash_handler_(NULL) {
- set_dump_path(dump_path);
-
- if (install_handler) {
- InstallHandlers();
-
- pthread_mutex_lock(&handler_stack_mutex_);
- if (handler_stack_ == NULL)
- handler_stack_ = new std::vector<ExceptionHandler *>;
- handler_stack_->push_back(this);
- pthread_mutex_unlock(&handler_stack_mutex_);
- }
-}
-
-// Runs before crashing: normal context.
-ExceptionHandler::~ExceptionHandler() {
- UninstallHandlers();
-}
-
-// Runs before crashing: normal context.
-bool ExceptionHandler::InstallHandlers() {
- // We run the signal handlers on an alternative stack because we might have
- // crashed because of a stack overflow.
-
- // We use this value rather than SIGSTKSZ because we would end up overrunning
- // such a small stack.
- static const unsigned kSigStackSize = 8192;
-
- signal_stack = malloc(kSigStackSize);
- stack_t stack;
- memset(&stack, 0, sizeof(stack));
- stack.ss_sp = signal_stack;
- stack.ss_size = kSigStackSize;
-
- if (sigaltstack(&stack, NULL) == -1)
- return false;
-
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sigemptyset(&sa.sa_mask);
-
- // mask all exception signals when we're handling one of them.
- for (unsigned i = 0; kExceptionSignals[i] != -1; ++i)
- sigaddset(&sa.sa_mask, kExceptionSignals[i]);
-
- sa.sa_sigaction = SignalHandler;
- sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
-
- for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) {
- struct sigaction* old = new struct sigaction;
- if (sigaction(kExceptionSignals[i], &sa, old) == -1)
- return false;
- old_handlers_.push_back(std::make_pair(kExceptionSignals[i], old));
- }
-}
-
-// Runs before crashing: normal context.
-void ExceptionHandler::UninstallHandlers() {
- for (unsigned i = 0; i < old_handlers_.size(); ++i) {
- struct sigaction *action =
- reinterpret_cast<struct sigaction*>(old_handlers_[i].second);
- sigaction(old_handlers_[i].first, action, NULL);
- delete action;
- }
-
- old_handlers_.clear();
-}
-
-// Runs before crashing: normal context.
-void ExceptionHandler::UpdateNextID() {
- GUID guid;
- char guid_str[kGUIDStringLength + 1];
- if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) {
- next_minidump_id_ = guid_str;
- next_minidump_id_c_ = next_minidump_id_.c_str();
-
- char minidump_path[PATH_MAX];
- snprintf(minidump_path, sizeof(minidump_path), "%s/%s.dmp",
- dump_path_c_,
- guid_str);
-
- next_minidump_path_ = minidump_path;
- next_minidump_path_c_ = next_minidump_path_.c_str();
- }
-}
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the crashing thread.
-// static
-void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
- // All the exception signals are blocked at this point.
-
- pthread_mutex_lock(&handler_stack_mutex_);
-
- if (!handler_stack_->size()) {
- pthread_mutex_unlock(&handler_stack_mutex_);
- return;
- }
-
- for (int i = handler_stack_->size() - 1; i >= 0; --i) {
- if ((*handler_stack_)[i]->HandleSignal(sig, info, uc)) {
- // successfully handled: We are in an invalid state since an exception
- // signal has been delivered. We don't call the exit handlers because
- // they could end up corrupting on-disk state.
- break;
- }
- }
-
- pthread_mutex_unlock(&handler_stack_mutex_);
-
- // Terminate ourselves with the same signal so that our parent knows that we
- // crashed. The default action for all the signals which we catch is Core, so
- // this is the end of us.
- signal(sig, SIG_DFL);
- tgkill(getpid(), sys_gettid(), sig);
-
- // not reached.
-}
-
-struct ThreadArgument {
- pid_t pid; // the crashing process
- ExceptionHandler* handler;
- const void* context; // a CrashContext structure
- size_t context_size;
-};
-
-// This is the entry function for the cloned process. We are in a compromised
-// context here: see the top of the file.
-// static
-int ExceptionHandler::ThreadEntry(void *arg) {
- const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
- return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
- thread_arg->context_size) == false;
-}
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the crashing thread.
-bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
- if (filter_ && !filter_(callback_context_))
- return false;
-
- // Allow ourselves to be dumped.
- sys_prctl(PR_SET_DUMPABLE, 1);
-
- CrashContext context;
- memcpy(&context.siginfo, info, sizeof(siginfo_t));
- memcpy(&context.context, uc, sizeof(struct ucontext));
- memcpy(&context.float_state, ((struct ucontext *)uc)->uc_mcontext.fpregs,
- sizeof(context.float_state));
- context.tid = sys_gettid();
-
- if (crash_handler_ && crash_handler_(&context, sizeof(context),
- callback_context_))
- return true;
-
- static const unsigned kChildStackSize = 8000;
- PageAllocator allocator;
- uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize);
- if (!stack)
- return false;
- // clone() needs the top-most address. (scrub just to be safe)
- stack += kChildStackSize;
- my_memset(stack - 16, 0, 16);
-
- ThreadArgument thread_arg;
- thread_arg.handler = this;
- thread_arg.pid = getpid();
- thread_arg.context = &context;
- thread_arg.context_size = sizeof(context);
-
- const pid_t child = sys_clone(
- ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
- &thread_arg, NULL, NULL, NULL);
- int r, status;
- do {
- r = sys_waitpid(child, &status, __WALL);
- } while (r == -1 && errno == EINTR);
-
- if (r == -1) {
- static const char msg[] = "ExceptionHandler::HandleSignal: waitpid failed:";
- sys_write(2, msg, sizeof(msg) - 1);
- sys_write(2, strerror(errno), strlen(strerror(errno)));
- sys_write(2, "\n", 1);
- }
-
- bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;
-
- if (callback_)
- success = callback_(dump_path_c_, next_minidump_id_c_,
- callback_context_, success);
-
- return success;
-}
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the cloned process.
-bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
- size_t context_size) {
- return google_breakpad::WriteMinidump(
- next_minidump_path_c_, crashing_process, context, context_size);
-}
-
-} // namespace google_breakpad
diff --git a/breakpad/linux/exception_handler.h b/breakpad/linux/exception_handler.h
deleted file mode 100644
index b579a6a..0000000
--- a/breakpad/linux/exception_handler.h
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
-#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
-
-#include <vector>
-#include <string>
-
-#include <signal.h>
-
-namespace google_breakpad {
-
-// ExceptionHandler
-//
-// ExceptionHandler can write a minidump file when an exception occurs,
-// or when WriteMinidump() is called explicitly by your program.
-//
-// To have the exception handler write minidumps when an uncaught exception
-// (crash) occurs, you should create an instance early in the execution
-// of your program, and keep it around for the entire time you want to
-// have crash handling active (typically, until shutdown).
-// (NOTE): There should be only be one this kind of exception handler
-// object per process.
-//
-// If you want to write minidumps without installing the exception handler,
-// you can create an ExceptionHandler with install_handler set to false,
-// then call WriteMinidump. You can also use this technique if you want to
-// use different minidump callbacks for different call sites.
-//
-// In either case, a callback function is called when a minidump is written,
-// which receives the unqiue id of the minidump. The caller can use this
-// id to collect and write additional application state, and to launch an
-// external crash-reporting application.
-//
-// Caller should try to make the callbacks as crash-friendly as possible,
-// it should avoid use heap memory allocation as much as possible.
-class ExceptionHandler {
- public:
- // A callback function to run before Breakpad performs any substantial
- // processing of an exception. A FilterCallback is called before writing
- // a minidump. context is the parameter supplied by the user as
- // callback_context when the handler was created.
- //
- // If a FilterCallback returns true, Breakpad will continue processing,
- // attempting to write a minidump. If a FilterCallback returns false,
- // Breakpad will immediately report the exception as unhandled without
- // writing a minidump, allowing another handler the opportunity to handle it.
- typedef bool (*FilterCallback)(void *context);
-
- // A callback function to run after the minidump has been written.
- // minidump_id is a unique id for the dump, so the minidump
- // file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied
- // by the user as callback_context when the handler was created. succeeded
- // indicates whether a minidump file was successfully written.
- //
- // If an exception occurred and the callback returns true, Breakpad will
- // treat the exception as fully-handled, suppressing any other handlers from
- // being notified of the exception. If the callback returns false, Breakpad
- // will treat the exception as unhandled, and allow another handler to handle
- // it. If there are no other handlers, Breakpad will report the exception to
- // the system as unhandled, allowing a debugger or native crash dialog the
- // opportunity to handle the exception. Most callback implementations
- // should normally return the value of |succeeded|, or when they wish to
- // not report an exception of handled, false. Callbacks will rarely want to
- // return true directly (unless |succeeded| is true).
- typedef bool (*MinidumpCallback)(const char *dump_path,
- const char *minidump_id,
- void *context,
- bool succeeded);
-
- // In certain cases, a user may wish to handle the generation of the minidump
- // themselves. In this case, they can install a handler callback which is
- // called when a crash has occured. If this function returns true, no other
- // processing of occurs and the process will shortly be crashed. If this
- // returns false, the normal processing continues.
- typedef bool (*HandlerCallback)(const void* crash_context,
- size_t crash_context_size,
- void* context);
-
- // Creates a new ExceptionHandler instance to handle writing minidumps.
- // Before writing a minidump, the optional filter callback will be called.
- // Its return value determines whether or not Breakpad should write a
- // minidump. Minidump files will be written to dump_path, and the optional
- // callback is called after writing the dump file, as described above.
- // If install_handler is true, then a minidump will be written whenever
- // an unhandled exception occurs. If it is false, minidumps will only
- // be written when WriteMinidump is called.
- ExceptionHandler(const std::string &dump_path,
- FilterCallback filter, MinidumpCallback callback,
- void *callback_context,
- bool install_handler);
- ~ExceptionHandler();
-
- // Get and set the minidump path.
- std::string dump_path() const { return dump_path_; }
- void set_dump_path(const std::string &dump_path) {
- dump_path_ = dump_path;
- dump_path_c_ = dump_path_.c_str();
- UpdateNextID();
- }
-
- void set_crash_handler(HandlerCallback callback) {
- crash_handler_ = callback;
- }
-
- // Writes a minidump immediately. This can be used to capture the
- // execution state independently of a crash. Returns true on success.
- bool WriteMinidump();
-
- // Convenience form of WriteMinidump which does not require an
- // ExceptionHandler instance.
- static bool WriteMinidump(const std::string &dump_path,
- MinidumpCallback callback,
- void *callback_context);
-
- // This structure is passed to minidump_writer.h:WriteMinidump via an opaque
- // blob. It shouldn't be needed in any user code.
- struct CrashContext {
- siginfo_t siginfo;
- pid_t tid; // the crashing thread.
- struct ucontext context;
- struct _libc_fpstate float_state;
- };
-
- private:
- bool InstallHandlers();
- void UninstallHandlers();
- void PreresolveSymbols();
-
- void UpdateNextID();
- static void SignalHandler(int sig, siginfo_t* info, void* uc);
- bool HandleSignal(int sig, siginfo_t* info, void* uc);
- static int ThreadEntry(void* arg);
- bool DoDump(pid_t crashing_process, const void* context,
- size_t context_size);
-
- const FilterCallback filter_;
- const MinidumpCallback callback_;
- void* const callback_context_;
-
- std::string dump_path_;
- std::string next_minidump_path_;
- std::string next_minidump_id_;
-
- // Pointers to C-string representations of the above. These are set
- // when the above are set so we can avoid calling c_str during
- // an exception.
- const char* dump_path_c_;
- const char* next_minidump_path_c_;
- const char* next_minidump_id_c_;
-
- const bool handler_installed_;
- void* signal_stack; // the handler stack.
- HandlerCallback crash_handler_;
-
- // The global exception handler stack. This is need becuase there may exist
- // multiple ExceptionHandler instances in a process. Each will have itself
- // registered in this stack.
- static std::vector<ExceptionHandler*> *handler_stack_;
- // The index of the handler that should handle the next exception.
- static unsigned handler_stack_index_;
- static pthread_mutex_t handler_stack_mutex_;
-
- // A vector of the old signal handlers. The void* is a pointer to a newly
- // allocated sigaction structure to avoid pulling in too many includes.
- std::vector<std::pair<int, void *> > old_handlers_;
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
diff --git a/breakpad/linux/exception_handler_unittest.cc b/breakpad/linux/exception_handler_unittest.cc
deleted file mode 100644
index f11cfdf..0000000
--- a/breakpad/linux/exception_handler_unittest.cc
+++ /dev/null
@@ -1,246 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#include <string>
-
-#include <stdint.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/poll.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-
-#include "base/eintr_wrapper.h"
-#include "breakpad/linux/exception_handler.h"
-#include "breakpad/linux/minidump_writer.h"
-#include "breakpad/linux/linux_libc_support.h"
-#include "breakpad/linux/linux_syscall_support.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using namespace google_breakpad;
-
-static void sigchld_handler(int signo) { }
-
-class ExceptionHandlerTest : public ::testing::Test {
- protected:
- void SetUp() {
- // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN.
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = sigchld_handler;
- ASSERT_NE(sigaction(SIGCHLD, &sa, &old_action), -1);
- }
-
- void TearDown() {
- sigaction(SIGCHLD, &old_action, NULL);
- }
-
- struct sigaction old_action;
-};
-
-TEST(ExceptionHandlerTest, Simple) {
- ExceptionHandler handler("/tmp", NULL, NULL, NULL, true);
-}
-
-static bool DoneCallback(const char* dump_path,
- const char* minidump_id,
- void* context,
- bool succeeded) {
- if (!succeeded)
- return succeeded;
-
- int fd = (intptr_t) context;
- uint32_t len = my_strlen(minidump_id);
- HANDLE_EINTR(sys_write(fd, &len, sizeof(len)));
- HANDLE_EINTR(sys_write(fd, minidump_id, len));
- sys_close(fd);
-
- return true;
-}
-
-TEST(ExceptionHandlerTest, ChildCrash) {
- int fds[2];
- ASSERT_NE(pipe(fds), -1);
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[0]);
- ExceptionHandler handler("/tmp", NULL, DoneCallback, (void*) fds[1],
- true);
- *reinterpret_cast<int*>(NULL) = 0;
- }
- close(fds[1]);
-
- int status;
- ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
- ASSERT_TRUE(WIFSIGNALED(status));
- ASSERT_EQ(WTERMSIG(status), SIGSEGV);
-
- struct pollfd pfd;
- memset(&pfd, 0, sizeof(pfd));
- pfd.fd = fds[0];
- pfd.events = POLLIN | POLLERR;
-
- const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
- ASSERT_EQ(r, 1);
- ASSERT_TRUE(pfd.revents & POLLIN);
-
- uint32_t len;
- ASSERT_EQ(read(fds[0], &len, sizeof(len)), sizeof(len));
- ASSERT_LT(len, 2048);
- char* filename = reinterpret_cast<char*>(malloc(len + 1));
- ASSERT_EQ(read(fds[0], filename, len), len);
- filename[len] = 0;
- close(fds[0]);
-
- const std::string minidump_filename = std::string("/tmp/") + filename +
- ".dmp";
-
- struct stat st;
- ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
- ASSERT_GT(st.st_size, 0u);
- unlink(minidump_filename.c_str());
-}
-
-static const unsigned kControlMsgSize =
- CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
-
-static bool
-CrashHandler(const void* crash_context, size_t crash_context_size,
- void* context) {
- const int fd = (intptr_t) context;
- int fds[2];
- pipe(fds);
-
- struct kernel_msghdr msg = {0};
- struct kernel_iovec iov;
- iov.iov_base = const_cast<void*>(crash_context);
- iov.iov_len = crash_context_size;
-
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- char cmsg[kControlMsgSize];
- memset(cmsg, 0, kControlMsgSize);
- msg.msg_control = cmsg;
- msg.msg_controllen = sizeof(cmsg);
-
- struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
- hdr->cmsg_level = SOL_SOCKET;
- hdr->cmsg_type = SCM_RIGHTS;
- hdr->cmsg_len = CMSG_LEN(sizeof(int));
- *((int*) CMSG_DATA(hdr)) = fds[1];
- hdr = CMSG_NXTHDR((struct msghdr*) &msg, hdr);
- hdr->cmsg_level = SOL_SOCKET;
- hdr->cmsg_type = SCM_CREDENTIALS;
- hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred));
- struct ucred *cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
- cred->uid = getuid();
- cred->gid = getgid();
- cred->pid = getpid();
-
- HANDLE_EINTR(sys_sendmsg(fd, &msg, 0));
- sys_close(fds[1]);
-
- char b;
- HANDLE_EINTR(sys_read(fds[0], &b, 1));
-
- return true;
-}
-
-TEST(ExceptionHandlerTest, ExternalDumper) {
- int fds[2];
- ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1);
- static const int on = 1;
- setsockopt(fds[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
- setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[0]);
- ExceptionHandler handler("/tmp", NULL, NULL, (void*) fds[1], true);
- handler.set_crash_handler(CrashHandler);
- *reinterpret_cast<int*>(NULL) = 0;
- }
-
- close(fds[1]);
- struct msghdr msg = {0};
- struct iovec iov;
- static const unsigned kCrashContextSize =
- sizeof(ExceptionHandler::CrashContext);
- char context[kCrashContextSize];
- char control[kControlMsgSize];
- iov.iov_base = context;
- iov.iov_len = kCrashContextSize;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = control;
- msg.msg_controllen = kControlMsgSize;
-
- const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0));
- ASSERT_EQ(n, kCrashContextSize);
- ASSERT_EQ(msg.msg_controllen, kControlMsgSize);
- ASSERT_EQ(msg.msg_flags, 0);
-
- pid_t crashing_pid = -1;
- int signal_fd = -1;
- for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
- hdr = CMSG_NXTHDR(&msg, hdr)) {
- if (hdr->cmsg_level != SOL_SOCKET)
- continue;
- if (hdr->cmsg_type == SCM_RIGHTS) {
- const unsigned len = hdr->cmsg_len -
- (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
- ASSERT_EQ(len, sizeof(int));
- signal_fd = *((int *) CMSG_DATA(hdr));
- } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
- const struct ucred *cred =
- reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
- crashing_pid = cred->pid;
- }
- }
-
- ASSERT_NE(crashing_pid, -1);
- ASSERT_NE(signal_fd, -1);
-
- char templ[] = "/tmp/exception-handler-unittest-XXXXXX";
- mktemp(templ);
- ASSERT_TRUE(WriteMinidump(templ, crashing_pid, context, kCrashContextSize));
- static const char b = 0;
- HANDLE_EINTR(write(signal_fd, &b, 1));
-
- int status;
- ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
- ASSERT_TRUE(WIFSIGNALED(status));
- ASSERT_EQ(WTERMSIG(status), SIGSEGV);
-
- struct stat st;
- ASSERT_EQ(stat(templ, &st), 0);
- ASSERT_GT(st.st_size, 0u);
- unlink(templ);
-}
diff --git a/breakpad/linux/file_id.cc b/breakpad/linux/file_id.cc
deleted file mode 100644
index ee0c0c2..0000000
--- a/breakpad/linux/file_id.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2006, 2009, 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.
-//
-// file_id.cc: Return a unique identifier for a file
-//
-// See file_id.h for documentation
-//
-
-#include "breakpad/linux/file_id.h"
-
-#include <arpa/inet.h>
-#include <elf.h>
-#include <fcntl.h>
-#include <link.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <cassert>
-#include <cstdio>
-
-namespace google_breakpad {
-
-FileID::FileID(const char* path) {
- strncpy(path_, path, sizeof(path_));
-}
-
-bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) {
- const size_t mapped_len = 4096; // Page size (matches WriteMappings())
- int fd = open(path_, O_RDONLY);
- if (fd < 0)
- return false;
- struct stat st;
- if (fstat(fd, &st) != 0 || st.st_size <= mapped_len) {
- close(fd);
- return false;
- }
- void* base = mmap(NULL, mapped_len,
- PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
- close(fd);
- if (base == MAP_FAILED)
- return false;
-
- memset(identifier, 0, kMDGUIDSize);
- uint8_t* ptr = reinterpret_cast<uint8_t*>(base);
- uint8_t* ptr_end = ptr + mapped_len;
- while (ptr < ptr_end) {
- for (unsigned i = 0; i < kMDGUIDSize; i++)
- identifier[i] ^= ptr[i];
- ptr += kMDGUIDSize;
- }
-
- munmap(base, mapped_len);
- return true;
-}
-
-// static
-void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
- char* buffer, int buffer_length) {
- uint8_t identifier_swapped[kMDGUIDSize];
-
- // Endian-ness swap to match dump processor expectation.
- memcpy(identifier_swapped, identifier, kMDGUIDSize);
- uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped);
- *data1 = htonl(*data1);
- uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4);
- *data2 = htons(*data2);
- uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6);
- *data3 = htons(*data3);
-
- int buffer_idx = 0;
- for (int idx = 0;
- (buffer_idx < buffer_length) && (idx < kMDGUIDSize);
- ++idx) {
- int hi = (identifier_swapped[idx] >> 4) & 0x0F;
- int lo = (identifier_swapped[idx]) & 0x0F;
-
- if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
- buffer[buffer_idx++] = '-';
-
- buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
- buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
- }
-
- // NULL terminate
- buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
-}
-
-} // namespace google_breakpad
diff --git a/breakpad/linux/file_id.h b/breakpad/linux/file_id.h
deleted file mode 100644
index 1504fa2..0000000
--- a/breakpad/linux/file_id.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2006, 2009, 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.
-//
-// file_id.h: Return a unique identifier for a file
-//
-
-#ifndef BREAKPAD_LINUX_FILE_ID_H_
-#define BREAKPAD_LINUX_FILE_ID_H_
-
-#include <limits.h>
-
-#include "common/linux/guid_creator.h"
-
-namespace google_breakpad {
-
-static const size_t kMDGUIDSize = sizeof(MDGUID);
-
-class FileID {
- public:
- explicit FileID(const char* path);
- ~FileID() {}
-
- // Load the identifier for the elf file path specified in the constructor into
- // |identifier|. Return false if the identifier could not be created for the
- // file.
- // The current implementation will XOR the first page of data to generate an
- // identifier.
- bool ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]);
-
- // Convert the |identifier| data to a NULL terminated string. The string will
- // be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE).
- // The |buffer| should be at least 37 bytes long to receive all of the data
- // and termination. Shorter buffers will contain truncated data.
- static void ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
- char* buffer, int buffer_length);
-
- private:
- // Storage for the path specified
- char path_[PATH_MAX];
-};
-
-} // namespace google_breakpad
-
-#endif // BREAKPAD_LINUX_FILE_ID_H_
diff --git a/breakpad/linux/generate-test-dump.cc b/breakpad/linux/generate-test-dump.cc
index ec668ed..bec9133 100644
--- a/breakpad/linux/generate-test-dump.cc
+++ b/breakpad/linux/generate-test-dump.cc
@@ -33,9 +33,9 @@
#include <unistd.h>
-#include "breakpad/linux/exception_handler.h"
-#include "breakpad/linux/linux_libc_support.h"
-#include "breakpad/linux/linux_syscall_support.h"
+#include "breakpad/src/client/linux/handler/exception_handler.h"
+#include "breakpad/src/common/linux/linux_libc_support.h"
+#include "breakpad/src/common/linux/linux_syscall_support.h"
static bool DumpCallback(const char* dump_path, const char* minidump_id,
void* context, bool success) {
diff --git a/breakpad/linux/line_reader.h b/breakpad/linux/line_reader.h
deleted file mode 100644
index 715e9e8..0000000
--- a/breakpad/linux/line_reader.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#include <stdint.h>
-#include <assert.h>
-#include <string.h>
-
-#include "breakpad/linux/linux_syscall_support.h"
-
-namespace google_breakpad {
-
-// A class for reading a file, line by line, without using fopen/fgets or other
-// functions which may allocate memory.
-class LineReader {
- public:
- LineReader(int fd)
- : fd_(fd),
- hit_eof_(false),
- buf_used_(0) {
- }
-
- // The maximum length of a line.
- static const size_t kMaxLineLen = 512;
-
- // Return the next line from the file.
- // line: (output) a pointer to the start of the line. The line is NUL
- // terminated.
- // len: (output) the length of the line (not inc the NUL byte)
- //
- // Returns true iff successful (false on EOF).
- //
- // One must call |PopLine| after this function, otherwise you'll continue to
- // get the same line over and over.
- bool GetNextLine(const char **line, unsigned *len) {
- for (;;) {
- if (buf_used_ == 0 && hit_eof_)
- return false;
-
- for (unsigned i = 0; i < buf_used_; ++i) {
- if (buf_[i] == '\n' || buf_[i] == 0) {
- buf_[i] = 0;
- *len = i;
- *line = buf_;
- return true;
- }
- }
-
- if (buf_used_ == sizeof(buf_)) {
- // we scanned the whole buffer and didn't find an end-of-line marker.
- // This line is too long to process.
- return false;
- }
-
- // We didn't find any end-of-line terminators in the buffer. However, if
- // this is the last line in the file it might not have one:
- if (hit_eof_) {
- assert(buf_used_);
- // There's room for the NUL because of the buf_used_ == sizeof(buf_)
- // check above.
- buf_[buf_used_] = 0;
- *len = buf_used_;
- buf_used_ += 1; // since we appended the NUL.
- *line = buf_;
- return true;
- }
-
- // Otherwise, we should pull in more data from the file
- const ssize_t n = sys_read(fd_, buf_ + buf_used_,
- sizeof(buf_) - buf_used_);
- if (n < 0) {
- return false;
- } else if (n == 0) {
- hit_eof_ = true;
- } else {
- buf_used_ += n;
- }
-
- // At this point, we have either set the hit_eof_ flag, or we have more
- // data to process...
- }
- }
-
- void PopLine(unsigned len) {
- // len doesn't include the NUL byte at the end.
-
- assert(buf_used_ >= len + 1);
- buf_used_ -= len + 1;
- memmove(buf_, buf_ + len + 1, buf_used_);
- }
-
- private:
- const int fd_;
-
- bool hit_eof_;
- unsigned buf_used_;
- char buf_[kMaxLineLen];
-};
-
-} // namespace google_breakpad
diff --git a/breakpad/linux/line_reader_unittest.cc b/breakpad/linux/line_reader_unittest.cc
deleted file mode 100644
index 0f92764..0000000
--- a/breakpad/linux/line_reader_unittest.cc
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "breakpad/linux/line_reader.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using namespace google_breakpad;
-
-static int TemporaryFile() {
- static const char templ[] = "/tmp/line-reader-unittest-XXXXXX";
- char templ_copy[sizeof(templ)];
- memcpy(templ_copy, templ, sizeof(templ));
- const int fd = mkstemp(templ_copy);
- if (fd >= 0)
- unlink(templ_copy);
-
- return fd;
-}
-
-namespace {
-typedef testing::Test LineReaderTest;
-}
-
-TEST(LineReaderTest, EmptyFile) {
- const int fd = TemporaryFile();
- LineReader reader(fd);
-
- const char *line;
- unsigned len;
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
- close(fd);
-}
-
-TEST(LineReaderTest, OneLineTerminated) {
- const int fd = TemporaryFile();
- write(fd, "a\n", 2);
- lseek(fd, 0, SEEK_SET);
- LineReader reader(fd);
-
- const char *line;
- unsigned len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ(len, 1);
- ASSERT_EQ(line[0], 'a');
- ASSERT_EQ(line[1], 0);
- reader.PopLine(len);
-
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
- close(fd);
-}
-
-TEST(LineReaderTest, OneLine) {
- const int fd = TemporaryFile();
- write(fd, "a", 1);
- lseek(fd, 0, SEEK_SET);
- LineReader reader(fd);
-
- const char *line;
- unsigned len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ(len, 1);
- ASSERT_EQ(line[0], 'a');
- ASSERT_EQ(line[1], 0);
- reader.PopLine(len);
-
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
- close(fd);
-}
-
-TEST(LineReaderTest, TwoLinesTerminated) {
- const int fd = TemporaryFile();
- write(fd, "a\nb\n", 4);
- lseek(fd, 0, SEEK_SET);
- LineReader reader(fd);
-
- const char *line;
- unsigned len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ(len, 1);
- ASSERT_EQ(line[0], 'a');
- ASSERT_EQ(line[1], 0);
- reader.PopLine(len);
-
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ(len, 1);
- ASSERT_EQ(line[0], 'b');
- ASSERT_EQ(line[1], 0);
- reader.PopLine(len);
-
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
- close(fd);
-}
-
-TEST(LineReaderTest, TwoLines) {
- const int fd = TemporaryFile();
- write(fd, "a\nb", 3);
- lseek(fd, 0, SEEK_SET);
- LineReader reader(fd);
-
- const char *line;
- unsigned len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ(len, 1);
- ASSERT_EQ(line[0], 'a');
- ASSERT_EQ(line[1], 0);
- reader.PopLine(len);
-
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ(len, 1);
- ASSERT_EQ(line[0], 'b');
- ASSERT_EQ(line[1], 0);
- reader.PopLine(len);
-
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
- close(fd);
-}
-
-TEST(LineReaderTest, MaxLength) {
- const int fd = TemporaryFile();
- char l[LineReader::kMaxLineLen - 1];
- memset(l, 'a', sizeof(l));
- write(fd, l, sizeof(l));
- lseek(fd, 0, SEEK_SET);
- LineReader reader(fd);
-
- const char *line;
- unsigned len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ(len, sizeof(l));
- ASSERT_TRUE(memcmp(l, line, sizeof(l)) == 0);
- ASSERT_EQ(line[len], 0);
-
- close(fd);
-}
-
-TEST(LineReaderTest, TooLong) {
- const int fd = TemporaryFile();
- char l[LineReader::kMaxLineLen];
- memset(l, 'a', sizeof(l));
- write(fd, l, sizeof(l));
- lseek(fd, 0, SEEK_SET);
- LineReader reader(fd);
-
- const char *line;
- unsigned len;
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
- close(fd);
-}
diff --git a/breakpad/linux/linux_dumper.cc b/breakpad/linux/linux_dumper.cc
deleted file mode 100644
index 7b6ab23..0000000
--- a/breakpad/linux/linux_dumper.cc
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright (c) 2009, 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.
-
-// This code deals with the mechanics of getting information about a crashed
-// process. Since this code may run in a compromised address space, the same
-// rules apply as detailed at the top of minidump_writer.h: no libc calls and
-// use the alternative allocator.
-
-#include "breakpad/linux/linux_dumper.h"
-
-#include <assert.h>
-#include <limits.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/ptrace.h>
-#include <sys/wait.h>
-
-#include "breakpad/linux/directory_reader.h"
-#include "breakpad/linux/line_reader.h"
-#include "breakpad/linux/linux_libc_support.h"
-#include "breakpad/linux/linux_syscall_support.h"
-
-// Suspend a thread by attaching to it.
-static bool SuspendThread(pid_t pid) {
- // This may fail if the thread has just died or debugged.
- errno = 0;
- if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
- errno != 0) {
- return false;
- }
- while (sys_waitpid(pid, NULL, __WALL) < 0) {
- if (errno != EINTR) {
- sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
- return false;
- }
- }
- return true;
-}
-
-// Resume a thread by detaching from it.
-static bool ResumeThread(pid_t pid) {
- return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
-}
-
-namespace google_breakpad {
-
-LinuxDumper::LinuxDumper(int pid)
- : pid_(pid),
- threads_suspened_(false),
- threads_(&allocator_, 8),
- mappings_(&allocator_) {
-}
-
-bool LinuxDumper::Init() {
- return EnumerateThreads(&threads_) &&
- EnumerateMappings(&mappings_);
-}
-
-bool LinuxDumper::ThreadsSuspend() {
- if (threads_suspened_)
- return true;
- bool good = true;
- for (size_t i = 0; i < threads_.size(); ++i)
- good &= SuspendThread(threads_[i]);
- threads_suspened_ = true;
- return good;
-}
-
-bool LinuxDumper::ThreadsResume() {
- if (!threads_suspened_)
- return false;
- bool good = true;
- for (size_t i = 0; i < threads_.size(); ++i)
- good &= ResumeThread(threads_[i]);
- threads_suspened_ = false;
- return good;
-}
-
-void
-LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const {
- assert(path);
- if (!path) {
- return;
- }
-
- path[0] = '\0';
-
- const unsigned pid_len = my_int_len(pid);
-
- assert(node);
- if (!node) {
- return;
- }
-
- size_t node_len = my_strlen(node);
- assert(node_len < NAME_MAX);
- if (node_len >= NAME_MAX) {
- return;
- }
-
- assert(node_len > 0);
- if (node_len == 0) {
- return;
- }
-
- assert(pid > 0);
- if (pid <= 0) {
- return;
- }
-
- const size_t total_length = 6 + pid_len + 1 + node_len;
-
- assert(total_length < NAME_MAX);
- if (total_length >= NAME_MAX) {
- return;
- }
-
- memcpy(path, "/proc/", 6);
- my_itos(path + 6, pid, pid_len);
- memcpy(path + 6 + pid_len, "/", 1);
- memcpy(path + 6 + pid_len + 1, node, node_len);
- memcpy(path + total_length, "\0", 1);
-}
-
-void*
-LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
- char auxv_path[80];
- BuildProcPath(auxv_path, pid, "auxv");
-
- // If BuildProcPath errors out due to invalid input, we'll handle it when
- // we try to sys_open the file.
-
- // Find the AT_SYSINFO_EHDR entry for linux-gate.so
- // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
- // information.
- int fd = sys_open(auxv_path, O_RDONLY, 0);
- if (fd < 0) {
- return NULL;
- }
-
- elf_aux_entry one_aux_entry;
- while (sys_read(fd,
- &one_aux_entry,
- sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
- one_aux_entry.a_type != AT_NULL) {
- if (one_aux_entry.a_type == AT_SYSINFO_EHDR) {
- close(fd);
- return reinterpret_cast<void*>(one_aux_entry.a_un.a_val);
- }
- }
- close(fd);
- return NULL;
-}
-
-bool
-LinuxDumper::EnumerateMappings(wasteful_vector<MappingInfo*>* result) const {
- char maps_path[80];
- BuildProcPath(maps_path, pid_, "maps");
-
- // linux_gate_loc is the beginning of the kernel's mapping of
- // linux-gate.so in the process. It doesn't actually show up in the
- // maps list as a filename, so we use the aux vector to find it's
- // load location and special case it's entry when creating the list
- // of mappings.
- const void* linux_gate_loc;
- linux_gate_loc = FindBeginningOfLinuxGateSharedLibrary(pid_);
-
- const int fd = sys_open(maps_path, O_RDONLY, 0);
- if (fd < 0)
- return false;
- LineReader* const line_reader = new(allocator_) LineReader(fd);
-
- const char* line;
- unsigned line_len;
- while (line_reader->GetNextLine(&line, &line_len)) {
- uintptr_t start_addr, end_addr, offset;
-
- const char* i1 = my_read_hex_ptr(&start_addr, line);
- if (*i1 == '-') {
- const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
- if (*i2 == ' ') {
- const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
- if (*i3 == ' ') {
- MappingInfo* const module = new(allocator_) MappingInfo;
- memset(module, 0, sizeof(MappingInfo));
- module->start_addr = start_addr;
- module->size = end_addr - start_addr;
- module->offset = offset;
- const char* name = NULL;
- // Only copy name if the name is a valid path name, or if
- // we've found the VDSO image
- if ((name = my_strchr(line, '/')) != NULL) {
- const unsigned l = my_strlen(name);
- if (l < sizeof(module->name))
- memcpy(module->name, name, l);
- } else if (linux_gate_loc &&
- reinterpret_cast<void*>(module->start_addr) ==
- linux_gate_loc) {
- memcpy(module->name,
- kLinuxGateLibraryName,
- my_strlen(kLinuxGateLibraryName));
- module->offset = 0;
- }
- result->push_back(module);
- }
- }
- }
- line_reader->PopLine(line_len);
- }
-
- sys_close(fd);
-
- return result->size() > 0;
-}
-
-// Parse /proc/$pid/task to list all the threads of the process identified by
-// pid.
-bool LinuxDumper::EnumerateThreads(wasteful_vector<pid_t>* result) const {
- char task_path[80];
- BuildProcPath(task_path, pid_, "task");
-
- const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
- if (fd < 0)
- return false;
- DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);
-
- // The directory may contain duplicate entries which we filter by assuming
- // that they are consecutive.
- int last_tid = -1;
- const char* dent_name;
- while (dir_reader->GetNextEntry(&dent_name)) {
- if (my_strcmp(dent_name, ".") &&
- my_strcmp(dent_name, "..")) {
- int tid = 0;
- if (my_strtoui(&tid, dent_name) &&
- last_tid != tid) {
- last_tid = tid;
- result->push_back(tid);
- }
- }
- dir_reader->PopEntry();
- }
-
- sys_close(fd);
- return true;
-}
-
-// Read thread info from /proc/$pid/status.
-// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailible,
-// these members are set to -1. Returns true iff all three members are
-// availible.
-bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) {
- assert(info != NULL);
- char status_path[80];
- BuildProcPath(status_path, tid, "status");
-
- const int fd = open(status_path, O_RDONLY);
- if (fd < 0)
- return false;
-
- LineReader* const line_reader = new(allocator_) LineReader(fd);
- const char* line;
- unsigned line_len;
-
- info->ppid = info->tgid = -1;
-
- while (line_reader->GetNextLine(&line, &line_len)) {
- if (my_strncmp("Tgid:\t", line, 6) == 0) {
- my_strtoui(&info->tgid, line + 6);
- } else if (my_strncmp("PPid:\t", line, 6) == 0) {
- my_strtoui(&info->ppid, line + 6);
- }
-
- line_reader->PopLine(line_len);
- }
-
- if (info->ppid == -1 || info->tgid == -1)
- return false;
-
- if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1 ||
- sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
- return false;
- }
-
-#if defined(__i386)
- if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1)
- return false;
-#endif
-
-#if defined(__i386) || defined(__x86_64)
- for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
- if (sys_ptrace(
- PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*> (offsetof(struct user,
- u_debugreg[0]) + i *
- sizeof(debugreg_t)),
- &info->dregs[i]) == -1) {
- return false;
- }
- }
-#endif
-
- const uint8_t* stack_pointer;
-#if defined(__i386)
- memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
-#elif defined(__x86_64)
- memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
-#else
-#error "This code hasn't been ported to your platform yet."
-#endif
-
- if (!GetStackInfo(&info->stack, &info->stack_len,
- (uintptr_t) stack_pointer))
- return false;
-
- return true;
-}
-
-// Get information about the stack, given the stack pointer. We don't try to
-// walk the stack since we might not have all the information needed to do
-// unwind. So we just grab, up to, 32k of stack.
-bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
- uintptr_t int_stack_pointer) {
-#if defined(__i386) || defined(__x86_64)
- static const bool stack_grows_down = true;
- static const uintptr_t page_size = 4096;
-#else
-#error "This code has not been ported to your platform yet."
-#endif
- // Move the stack pointer to the bottom of the page that it's in.
- uint8_t* const stack_pointer =
- reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
-
- // The number of bytes of stack which we try to capture.
- static unsigned kStackToCapture = 32 * 1024;
-
- const MappingInfo* mapping = FindMapping(stack_pointer);
- if (!mapping)
- return false;
- if (stack_grows_down) {
- const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr;
- const ptrdiff_t distance_to_end =
- static_cast<ptrdiff_t>(mapping->size) - offset;
- *stack_len = distance_to_end > kStackToCapture ?
- kStackToCapture : distance_to_end;
- *stack = stack_pointer;
- } else {
- const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr;
- *stack_len = offset > kStackToCapture ? kStackToCapture : offset;
- *stack = stack_pointer - *stack_len;
- }
-
- return true;
-}
-
-// static
-void LinuxDumper::CopyFromProcess(void* dest, pid_t child, const void* src,
- size_t length) {
- unsigned long tmp;
- size_t done = 0;
- static const size_t word_size = sizeof(tmp);
- uint8_t* const local = (uint8_t*) dest;
- uint8_t* const remote = (uint8_t*) src;
-
- while (done < length) {
- const size_t l = length - done > word_size ? word_size : length - done;
- if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1)
- tmp = 0;
- memcpy(local + done, &tmp, l);
- done += l;
- }
-}
-
-// Find the mapping which the given memory address falls in.
-const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
- const uintptr_t addr = (uintptr_t) address;
-
- for (size_t i = 0; i < mappings_.size(); ++i) {
- const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
- if (addr >= start && addr - start < mappings_[i]->size)
- return mappings_[i];
- }
-
- return NULL;
-}
-
-} // namespace google_breakpad
diff --git a/breakpad/linux/linux_dumper.h b/breakpad/linux/linux_dumper.h
deleted file mode 100644
index 9a81364..0000000
--- a/breakpad/linux/linux_dumper.h
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#ifndef CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_
-#define CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_
-
-#include <sys/types.h>
-#include <elf.h>
-#include <stdint.h>
-#include <sys/user.h>
-#include <linux/limits.h>
-
-#include "breakpad/linux/memory.h"
-
-namespace google_breakpad {
-
-typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t;
-
-// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
-#if defined(__i386)
-typedef Elf32_auxv_t elf_aux_entry;
-#elif defined(__x86_64__)
-typedef Elf64_auxv_t elf_aux_entry;
-#endif
-// When we find the VDSO mapping in the process's address space, this
-// is the name we use for it when writing it to the minidump.
-// This should always be less than NAME_MAX!
-const char kLinuxGateLibraryName[] = "linux-gate.so";
-
-// We produce one of these structures for each thread in the crashed process.
-struct ThreadInfo {
- pid_t tgid; // thread group id
- pid_t ppid; // parent process
-
- // Even on platforms where the stack grows down, the following will point to
- // the smallest address in the stack.
- const void* stack; // pointer to the stack area
- size_t stack_len; // length of the stack to copy
-
- user_regs_struct regs;
- user_fpregs_struct fpregs;
-#if defined(__i386)
- user_fpxregs_struct fpxregs;
-#endif
-
-#if defined(__i386) || defined(__x86_64)
- static const unsigned kNumDebugRegisters = 8;
- debugreg_t dregs[8];
-#endif
-};
-
-// One of these is produced for each mapping in the process (i.e. line in
-// /proc/$x/maps).
-struct MappingInfo {
- uintptr_t start_addr;
- size_t size;
- size_t offset; // offset into the backed file.
- char name[NAME_MAX];
-};
-
-class LinuxDumper {
- public:
- explicit LinuxDumper(pid_t pid);
-
- // Parse the data for |threads| and |mappings|.
- bool Init();
-
- // Suspend/resume all threads in the given process.
- bool ThreadsSuspend();
- bool ThreadsResume();
-
- // Read information about the given thread. Returns true on success. One must
- // have called |ThreadsSuspend| first.
- bool ThreadInfoGet(pid_t tid, ThreadInfo* info);
-
- // These are only valid after a call to |Init|.
- const wasteful_vector<pid_t> &threads() { return threads_; }
- const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
- const MappingInfo* FindMapping(const void* address) const;
-
- // Find a block of memory to take as the stack given the top of stack pointer.
- // stack: (output) the lowest address in the memory area
- // stack_len: (output) the length of the memory area
- // stack_top: the current top of the stack
- bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top);
-
- PageAllocator* allocator() { return &allocator_; }
-
- // memcpy from a remote process.
- static void CopyFromProcess(void* dest, pid_t child, const void* src,
- size_t length);
-
- // Builds a proc path for a certain pid for a node. path is a
- // character array that is overwritten, and node is the final node
- // without any slashes.
- void BuildProcPath(char* path, pid_t pid, const char* node) const;
-
- // Utility method to find the location of where the kernel has
- // mapped linux-gate.so in memory(shows up in /proc/pid/maps as
- // [vdso], but we can't guarantee that it's the only virtual dynamic
- // shared object. Parsing the auxilary vector for AT_SYSINFO_EHDR
- // is the safest way to go.)
- void* FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const;
- private:
- bool EnumerateMappings(wasteful_vector<MappingInfo*>* result) const;
- bool EnumerateThreads(wasteful_vector<pid_t>* result) const;
-
- const pid_t pid_;
-
- mutable PageAllocator allocator_;
-
- bool threads_suspened_;
- wasteful_vector<pid_t> threads_; // the ids of all the threads
- wasteful_vector<MappingInfo*> mappings_; // info from /proc/<pid>/maps
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_
diff --git a/breakpad/linux/linux_dumper_unittest.cc b/breakpad/linux/linux_dumper_unittest.cc
deleted file mode 100644
index 34b4e94..0000000
--- a/breakpad/linux/linux_dumper_unittest.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#include <unistd.h>
-
-#include "breakpad/linux/linux_dumper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using namespace google_breakpad;
-
-namespace {
-typedef testing::Test LinuxDumperTest;
-}
-
-TEST(LinuxDumperTest, Setup) {
- LinuxDumper dumper(getpid());
-}
-
-TEST(LinuxDumperTest, FindMappings) {
- LinuxDumper dumper(getpid());
- ASSERT_TRUE(dumper.Init());
-
- ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(getpid)));
- ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(printf)));
- ASSERT_FALSE(dumper.FindMapping(NULL));
-}
-
-TEST(LinuxDumperTest, ThreadList) {
- LinuxDumper dumper(getpid());
- ASSERT_TRUE(dumper.Init());
-
- ASSERT_GE(dumper.threads().size(), 1);
- bool found = false;
- for (size_t i = 0; i < dumper.threads().size(); ++i) {
- if (dumper.threads()[i] == getpid()) {
- found = true;
- break;
- }
- }
-}
-
-TEST(LinuxDumperTest, BuildProcPath) {
- const pid_t pid = getpid();
- LinuxDumper dumper(pid);
-
- char maps_path[256] = "dummymappath";
- char maps_path_expected[256];
- snprintf(maps_path_expected, sizeof(maps_path_expected),
- "/proc/%d/maps", pid);
- dumper.BuildProcPath(maps_path, pid, "maps");
- ASSERT_STREQ(maps_path, maps_path_expected);
-
- // In release mode, we expect BuildProcPath to handle the invalid
- // parameters correctly and fill map_path with an empty
- // NULL-terminated string.
-#ifdef NDEBUG
- snprintf(maps_path, sizeof(maps_path), "dummymappath");
- dumper.BuildProcPath(maps_path, 0, "maps");
- EXPECT_STREQ(maps_path, "");
-
- snprintf(maps_path, sizeof(maps_path), "dummymappath");
- dumper.BuildProcPath(maps_path, getpid(), "");
- EXPECT_STREQ(maps_path, "");
-
- snprintf(maps_path, sizeof(maps_path), "dummymappath");
- dumper.BuildProcPath(maps_path, getpid(), NULL);
- EXPECT_STREQ(maps_path, "");
-#endif
-}
-
-TEST(LinuxDumperTest, MappingsIncludeLinuxGate) {
- LinuxDumper dumper(getpid());
- ASSERT_TRUE(dumper.Init());
-
- void* linux_gate_loc = dumper.FindBeginningOfLinuxGateSharedLibrary(getpid());
- if (linux_gate_loc) {
- bool found_linux_gate = false;
-
- const wasteful_vector<MappingInfo*> mappings = dumper.mappings();
- const MappingInfo* mapping;
- for (unsigned i = 0; i < mappings.size(); ++i) {
- mapping = mappings[i];
- if (!strcmp(mapping->name, kLinuxGateLibraryName)) {
- found_linux_gate = true;
- break;
- }
- }
- EXPECT_TRUE(found_linux_gate);
- EXPECT_EQ(linux_gate_loc, reinterpret_cast<void*>(mapping->start_addr));
- EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG));
- }
-}
diff --git a/breakpad/linux/linux_libc_support.h b/breakpad/linux/linux_libc_support.h
deleted file mode 100644
index e08f27f..0000000
--- a/breakpad/linux/linux_libc_support.h
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright (c) 2009, 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.
-
-// This header provides replacements for libc functions that we need. We if
-// call the libc functions directly we risk crashing in the dynamic linker as
-// it tries to resolve uncached PLT entries.
-
-#ifndef CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
-#define CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
-
-#include <stdint.h>
-#include <limits.h>
-#include <sys/types.h>
-
-extern "C" {
-
-static inline size_t
-my_strlen(const char* s) {
- size_t len = 0;
- while (*s++) len++;
- return len;
-}
-
-static inline int
-my_strcmp(const char* a, const char* b) {
- for (;;) {
- if (*a < *b)
- return -1;
- else if (*a > *b)
- return 1;
- else if (*a == 0)
- return 0;
- a++;
- b++;
- }
-}
-
-static inline int
-my_strncmp(const char* a, const char* b, size_t len) {
- for (size_t i = 0; i < len; ++i) {
- if (*a < *b)
- return -1;
- else if (*a > *b)
- return 1;
- else if (*a == 0)
- return 0;
- a++;
- b++;
- }
-
- return 0;
-}
-
-// Parse a non-negative integer.
-// result: (output) the resulting non-negative integer
-// s: a NUL terminated string
-// Return true iff successful.
-static inline bool
-my_strtoui(int* result, const char* s) {
- if (*s == 0)
- return false;
- int r = 0;
- for (;; s++) {
- if (*s == 0)
- break;
- const int old_r = r;
- r *= 10;
- if (*s < '0' || *s > '9')
- return false;
- r += *s - '0';
- if (r < old_r)
- return false;
- }
-
- *result = r;
- return true;
-}
-
-// Return the length of the given, non-negative integer when expressed in base
-// 10.
-static inline unsigned
-my_int_len(int i) {
- if (!i)
- return 1;
-
- int len = 0;
- while (i) {
- len++;
- i /= 10;
- }
-
- return len;
-}
-
-// Convert a non-negative integer to a string
-// output: (output) the resulting string is written here. This buffer must be
-// large enough to hold the resulting string. Call |my_int_len| to get the
-// required length.
-// i: the non-negative integer to serialise.
-// i_len: the length of the integer in base 10 (see |my_int_len|).
-static inline void
-my_itos(char* output, int i, unsigned i_len) {
- for (unsigned index = i_len; index; --index, i /= 10)
- output[index - 1] = '0' + (i % 10);
-}
-
-static inline const char*
-my_strchr(const char* haystack, char needle) {
- while (*haystack && *haystack != needle)
- haystack++;
- if (*haystack == needle)
- return haystack;
- return (const char*) 0;
-}
-
-// Read a hex value
-// result: (output) the resulting value
-// s: a string
-// Returns a pointer to the first invalid charactor.
-static inline const char*
-my_read_hex_ptr(uintptr_t* result, const char* s) {
- uintptr_t r = 0;
-
- for (;; ++s) {
- if (*s >= '0' && *s <= '9') {
- r <<= 4;
- r += *s - '0';
- } else if (*s >= 'a' && *s <= 'f') {
- r <<= 4;
- r += (*s - 'a') + 10;
- } else if (*s >= 'A' && *s <= 'F') {
- r <<= 4;
- r += (*s - 'A') + 10;
- } else {
- break;
- }
- }
-
- *result = r;
- return s;
-}
-
-static inline void
-my_memset(void* ip, char c, size_t len) {
- char* p = (char *) ip;
- while (len--)
- *p++ = c;
-}
-
-} // extern "C"
-
-#endif // CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
diff --git a/breakpad/linux/linux_libc_support_unittest.cc b/breakpad/linux/linux_libc_support_unittest.cc
deleted file mode 100644
index 3b5d611..0000000
--- a/breakpad/linux/linux_libc_support_unittest.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#include "breakpad/linux/linux_libc_support.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-typedef testing::Test LinuxLibcSupportTest;
-}
-
-TEST(LinuxLibcSupportTest, strlen) {
- static const char* test_data[] = { "", "a", "aa", "aaa", "aabc", NULL };
- for (unsigned i = 0; ; ++i) {
- if (!test_data[i])
- break;
- ASSERT_EQ(strlen(test_data[i]), my_strlen(test_data[i]));
- }
-}
-
-TEST(LinuxLibcSupportTest, strcmp) {
- static const char* test_data[] = {
- "", "",
- "a", "",
- "", "a",
- "a", "b",
- "a", "a",
- "ab", "aa",
- "abc", "ab",
- "abc", "abc",
- NULL,
- };
-
- for (unsigned i = 0; ; ++i) {
- if (!test_data[i*2])
- break;
- ASSERT_EQ(my_strcmp(test_data[i*2], test_data[i*2 + 1]),
- strcmp(test_data[i*2], test_data[i*2 + 1]));
- }
-}
-
-TEST(LinuxLibcSupportTest, strtoui) {
- int result;
-
- ASSERT_FALSE(my_strtoui(&result, ""));
- ASSERT_FALSE(my_strtoui(&result, "-1"));
- ASSERT_FALSE(my_strtoui(&result, "-"));
- ASSERT_FALSE(my_strtoui(&result, "a"));
- ASSERT_FALSE(my_strtoui(&result, "23472893472938472987987398472398"));
-
- ASSERT_TRUE(my_strtoui(&result, "0"));
- ASSERT_EQ(result, 0);
- ASSERT_TRUE(my_strtoui(&result, "1"));
- ASSERT_EQ(result, 1);
- ASSERT_TRUE(my_strtoui(&result, "12"));
- ASSERT_EQ(result, 12);
- ASSERT_TRUE(my_strtoui(&result, "123"));
- ASSERT_EQ(result, 123);
- ASSERT_TRUE(my_strtoui(&result, "0123"));
- ASSERT_EQ(result, 123);
-}
-
-TEST(LinuxLibcSupportTest, int_len) {
- ASSERT_EQ(my_int_len(0), 1);
- ASSERT_EQ(my_int_len(2), 1);
- ASSERT_EQ(my_int_len(5), 1);
- ASSERT_EQ(my_int_len(9), 1);
- ASSERT_EQ(my_int_len(10), 2);
- ASSERT_EQ(my_int_len(99), 2);
- ASSERT_EQ(my_int_len(100), 3);
- ASSERT_EQ(my_int_len(101), 3);
- ASSERT_EQ(my_int_len(1000), 4);
-}
-
-TEST(LinuxLibcSupportTest, itos) {
- char buf[10];
-
- my_itos(buf, 0, 1);
- ASSERT_EQ(0, memcmp(buf, "0", 1));
-
- my_itos(buf, 1, 1);
- ASSERT_EQ(0, memcmp(buf, "1", 1));
-
- my_itos(buf, 10, 2);
- ASSERT_EQ(0, memcmp(buf, "10", 2));
-
- my_itos(buf, 63, 2);
- ASSERT_EQ(0, memcmp(buf, "63", 2));
-
- my_itos(buf, 101, 3);
- ASSERT_EQ(0, memcmp(buf, "101", 2));
-}
-
-TEST(LinuxLibcSupportTest, strchr) {
- ASSERT_EQ(NULL, my_strchr("abc", 'd'));
- ASSERT_EQ(NULL, my_strchr("", 'd'));
- ASSERT_EQ(NULL, my_strchr("efghi", 'd'));
-
- ASSERT_TRUE(my_strchr("a", 'a'));
- ASSERT_TRUE(my_strchr("abc", 'a'));
- ASSERT_TRUE(my_strchr("bcda", 'a'));
- ASSERT_TRUE(my_strchr("sdfasdf", 'a'));
-}
-
-TEST(LinuxLibcSupportTest, read_hex_ptr) {
- uintptr_t result;
- const char* last;
-
- last = my_read_hex_ptr(&result, "");
- ASSERT_EQ(result, 0);
- ASSERT_EQ(*last, 0);
-
- last = my_read_hex_ptr(&result, "0");
- ASSERT_EQ(result, 0);
- ASSERT_EQ(*last, 0);
-
- last = my_read_hex_ptr(&result, "0123");
- ASSERT_EQ(result, 0x123);
- ASSERT_EQ(*last, 0);
-
- last = my_read_hex_ptr(&result, "0123a");
- ASSERT_EQ(result, 0x123a);
- ASSERT_EQ(*last, 0);
-
- last = my_read_hex_ptr(&result, "0123a-");
- ASSERT_EQ(result, 0x123a);
- ASSERT_EQ(*last, '-');
-}
diff --git a/breakpad/linux/linux_syscall_support.h b/breakpad/linux/linux_syscall_support.h
deleted file mode 100644
index 8f4de92..0000000
--- a/breakpad/linux/linux_syscall_support.h
+++ /dev/null
@@ -1,2800 +0,0 @@
-/* Copyright (c) 2005-2008, 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.
- *
- * ---
- * Author: Markus Gutschke
- */
-
-/* This file includes Linux-specific support functions common to the
- * coredumper and the thread lister; primarily, this is a collection
- * of direct system calls, and a couple of symbols missing from
- * standard header files.
- * There are a few options that the including file can set to control
- * the behavior of this file:
- *
- * SYS_CPLUSPLUS:
- * The entire header file will normally be wrapped in 'extern "C" { }",
- * making it suitable for compilation as both C and C++ source. If you
- * do not want to do this, you can set the SYS_CPLUSPLUS macro to inhibit
- * the wrapping. N.B. doing so will suppress inclusion of all prerequisite
- * system header files, too. It is the caller's responsibility to provide
- * the necessary definitions.
- *
- * SYS_ERRNO:
- * All system calls will update "errno" unless overriden by setting the
- * SYS_ERRNO macro prior to including this file. SYS_ERRNO should be
- * an l-value.
- *
- * SYS_INLINE:
- * New symbols will be defined "static inline", unless overridden by
- * the SYS_INLINE macro.
- *
- * SYS_LINUX_SYSCALL_SUPPORT_H
- * This macro is used to avoid multiple inclusions of this header file.
- * If you need to include this file more than once, make sure to
- * unset SYS_LINUX_SYSCALL_SUPPORT_H before each inclusion.
- *
- * SYS_PREFIX:
- * New system calls will have a prefix of "sys_" unless overridden by
- * the SYS_PREFIX macro. Valid values for this macro are [0..9] which
- * results in prefixes "sys[0..9]_". It is also possible to set this
- * macro to -1, which avoids all prefixes.
- *
- * This file defines a few internal symbols that all start with "LSS_".
- * Do not access these symbols from outside this file. They are not part
- * of the supported API.
- */
-#ifndef SYS_LINUX_SYSCALL_SUPPORT_H
-#define SYS_LINUX_SYSCALL_SUPPORT_H
-
-/* We currently only support x86-32, x86-64, ARM, MIPS, and PPC on Linux.
- * Porting to other related platforms should not be difficult.
- */
-#if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \
- defined(__mips__) || defined(__PPC__)) && defined(__linux)
-
-#ifndef SYS_CPLUSPLUS
-#ifdef __cplusplus
-/* Some system header files in older versions of gcc neglect to properly
- * handle being included from C++. As it appears to be harmless to have
- * multiple nested 'extern "C"' blocks, just add another one here.
- */
-extern "C" {
-#endif
-
-#include <errno.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <syscall.h>
-#include <unistd.h>
-#include <linux/unistd.h>
-#include <endian.h>
-
-#ifdef __mips__
-/* Include definitions of the ABI currently in use. */
-#include <sgidefs.h>
-#endif
-
-#endif
-
-/* As glibc often provides subtly incompatible data structures (and implicit
- * wrapper functions that convert them), we provide our own kernel data
- * structures for use by the system calls.
- * These structures have been developed by using Linux 2.6.23 headers for
- * reference. Note though, we do not care about exact API compatibility
- * with the kernel, and in fact the kernel often does not have a single
- * API that works across architectures. Instead, we try to mimic the glibc
- * API where reasonable, and only guarantee ABI compatibility with the
- * kernel headers.
- * Most notably, here are a few changes that were made to the structures
- * defined by kernel headers:
- *
- * - we only define structures, but not symbolic names for kernel data
- * types. For the latter, we directly use the native C datatype
- * (i.e. "unsigned" instead of "mode_t").
- * - in a few cases, it is possible to define identical structures for
- * both 32bit (e.g. i386) and 64bit (e.g. x86-64) platforms by
- * standardizing on the 64bit version of the data types. In particular,
- * this means that we use "unsigned" where the 32bit headers say
- * "unsigned long".
- * - overall, we try to minimize the number of cases where we need to
- * conditionally define different structures.
- * - the "struct kernel_sigaction" class of structures have been
- * modified to more closely mimic glibc's API by introducing an
- * anonymous union for the function pointer.
- * - a small number of field names had to have an underscore appended to
- * them, because glibc defines a global macro by the same name.
- */
-
-/* include/linux/dirent.h */
-struct kernel_dirent64 {
- unsigned long long d_ino;
- long long d_off;
- unsigned short d_reclen;
- unsigned char d_type;
- char d_name[256];
-};
-
-/* include/linux/dirent.h */
-struct kernel_dirent {
- long d_ino;
- long d_off;
- unsigned short d_reclen;
- char d_name[256];
-};
-
-/* include/linux/uio.h */
-struct kernel_iovec {
- void *iov_base;
- unsigned long iov_len;
-};
-
-/* include/linux/socket.h */
-struct kernel_msghdr {
- void *msg_name;
- int msg_namelen;
- struct kernel_iovec*msg_iov;
- unsigned long msg_iovlen;
- void *msg_control;
- unsigned long msg_controllen;
- unsigned msg_flags;
-};
-
-/* include/asm-generic/poll.h */
-struct kernel_pollfd {
- int fd;
- short events;
- short revents;
-};
-
-/* include/linux/resource.h */
-struct kernel_rlimit {
- unsigned long rlim_cur;
- unsigned long rlim_max;
-};
-
-/* include/linux/time.h */
-struct kernel_timespec {
- long tv_sec;
- long tv_nsec;
-};
-
-/* include/linux/time.h */
-struct kernel_timeval {
- long tv_sec;
- long tv_usec;
-};
-
-/* include/linux/resource.h */
-struct kernel_rusage {
- struct kernel_timeval ru_utime;
- struct kernel_timeval ru_stime;
- long ru_maxrss;
- long ru_ixrss;
- long ru_idrss;
- long ru_isrss;
- long ru_minflt;
- long ru_majflt;
- long ru_nswap;
- long ru_inblock;
- long ru_oublock;
- long ru_msgsnd;
- long ru_msgrcv;
- long ru_nsignals;
- long ru_nvcsw;
- long ru_nivcsw;
-};
-
-struct siginfo;
-#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__PPC__)
-
-/* include/asm-{arm,i386,mips,ppc}/signal.h */
-struct kernel_old_sigaction {
- union {
- void (*sa_handler_)(int);
- void (*sa_sigaction_)(int, struct siginfo *, void *);
- };
- unsigned long sa_mask;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
-} __attribute__((packed,aligned(4)));
-#elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32)
- #define kernel_old_sigaction kernel_sigaction
-#endif
-
-/* Some kernel functions (e.g. sigaction() in 2.6.23) require that the
- * exactly match the size of the signal set, even though the API was
- * intended to be extensible. We define our own KERNEL_NSIG to deal with
- * this.
- * Please note that glibc provides signals [1.._NSIG-1], whereas the
- * kernel (and this header) provides the range [1..KERNEL_NSIG]. The
- * actual number of signals is obviously the same, but the constants
- * differ by one.
- */
-#ifdef __mips__
-#define KERNEL_NSIG 128
-#else
-#define KERNEL_NSIG 64
-#endif
-
-/* include/asm-{arm,i386,mips,x86_64}/signal.h */
-struct kernel_sigset_t {
- unsigned long sig[(KERNEL_NSIG + 8*sizeof(unsigned long) - 1)/
- (8*sizeof(unsigned long))];
-};
-
-/* include/asm-{arm,i386,mips,x86_64,ppc}/signal.h */
-struct kernel_sigaction {
-#ifdef __mips__
- unsigned long sa_flags;
- union {
- void (*sa_handler_)(int);
- void (*sa_sigaction_)(int, struct siginfo *, void *);
- };
- struct kernel_sigset_t sa_mask;
-#else
- union {
- void (*sa_handler_)(int);
- void (*sa_sigaction_)(int, struct siginfo *, void *);
- };
- unsigned long sa_flags;
- void (*sa_restorer)(void);
- struct kernel_sigset_t sa_mask;
-#endif
-};
-
-/* include/linux/socket.h */
-struct kernel_sockaddr {
- unsigned short sa_family;
- char sa_data[14];
-};
-
-/* include/asm-{arm,i386,mips,ppc}/stat.h */
-#ifdef __mips__
-#if _MIPS_SIM == _MIPS_SIM_ABI64
-struct kernel_stat {
-#else
-struct kernel_stat64 {
-#endif
- unsigned st_dev;
- unsigned __pad0[3];
- unsigned long long st_ino;
- unsigned st_mode;
- unsigned st_nlink;
- unsigned st_uid;
- unsigned st_gid;
- unsigned st_rdev;
- unsigned __pad1[3];
- long long st_size;
- unsigned st_atime_;
- unsigned st_atime_nsec_;
- unsigned st_mtime_;
- unsigned st_mtime_nsec_;
- unsigned st_ctime_;
- unsigned st_ctime_nsec_;
- unsigned st_blksize;
- unsigned __pad2;
- unsigned long long st_blocks;
-};
-#elif defined __PPC__
-struct kernel_stat64 {
- unsigned long long st_dev;
- unsigned long long st_ino;
- unsigned st_mode;
- unsigned st_nlink;
- unsigned st_uid;
- unsigned st_gid;
- unsigned long long st_rdev;
- unsigned short int __pad2;
- long long st_size;
- long st_blksize;
- long long st_blocks;
- long st_atime_;
- unsigned long st_atime_nsec_;
- long st_mtime_;
- unsigned long st_mtime_nsec_;
- long st_ctime_;
- unsigned long st_ctime_nsec_;
- unsigned long __unused4;
- unsigned long __unused5;
-};
-#else
-struct kernel_stat64 {
- unsigned long long st_dev;
- unsigned char __pad0[4];
- unsigned __st_ino;
- unsigned st_mode;
- unsigned st_nlink;
- unsigned st_uid;
- unsigned st_gid;
- unsigned long long st_rdev;
- unsigned char __pad3[4];
- long long st_size;
- unsigned st_blksize;
- unsigned long long st_blocks;
- unsigned st_atime_;
- unsigned st_atime_nsec_;
- unsigned st_mtime_;
- unsigned st_mtime_nsec_;
- unsigned st_ctime_;
- unsigned st_ctime_nsec_;
- unsigned long long st_ino;
-};
-#endif
-
-/* include/asm-{arm,i386,mips,x86_64,ppc}/stat.h */
-#if defined(__i386__) || defined(__ARM_ARCH_3__)
-struct kernel_stat {
- /* The kernel headers suggest that st_dev and st_rdev should be 32bit
- * quantities encoding 12bit major and 20bit minor numbers in an interleaved
- * format. In reality, we do not see useful data in the top bits. So,
- * we'll leave the padding in here, until we find a better solution.
- */
- unsigned short st_dev;
- short pad1;
- unsigned st_ino;
- unsigned short st_mode;
- unsigned short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
- unsigned short st_rdev;
- short pad2;
- unsigned st_size;
- unsigned st_blksize;
- unsigned st_blocks;
- unsigned st_atime_;
- unsigned st_atime_nsec_;
- unsigned st_mtime_;
- unsigned st_mtime_nsec_;
- unsigned st_ctime_;
- unsigned st_ctime_nsec_;
- unsigned __unused4;
- unsigned __unused5;
-};
-#elif defined(__x86_64__)
-struct kernel_stat {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned long st_nlink;
- unsigned st_mode;
- unsigned st_uid;
- unsigned st_gid;
- unsigned __pad0;
- unsigned long st_rdev;
- long st_size;
- long st_blksize;
- long st_blocks;
- unsigned long st_atime_;
- unsigned long st_atime_nsec_;
- unsigned long st_mtime_;
- unsigned long st_mtime_nsec_;
- unsigned long st_ctime_;
- unsigned long st_ctime_nsec_;
- long __unused[3];
-};
-#elif defined(__PPC__)
-struct kernel_stat {
- unsigned st_dev;
- unsigned long st_ino; // ino_t
- unsigned long st_mode; // mode_t
- unsigned short st_nlink; // nlink_t
- unsigned st_uid; // uid_t
- unsigned st_gid; // gid_t
- unsigned st_rdev;
- long st_size; // off_t
- unsigned long st_blksize;
- unsigned long st_blocks;
- unsigned long st_atime_;
- unsigned long st_atime_nsec_;
- unsigned long st_mtime_;
- unsigned long st_mtime_nsec_;
- unsigned long st_ctime_;
- unsigned long st_ctime_nsec_;
- unsigned long __unused4;
- unsigned long __unused5;
-};
-#elif (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64)
-struct kernel_stat {
- unsigned st_dev;
- int st_pad1[3];
- unsigned st_ino;
- unsigned st_mode;
- unsigned st_nlink;
- unsigned st_uid;
- unsigned st_gid;
- unsigned st_rdev;
- int st_pad2[2];
- long st_size;
- int st_pad3;
- long st_atime_;
- long st_atime_nsec_;
- long st_mtime_;
- long st_mtime_nsec_;
- long st_ctime_;
- long st_ctime_nsec_;
- int st_blksize;
- int st_blocks;
- int st_pad4[14];
-};
-#endif
-
-/* include/asm-{arm,i386,mips,x86_64,ppc}/statfs.h */
-#ifdef __mips__
-#if _MIPS_SIM != _MIPS_SIM_ABI64
-struct kernel_statfs64 {
- unsigned long f_type;
- unsigned long f_bsize;
- unsigned long f_frsize;
- unsigned long __pad;
- unsigned long long f_blocks;
- unsigned long long f_bfree;
- unsigned long long f_files;
- unsigned long long f_ffree;
- unsigned long long f_bavail;
- struct { int val[2]; } f_fsid;
- unsigned long f_namelen;
- unsigned long f_spare[6];
-};
-#endif
-#elif !defined(__x86_64__)
-struct kernel_statfs64 {
- unsigned long f_type;
- unsigned long f_bsize;
- unsigned long long f_blocks;
- unsigned long long f_bfree;
- unsigned long long f_bavail;
- unsigned long long f_files;
- unsigned long long f_ffree;
- struct { int val[2]; } f_fsid;
- unsigned long f_namelen;
- unsigned long f_frsize;
- unsigned long f_spare[5];
-};
-#endif
-
-/* include/asm-{arm,i386,mips,x86_64,ppc,generic}/statfs.h */
-#ifdef __mips__
-struct kernel_statfs {
- long f_type;
- long f_bsize;
- long f_frsize;
- long f_blocks;
- long f_bfree;
- long f_files;
- long f_ffree;
- long f_bavail;
- struct { int val[2]; } f_fsid;
- long f_namelen;
- long f_spare[6];
-};
-#else
-struct kernel_statfs {
- /* x86_64 actually defines all these fields as signed, whereas all other */
- /* platforms define them as unsigned. Leaving them at unsigned should not */
- /* cause any problems. */
- unsigned long f_type;
- unsigned long f_bsize;
- unsigned long f_blocks;
- unsigned long f_bfree;
- unsigned long f_bavail;
- unsigned long f_files;
- unsigned long f_ffree;
- struct { int val[2]; } f_fsid;
- unsigned long f_namelen;
- unsigned long f_frsize;
- unsigned long f_spare[5];
-};
-#endif
-
-
-/* Definitions missing from the standard header files */
-#ifndef O_DIRECTORY
-#if defined(__ARM_ARCH_3__)
-#define O_DIRECTORY 0040000
-#else
-#define O_DIRECTORY 0200000
-#endif
-#endif
-#ifndef NT_PRXFPREG
-#define NT_PRXFPREG 0x46e62b7f
-#endif
-#ifndef PTRACE_GETFPXREGS
-#define PTRACE_GETFPXREGS ((enum __ptrace_request)18)
-#endif
-#ifndef PR_GET_DUMPABLE
-#define PR_GET_DUMPABLE 3
-#endif
-#ifndef PR_SET_DUMPABLE
-#define PR_SET_DUMPABLE 4
-#endif
-#ifndef AT_FDCWD
-#define AT_FDCWD (-100)
-#endif
-#ifndef AT_SYMLINK_NOFOLLOW
-#define AT_SYMLINK_NOFOLLOW 0x100
-#endif
-#ifndef AT_REMOVEDIR
-#define AT_REMOVEDIR 0x200
-#endif
-#ifndef MREMAP_FIXED
-#define MREMAP_FIXED 2
-#endif
-#ifndef SA_RESTORER
-#define SA_RESTORER 0x04000000
-#endif
-
-#if defined(__i386__)
-#ifndef __NR_setresuid
-#define __NR_setresuid 164
-#define __NR_setresgid 170
-#endif
-#ifndef __NR_rt_sigaction
-#define __NR_rt_sigaction 174
-#define __NR_rt_sigprocmask 175
-#define __NR_rt_sigpending 176
-#define __NR_rt_sigsuspend 179
-#endif
-#ifndef __NR_pread64
-#define __NR_pread64 180
-#endif
-#ifndef __NR_pwrite64
-#define __NR_pwrite64 181
-#endif
-#ifndef __NR_ugetrlimit
-#define __NR_ugetrlimit 191
-#endif
-#ifndef __NR_stat64
-#define __NR_stat64 195
-#endif
-#ifndef __NR_fstat64
-#define __NR_fstat64 197
-#endif
-#ifndef __NR_setresuid32
-#define __NR_setresuid32 208
-#define __NR_setresgid32 210
-#endif
-#ifndef __NR_setfsuid32
-#define __NR_setfsuid32 215
-#define __NR_setfsgid32 216
-#endif
-#ifndef __NR_getdents64
-#define __NR_getdents64 220
-#endif
-#ifndef __NR_gettid
-#define __NR_gettid 224
-#endif
-#ifndef __NR_readahead
-#define __NR_readahead 225
-#endif
-#ifndef __NR_setxattr
-#define __NR_setxattr 226
-#endif
-#ifndef __NR_lsetxattr
-#define __NR_lsetxattr 227
-#endif
-#ifndef __NR_getxattr
-#define __NR_getxattr 229
-#endif
-#ifndef __NR_lgetxattr
-#define __NR_lgetxattr 230
-#endif
-#ifndef __NR_futex
-#define __NR_futex 240
-#endif
-#ifndef __NR_sched_setaffinity
-#define __NR_sched_setaffinity 241
-#define __NR_sched_getaffinity 242
-#endif
-#ifndef __NR_set_tid_address
-#define __NR_set_tid_address 258
-#endif
-#ifndef __NR_statfs64
-#define __NR_statfs64 268
-#endif
-#ifndef __NR_fstatfs64
-#define __NR_fstatfs64 269
-#endif
-#ifndef __NR_fadvise64_64
-#define __NR_fadvise64_64 272
-#endif
-#ifndef __NR_openat
-#define __NR_openat 295
-#endif
-#ifndef __NR_fstatat64
-#define __NR_fstatat64 300
-#endif
-#ifndef __NR_unlinkat
-#define __NR_unlinkat 301
-#endif
-#ifndef __NR_move_pages
-#define __NR_move_pages 317
-#endif
-/* End of i386 definitions */
-#elif defined(__ARM_ARCH_3__)
-#ifndef __NR_setresuid
-#define __NR_setresuid (__NR_SYSCALL_BASE + 164)
-#define __NR_setresgid (__NR_SYSCALL_BASE + 170)
-#endif
-#ifndef __NR_rt_sigaction
-#define __NR_rt_sigaction (__NR_SYSCALL_BASE + 174)
-#define __NR_rt_sigprocmask (__NR_SYSCALL_BASE + 175)
-#define __NR_rt_sigpending (__NR_SYSCALL_BASE + 176)
-#define __NR_rt_sigsuspend (__NR_SYSCALL_BASE + 179)
-#endif
-#ifndef __NR_pread64
-#define __NR_pread64 (__NR_SYSCALL_BASE + 180)
-#endif
-#ifndef __NR_pwrite64
-#define __NR_pwrite64 (__NR_SYSCALL_BASE + 181)
-#endif
-#ifndef __NR_ugetrlimit
-#define __NR_ugetrlimit (__NR_SYSCALL_BASE + 191)
-#endif
-#ifndef __NR_stat64
-#define __NR_stat64 (__NR_SYSCALL_BASE + 195)
-#endif
-#ifndef __NR_fstat64
-#define __NR_fstat64 (__NR_SYSCALL_BASE + 197)
-#endif
-#ifndef __NR_setresuid32
-#define __NR_setresuid32 (__NR_SYSCALL_BASE + 208)
-#define __NR_setresgid32 (__NR_SYSCALL_BASE + 210)
-#endif
-#ifndef __NR_setfsuid32
-#define __NR_setfsuid32 (__NR_SYSCALL_BASE + 215)
-#define __NR_setfsgid32 (__NR_SYSCALL_BASE + 216)
-#endif
-#ifndef __NR_getdents64
-#define __NR_getdents64 (__NR_SYSCALL_BASE + 217)
-#endif
-#ifndef __NR_gettid
-#define __NR_gettid (__NR_SYSCALL_BASE + 224)
-#endif
-#ifndef __NR_readahead
-#define __NR_readahead (__NR_SYSCALL_BASE + 225)
-#endif
-#ifndef __NR_setxattr
-#define __NR_setxattr (__NR_SYSCALL_BASE + 226)
-#endif
-#ifndef __NR_lsetxattr
-#define __NR_lsetxattr (__NR_SYSCALL_BASE + 227)
-#endif
-#ifndef __NR_getxattr
-#define __NR_getxattr (__NR_SYSCALL_BASE + 229)
-#endif
-#ifndef __NR_lgetxattr
-#define __NR_lgetxattr (__NR_SYSCALL_BASE + 230)
-#endif
-#ifndef __NR_futex
-#define __NR_futex (__NR_SYSCALL_BASE + 240)
-#endif
-#ifndef __NR_sched_setaffinity
-#define __NR_sched_setaffinity (__NR_SYSCALL_BASE + 241)
-#define __NR_sched_getaffinity (__NR_SYSCALL_BASE + 242)
-#endif
-#ifndef __NR_set_tid_address
-#define __NR_set_tid_address (__NR_SYSCALL_BASE + 256)
-#endif
-#ifndef __NR_statfs64
-#define __NR_statfs64 (__NR_SYSCALL_BASE + 266)
-#endif
-#ifndef __NR_fstatfs64
-#define __NR_fstatfs64 (__NR_SYSCALL_BASE + 267)
-#endif
-#ifndef __NR_move_pages
-#define __NR_move_pages (__NR_SYSCALL_BASE + 344)
-#endif
-/* End of ARM 3 definitions */
-#elif defined(__x86_64__)
-#ifndef __NR_setresuid
-#define __NR_setresuid 117
-#define __NR_setresgid 119
-#endif
-#ifndef __NR_gettid
-#define __NR_gettid 186
-#endif
-#ifndef __NR_readahead
-#define __NR_readahead 187
-#endif
-#ifndef __NR_setxattr
-#define __NR_setxattr 188
-#endif
-#ifndef __NR_lsetxattr
-#define __NR_lsetxattr 189
-#endif
-#ifndef __NR_getxattr
-#define __NR_getxattr 191
-#endif
-#ifndef __NR_lgetxattr
-#define __NR_lgetxattr 192
-#endif
-#ifndef __NR_futex
-#define __NR_futex 202
-#endif
-#ifndef __NR_sched_setaffinity
-#define __NR_sched_setaffinity 203
-#define __NR_sched_getaffinity 204
-#endif
-#ifndef __NR_getdents64
-#define __NR_getdents64 217
-#endif
-#ifndef __NR_set_tid_address
-#define __NR_set_tid_address 218
-#endif
-#ifndef __NR_fadvise64
-#define __NR_fadvise64 221
-#endif
-#ifndef __NR_openat
-#define __NR_openat 257
-#endif
-#ifndef __NR_newfstatat
-#define __NR_newfstatat 262
-#endif
-#ifndef __NR_unlinkat
-#define __NR_unlinkat 263
-#endif
-#ifndef __NR_move_pages
-#define __NR_move_pages 279
-#endif
-/* End of x86-64 definitions */
-#elif defined(__mips__)
-#if _MIPS_SIM == _MIPS_SIM_ABI32
-#ifndef __NR_setresuid
-#define __NR_setresuid (__NR_Linux + 185)
-#define __NR_setresgid (__NR_Linux + 190)
-#endif
-#ifndef __NR_rt_sigaction
-#define __NR_rt_sigaction (__NR_Linux + 194)
-#define __NR_rt_sigprocmask (__NR_Linux + 195)
-#define __NR_rt_sigpending (__NR_Linux + 196)
-#define __NR_rt_sigsuspend (__NR_Linux + 199)
-#endif
-#ifndef __NR_pread64
-#define __NR_pread64 (__NR_Linux + 200)
-#endif
-#ifndef __NR_pwrite64
-#define __NR_pwrite64 (__NR_Linux + 201)
-#endif
-#ifndef __NR_stat64
-#define __NR_stat64 (__NR_Linux + 213)
-#endif
-#ifndef __NR_fstat64
-#define __NR_fstat64 (__NR_Linux + 215)
-#endif
-#ifndef __NR_getdents64
-#define __NR_getdents64 (__NR_Linux + 219)
-#endif
-#ifndef __NR_gettid
-#define __NR_gettid (__NR_Linux + 222)
-#endif
-#ifndef __NR_readahead
-#define __NR_readahead (__NR_Linux + 223)
-#endif
-#ifndef __NR_setxattr
-#define __NR_setxattr (__NR_Linux + 224)
-#endif
-#ifndef __NR_lsetxattr
-#define __NR_lsetxattr (__NR_Linux + 225)
-#endif
-#ifndef __NR_getxattr
-#define __NR_getxattr (__NR_Linux + 227)
-#endif
-#ifndef __NR_lgetxattr
-#define __NR_lgetxattr (__NR_Linux + 228)
-#endif
-#ifndef __NR_futex
-#define __NR_futex (__NR_Linux + 238)
-#endif
-#ifndef __NR_sched_setaffinity
-#define __NR_sched_setaffinity (__NR_Linux + 239)
-#define __NR_sched_getaffinity (__NR_Linux + 240)
-#endif
-#ifndef __NR_set_tid_address
-#define __NR_set_tid_address (__NR_Linux + 252)
-#endif
-#ifndef __NR_statfs64
-#define __NR_statfs64 (__NR_Linux + 255)
-#endif
-#ifndef __NR_fstatfs64
-#define __NR_fstatfs64 (__NR_Linux + 256)
-#endif
-#ifndef __NR_openat
-#define __NR_openat (__NR_Linux + 288)
-#endif
-#ifndef __NR_fstatat
-#define __NR_fstatat (__NR_Linux + 293)
-#endif
-#ifndef __NR_unlinkat
-#define __NR_unlinkat (__NR_Linux + 294)
-#endif
-#ifndef __NR_move_pages
-#define __NR_move_pages (__NR_Linux + 308)
-#endif
-/* End of MIPS (old 32bit API) definitions */
-#elif _MIPS_SIM == _MIPS_SIM_ABI64
-#ifndef __NR_setresuid
-#define __NR_setresuid (__NR_Linux + 115)
-#define __NR_setresgid (__NR_Linux + 117)
-#endif
-#ifndef __NR_gettid
-#define __NR_gettid (__NR_Linux + 178)
-#endif
-#ifndef __NR_readahead
-#define __NR_readahead (__NR_Linux + 179)
-#endif
-#ifndef __NR_setxattr
-#define __NR_setxattr (__NR_Linux + 180)
-#endif
-#ifndef __NR_lsetxattr
-#define __NR_lsetxattr (__NR_Linux + 181)
-#endif
-#ifndef __NR_getxattr
-#define __NR_getxattr (__NR_Linux + 183)
-#endif
-#ifndef __NR_lgetxattr
-#define __NR_lgetxattr (__NR_Linux + 184)
-#endif
-#ifndef __NR_futex
-#define __NR_futex (__NR_Linux + 194)
-#endif
-#ifndef __NR_sched_setaffinity
-#define __NR_sched_setaffinity (__NR_Linux + 195)
-#define __NR_sched_getaffinity (__NR_Linux + 196)
-#endif
-#ifndef __NR_set_tid_address
-#define __NR_set_tid_address (__NR_Linux + 212)
-#endif
-#ifndef __NR_openat
-#define __NR_openat (__NR_Linux + 247)
-#endif
-#ifndef __NR_fstatat
-#define __NR_fstatat (__NR_Linux + 252)
-#endif
-#ifndef __NR_unlinkat
-#define __NR_unlinkat (__NR_Linux + 253)
-#endif
-#ifndef __NR_move_pages
-#define __NR_move_pages (__NR_Linux + 267)
-#endif
-/* End of MIPS (64bit API) definitions */
-#else
-#ifndef __NR_setresuid
-#define __NR_setresuid (__NR_Linux + 115)
-#define __NR_setresgid (__NR_Linux + 117)
-#endif
-#ifndef __NR_gettid
-#define __NR_gettid (__NR_Linux + 178)
-#endif
-#ifndef __NR_readahead
-#define __NR_readahead (__NR_Linux + 179)
-#endif
-#ifndef __NR_setxattr
-#define __NR_setxattr (__NR_Linux + 180)
-#endif
-#ifndef __NR_lsetxattr
-#define __NR_lsetxattr (__NR_Linux + 181)
-#endif
-#ifndef __NR_getxattr
-#define __NR_getxattr (__NR_Linux + 183)
-#endif
-#ifndef __NR_lgetxattr
-#define __NR_lgetxattr (__NR_Linux + 184)
-#endif
-#ifndef __NR_futex
-#define __NR_futex (__NR_Linux + 194)
-#endif
-#ifndef __NR_sched_setaffinity
-#define __NR_sched_setaffinity (__NR_Linux + 195)
-#define __NR_sched_getaffinity (__NR_Linux + 196)
-#endif
-#ifndef __NR_set_tid_address
-#define __NR_set_tid_address (__NR_Linux + 213)
-#endif
-#ifndef __NR_statfs64
-#define __NR_statfs64 (__NR_Linux + 217)
-#endif
-#ifndef __NR_fstatfs64
-#define __NR_fstatfs64 (__NR_Linux + 218)
-#endif
-#ifndef __NR_openat
-#define __NR_openat (__NR_Linux + 251)
-#endif
-#ifndef __NR_fstatat
-#define __NR_fstatat (__NR_Linux + 256)
-#endif
-#ifndef __NR_unlinkat
-#define __NR_unlinkat (__NR_Linux + 257)
-#endif
-#ifndef __NR_move_pages
-#define __NR_move_pages (__NR_Linux + 271)
-#endif
-/* End of MIPS (new 32bit API) definitions */
-#endif
-/* End of MIPS definitions */
-#elif defined(__PPC__)
-#ifndef __NR_setfsuid
-#define __NR_setfsuid 138
-#define __NR_setfsgid 139
-#endif
-#ifndef __NR_setresuid
-#define __NR_setresuid 164
-#define __NR_setresgid 169
-#endif
-#ifndef __NR_rt_sigaction
-#define __NR_rt_sigaction 173
-#define __NR_rt_sigprocmask 174
-#define __NR_rt_sigpending 175
-#define __NR_rt_sigsuspend 178
-#endif
-#ifndef __NR_pread64
-#define __NR_pread64 179
-#endif
-#ifndef __NR_pwrite64
-#define __NR_pwrite64 180
-#endif
-#ifndef __NR_ugetrlimit
-#define __NR_ugetrlimit 190
-#endif
-#ifndef __NR_readahead
-#define __NR_readahead 191
-#endif
-#ifndef __NR_stat64
-#define __NR_stat64 195
-#endif
-#ifndef __NR_fstat64
-#define __NR_fstat64 197
-#endif
-#ifndef __NR_getdents64
-#define __NR_getdents64 202
-#endif
-#ifndef __NR_gettid
-#define __NR_gettid 207
-#endif
-#ifndef __NR_setxattr
-#define __NR_setxattr 209
-#endif
-#ifndef __NR_lsetxattr
-#define __NR_lsetxattr 210
-#endif
-#ifndef __NR_getxattr
-#define __NR_getxattr 212
-#endif
-#ifndef __NR_lgetxattr
-#define __NR_lgetxattr 213
-#endif
-#ifndef __NR_futex
-#define __NR_futex 221
-#endif
-#ifndef __NR_sched_setaffinity
-#define __NR_sched_setaffinity 222
-#define __NR_sched_getaffinity 223
-#endif
-#ifndef __NR_set_tid_address
-#define __NR_set_tid_address 232
-#endif
-#ifndef __NR_statfs64
-#define __NR_statfs64 252
-#endif
-#ifndef __NR_fstatfs64
-#define __NR_fstatfs64 253
-#endif
-#ifndef __NR_fadvise64_64
-#define __NR_fadvise64_64 254
-#endif
-#ifndef __NR_openat
-#define __NR_openat 286
-#endif
-#ifndef __NR_fstatat64
-#define __NR_fstatat64 291
-#endif
-#ifndef __NR_unlinkat
-#define __NR_unlinkat 292
-#endif
-#ifndef __NR_move_pages
-#define __NR_move_pages 301
-#endif
-/* End of powerpc defininitions */
-#endif
-
-
-/* After forking, we must make sure to only call system calls. */
-#if __BOUNDED_POINTERS__
- #error "Need to port invocations of syscalls for bounded ptrs"
-#else
- /* The core dumper and the thread lister get executed after threads
- * have been suspended. As a consequence, we cannot call any functions
- * that acquire locks. Unfortunately, libc wraps most system calls
- * (e.g. in order to implement pthread_atfork, and to make calls
- * cancellable), which means we cannot call these functions. Instead,
- * we have to call syscall() directly.
- */
- #undef LSS_ERRNO
- #ifdef SYS_ERRNO
- /* Allow the including file to override the location of errno. This can
- * be useful when using clone() with the CLONE_VM option.
- */
- #define LSS_ERRNO SYS_ERRNO
- #else
- #define LSS_ERRNO errno
- #endif
-
- #undef LSS_INLINE
- #ifdef SYS_INLINE
- #define LSS_INLINE SYS_INLINE
- #else
- #define LSS_INLINE static inline
- #endif
-
- /* Allow the including file to override the prefix used for all new
- * system calls. By default, it will be set to "sys_".
- */
- #undef LSS_NAME
- #ifndef SYS_PREFIX
- #define LSS_NAME(name) sys_##name
- #elif SYS_PREFIX < 0
- #define LSS_NAME(name) name
- #elif SYS_PREFIX == 0
- #define LSS_NAME(name) sys0_##name
- #elif SYS_PREFIX == 1
- #define LSS_NAME(name) sys1_##name
- #elif SYS_PREFIX == 2
- #define LSS_NAME(name) sys2_##name
- #elif SYS_PREFIX == 3
- #define LSS_NAME(name) sys3_##name
- #elif SYS_PREFIX == 4
- #define LSS_NAME(name) sys4_##name
- #elif SYS_PREFIX == 5
- #define LSS_NAME(name) sys5_##name
- #elif SYS_PREFIX == 6
- #define LSS_NAME(name) sys6_##name
- #elif SYS_PREFIX == 7
- #define LSS_NAME(name) sys7_##name
- #elif SYS_PREFIX == 8
- #define LSS_NAME(name) sys8_##name
- #elif SYS_PREFIX == 9
- #define LSS_NAME(name) sys9_##name
- #endif
-
- #undef LSS_RETURN
- #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__))
- /* Failing system calls return a negative result in the range of
- * -1..-4095. These are "errno" values with the sign inverted.
- */
- #define LSS_RETURN(type, res) \
- do { \
- if ((unsigned long)(res) >= (unsigned long)(-4095)) { \
- LSS_ERRNO = -(res); \
- res = -1; \
- } \
- return (type) (res); \
- } while (0)
- #elif defined(__mips__)
- /* On MIPS, failing system calls return -1, and set errno in a
- * separate CPU register.
- */
- #define LSS_RETURN(type, res, err) \
- do { \
- if (err) { \
- LSS_ERRNO = (res); \
- res = -1; \
- } \
- return (type) (res); \
- } while (0)
- #elif defined(__PPC__)
- /* On PPC, failing system calls return -1, and set errno in a
- * separate CPU register. See linux/unistd.h.
- */
- #define LSS_RETURN(type, res, err) \
- do { \
- if (err & 0x10000000 ) { \
- LSS_ERRNO = (res); \
- res = -1; \
- } \
- return (type) (res); \
- } while (0)
- #endif
- #if defined(__i386__)
- /* In PIC mode (e.g. when building shared libraries), gcc for i386
- * reserves ebx. Unfortunately, most distribution ship with implementations
- * of _syscallX() which clobber ebx.
- * Also, most definitions of _syscallX() neglect to mark "memory" as being
- * clobbered. This causes problems with compilers, that do a better job
- * at optimizing across __asm__ calls.
- * So, we just have to redefine all of the _syscallX() macros.
- */
- #undef LSS_BODY
- #define LSS_BODY(type,args...) \
- long __res; \
- __asm__ __volatile__("push %%ebx\n" \
- "movl %2,%%ebx\n" \
- "int $0x80\n" \
- "pop %%ebx" \
- args \
- : "memory"); \
- LSS_RETURN(type,__res)
- #undef _syscall0
- #define _syscall0(type,name) \
- type LSS_NAME(name)(void) { \
- long __res; \
- __asm__ volatile("int $0x80" \
- : "=a" (__res) \
- : "0" (__NR_##name) \
- : "memory"); \
- LSS_RETURN(type,__res); \
- }
- #undef _syscall1
- #define _syscall1(type,name,type1,arg1) \
- type LSS_NAME(name)(type1 arg1) { \
- LSS_BODY(type, \
- : "=a" (__res) \
- : "0" (__NR_##name), "ri" ((long)(arg1))); \
- }
- #undef _syscall2
- #define _syscall2(type,name,type1,arg1,type2,arg2) \
- type LSS_NAME(name)(type1 arg1,type2 arg2) { \
- LSS_BODY(type, \
- : "=a" (__res) \
- : "0" (__NR_##name),"ri" ((long)(arg1)), "c" ((long)(arg2))); \
- }
- #undef _syscall3
- #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
- type LSS_NAME(name)(type1 arg1,type2 arg2,type3 arg3) { \
- LSS_BODY(type, \
- : "=a" (__res) \
- : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \
- "d" ((long)(arg3))); \
- }
- #undef _syscall4
- #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
- LSS_BODY(type, \
- : "=a" (__res) \
- : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \
- "d" ((long)(arg3)),"S" ((long)(arg4))); \
- }
- #undef _syscall5
- #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5) { \
- long __res; \
- __asm__ __volatile__("push %%ebx\n" \
- "movl %2,%%ebx\n" \
- "movl %1,%%eax\n" \
- "int $0x80\n" \
- "pop %%ebx" \
- : "=a" (__res) \
- : "i" (__NR_##name), "ri" ((long)(arg1)), \
- "c" ((long)(arg2)), "d" ((long)(arg3)), \
- "S" ((long)(arg4)), "D" ((long)(arg5)) \
- : "memory"); \
- LSS_RETURN(type,__res); \
- }
- #undef _syscall6
- #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5,type6,arg6) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5, type6 arg6) { \
- long __res; \
- struct { long __a1; long __a6; } __s = { (long)arg1, (long) arg6 }; \
- __asm__ __volatile__("push %%ebp\n" \
- "push %%ebx\n" \
- "movl 4(%2),%%ebp\n" \
- "movl 0(%2), %%ebx\n" \
- "movl %1,%%eax\n" \
- "int $0x80\n" \
- "pop %%ebx\n" \
- "pop %%ebp" \
- : "=a" (__res) \
- : "i" (__NR_##name), "0" ((long)(&__s)), \
- "c" ((long)(arg2)), "d" ((long)(arg3)), \
- "S" ((long)(arg4)), "D" ((long)(arg5)) \
- : "memory"); \
- LSS_RETURN(type,__res); \
- }
- LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
- int flags, void *arg, int *parent_tidptr,
- void *newtls, int *child_tidptr) {
- long __res;
- __asm__ __volatile__(/* if (fn == NULL)
- * return -EINVAL;
- */
- "movl %3,%%ecx\n"
- "jecxz 1f\n"
-
- /* if (child_stack == NULL)
- * return -EINVAL;
- */
- "movl %4,%%ecx\n"
- "jecxz 1f\n"
-
- /* Set up alignment of the child stack:
- * child_stack = (child_stack & ~0xF) - 20;
- */
- "andl $-16,%%ecx\n"
- "subl $20,%%ecx\n"
-
- /* Push "arg" and "fn" onto the stack that will be
- * used by the child.
- */
- "movl %6,%%eax\n"
- "movl %%eax,4(%%ecx)\n"
- "movl %3,%%eax\n"
- "movl %%eax,(%%ecx)\n"
-
- /* %eax = syscall(%eax = __NR_clone,
- * %ebx = flags,
- * %ecx = child_stack,
- * %edx = parent_tidptr,
- * %esi = newtls,
- * %edi = child_tidptr)
- * Also, make sure that %ebx gets preserved as it is
- * used in PIC mode.
- */
- "movl %8,%%esi\n"
- "movl %7,%%edx\n"
- "movl %5,%%eax\n"
- "movl %9,%%edi\n"
- "pushl %%ebx\n"
- "movl %%eax,%%ebx\n"
- "movl %2,%%eax\n"
- "int $0x80\n"
-
- /* In the parent: restore %ebx
- * In the child: move "fn" into %ebx
- */
- "popl %%ebx\n"
-
- /* if (%eax != 0)
- * return %eax;
- */
- "test %%eax,%%eax\n"
- "jnz 1f\n"
-
- /* In the child, now. Terminate frame pointer chain.
- */
- "movl $0,%%ebp\n"
-
- /* Call "fn". "arg" is already on the stack.
- */
- "call *%%ebx\n"
-
- /* Call _exit(%ebx). Unfortunately older versions
- * of gcc restrict the number of arguments that can
- * be passed to asm(). So, we need to hard-code the
- * system call number.
- */
- "movl %%eax,%%ebx\n"
- "movl $1,%%eax\n"
- "int $0x80\n"
-
- /* Return to parent.
- */
- "1:\n"
- : "=a" (__res)
- : "0"(-EINVAL), "i"(__NR_clone),
- "m"(fn), "m"(child_stack), "m"(flags), "m"(arg),
- "m"(parent_tidptr), "m"(newtls), "m"(child_tidptr)
- : "memory", "ecx", "edx", "esi", "edi");
- LSS_RETURN(int, __res);
- }
-
- #define __NR__fadvise64_64 __NR_fadvise64_64
- LSS_INLINE _syscall6(int, _fadvise64_64, int, fd,
- unsigned, offset_lo, unsigned, offset_hi,
- unsigned, len_lo, unsigned, len_hi,
- int, advice)
-
- LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset,
- loff_t len, int advice) {
- return LSS_NAME(_fadvise64_64)(fd,
- (unsigned)offset, (unsigned)(offset >>32),
- (unsigned)len, (unsigned)(len >> 32),
- advice);
- }
-
- LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) {
- /* On i386, the kernel does not know how to return from a signal
- * handler. Instead, it relies on user space to provide a
- * restorer function that calls the {rt_,}sigreturn() system call.
- * Unfortunately, we cannot just reference the glibc version of this
- * function, as glibc goes out of its way to make it inaccessible.
- */
- void (*res)(void);
- __asm__ __volatile__("call 2f\n"
- "0:.align 16\n"
- "1:movl %1,%%eax\n"
- "int $0x80\n"
- "2:popl %0\n"
- "addl $(1b-0b),%0\n"
- : "=a" (res)
- : "i" (__NR_rt_sigreturn));
- return res;
- }
- LSS_INLINE void (*LSS_NAME(restore)(void))(void) {
- /* On i386, the kernel does not know how to return from a signal
- * handler. Instead, it relies on user space to provide a
- * restorer function that calls the {rt_,}sigreturn() system call.
- * Unfortunately, we cannot just reference the glibc version of this
- * function, as glibc goes out of its way to make it inaccessible.
- */
- void (*res)(void);
- __asm__ __volatile__("call 2f\n"
- "0:.align 16\n"
- "1:pop %%eax\n"
- "movl %1,%%eax\n"
- "int $0x80\n"
- "2:popl %0\n"
- "addl $(1b-0b),%0\n"
- : "=a" (res)
- : "i" (__NR_sigreturn));
- return res;
- }
- #elif defined(__x86_64__)
- /* There are no known problems with any of the _syscallX() macros
- * currently shipping for x86_64, but we still need to be able to define
- * our own version so that we can override the location of the errno
- * location (e.g. when using the clone() system call with the CLONE_VM
- * option).
- */
- #undef LSS_BODY
- #define LSS_BODY(type,name, ...) \
- long __res; \
- __asm__ __volatile__("syscall" : "=a" (__res) : "0" (__NR_##name), \
- ##__VA_ARGS__ : "r11", "rcx", "memory"); \
- LSS_RETURN(type, __res)
- #undef _syscall0
- #define _syscall0(type,name) \
- type LSS_NAME(name)() { \
- LSS_BODY(type, name); \
- }
- #undef _syscall1
- #define _syscall1(type,name,type1,arg1) \
- type LSS_NAME(name)(type1 arg1) { \
- LSS_BODY(type, name, "D" ((long)(arg1))); \
- }
- #undef _syscall2
- #define _syscall2(type,name,type1,arg1,type2,arg2) \
- type LSS_NAME(name)(type1 arg1, type2 arg2) { \
- LSS_BODY(type, name, "D" ((long)(arg1)), "S" ((long)(arg2))); \
- }
- #undef _syscall3
- #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \
- LSS_BODY(type, name, "D" ((long)(arg1)), "S" ((long)(arg2)), \
- "d" ((long)(arg3))); \
- }
- #undef _syscall4
- #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
- long __res; \
- __asm__ __volatile__("movq %5,%%r10; syscall" : \
- "=a" (__res) : "0" (__NR_##name), \
- "D" ((long)(arg1)), "S" ((long)(arg2)), "d" ((long)(arg3)), \
- "g" ((long)(arg4)) : "r10", "r11", "rcx", "memory"); \
- LSS_RETURN(type, __res); \
- }
- #undef _syscall5
- #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5) { \
- long __res; \
- __asm__ __volatile__("movq %5,%%r10; movq %6,%%r8; syscall" : \
- "=a" (__res) : "0" (__NR_##name), \
- "D" ((long)(arg1)), "S" ((long)(arg2)), "d" ((long)(arg3)), \
- "g" ((long)(arg4)), "g" ((long)(arg5)) : \
- "r8", "r10", "r11", "rcx", "memory"); \
- LSS_RETURN(type, __res); \
- }
- #undef _syscall6
- #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5,type6,arg6) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5, type6 arg6) { \
- long __res; \
- __asm__ __volatile__("movq %5,%%r10; movq %6,%%r8; movq %7,%%r9;" \
- "syscall" : \
- "=a" (__res) : "0" (__NR_##name), \
- "D" ((long)(arg1)), "S" ((long)(arg2)), "d" ((long)(arg3)), \
- "g" ((long)(arg4)), "g" ((long)(arg5)), "g" ((long)(arg6)) : \
- "r8", "r9", "r10", "r11", "rcx", "memory"); \
- LSS_RETURN(type, __res); \
- }
- LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
- int flags, void *arg, int *parent_tidptr,
- void *newtls, int *child_tidptr) {
- long __res;
- {
- register void *__tls __asm__("r8") = newtls;
- register int *__ctid __asm__("r10") = child_tidptr;
- __asm__ __volatile__(/* if (fn == NULL)
- * return -EINVAL;
- */
- "testq %4,%4\n"
- "jz 1f\n"
-
- /* if (child_stack == NULL)
- * return -EINVAL;
- */
- "testq %5,%5\n"
- "jz 1f\n"
-
- /* childstack -= 2*sizeof(void *);
- */
- "subq $16,%5\n"
-
- /* Push "arg" and "fn" onto the stack that will be
- * used by the child.
- */
- "movq %7,8(%5)\n"
- "movq %4,0(%5)\n"
-
- /* %rax = syscall(%rax = __NR_clone,
- * %rdi = flags,
- * %rsi = child_stack,
- * %rdx = parent_tidptr,
- * %r8 = new_tls,
- * %r10 = child_tidptr)
- */
- "movq %2,%%rax\n"
- "syscall\n"
-
- /* if (%rax != 0)
- * return;
- */
- "testq %%rax,%%rax\n"
- "jnz 1f\n"
-
- /* In the child. Terminate frame pointer chain.
- */
- "xorq %%rbp,%%rbp\n"
-
- /* Call "fn(arg)".
- */
- "popq %%rax\n"
- "popq %%rdi\n"
- "call *%%rax\n"
-
- /* Call _exit(%ebx).
- */
- "movq %%rax,%%rdi\n"
- "movq %3,%%rax\n"
- "syscall\n"
-
- /* Return to parent.
- */
- "1:\n"
- : "=a" (__res)
- : "0"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit),
- "r"(fn), "S"(child_stack), "D"(flags), "r"(arg),
- "d"(parent_tidptr), "r"(__tls), "r"(__ctid)
- : "memory", "r11", "rcx");
- }
- LSS_RETURN(int, __res);
- }
- LSS_INLINE _syscall4(int, fadvise64, int, fd, loff_t, offset, loff_t, len,
- int, advice)
-
- LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) {
- /* On x86-64, the kernel does not know how to return from
- * a signal handler. Instead, it relies on user space to provide a
- * restorer function that calls the rt_sigreturn() system call.
- * Unfortunately, we cannot just reference the glibc version of this
- * function, as glibc goes out of its way to make it inaccessible.
- */
- void (*res)(void);
- __asm__ __volatile__("call 2f\n"
- "0:.align 16\n"
- "1:movq %1,%%rax\n"
- "syscall\n"
- "2:popq %0\n"
- "addq $(1b-0b),%0\n"
- : "=a" (res)
- : "i" (__NR_rt_sigreturn));
- return res;
- }
- #elif defined(__ARM_ARCH_3__)
- /* Most definitions of _syscallX() neglect to mark "memory" as being
- * clobbered. This causes problems with compilers, that do a better job
- * at optimizing across __asm__ calls.
- * So, we just have to redefine all fo the _syscallX() macros.
- */
- #undef LSS_REG
- #define LSS_REG(r,a) register long __r##r __asm__("r"#r) = (long)a
- #undef LSS_BODY
- #define LSS_BODY(type,name,args...) \
- register long __res_r0 __asm__("r0"); \
- long __res; \
- __asm__ __volatile__ (__syscall(name) \
- : "=r"(__res_r0) : args : "lr", "memory"); \
- __res = __res_r0; \
- LSS_RETURN(type, __res)
- #undef _syscall0
- #define _syscall0(type, name) \
- type LSS_NAME(name)() { \
- LSS_BODY(type, name); \
- }
- #undef _syscall1
- #define _syscall1(type, name, type1, arg1) \
- type LSS_NAME(name)(type1 arg1) { \
- LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \
- }
- #undef _syscall2
- #define _syscall2(type, name, type1, arg1, type2, arg2) \
- type LSS_NAME(name)(type1 arg1, type2 arg2) { \
- LSS_REG(0, arg1); LSS_REG(1, arg2); \
- LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \
- }
- #undef _syscall3
- #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \
- LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
- LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \
- }
- #undef _syscall4
- #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
- LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
- LSS_REG(3, arg4); \
- LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \
- }
- #undef _syscall5
- #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5) { \
- LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
- LSS_REG(3, arg4); LSS_REG(4, arg5); \
- LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \
- "r"(__r4)); \
- }
- #undef _syscall6
- #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5,type6,arg6) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5, type6 arg6) { \
- LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
- LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \
- LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \
- "r"(__r4), "r"(__r5)); \
- }
- LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
- int flags, void *arg, int *parent_tidptr,
- void *newtls, int *child_tidptr) {
- long __res;
- {
- register int __flags __asm__("r0") = flags;
- register void *__stack __asm__("r1") = child_stack;
- register void *__ptid __asm__("r2") = parent_tidptr;
- register void *__tls __asm__("r3") = newtls;
- register int *__ctid __asm__("r4") = child_tidptr;
- __asm__ __volatile__(/* if (fn == NULL || child_stack == NULL)
- * return -EINVAL;
- */
- "cmp %2,#0\n"
- "cmpne %3,#0\n"
- "moveq %0,%1\n"
- "beq 1f\n"
-
- /* Push "arg" and "fn" onto the stack that will be
- * used by the child.
- */
- "str %5,[%3,#-4]!\n"
- "str %2,[%3,#-4]!\n"
-
- /* %r0 = syscall(%r0 = flags,
- * %r1 = child_stack,
- * %r2 = parent_tidptr,
- * %r3 = newtls,
- * %r4 = child_tidptr)
- */
- __syscall(clone)"\n"
-
- /* if (%r0 != 0)
- * return %r0;
- */
- "movs %0,r0\n"
- "bne 1f\n"
-
- /* In the child, now. Call "fn(arg)".
- */
- "ldr r0,[sp, #4]\n"
- "mov lr,pc\n"
- "ldr pc,[sp]\n"
-
- /* Call _exit(%r0).
- */
- __syscall(exit)"\n"
- "1:\n"
- : "=r" (__res)
- : "i"(-EINVAL),
- "r"(fn), "r"(__stack), "r"(__flags), "r"(arg),
- "r"(__ptid), "r"(__tls), "r"(__ctid)
- : "lr", "memory");
- }
- LSS_RETURN(int, __res);
- }
- #elif defined(__mips__)
- #undef LSS_REG
- #define LSS_REG(r,a) register unsigned long __r##r __asm__("$"#r) = \
- (unsigned long)(a)
- #undef LSS_BODY
- #define LSS_BODY(type,name,r7,...) \
- register unsigned long __v0 __asm__("$2") = __NR_##name; \
- __asm__ __volatile__ ("syscall\n" \
- : "=&r"(__v0), r7 (__r7) \
- : "0"(__v0), ##__VA_ARGS__ \
- : "$8", "$9", "$10", "$11", "$12", \
- "$13", "$14", "$15", "$24", "memory"); \
- LSS_RETURN(type, __v0, __r7)
- #undef _syscall0
- #define _syscall0(type, name) \
- type LSS_NAME(name)() { \
- register unsigned long __r7 __asm__("$7"); \
- LSS_BODY(type, name, "=r"); \
- }
- #undef _syscall1
- #define _syscall1(type, name, type1, arg1) \
- type LSS_NAME(name)(type1 arg1) { \
- register unsigned long __r7 __asm__("$7"); \
- LSS_REG(4, arg1); LSS_BODY(type, name, "=r", "r"(__r4)); \
- }
- #undef _syscall2
- #define _syscall2(type, name, type1, arg1, type2, arg2) \
- type LSS_NAME(name)(type1 arg1, type2 arg2) { \
- register unsigned long __r7 __asm__("$7"); \
- LSS_REG(4, arg1); LSS_REG(5, arg2); \
- LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5)); \
- }
- #undef _syscall3
- #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \
- register unsigned long __r7 __asm__("$7"); \
- LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \
- LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5), "r"(__r6)); \
- }
- #undef _syscall4
- #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
- LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \
- LSS_REG(7, arg4); \
- LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6)); \
- }
- #undef _syscall5
- #if _MIPS_SIM == _MIPS_SIM_ABI32
- /* The old 32bit MIPS system call API passes the fifth and sixth argument
- * on the stack, whereas the new APIs use registers "r8" and "r9".
- */
- #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5) { \
- LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \
- LSS_REG(7, arg4); \
- register unsigned long __v0 __asm__("$2"); \
- __asm__ __volatile__ (".set noreorder\n" \
- "lw $2, %6\n" \
- "subu $29, 32\n" \
- "sw $2, 16($29)\n" \
- "li $2, %2\n" \
- "syscall\n" \
- "addiu $29, 32\n" \
- ".set reorder\n" \
- : "=&r"(__v0), "+r" (__r7) \
- : "i" (__NR_##name), "r"(__r4), "r"(__r5), \
- "r"(__r6), "m" ((unsigned long)arg5) \
- : "$8", "$9", "$10", "$11", "$12", \
- "$13", "$14", "$15", "$24", "memory"); \
- LSS_RETURN(type, __v0, __r7); \
- }
- #else
- #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5) { \
- LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \
- LSS_REG(7, arg4); LSS_REG(8, arg5); \
- LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \
- "r"(__r8)); \
- }
- #endif
- #undef _syscall6
- #if _MIPS_SIM == _MIPS_SIM_ABI32
- /* The old 32bit MIPS system call API passes the fifth and sixth argument
- * on the stack, whereas the new APIs use registers "r8" and "r9".
- */
- #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5,type6,arg6) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5, type6 arg6) { \
- LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \
- LSS_REG(7, arg4); \
- register unsigned long __v0 __asm__("$2"); \
- __asm__ __volatile__ (".set noreorder\n" \
- "lw $2, %6\n" \
- "lw $8, %7\n" \
- "subu $29, 32\n" \
- "sw $2, 16($29)\n" \
- "sw $8, 20($29)\n" \
- "li $2, %2\n" \
- "syscall\n" \
- "addiu $29, 32\n" \
- ".set reorder\n" \
- : "=&r"(__v0), "+r" (__r7) \
- : "i" (__NR_##name), "r"(__r4), "r"(__r5), \
- "r"(__r6), "r" ((unsigned long)arg5), \
- "r" ((unsigned long)arg6) \
- : "$8", "$9", "$10", "$11", "$12", \
- "$13", "$14", "$15", "$24", "memory"); \
- LSS_RETURN(type, __v0, __r7); \
- }
- #else
- #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5,type6,arg6) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5,type6 arg6) { \
- LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \
- LSS_REG(7, arg4); LSS_REG(8, arg5); LSS_REG(9, arg6); \
- LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \
- "r"(__r8), "r"(__r9)); \
- }
- #endif
- LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
- int flags, void *arg, int *parent_tidptr,
- void *newtls, int *child_tidptr) {
- register unsigned long __v0 __asm__("$2");
- register unsigned long __r7 __asm__("$7") = (unsigned long)newtls;
- {
- register int __flags __asm__("$4") = flags;
- register void *__stack __asm__("$5") = child_stack;
- register void *__ptid __asm__("$6") = parent_tidptr;
- register int *__ctid __asm__("$8") = child_tidptr;
- __asm__ __volatile__(
- #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32
- "subu $29,24\n"
- #elif _MIPS_SIM == _MIPS_SIM_NABI32
- "sub $29,16\n"
- #else
- "dsubu $29,16\n"
- #endif
-
- /* if (fn == NULL || child_stack == NULL)
- * return -EINVAL;
- */
- "li %0,%2\n"
- "beqz %5,1f\n"
- "beqz %6,1f\n"
-
- /* Push "arg" and "fn" onto the stack that will be
- * used by the child.
- */
- #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32
- "subu %6,32\n"
- "sw %5,0(%6)\n"
- "sw %8,4(%6)\n"
- #elif _MIPS_SIM == _MIPS_SIM_NABI32
- "sub %6,32\n"
- "sw %5,0(%6)\n"
- "sw %8,8(%6)\n"
- #else
- "dsubu %6,32\n"
- "sd %5,0(%6)\n"
- "sd %8,8(%6)\n"
- #endif
-
- /* $7 = syscall($4 = flags,
- * $5 = child_stack,
- * $6 = parent_tidptr,
- * $7 = newtls,
- * $8 = child_tidptr)
- */
- "li $2,%3\n"
- "syscall\n"
-
- /* if ($7 != 0)
- * return $2;
- */
- "bnez $7,1f\n"
- "bnez $2,1f\n"
-
- /* In the child, now. Call "fn(arg)".
- */
- #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32
- "lw $25,0($29)\n"
- "lw $4,4($29)\n"
- #elif _MIPS_SIM == _MIPS_SIM_NABI32
- "lw $25,0($29)\n"
- "lw $4,8($29)\n"
- #else
- "ld $25,0($29)\n"
- "ld $4,8($29)\n"
- #endif
- "jalr $25\n"
-
- /* Call _exit($2)
- */
- "move $4,$2\n"
- "li $2,%4\n"
- "syscall\n"
-
- "1:\n"
- #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32
- "addu $29, 24\n"
- #elif _MIPS_SIM == _MIPS_SIM_NABI32
- "add $29, 16\n"
- #else
- "daddu $29,16\n"
- #endif
- : "=&r" (__v0), "=r" (__r7)
- : "i"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit),
- "r"(fn), "r"(__stack), "r"(__flags), "r"(arg),
- "r"(__ptid), "r"(__r7), "r"(__ctid)
- : "$9", "$10", "$11", "$12", "$13", "$14", "$15",
- "$24", "memory");
- }
- LSS_RETURN(int, __v0, __r7);
- }
- #elif defined (__PPC__)
- #undef LSS_LOADARGS_0
- #define LSS_LOADARGS_0(name, dummy...) \
- __sc_0 = __NR_##name
- #undef LSS_LOADARGS_1
- #define LSS_LOADARGS_1(name, arg1) \
- LSS_LOADARGS_0(name); \
- __sc_3 = (unsigned long) (arg1)
- #undef LSS_LOADARGS_2
- #define LSS_LOADARGS_2(name, arg1, arg2) \
- LSS_LOADARGS_1(name, arg1); \
- __sc_4 = (unsigned long) (arg2)
- #undef LSS_LOADARGS_3
- #define LSS_LOADARGS_3(name, arg1, arg2, arg3) \
- LSS_LOADARGS_2(name, arg1, arg2); \
- __sc_5 = (unsigned long) (arg3)
- #undef LSS_LOADARGS_4
- #define LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4) \
- LSS_LOADARGS_3(name, arg1, arg2, arg3); \
- __sc_6 = (unsigned long) (arg4)
- #undef LSS_LOADARGS_5
- #define LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5) \
- LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4); \
- __sc_7 = (unsigned long) (arg5)
- #undef LSS_LOADARGS_6
- #define LSS_LOADARGS_6(name, arg1, arg2, arg3, arg4, arg5, arg6) \
- LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5); \
- __sc_8 = (unsigned long) (arg6)
- #undef LSS_ASMINPUT_0
- #define LSS_ASMINPUT_0 "0" (__sc_0)
- #undef LSS_ASMINPUT_1
- #define LSS_ASMINPUT_1 LSS_ASMINPUT_0, "1" (__sc_3)
- #undef LSS_ASMINPUT_2
- #define LSS_ASMINPUT_2 LSS_ASMINPUT_1, "2" (__sc_4)
- #undef LSS_ASMINPUT_3
- #define LSS_ASMINPUT_3 LSS_ASMINPUT_2, "3" (__sc_5)
- #undef LSS_ASMINPUT_4
- #define LSS_ASMINPUT_4 LSS_ASMINPUT_3, "4" (__sc_6)
- #undef LSS_ASMINPUT_5
- #define LSS_ASMINPUT_5 LSS_ASMINPUT_4, "5" (__sc_7)
- #undef LSS_ASMINPUT_6
- #define LSS_ASMINPUT_6 LSS_ASMINPUT_5, "6" (__sc_8)
- #undef LSS_BODY
- #define LSS_BODY(nr, type, name, args...) \
- long __sc_ret, __sc_err; \
- { \
- register unsigned long __sc_0 __asm__ ("r0"); \
- register unsigned long __sc_3 __asm__ ("r3"); \
- register unsigned long __sc_4 __asm__ ("r4"); \
- register unsigned long __sc_5 __asm__ ("r5"); \
- register unsigned long __sc_6 __asm__ ("r6"); \
- register unsigned long __sc_7 __asm__ ("r7"); \
- register unsigned long __sc_8 __asm__ ("r8"); \
- \
- LSS_LOADARGS_##nr(name, args); \
- __asm__ __volatile__ \
- ("sc\n\t" \
- "mfcr %0" \
- : "=&r" (__sc_0), \
- "=&r" (__sc_3), "=&r" (__sc_4), \
- "=&r" (__sc_5), "=&r" (__sc_6), \
- "=&r" (__sc_7), "=&r" (__sc_8) \
- : LSS_ASMINPUT_##nr \
- : "cr0", "ctr", "memory", \
- "r9", "r10", "r11", "r12"); \
- __sc_ret = __sc_3; \
- __sc_err = __sc_0; \
- } \
- LSS_RETURN(type, __sc_ret, __sc_err)
- #undef _syscall0
- #define _syscall0(type, name) \
- type LSS_NAME(name)(void) { \
- LSS_BODY(0, type, name); \
- }
- #undef _syscall1
- #define _syscall1(type, name, type1, arg1) \
- type LSS_NAME(name)(type1 arg1) { \
- LSS_BODY(1, type, name, arg1); \
- }
- #undef _syscall2
- #define _syscall2(type, name, type1, arg1, type2, arg2) \
- type LSS_NAME(name)(type1 arg1, type2 arg2) { \
- LSS_BODY(2, type, name, arg1, arg2); \
- }
- #undef _syscall3
- #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \
- LSS_BODY(3, type, name, arg1, arg2, arg3); \
- }
- #undef _syscall4
- #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
- type4, arg4) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
- LSS_BODY(4, type, name, arg1, arg2, arg3, arg4); \
- }
- #undef _syscall5
- #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
- type4, arg4, type5, arg5) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5) { \
- LSS_BODY(5, type, name, arg1, arg2, arg3, arg4, arg5); \
- }
- #undef _syscall6
- #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
- type4, arg4, type5, arg5, type6, arg6) \
- type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5, type6 arg6) { \
- LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \
- }
- /* clone function adapted from glibc 2.3.6 clone.S */
- /* TODO(csilvers): consider wrapping some args up in a struct, like we
- * do for i386's _syscall6, so we can compile successfully on gcc 2.95
- */
- LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
- int flags, void *arg, int *parent_tidptr,
- void *newtls, int *child_tidptr) {
- long __ret, __err;
- {
- register int (*__fn)(void *) __asm__ ("r8") = fn;
- register void *__cstack __asm__ ("r4") = child_stack;
- register int __flags __asm__ ("r3") = flags;
- register void * __arg __asm__ ("r9") = arg;
- register int * __ptidptr __asm__ ("r5") = parent_tidptr;
- register void * __newtls __asm__ ("r6") = newtls;
- register int * __ctidptr __asm__ ("r7") = child_tidptr;
- __asm__ __volatile__(
- /* check for fn == NULL
- * and child_stack == NULL
- */
- "cmpwi cr0, %6, 0\n\t"
- "cmpwi cr1, %7, 0\n\t"
- "cror cr0*4+eq, cr1*4+eq, cr0*4+eq\n\t"
- "beq- cr0, 1f\n\t"
-
- /* set up stack frame for child */
- "clrrwi %7, %7, 4\n\t"
- "li 0, 0\n\t"
- "stwu 0, -16(%7)\n\t"
-
- /* fn, arg, child_stack are saved across the syscall: r28-30 */
- "mr 28, %6\n\t"
- "mr 29, %7\n\t"
- "mr 27, %9\n\t"
-
- /* syscall */
- "li 0, %4\n\t"
- /* flags already in r3
- * child_stack already in r4
- * ptidptr already in r5
- * newtls already in r6
- * ctidptr already in r7
- */
- "sc\n\t"
-
- /* Test if syscall was successful */
- "cmpwi cr1, 3, 0\n\t"
- "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
- "bne- cr1, 1f\n\t"
-
- /* Do the function call */
- "mtctr 28\n\t"
- "mr 3, 27\n\t"
- "bctrl\n\t"
-
- /* Call _exit(r3) */
- "li 0, %5\n\t"
- "sc\n\t"
-
- /* Return to parent */
- "1:\n"
- "mfcr %1\n\t"
- "mr %0, 3\n\t"
- : "=r" (__ret), "=r" (__err)
- : "0" (-1), "1" (EINVAL),
- "i" (__NR_clone), "i" (__NR_exit),
- "r" (__fn), "r" (__cstack), "r" (__flags),
- "r" (__arg), "r" (__ptidptr), "r" (__newtls),
- "r" (__ctidptr)
- : "cr0", "cr1", "memory", "ctr",
- "r0", "r29", "r27", "r28");
- }
- LSS_RETURN(int, __ret, __err);
- }
- #endif
- #define __NR__exit __NR_exit
- #define __NR__gettid __NR_gettid
- #define __NR__mremap __NR_mremap
- LSS_INLINE _syscall1(int, chdir, const char *,p)
- LSS_INLINE _syscall1(int, close, int, f)
- LSS_INLINE _syscall1(int, dup, int, f)
- LSS_INLINE _syscall2(int, dup2, int, s,
- int, d)
- LSS_INLINE _syscall3(int, execve, const char*, f,
- const char*const*,a,const char*const*, e)
- LSS_INLINE _syscall1(int, _exit, int, e)
- LSS_INLINE _syscall3(int, fcntl, int, f,
- int, c, long, a)
- LSS_INLINE _syscall0(pid_t, fork)
- LSS_INLINE _syscall2(int, fstat, int, f,
- struct kernel_stat*, b)
- LSS_INLINE _syscall2(int, fstatfs, int, f,
- struct kernel_statfs*, b)
- LSS_INLINE _syscall4(int, futex, int*, a,
- int, o, int, v,
- struct kernel_timespec*, t)
- LSS_INLINE _syscall3(int, getdents, int, f,
- struct kernel_dirent*, d, int, c)
- LSS_INLINE _syscall3(int, getdents64, int, f,
- struct kernel_dirent64*, d, int, c)
- LSS_INLINE _syscall0(gid_t, getegid)
- LSS_INLINE _syscall0(uid_t, geteuid)
- LSS_INLINE _syscall0(pid_t, getpgrp)
- LSS_INLINE _syscall0(pid_t, getpid)
- LSS_INLINE _syscall0(pid_t, getppid)
- LSS_INLINE _syscall2(int, getpriority, int, a,
- int, b)
- LSS_INLINE _syscall2(int, getrlimit, int, r,
- struct kernel_rlimit*, l)
- LSS_INLINE _syscall1(pid_t, getsid, pid_t, p)
- LSS_INLINE _syscall0(pid_t, _gettid)
- LSS_INLINE _syscall5(int, setxattr, const char *,p,
- const char *, n, const void *,v,
- size_t, s, int, f)
- LSS_INLINE _syscall5(int, lsetxattr, const char *,p,
- const char *, n, const void *,v,
- size_t, s, int, f)
- LSS_INLINE _syscall4(ssize_t, getxattr, const char *,p,
- const char *, n, void *, v, size_t, s)
- LSS_INLINE _syscall4(ssize_t, lgetxattr, const char *,p,
- const char *, n, void *, v, size_t, s)
- LSS_INLINE _syscall2(int, kill, pid_t, p,
- int, s)
- LSS_INLINE _syscall3(off_t, lseek, int, f,
- off_t, o, int, w)
- LSS_INLINE _syscall2(int, munmap, void*, s,
- size_t, l)
- LSS_INLINE _syscall6(long, move_pages, pid_t, p,
- unsigned long, n, void **,g, int *, d,
- int *, s, int, f)
- LSS_INLINE _syscall5(void*, _mremap, void*, o,
- size_t, os, size_t, ns,
- unsigned long, f, void *, a)
- LSS_INLINE _syscall3(int, open, const char*, p,
- int, f, int, m)
- LSS_INLINE _syscall3(int, poll, struct kernel_pollfd*, u,
- unsigned int, n, int, t)
- LSS_INLINE _syscall2(int, prctl, int, o,
- long, a)
- LSS_INLINE _syscall4(long, ptrace, int, r,
- pid_t, p, void *, a, void *, d)
- LSS_INLINE _syscall3(ssize_t, read, int, f,
- void *, b, size_t, c)
- LSS_INLINE _syscall3(int, readlink, const char*, p,
- char*, b, size_t, s)
- LSS_INLINE _syscall4(int, rt_sigaction, int, s,
- const struct kernel_sigaction*, a,
- struct kernel_sigaction*, o, size_t, c)
- LSS_INLINE _syscall2(int, rt_sigpending, struct kernel_sigset_t *, s,
- size_t, c)
- LSS_INLINE _syscall4(int, rt_sigprocmask, int, h,
- const struct kernel_sigset_t*, s,
- struct kernel_sigset_t*, o, size_t, c);
- LSS_INLINE _syscall2(int, rt_sigsuspend,
- const struct kernel_sigset_t*, s, size_t, c);
- LSS_INLINE _syscall3(int, sched_getaffinity,pid_t, p,
- unsigned int, l, unsigned long *, m)
- LSS_INLINE _syscall3(int, sched_setaffinity,pid_t, p,
- unsigned int, l, unsigned long *, m)
- LSS_INLINE _syscall0(int, sched_yield)
- LSS_INLINE _syscall1(long, set_tid_address, int *, t)
- LSS_INLINE _syscall1(int, setfsgid, gid_t, g)
- LSS_INLINE _syscall1(int, setfsuid, uid_t, u)
- LSS_INLINE _syscall2(int, setpgid, pid_t, p,
- pid_t, g)
- LSS_INLINE _syscall3(int, setpriority, int, a,
- int, b, int, p)
- LSS_INLINE _syscall3(int, setresgid, gid_t, r,
- gid_t, e, gid_t, s)
- LSS_INLINE _syscall3(int, setresuid, uid_t, r,
- uid_t, e, uid_t, s)
- LSS_INLINE _syscall2(int, setrlimit, int, r,
- const struct kernel_rlimit*, l)
- LSS_INLINE _syscall0(pid_t, setsid)
- LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s,
- const stack_t*, o)
- LSS_INLINE _syscall2(int, stat, const char*, f,
- struct kernel_stat*, b)
- LSS_INLINE _syscall2(int, statfs, const char*, f,
- struct kernel_statfs*, b)
- LSS_INLINE _syscall1(int, unlink, const char*, f)
- LSS_INLINE _syscall3(ssize_t, write, int, f,
- const void *, b, size_t, c)
- LSS_INLINE _syscall3(ssize_t, writev, int, f,
- const struct kernel_iovec*, v, size_t, c)
- #if defined(__x86_64__) || \
- (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32)
- LSS_INLINE _syscall3(int, recvmsg, int, s,
- struct kernel_msghdr*, m, int, f)
- LSS_INLINE _syscall3(int, sendmsg, int, s,
- const struct kernel_msghdr*, m, int, f)
- LSS_INLINE _syscall6(int, sendto, int, s,
- const void*, m, size_t, l,
- int, f,
- const struct kernel_sockaddr*, a, int, t)
- LSS_INLINE _syscall2(int, shutdown, int, s,
- int, h)
- LSS_INLINE _syscall3(int, socket, int, d,
- int, t, int, p)
- LSS_INLINE _syscall4(int, socketpair, int, d,
- int, t, int, p, int*, s)
- #endif
- #if defined(__x86_64__)
- LSS_INLINE _syscall6(void*, mmap, void*, s,
- size_t, l, int, p,
- int, f, int, d,
- __off64_t, o)
- LSS_INLINE _syscall4(int, newfstatat, int, d,
- const char *, p,
- struct kernel_stat*, b, int, f)
-
- LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) {
- return LSS_NAME(setfsgid)(gid);
- }
-
- LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) {
- return LSS_NAME(setfsuid)(uid);
- }
-
- LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) {
- return LSS_NAME(setresgid)(rgid, egid, sgid);
- }
-
- LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) {
- return LSS_NAME(setresuid)(ruid, euid, suid);
- }
-
- LSS_INLINE int LSS_NAME(sigaction)(int signum,
- const struct kernel_sigaction *act,
- struct kernel_sigaction *oldact) {
- /* On x86_64, the kernel requires us to always set our own
- * SA_RESTORER in order to be able to return from a signal handler.
- * This function must have a "magic" signature that the "gdb"
- * (and maybe the kernel?) can recognize.
- */
- if (act != NULL && !(act->sa_flags & SA_RESTORER)) {
- struct kernel_sigaction a = *act;
- a.sa_flags |= SA_RESTORER;
- a.sa_restorer = LSS_NAME(restore_rt)();
- return LSS_NAME(rt_sigaction)(signum, &a, oldact,
- (KERNEL_NSIG+7)/8);
- } else {
- return LSS_NAME(rt_sigaction)(signum, act, oldact,
- (KERNEL_NSIG+7)/8);
- }
- }
-
- LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) {
- return LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8);
- }
-
- LSS_INLINE int LSS_NAME(sigprocmask)(int how,
- const struct kernel_sigset_t *set,
- struct kernel_sigset_t *oldset) {
- return LSS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG+7)/8);
- }
-
- LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) {
- return LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8);
- }
- #endif
- #if defined(__x86_64__) || defined(__ARM_ARCH_3__) || \
- (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32)
- LSS_INLINE _syscall4(pid_t, wait4, pid_t, p,
- int*, s, int, o,
- struct kernel_rusage*, r)
-
- LSS_INLINE pid_t LSS_NAME(waitpid)(pid_t pid, int *status, int options){
- return LSS_NAME(wait4)(pid, status, options, 0);
- }
- #endif
- #if defined(__i386__) || defined(__x86_64__)
- LSS_INLINE _syscall4(int, openat, int, d, const char *, p, int, f, int, m)
- LSS_INLINE _syscall3(int, unlinkat, int, d, const char *, p, int, f)
- #endif
- #if defined(__i386__) || defined(__ARM_ARCH_3__)
- #define __NR__setfsgid32 __NR_setfsgid32
- #define __NR__setfsuid32 __NR_setfsuid32
- #define __NR__setresgid32 __NR_setresgid32
- #define __NR__setresuid32 __NR_setresuid32
- LSS_INLINE _syscall2(int, ugetrlimit, int, r,
- struct kernel_rlimit*, l)
- LSS_INLINE _syscall1(int, _setfsgid32, gid_t, f)
- LSS_INLINE _syscall1(int, _setfsuid32, uid_t, f)
- LSS_INLINE _syscall3(int, _setresgid32, gid_t, r,
- gid_t, e, gid_t, s)
- LSS_INLINE _syscall3(int, _setresuid32, uid_t, r,
- uid_t, e, uid_t, s)
-
- LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) {
- int rc;
- if ((rc = LSS_NAME(_setfsgid32)(gid)) < 0 &&
- LSS_ERRNO == ENOSYS) {
- if ((unsigned int)gid & ~0xFFFFu) {
- rc = EINVAL;
- } else {
- rc = LSS_NAME(setfsgid)(gid);
- }
- }
- return rc;
- }
-
- LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) {
- int rc;
- if ((rc = LSS_NAME(_setfsuid32)(uid)) < 0 &&
- LSS_ERRNO == ENOSYS) {
- if ((unsigned int)uid & ~0xFFFFu) {
- rc = EINVAL;
- } else {
- rc = LSS_NAME(setfsuid)(uid);
- }
- }
- return rc;
- }
-
- LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) {
- int rc;
- if ((rc = LSS_NAME(_setresgid32)(rgid, egid, sgid)) < 0 &&
- LSS_ERRNO == ENOSYS) {
- if ((unsigned int)rgid & ~0xFFFFu ||
- (unsigned int)egid & ~0xFFFFu ||
- (unsigned int)sgid & ~0xFFFFu) {
- rc = EINVAL;
- } else {
- rc = LSS_NAME(setresgid)(rgid, egid, sgid);
- }
- }
- return rc;
- }
-
- LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) {
- int rc;
- if ((rc = LSS_NAME(_setresuid32)(ruid, euid, suid)) < 0 &&
- LSS_ERRNO == ENOSYS) {
- if ((unsigned int)ruid & ~0xFFFFu ||
- (unsigned int)euid & ~0xFFFFu ||
- (unsigned int)suid & ~0xFFFFu) {
- rc = EINVAL;
- } else {
- rc = LSS_NAME(setresuid)(ruid, euid, suid);
- }
- }
- return rc;
- }
- #endif
- LSS_INLINE int LSS_NAME(sigemptyset)(struct kernel_sigset_t *set) {
- memset(&set->sig, 0, sizeof(set->sig));
- return 0;
- }
-
- LSS_INLINE int LSS_NAME(sigfillset)(struct kernel_sigset_t *set) {
- memset(&set->sig, -1, sizeof(set->sig));
- return 0;
- }
-
- LSS_INLINE int LSS_NAME(sigaddset)(struct kernel_sigset_t *set,
- int signum) {
- if (signum < 1 || signum > (int)(8*sizeof(set->sig))) {
- LSS_ERRNO = EINVAL;
- return -1;
- } else {
- set->sig[(signum - 1)/(8*sizeof(set->sig[0]))]
- |= 1UL << ((signum - 1) % (8*sizeof(set->sig[0])));
- return 0;
- }
- }
-
- LSS_INLINE int LSS_NAME(sigdelset)(struct kernel_sigset_t *set,
- int signum) {
- if (signum < 1 || signum > (int)(8*sizeof(set->sig))) {
- LSS_ERRNO = EINVAL;
- return -1;
- } else {
- set->sig[(signum - 1)/(8*sizeof(set->sig[0]))]
- &= ~(1UL << ((signum - 1) % (8*sizeof(set->sig[0]))));
- return 0;
- }
- }
-
- LSS_INLINE int LSS_NAME(sigismember)(struct kernel_sigset_t *set,
- int signum) {
- if (signum < 1 || signum > (int)(8*sizeof(set->sig))) {
- LSS_ERRNO = EINVAL;
- return -1;
- } else {
- return !!(set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] &
- (1UL << ((signum - 1) % (8*sizeof(set->sig[0])))));
- }
- }
- #if defined(__i386__) || defined(__ARM_ARCH_3__) || \
- (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || defined(__PPC__)
- #define __NR__sigaction __NR_sigaction
- #define __NR__sigpending __NR_sigpending
- #define __NR__sigprocmask __NR_sigprocmask
- #define __NR__sigsuspend __NR_sigsuspend
- #define __NR__socketcall __NR_socketcall
- LSS_INLINE _syscall2(int, fstat64, int, f,
- struct kernel_stat64 *, b)
- LSS_INLINE _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
- loff_t *, res, uint, wh)
- LSS_INLINE _syscall1(void*, mmap, void*, a)
- LSS_INLINE _syscall6(void*, mmap2, void*, s,
- size_t, l, int, p,
- int, f, int, d,
- __off64_t, o)
- LSS_INLINE _syscall3(int, _sigaction, int, s,
- const struct kernel_old_sigaction*, a,
- struct kernel_old_sigaction*, o)
- LSS_INLINE _syscall1(int, _sigpending, unsigned long*, s)
- LSS_INLINE _syscall3(int, _sigprocmask, int, h,
- const unsigned long*, s,
- unsigned long*, o)
- #ifdef __PPC__
- LSS_INLINE _syscall1(int, _sigsuspend, unsigned long, s)
- #else
- LSS_INLINE _syscall3(int, _sigsuspend, const void*, a,
- int, b,
- unsigned long, s)
- #endif
- LSS_INLINE _syscall2(int, stat64, const char *, p,
- struct kernel_stat64 *, b)
-
- LSS_INLINE int LSS_NAME(sigaction)(int signum,
- const struct kernel_sigaction *act,
- struct kernel_sigaction *oldact) {
- int old_errno = LSS_ERRNO;
- int rc;
- struct kernel_sigaction a;
- if (act != NULL) {
- a = *act;
- #ifdef __i386__
- /* On i386, the kernel requires us to always set our own
- * SA_RESTORER when using realtime signals. Otherwise, it does not
- * know how to return from a signal handler. This function must have
- * a "magic" signature that the "gdb" (and maybe the kernel?) can
- * recognize.
- * Apparently, a SA_RESTORER is implicitly set by the kernel, when
- * using non-realtime signals.
- *
- * TODO: Test whether ARM needs a restorer
- */
- if (!(a.sa_flags & SA_RESTORER)) {
- a.sa_flags |= SA_RESTORER;
- a.sa_restorer = (a.sa_flags & SA_SIGINFO)
- ? LSS_NAME(restore_rt)() : LSS_NAME(restore)();
- }
- #endif
- }
- rc = LSS_NAME(rt_sigaction)(signum, act ? &a : act, oldact,
- (KERNEL_NSIG+7)/8);
- if (rc < 0 && LSS_ERRNO == ENOSYS) {
- struct kernel_old_sigaction oa, ooa, *ptr_a = &oa, *ptr_oa = &ooa;
- if (!act) {
- ptr_a = NULL;
- } else {
- oa.sa_handler_ = act->sa_handler_;
- memcpy(&oa.sa_mask, &act->sa_mask, sizeof(oa.sa_mask));
- #ifndef __mips__
- oa.sa_restorer = act->sa_restorer;
- #endif
- oa.sa_flags = act->sa_flags;
- }
- if (!oldact) {
- ptr_oa = NULL;
- }
- LSS_ERRNO = old_errno;
- rc = LSS_NAME(_sigaction)(signum, ptr_a, ptr_oa);
- if (rc == 0 && oldact) {
- if (act) {
- memcpy(oldact, act, sizeof(*act));
- } else {
- memset(oldact, 0, sizeof(*oldact));
- }
- oldact->sa_handler_ = ptr_oa->sa_handler_;
- oldact->sa_flags = ptr_oa->sa_flags;
- memcpy(&oldact->sa_mask, &ptr_oa->sa_mask, sizeof(ptr_oa->sa_mask));
- #ifndef __mips__
- oldact->sa_restorer = ptr_oa->sa_restorer;
- #endif
- }
- }
- return rc;
- }
-
- LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) {
- int old_errno = LSS_ERRNO;
- int rc = LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8);
- if (rc < 0 && LSS_ERRNO == ENOSYS) {
- LSS_ERRNO = old_errno;
- LSS_NAME(sigemptyset)(set);
- rc = LSS_NAME(_sigpending)(&set->sig[0]);
- }
- return rc;
- }
-
- LSS_INLINE int LSS_NAME(sigprocmask)(int how,
- const struct kernel_sigset_t *set,
- struct kernel_sigset_t *oldset) {
- int olderrno = LSS_ERRNO;
- int rc = LSS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG+7)/8);
- if (rc < 0 && LSS_ERRNO == ENOSYS) {
- LSS_ERRNO = olderrno;
- if (oldset) {
- LSS_NAME(sigemptyset)(oldset);
- }
- rc = LSS_NAME(_sigprocmask)(how,
- set ? &set->sig[0] : NULL,
- oldset ? &oldset->sig[0] : NULL);
- }
- return rc;
- }
-
- LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) {
- int olderrno = LSS_ERRNO;
- int rc = LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8);
- if (rc < 0 && LSS_ERRNO == ENOSYS) {
- LSS_ERRNO = olderrno;
- rc = LSS_NAME(_sigsuspend)(
- #ifndef __PPC__
- set, 0,
- #endif
- set->sig[0]);
- }
- return rc;
- }
- #endif
- #if defined(__PPC__)
- #undef LSS_SC_LOADARGS_0
- #define LSS_SC_LOADARGS_0(dummy...)
- #undef LSS_SC_LOADARGS_1
- #define LSS_SC_LOADARGS_1(arg1) \
- __sc_4 = (unsigned long) (arg1)
- #undef LSS_SC_LOADARGS_2
- #define LSS_SC_LOADARGS_2(arg1, arg2) \
- LSS_SC_LOADARGS_1(arg1); \
- __sc_5 = (unsigned long) (arg2)
- #undef LSS_SC_LOADARGS_3
- #define LSS_SC_LOADARGS_3(arg1, arg2, arg3) \
- LSS_SC_LOADARGS_2(arg1, arg2); \
- __sc_6 = (unsigned long) (arg3)
- #undef LSS_SC_LOADARGS_4
- #define LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4) \
- LSS_SC_LOADARGS_3(arg1, arg2, arg3); \
- __sc_7 = (unsigned long) (arg4)
- #undef LSS_SC_LOADARGS_5
- #define LSS_SC_LOADARGS_5(arg1, arg2, arg3, arg4, arg5) \
- LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4); \
- __sc_8 = (unsigned long) (arg5)
- #undef LSS_SC_BODY
- #define LSS_SC_BODY(nr, type, opt, args...) \
- long __sc_ret, __sc_err; \
- { \
- register unsigned long __sc_0 __asm__ ("r0") = __NR_socketcall; \
- register unsigned long __sc_3 __asm__ ("r3") = opt; \
- register unsigned long __sc_4 __asm__ ("r4"); \
- register unsigned long __sc_5 __asm__ ("r5"); \
- register unsigned long __sc_6 __asm__ ("r6"); \
- register unsigned long __sc_7 __asm__ ("r7"); \
- register unsigned long __sc_8 __asm__ ("r8"); \
- LSS_SC_LOADARGS_##nr(args); \
- __asm__ __volatile__ \
- ("stwu 1, -48(1)\n\t" \
- "stw 4, 20(1)\n\t" \
- "stw 5, 24(1)\n\t" \
- "stw 6, 28(1)\n\t" \
- "stw 7, 32(1)\n\t" \
- "stw 8, 36(1)\n\t" \
- "addi 4, 1, 20\n\t" \
- "sc\n\t" \
- "mfcr %0" \
- : "=&r" (__sc_0), \
- "=&r" (__sc_3), "=&r" (__sc_4), \
- "=&r" (__sc_5), "=&r" (__sc_6), \
- "=&r" (__sc_7), "=&r" (__sc_8) \
- : LSS_ASMINPUT_##nr \
- : "cr0", "ctr", "memory"); \
- __sc_ret = __sc_3; \
- __sc_err = __sc_0; \
- } \
- LSS_RETURN(type, __sc_ret, __sc_err)
-
- LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg,
- int flags){
- LSS_SC_BODY(3, ssize_t, 17, s, msg, flags);
- }
-
- LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s,
- const struct kernel_msghdr *msg,
- int flags) {
- LSS_SC_BODY(3, ssize_t, 16, s, msg, flags);
- }
-
- // TODO(csilvers): why is this ifdef'ed out?
-#if 0
- LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len,
- int flags,
- const struct kernel_sockaddr *to,
- unsigned int tolen) {
- LSS_BODY(6, ssize_t, 11, s, buf, len, flags, to, tolen);
- }
-#endif
-
- LSS_INLINE int LSS_NAME(shutdown)(int s, int how) {
- LSS_SC_BODY(2, int, 13, s, how);
- }
-
- LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) {
- LSS_SC_BODY(3, int, 1, domain, type, protocol);
- }
-
- LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol,
- int sv[2]) {
- LSS_SC_BODY(4, int, 8, d, type, protocol, sv);
- }
- #endif
- #if defined(__i386__) || defined(__ARM_ARCH_3__) || \
- (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32)
- #define __NR__socketcall __NR_socketcall
- LSS_INLINE _syscall2(int, _socketcall, int, c,
- va_list, a)
-
- LSS_INLINE int LSS_NAME(socketcall)(int op, ...) {
- int rc;
- va_list ap;
- va_start(ap, op);
- rc = LSS_NAME(_socketcall)(op, ap);
- va_end(ap);
- return rc;
- }
-
- LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg,
- int flags){
- return (ssize_t)LSS_NAME(socketcall)(17, s, msg, flags);
- }
-
- LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s,
- const struct kernel_msghdr *msg,
- int flags) {
- return (ssize_t)LSS_NAME(socketcall)(16, s, msg, flags);
- }
-
- LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len,
- int flags,
- const struct kernel_sockaddr *to,
- unsigned int tolen) {
- return (ssize_t)LSS_NAME(socketcall)(11, s, buf, len, flags, to, tolen);
- }
-
- LSS_INLINE int LSS_NAME(shutdown)(int s, int how) {
- return LSS_NAME(socketcall)(13, s, how);
- }
-
- LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) {
- return LSS_NAME(socketcall)(1, domain, type, protocol);
- }
-
- LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol,
- int sv[2]) {
- return LSS_NAME(socketcall)(8, d, type, protocol, sv);
- }
- #endif
- #if defined(__i386__) || defined(__PPC__)
- LSS_INLINE _syscall4(int, fstatat64, int, d,
- const char *, p,
- struct kernel_stat64 *, b, int, f)
- #endif
- #if defined(__i386__) || defined(__PPC__) || \
- (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32)
- LSS_INLINE _syscall3(pid_t, waitpid, pid_t, p,
- int*, s, int, o)
- #endif
- #if defined(__mips__)
- /* sys_pipe() on MIPS has non-standard calling conventions, as it returns
- * both file handles through CPU registers.
- */
- LSS_INLINE int LSS_NAME(pipe)(int *p) {
- register unsigned long __v0 __asm__("$2") = __NR_pipe;
- register unsigned long __v1 __asm__("$3");
- register unsigned long __r7 __asm__("$7");
- __asm__ __volatile__ ("syscall\n"
- : "=&r"(__v0), "=&r"(__v1), "+r" (__r7)
- : "0"(__v0)
- : "$8", "$9", "$10", "$11", "$12",
- "$13", "$14", "$15", "$24", "memory");
- if (__r7) {
- LSS_ERRNO = __v0;
- return -1;
- } else {
- p[0] = __v0;
- p[1] = __v1;
- return 0;
- }
- }
- #else
- LSS_INLINE _syscall1(int, pipe, int *, p)
- #endif
- /* TODO(csilvers): see if ppc can/should support this as well */
- #if defined(__i386__) || defined(__ARM_ARCH_3__) || \
- (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64)
- #define __NR__statfs64 __NR_statfs64
- #define __NR__fstatfs64 __NR_fstatfs64
- LSS_INLINE _syscall3(int, _statfs64, const char*, p,
- size_t, s,struct kernel_statfs64*, b)
- LSS_INLINE _syscall3(int, _fstatfs64, int, f,
- size_t, s,struct kernel_statfs64*, b)
- LSS_INLINE int LSS_NAME(statfs64)(const char *p,
- struct kernel_statfs64 *b) {
- return LSS_NAME(_statfs64)(p, sizeof(*b), b);
- }
- LSS_INLINE int LSS_NAME(fstatfs64)(int f,struct kernel_statfs64 *b) {
- return LSS_NAME(_fstatfs64)(f, sizeof(*b), b);
- }
- #endif
-
- LSS_INLINE int LSS_NAME(execv)(const char *path, const char *const argv[]) {
- extern char **environ;
- return LSS_NAME(execve)(path, argv, (const char *const *)environ);
- }
-
- LSS_INLINE pid_t LSS_NAME(gettid)() {
- pid_t tid = LSS_NAME(_gettid)();
- if (tid != -1) {
- return tid;
- }
- return LSS_NAME(getpid)();
- }
-
- LSS_INLINE void *LSS_NAME(mremap)(void *old_address, size_t old_size,
- size_t new_size, int flags, ...) {
- va_list ap;
- void *new_address, *rc;
- va_start(ap, flags);
- new_address = va_arg(ap, void *);
- rc = LSS_NAME(_mremap)(old_address, old_size, new_size,
- flags, new_address);
- va_end(ap);
- return rc;
- }
-
- LSS_INLINE int LSS_NAME(ptrace_detach)(pid_t pid) {
- /* PTRACE_DETACH can sometimes forget to wake up the tracee and it
- * then sends job control signals to the real parent, rather than to
- * the tracer. We reduce the risk of this happening by starting a
- * whole new time slice, and then quickly sending a SIGCONT signal
- * right after detaching from the tracee.
- */
- int rc, err;
- LSS_NAME(sched_yield)();
- rc = LSS_NAME(ptrace)(PTRACE_DETACH, pid, (void *)0, (void *)0);
- err = LSS_ERRNO;
- LSS_NAME(kill)(pid, SIGCONT);
- LSS_ERRNO = err;
- return rc;
- }
-
- LSS_INLINE int LSS_NAME(raise)(int sig) {
- return LSS_NAME(kill)(LSS_NAME(getpid)(), sig);
- }
-
- LSS_INLINE int LSS_NAME(setpgrp)() {
- return LSS_NAME(setpgid)(0, 0);
- }
-
- LSS_INLINE int LSS_NAME(sysconf)(int name) {
- extern int __getpagesize(void);
- switch (name) {
- case _SC_OPEN_MAX: {
- struct kernel_rlimit limit;
- return LSS_NAME(getrlimit)(RLIMIT_NOFILE, &limit) < 0
- ? 8192 : limit.rlim_cur;
- }
- case _SC_PAGESIZE:
- return __getpagesize();
- default:
- errno = ENOSYS;
- return -1;
- }
- }
- #if defined(__x86_64__) || \
- (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI64)
- /* pread64() and pwrite64() do not exist on 64-bit systems... */
- LSS_INLINE _syscall3(int, readahead, int, f,
- loff_t, o, unsigned, c)
- #else
- #define __NR__pread64 __NR_pread64
- #define __NR__pwrite64 __NR_pwrite64
- #define __NR__readahead __NR_readahead
- LSS_INLINE _syscall5(ssize_t, _pread64, int, f,
- void *, b, size_t, c, unsigned, o1,
- unsigned, o2)
- LSS_INLINE _syscall5(ssize_t, _pwrite64, int, f,
- const void *, b, size_t, c, unsigned, o1,
- long, o2)
- LSS_INLINE _syscall4(int, _readahead, int, f,
- unsigned, o1, unsigned, o2, size_t, c);
- /* We force 64bit-wide parameters onto the stack, then access each
- * 32-bit component individually. This guarantees that we build the
- * correct parameters independent of the native byte-order of the
- * underlying architecture.
- */
- LSS_INLINE ssize_t LSS_NAME(pread64)(int fd, void *buf, size_t count,
- loff_t off) {
- union { loff_t off; unsigned arg[2]; } o = { off };
- return LSS_NAME(_pread64)(fd, buf, count, o.arg[0], o.arg[1]);
- }
- LSS_INLINE ssize_t LSS_NAME(pwrite64)(int fd, const void *buf,
- size_t count, loff_t off) {
- union { loff_t off; unsigned arg[2]; } o = { off };
- return LSS_NAME(_pwrite64)(fd, buf, count, o.arg[0], o.arg[1]);
- }
- LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, int len) {
- union { loff_t off; unsigned arg[2]; } o = { off };
- return LSS_NAME(_readahead)(fd, o.arg[0], o.arg[1], len);
- }
- #endif
-#endif
-
-#if defined(__cplusplus) && !defined(SYS_CPLUSPLUS)
-}
-#endif
-
-#endif
-#endif
diff --git a/breakpad/linux/memory.h b/breakpad/linux/memory.h
deleted file mode 100644
index 94e2175..0000000
--- a/breakpad/linux/memory.h
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#ifndef CLIENT_LINUX_HANDLER_MEMORY_H_
-#define CLIENT_LINUX_HANDLER_MEMORY_H_
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-#include "breakpad/linux/linux_syscall_support.h"
-
-namespace google_breakpad {
-
-// This is very simple allocator which fetches pages from the kernel directly.
-// Thus, it can be used even when the heap may be corrupted.
-//
-// There is no free operation. The pages are only freed when the object is
-// destroyed.
-class PageAllocator {
- public:
- PageAllocator()
- : page_size_(getpagesize()),
- last_(NULL),
- current_page_(NULL),
- page_offset_(0) {
- }
-
- ~PageAllocator() {
- FreeAll();
- }
-
- void *Alloc(unsigned bytes) {
- if (!bytes)
- return NULL;
-
- if (current_page_ && page_size_ - page_offset_ >= bytes) {
- uint8_t *const ret = current_page_ + page_offset_;
- page_offset_ += bytes;
- if (page_offset_ == page_size_) {
- page_offset_ = 0;
- current_page_ = NULL;
- }
-
- return ret;
- }
-
- const unsigned pages =
- (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_;
- uint8_t *const ret = GetNPages(pages);
- if (!ret)
- return NULL;
-
- page_offset_ = (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % page_size_;
- current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL;
-
- return ret + sizeof(PageHeader);
- }
-
- private:
- uint8_t *GetNPages(unsigned num_pages) {
-#ifdef __x86_64
- void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-#else
- void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-#endif
- if (a == MAP_FAILED)
- return NULL;
-
- struct PageHeader *header = reinterpret_cast<PageHeader*>(a);
- header->next = last_;
- header->num_pages = num_pages;
- last_ = header;
-
- return reinterpret_cast<uint8_t*>(a);
- }
-
- void FreeAll() {
- PageHeader *next;
-
- for (PageHeader *cur = last_; cur; cur = next) {
- next = cur->next;
- sys_munmap(cur, cur->num_pages * page_size_);
- }
- }
-
- struct PageHeader {
- PageHeader *next; // pointer to the start of the next set of pages.
- unsigned num_pages; // the number of pages in this set.
- };
-
- const unsigned page_size_;
- PageHeader *last_;
- uint8_t *current_page_;
- unsigned page_offset_;
-};
-
-// A wasteful vector is like a normal std::vector, except that it's very much
-// simplier and it allocates memory from a PageAllocator. It's wasteful
-// because, when resizing, it always allocates a whole new array since the
-// PageAllocator doesn't support realloc.
-template<class T>
-class wasteful_vector {
- public:
- wasteful_vector(PageAllocator *allocator, unsigned size_hint = 16)
- : allocator_(allocator),
- a_((T*) allocator->Alloc(sizeof(T) * size_hint)),
- allocated_(size_hint),
- used_(0) {
- }
-
- void push_back(const T& new_element) {
- if (used_ == allocated_)
- Realloc(allocated_ * 2);
- a_[used_++] = new_element;
- }
-
- size_t size() const {
- return used_;
- }
-
- T& operator[](size_t index) {
- return a_[index];
- }
-
- const T& operator[](size_t index) const {
- return a_[index];
- }
-
- private:
- void Realloc(unsigned new_size) {
- T *new_array =
- reinterpret_cast<T*>(allocator_->Alloc(sizeof(T) * new_size));
- memcpy(new_array, a_, used_ * sizeof(T));
- a_ = new_array;
- allocated_ = new_size;
- }
-
- PageAllocator *const allocator_;
- T *a_; // pointer to an array of |allocated_| elements.
- unsigned allocated_; // size of |a_|, in elements.
- unsigned used_; // number of used slots in |a_|.
-};
-
-} // namespace google_breakpad
-
-inline void* operator new(size_t nbytes,
- google_breakpad::PageAllocator& allocator) {
- return allocator.Alloc(nbytes);
-}
-
-#endif // CLIENT_LINUX_HANDLER_MEMORY_H_
diff --git a/breakpad/linux/memory_unittest.cc b/breakpad/linux/memory_unittest.cc
deleted file mode 100644
index 22b6439..0000000
--- a/breakpad/linux/memory_unittest.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#include "breakpad/linux/memory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using namespace google_breakpad;
-
-namespace {
-typedef testing::Test PageAllocatorTest;
-}
-
-TEST(PageAllocatorTest, Setup) {
- PageAllocator allocator;
-}
-
-TEST(PageAllocatorTest, SmallObjects) {
- PageAllocator allocator;
-
- for (unsigned i = 1; i < 1024; ++i) {
- uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
- ASSERT_FALSE(p == NULL);
- memset(p, 0, i);
- }
-}
-
-TEST(PageAllocatorTest, LargeObject) {
- PageAllocator allocator;
-
- uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(10000));
- ASSERT_FALSE(p == NULL);
- for (unsigned i = 1; i < 10; ++i) {
- uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
- ASSERT_FALSE(p == NULL);
- memset(p, 0, i);
- }
-}
-
-namespace {
-typedef testing::Test WastefulVectorTest;
-}
-
-TEST(WastefulVectorTest, Setup) {
- PageAllocator allocator_;
- wasteful_vector<int> v(&allocator_);
- ASSERT_EQ(v.size(), 0u);
-}
-
-TEST(WastefulVectorTest, Simple) {
- PageAllocator allocator_;
- wasteful_vector<int> v(&allocator_);
-
- for (unsigned i = 0; i < 256; ++i)
- v.push_back(i);
- ASSERT_EQ(v.size(), 256u);
- for (unsigned i = 0; i < 256; ++i)
- ASSERT_EQ(v[i], i);
-}
diff --git a/breakpad/linux/minidump-2-core.cc b/breakpad/linux/minidump-2-core.cc
deleted file mode 100644
index db3e5cf..0000000
--- a/breakpad/linux/minidump-2-core.cc
+++ /dev/null
@@ -1,603 +0,0 @@
-// Copyright (c) 2009, 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.
-
-// Converts a minidump file to a core file which gdb can read.
-// Large parts lifted from the userspace core dumper:
-// http://code.google.com/p/google-coredumper/
-//
-// Usage: minidump-2-core 1234.dmp > core
-
-#include <vector>
-
-#include <stdio.h>
-#include <string.h>
-
-#include <elf.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/user.h>
-#include <sys/mman.h>
-
-#include "google_breakpad/common/minidump_format.h"
-#include "google_breakpad/common/minidump_cpu_x86.h"
-#include "breakpad/linux/linux_syscall_support.h"
-#include "breakpad/linux/minidump_format_linux.h"
-
-#if __WORDSIZE == 64
- #define ELF_CLASS ELFCLASS64
- #define Ehdr Elf64_Ehdr
- #define Phdr Elf64_Phdr
- #define Shdr Elf64_Shdr
- #define Nhdr Elf64_Nhdr
- #define auxv_t Elf64_auxv_t
-#else
- #define ELF_CLASS ELFCLASS32
- #define Ehdr Elf32_Ehdr
- #define Phdr Elf32_Phdr
- #define Shdr Elf32_Shdr
- #define Nhdr Elf32_Nhdr
- #define auxv_t Elf32_auxv_t
-#endif
-
-
-#if defined(__x86_64__)
- #define ELF_ARCH EM_X86_64
-#elif defined(__i386__)
- #define ELF_ARCH EM_386
-#elif defined(__ARM_ARCH_3__)
- #define ELF_ARCH EM_ARM
-#elif defined(__mips__)
- #define ELF_ARCH EM_MIPS
-#endif
-
-static int usage(const char* argv0) {
- fprintf(stderr, "Usage: %s <minidump file>\n", argv0);
- return 1;
-}
-
-// Write all of the given buffer, handling short writes and EINTR. Return true
-// iff successful.
-static bool
-writea(int fd, const void* idata, size_t length) {
- const uint8_t* data = (const uint8_t*) idata;
-
- size_t done = 0;
- while (done < length) {
- ssize_t r;
- do {
- r = write(fd, data + done, length - done);
- } while (r == -1 && errno == EINTR);
-
- if (r < 1)
- return false;
- done += r;
- }
-
- return true;
-}
-
-// A range of a mmaped file.
-class MMappedRange {
- public:
- MMappedRange(const void* data, size_t length)
- : data_(reinterpret_cast<const uint8_t*>(data)),
- length_(length) {
- }
-
- // Get an object of |length| bytes at |offset| and return a pointer to it
- // unless it's out of bounds.
- const void* GetObject(size_t offset, size_t length) {
- if (offset + length < offset)
- return NULL;
- if (offset + length > length_)
- return NULL;
- return data_ + offset;
- }
-
- // Get element |index| of an array of objects of length |length| starting at
- // |offset| bytes. Return NULL if out of bounds.
- const void* GetArrayElement(size_t offset, size_t length, unsigned index) {
- const size_t element_offset = offset + index * length;
- return GetObject(element_offset, length);
- }
-
- // Return a new range which is a subset of this range.
- MMappedRange Subrange(const MDLocationDescriptor& location) const {
- if (location.rva > length_ ||
- location.rva + location.data_size < location.rva ||
- location.rva + location.data_size > length_) {
- return MMappedRange(NULL, 0);
- }
-
- return MMappedRange(data_ + location.rva, location.data_size);
- }
-
- const uint8_t* data() const { return data_; }
- size_t length() const { return length_; }
-
- private:
- const uint8_t* const data_;
- const size_t length_;
-};
-
-/* Dynamically determines the byte sex of the system. Returns non-zero
- * for big-endian machines.
- */
-static inline int sex() {
- int probe = 1;
- return !*(char *)&probe;
-}
-
-typedef struct elf_timeval { /* Time value with microsecond resolution */
- long tv_sec; /* Seconds */
- long tv_usec; /* Microseconds */
-} elf_timeval;
-
-typedef struct elf_siginfo { /* Information about signal (unused) */
- int32_t si_signo; /* Signal number */
- int32_t si_code; /* Extra code */
- int32_t si_errno; /* Errno */
-} elf_siginfo;
-
-typedef struct prstatus { /* Information about thread; includes CPU reg*/
- elf_siginfo pr_info; /* Info associated with signal */
- uint16_t pr_cursig; /* Current signal */
- unsigned long pr_sigpend; /* Set of pending signals */
- unsigned long pr_sighold; /* Set of held signals */
- pid_t pr_pid; /* Process ID */
- pid_t pr_ppid; /* Parent's process ID */
- pid_t pr_pgrp; /* Group ID */
- pid_t pr_sid; /* Session ID */
- elf_timeval pr_utime; /* User time */
- elf_timeval pr_stime; /* System time */
- elf_timeval pr_cutime; /* Cumulative user time */
- elf_timeval pr_cstime; /* Cumulative system time */
- user_regs_struct pr_reg; /* CPU registers */
- uint32_t pr_fpvalid; /* True if math co-processor being used */
-} prstatus;
-
-typedef struct prpsinfo { /* Information about process */
- unsigned char pr_state; /* Numeric process state */
- char pr_sname; /* Char for pr_state */
- unsigned char pr_zomb; /* Zombie */
- signed char pr_nice; /* Nice val */
- unsigned long pr_flag; /* Flags */
-#if defined(__x86_64__) || defined(__mips__)
- uint32_t pr_uid; /* User ID */
- uint32_t pr_gid; /* Group ID */
-#else
- uint16_t pr_uid; /* User ID */
- uint16_t pr_gid; /* Group ID */
-#endif
- pid_t pr_pid; /* Process ID */
- pid_t pr_ppid; /* Parent's process ID */
- pid_t pr_pgrp; /* Group ID */
- pid_t pr_sid; /* Session ID */
- char pr_fname[16]; /* Filename of executable */
- char pr_psargs[80]; /* Initial part of arg list */
-} prpsinfo;
-
-// We parse the minidump file and keep the parsed information in this structure.
-struct CrashedProcess {
- CrashedProcess()
- : crashing_tid(-1),
- auxv(NULL),
- auxv_length(0) {
- memset(&prps, 0, sizeof(prps));
- prps.pr_sname = 'R';
- }
-
- struct Mapping {
- uint64_t start_address, end_address;
- };
- std::vector<Mapping> mappings;
-
- pid_t crashing_tid;
- int fatal_signal;
-
- struct Thread {
- pid_t tid;
- user_regs_struct regs;
- user_fpregs_struct fpregs;
- user_fpxregs_struct fpxregs;
- uintptr_t stack_addr;
- const uint8_t* stack;
- size_t stack_length;
- };
- std::vector<Thread> threads;
-
- const uint8_t* auxv;
- size_t auxv_length;
-
- prpsinfo prps;
-};
-
-static uint32_t
-U32(const uint8_t* data) {
- uint32_t v;
- memcpy(&v, data, sizeof(v));
- return v;
-}
-
-static uint16_t
-U16(const uint8_t* data) {
- uint16_t v;
- memcpy(&v, data, sizeof(v));
- return v;
-}
-
-#if defined(__i386__)
-static void
-ParseThreadRegisters(CrashedProcess::Thread* thread, MMappedRange range) {
- const MDRawContextX86* rawregs =
- (const MDRawContextX86*) range.GetObject(0, sizeof(MDRawContextX86));
-
- thread->regs.ebx = rawregs->ebx;
- thread->regs.ecx = rawregs->ecx;
- thread->regs.edx = rawregs->edx;
- thread->regs.esi = rawregs->esi;
- thread->regs.edi = rawregs->edi;
- thread->regs.ebp = rawregs->ebp;
- thread->regs.eax = rawregs->eax;
- thread->regs.xds = rawregs->ds;
- thread->regs.xes = rawregs->es;
- thread->regs.xfs = rawregs->fs;
- thread->regs.xgs = rawregs->gs;
- thread->regs.orig_eax = rawregs->eax;
- thread->regs.eip = rawregs->eip;
- thread->regs.xcs = rawregs->cs;
- thread->regs.eflags = rawregs->eflags;
- thread->regs.esp = rawregs->esp;
- thread->regs.xss = rawregs->ss;
-
- thread->fpregs.cwd = rawregs->float_save.control_word;
- thread->fpregs.swd = rawregs->float_save.status_word;
- thread->fpregs.twd = rawregs->float_save.tag_word;
- thread->fpregs.fip = rawregs->float_save.error_offset;
- thread->fpregs.fcs = rawregs->float_save.error_selector;
- thread->fpregs.foo = rawregs->float_save.data_offset;
- thread->fpregs.fos = rawregs->float_save.data_selector;
- memcpy(thread->fpregs.st_space, rawregs->float_save.register_area,
- 10 * 8);
-
- thread->fpxregs.cwd = rawregs->float_save.control_word;
- thread->fpxregs.swd = rawregs->float_save.status_word;
- thread->fpxregs.twd = rawregs->float_save.tag_word;
- thread->fpxregs.fop = U16(rawregs->extended_registers + 6);
- thread->fpxregs.fip = U16(rawregs->extended_registers + 8);
- thread->fpxregs.fcs = U16(rawregs->extended_registers + 12);
- thread->fpxregs.foo = U16(rawregs->extended_registers + 16);
- thread->fpxregs.fos = U16(rawregs->extended_registers + 20);
- thread->fpxregs.mxcsr = U32(rawregs->extended_registers + 24);
- memcpy(thread->fpxregs.st_space, rawregs->extended_registers + 32, 128);
- memcpy(thread->fpxregs.xmm_space, rawregs->extended_registers + 160, 128);
-}
-#else
-#error "This code has not been ported to your platform yet"
-#endif
-
-static void
-ParseThreadList(CrashedProcess* crashinfo, MMappedRange range,
- const MMappedRange& full_file) {
- const uint32_t num_threads =
- *(const uint32_t*) range.GetObject(0, sizeof(uint32_t));
- for (unsigned i = 0; i < num_threads; ++i) {
- CrashedProcess::Thread thread;
- memset(&thread, 0, sizeof(thread));
- const MDRawThread* rawthread =
- (MDRawThread*) range.GetArrayElement(sizeof(uint32_t),
- sizeof(MDRawThread), i);
- thread.tid = rawthread->thread_id;
- thread.stack_addr = rawthread->stack.start_of_memory_range;
- MMappedRange stack_range = full_file.Subrange(rawthread->stack.memory);
- thread.stack = stack_range.data();
- thread.stack_length = rawthread->stack.memory.data_size;
-
- ParseThreadRegisters(&thread,
- full_file.Subrange(rawthread->thread_context));
-
- crashinfo->threads.push_back(thread);
- }
-}
-
-static void
-ParseAuxVector(CrashedProcess* crashinfo, MMappedRange range) {
- crashinfo->auxv = range.data();
- crashinfo->auxv_length = range.length();
-}
-
-static void
-ParseCmdLine(CrashedProcess* crashinfo, MMappedRange range) {
- const char* cmdline = (const char*) range.data();
- for (size_t i = 0; i < range.length(); ++i) {
- if (cmdline[i] == 0) {
- static const size_t fname_len = sizeof(crashinfo->prps.pr_fname) - 1;
- static const size_t args_len = sizeof(crashinfo->prps.pr_psargs) - 1;
- memset(crashinfo->prps.pr_fname, 0, fname_len + 1);
- memset(crashinfo->prps.pr_psargs, 0, args_len + 1);
- const char* binary_name = strrchr(cmdline, '/');
- if (binary_name) {
- binary_name++;
- const unsigned len = strlen(binary_name);
- memcpy(crashinfo->prps.pr_fname, binary_name,
- len > fname_len ? fname_len : len);
- } else {
- memcpy(crashinfo->prps.pr_fname, cmdline,
- i > fname_len ? fname_len : i);
- }
-
- const unsigned len = range.length() > args_len ?
- args_len : range.length();
- memcpy(crashinfo->prps.pr_psargs, cmdline, len);
- for (unsigned i = 0; i < len; ++i) {
- if (crashinfo->prps.pr_psargs[i] == 0)
- crashinfo->prps.pr_psargs[i] = ' ';
- }
- }
- }
-}
-
-static void
-ParseExceptionStream(CrashedProcess* crashinfo, MMappedRange range) {
- const MDRawExceptionStream* exp =
- (MDRawExceptionStream*) range.GetObject(0, sizeof(MDRawExceptionStream));
- crashinfo->crashing_tid = exp->thread_id;
- crashinfo->fatal_signal = (int) exp->exception_record.exception_code;
-}
-
-static bool
-WriteThread(const CrashedProcess::Thread& thread, int fatal_signal) {
- struct prstatus pr;
- memset(&pr, 0, sizeof(pr));
-
- pr.pr_info.si_signo = fatal_signal;
- pr.pr_cursig = fatal_signal;
- pr.pr_pid = thread.tid;
- memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct));
-
- Nhdr nhdr;
- memset(&nhdr, 0, sizeof(nhdr));
- nhdr.n_namesz = 5;
- nhdr.n_descsz = sizeof(struct prstatus);
- nhdr.n_type = NT_PRSTATUS;
- if (!writea(1, &nhdr, sizeof(nhdr)) ||
- !writea(1, "CORE\0\0\0\0", 8) ||
- !writea(1, &pr, sizeof(struct prstatus))) {
- return false;
- }
-
- nhdr.n_descsz = sizeof(user_fpregs_struct);
- nhdr.n_type = NT_FPREGSET;
- if (!writea(1, &nhdr, sizeof(nhdr)) ||
- !writea(1, "CORE\0\0\0\0", 8) ||
- !writea(1, &thread.fpregs, sizeof(user_fpregs_struct))) {
- return false;
- }
-
- nhdr.n_descsz = sizeof(user_fpxregs_struct);
- nhdr.n_type = NT_PRXFPREG;
- if (!writea(1, &nhdr, sizeof(nhdr)) ||
- !writea(1, "LINUX\0\0\0", 8) ||
- !writea(1, &thread.fpxregs, sizeof(user_fpxregs_struct))) {
- return false;
- }
-
- return true;
-}
-
-static void
-ParseModuleStream(CrashedProcess* crashinfo, MMappedRange range) {
- const uint32_t num_mappings =
- *(const uint32_t*) range.GetObject(0, sizeof(uint32_t));
- for (unsigned i = 0; i < num_mappings; ++i) {
- CrashedProcess::Mapping mapping;
- const MDRawModule* rawmodule =
- (MDRawModule*) range.GetArrayElement(sizeof(uint32_t),
- MD_MODULE_SIZE, i);
- mapping.start_address = rawmodule->base_of_image;
- mapping.end_address = rawmodule->size_of_image + rawmodule->base_of_image;
-
- crashinfo->mappings.push_back(mapping);
- }
-}
-
-int
-main(int argc, char** argv) {
- if (argc != 2)
- return usage(argv[0]);
-
- const int fd = open(argv[1], O_RDONLY);
- if (fd < 0)
- return usage(argv[0]);
-
- struct stat st;
- fstat(fd, &st);
-
- const void* bytes = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
- close(fd);
- if (bytes == MAP_FAILED) {
- perror("Failed to mmap dump file");
- return 1;
- }
-
- MMappedRange dump(bytes, st.st_size);
-
- const MDRawHeader* header =
- (const MDRawHeader*) dump.GetObject(0, sizeof(MDRawHeader));
-
- CrashedProcess crashinfo;
-
- for (unsigned i = 0; i < header->stream_count; ++i) {
- const MDRawDirectory* dirent =
- (const MDRawDirectory*) dump.GetArrayElement(
- header->stream_directory_rva, sizeof(MDRawDirectory), i);
- switch (dirent->stream_type) {
- case MD_THREAD_LIST_STREAM:
- ParseThreadList(&crashinfo, dump.Subrange(dirent->location), dump);
- break;
- case MD_LINUX_AUXV:
- ParseAuxVector(&crashinfo, dump.Subrange(dirent->location));
- break;
- case MD_LINUX_CMD_LINE:
- ParseCmdLine(&crashinfo, dump.Subrange(dirent->location));
- break;
- case MD_EXCEPTION_STREAM:
- ParseExceptionStream(&crashinfo, dump.Subrange(dirent->location));
- break;
- case MD_MODULE_LIST_STREAM:
- ParseModuleStream(&crashinfo, dump.Subrange(dirent->location));
- default:
- fprintf(stderr, "Skipping %x\n", dirent->stream_type);
- }
- }
-
- // Write the ELF header. The file will look like:
- // ELF header
- // Phdr for the PT_NOTE
- // Phdr for each of the thread stacks
- // PT_NOTE
- // each of the thread stacks
- Ehdr ehdr;
- memset(&ehdr, 0, sizeof(Ehdr));
- ehdr.e_ident[0] = ELFMAG0;
- ehdr.e_ident[1] = ELFMAG1;
- ehdr.e_ident[2] = ELFMAG2;
- ehdr.e_ident[3] = ELFMAG3;
- ehdr.e_ident[4] = ELF_CLASS;
- ehdr.e_ident[5] = sex() ? ELFDATA2MSB : ELFDATA2LSB;
- ehdr.e_ident[6] = EV_CURRENT;
- ehdr.e_type = ET_CORE;
- ehdr.e_machine = ELF_ARCH;
- ehdr.e_version = EV_CURRENT;
- ehdr.e_phoff = sizeof(Ehdr);
- ehdr.e_ehsize = sizeof(Ehdr);
- ehdr.e_phentsize= sizeof(Phdr);
- ehdr.e_phnum = 1 + crashinfo.threads.size() + crashinfo.mappings.size();
- ehdr.e_shentsize= sizeof(Shdr);
- if (!writea(1, &ehdr, sizeof(Ehdr)))
- return 1;
-
- size_t offset = sizeof(Ehdr) +
- (1 + crashinfo.threads.size() +
- crashinfo.mappings.size()) * sizeof(Phdr);
- size_t filesz = sizeof(Nhdr) + 8 + sizeof(prpsinfo) +
- // sizeof(Nhdr) + 8 + sizeof(user) +
- sizeof(Nhdr) + 8 + crashinfo.auxv_length +
- crashinfo.threads.size() * (
- (sizeof(Nhdr) + 8 + sizeof(prstatus)) +
- sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct) +
- sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct));
-
- Phdr phdr;
- memset(&phdr, 0, sizeof(Phdr));
- phdr.p_type = PT_NOTE;
- phdr.p_offset = offset;
- phdr.p_filesz = filesz;
- if (!writea(1, &phdr, sizeof(phdr)))
- return 1;
-
- phdr.p_type = PT_LOAD;
- phdr.p_align = getpagesize();
- size_t note_align = phdr.p_align - ((offset+filesz) % phdr.p_align);
- if (note_align == phdr.p_align)
- note_align = 0;
- offset += note_align;
-
- for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
- const CrashedProcess::Thread& thread = crashinfo.threads[i];
- offset += filesz;
- filesz = thread.stack_length;
- phdr.p_offset = offset;
- phdr.p_vaddr = thread.stack_addr;
- phdr.p_filesz = phdr.p_memsz = filesz;
- phdr.p_flags = PF_R | PF_W;
- if (!writea(1, &phdr, sizeof(phdr)))
- return 1;
- }
-
- for (unsigned i = 0; i < crashinfo.mappings.size(); ++i) {
- const CrashedProcess::Mapping& mapping = crashinfo.mappings[i];
- phdr.p_offset = 0;
- phdr.p_vaddr = mapping.start_address;
- phdr.p_filesz = 0;
- phdr.p_flags = PF_R;
- phdr.p_memsz = mapping.end_address - mapping.start_address;
- if (!writea(1, &phdr, sizeof(phdr)))
- return 1;
- }
-
- Nhdr nhdr;
- memset(&nhdr, 0, sizeof(nhdr));
- nhdr.n_namesz = 5;
- nhdr.n_descsz = sizeof(prpsinfo);
- nhdr.n_type = NT_PRPSINFO;
- if (!writea(1, &nhdr, sizeof(nhdr)) ||
- !writea(1, "CORE\0\0\0\0", 8) ||
- !writea(1, &crashinfo.prps, sizeof(prpsinfo))) {
- return 1;
- }
-
- nhdr.n_descsz = crashinfo.auxv_length;
- nhdr.n_type = NT_AUXV;
- if (!writea(1, &nhdr, sizeof(nhdr)) ||
- !writea(1, "CORE\0\0\0\0", 8) ||
- !writea(1, &crashinfo.auxv, crashinfo.auxv_length)) {
- return 1;
- }
-
- for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
- if (crashinfo.threads[i].tid == crashinfo.crashing_tid) {
- WriteThread(crashinfo.threads[i], crashinfo.fatal_signal);
- break;
- }
- }
-
- for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
- if (crashinfo.threads[i].tid != crashinfo.crashing_tid)
- WriteThread(crashinfo.threads[i], 0);
- }
-
- if (note_align) {
- char scratch[note_align];
- memset(scratch, 0, sizeof(scratch));
- if (!writea(1, scratch, sizeof(scratch)))
- return 1;
- }
-
- for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
- const CrashedProcess::Thread& thread = crashinfo.threads[i];
- if (!writea(1, thread.stack, thread.stack_length))
- return 1;
- }
-
- munmap(const_cast<void*>(bytes), st.st_size);
-
- return 0;
-}
diff --git a/breakpad/linux/minidump_file_writer.cc b/breakpad/linux/minidump_file_writer.cc
deleted file mode 100644
index 6b02416..0000000
--- a/breakpad/linux/minidump_file_writer.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright (c) 2006, 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.
-
-// minidump_file_writer.cc: Minidump file writer implementation.
-//
-// See minidump_file_writer.h for documentation.
-
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "breakpad/linux/linux_syscall_support.h"
-#include "breakpad/linux/linux_libc_support.h"
-#include "client/minidump_file_writer-inl.h"
-#include "common/string_conversion.h"
-
-namespace google_breakpad {
-
-const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1);
-
-MinidumpFileWriter::MinidumpFileWriter() : file_(-1), position_(0), size_(0) {
-}
-
-MinidumpFileWriter::~MinidumpFileWriter() {
- Close();
-}
-
-bool MinidumpFileWriter::Open(const char *path) {
- assert(file_ == -1);
- file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
-
- return file_ != -1;
-}
-
-bool MinidumpFileWriter::Close() {
- bool result = true;
-
- if (file_ != -1) {
- ftruncate(file_, position_);
- result = (sys_close(file_) == 0);
- file_ = -1;
- }
-
- return result;
-}
-
-bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
- unsigned int length,
- TypedMDRVA<MDString> *mdstring) {
- bool result = true;
- if (sizeof(wchar_t) == sizeof(u_int16_t)) {
- // Shortcut if wchar_t is the same size as MDString's buffer
- result = mdstring->Copy(str, mdstring->get()->length);
- } else {
- u_int16_t out[2];
- int out_idx = 0;
-
- // Copy the string character by character
- while (length && result) {
- UTF32ToUTF16Char(*str, out);
- if (!out[0])
- return false;
-
- // Process one character at a time
- --length;
- ++str;
-
- // Append the one or two UTF-16 characters. The first one will be non-
- // zero, but the second one may be zero, depending on the conversion from
- // UTF-32.
- int out_count = out[1] ? 2 : 1;
- int out_size = sizeof(u_int16_t) * out_count;
- result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
- out_idx += out_count;
- }
- }
- return result;
-}
-
-bool MinidumpFileWriter::CopyStringToMDString(const char *str,
- unsigned int length,
- TypedMDRVA<MDString> *mdstring) {
- bool result = true;
- u_int16_t out[2];
- int out_idx = 0;
-
- // Copy the string character by character
- while (length && result) {
- int conversion_count = UTF8ToUTF16Char(str, length, out);
- if (!conversion_count)
- return false;
-
- // Move the pointer along based on the nubmer of converted characters
- length -= conversion_count;
- str += conversion_count;
-
- // Append the one or two UTF-16 characters
- int out_count = out[1] ? 2 : 1;
- int out_size = sizeof(u_int16_t) * out_count;
- result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
- out_idx += out_count;
- }
- return result;
-}
-
-template <typename CharType>
-bool MinidumpFileWriter::WriteStringCore(const CharType *str,
- unsigned int length,
- MDLocationDescriptor *location) {
- assert(str);
- assert(location);
- // Calculate the mdstring length by either limiting to |length| as passed in
- // or by finding the location of the NULL character.
- unsigned int mdstring_length = 0;
- if (!length)
- length = INT_MAX;
- for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length)
- ;
-
- // Allocate the string buffer
- TypedMDRVA<MDString> mdstring(this);
- if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(u_int16_t)))
- return false;
-
- // Set length excluding the NULL and copy the string
- mdstring.get()->length = mdstring_length * sizeof(u_int16_t);
- bool result = CopyStringToMDString(str, mdstring_length, &mdstring);
-
- // NULL terminate
- if (result) {
- u_int16_t ch = 0;
- result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch));
-
- if (result)
- *location = mdstring.location();
- }
-
- return result;
-}
-
-bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length,
- MDLocationDescriptor *location) {
- return WriteStringCore(str, length, location);
-}
-
-bool MinidumpFileWriter::WriteString(const char *str, unsigned int length,
- MDLocationDescriptor *location) {
- return WriteStringCore(str, length, location);
-}
-
-bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
- MDMemoryDescriptor *output) {
- assert(src);
- assert(output);
- UntypedMDRVA mem(this);
-
- if (!mem.Allocate(size))
- return false;
- if (!mem.Copy(src, mem.size()))
- return false;
-
- output->start_of_memory_range = reinterpret_cast<u_int64_t>(src);
- output->memory = mem.location();
-
- return true;
-}
-
-MDRVA MinidumpFileWriter::Allocate(size_t size) {
- assert(size);
- assert(file_ != -1);
- size_t aligned_size = (size + 7) & ~7; // 64-bit alignment
-
- if (position_ + aligned_size > size_) {
- size_t growth = aligned_size;
- size_t minimal_growth = getpagesize();
-
- // Ensure that the file grows by at least the size of a memory page
- if (growth < minimal_growth)
- growth = minimal_growth;
-
- size_t new_size = size_ + growth;
- if (ftruncate(file_, new_size) != 0)
- return kInvalidMDRVA;
-
- size_ = new_size;
- }
-
- MDRVA current_position = position_;
- position_ += static_cast<MDRVA>(aligned_size);
-
- return current_position;
-}
-
-bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) {
- assert(src);
- assert(size);
- assert(file_ != -1);
-
- // Ensure that the data will fit in the allocated space
- if (size + position > size_)
- return false;
-
- // Seek and write the data
- if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
- if (sys_write(file_, src, size) == size)
- return true;
- }
-
- return false;
-}
-
-bool UntypedMDRVA::Allocate(size_t size) {
- assert(size_ == 0);
- size_ = size;
- position_ = writer_->Allocate(size_);
- return position_ != MinidumpFileWriter::kInvalidMDRVA;
-}
-
-bool UntypedMDRVA::Copy(MDRVA position, const void *src, size_t size) {
- assert(src);
- assert(size);
- assert(position + size <= position_ + size_);
- return writer_->Copy(position, src, size);
-}
-
-} // namespace google_breakpad
diff --git a/breakpad/linux/minidump_format_linux.h b/breakpad/linux/minidump_format_linux.h
deleted file mode 100644
index b710462..0000000
--- a/breakpad/linux/minidump_format_linux.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#ifndef CLIENT_LINUX_MINIDUMP_FORMAT_LINUX_H_
-#define CLIENT_LINUX_MINIDUMP_FORMAT_LINUX_H_
-
-// These are additional minidump stream values which are specific to the linux
-// breakpad implementation.
-enum {
- MD_LINUX_CPU_INFO = 0x47670003, /* /proc/cpuinfo */
- MD_LINUX_PROC_STATUS = 0x47670004, /* /proc/$x/status */
- MD_LINUX_LSB_RELEASE = 0x47670005, /* /etc/lsb-release */
- MD_LINUX_CMD_LINE = 0x47670006, /* /proc/$x/cmdline */
- MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */
- MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */
-};
-
-#endif // CLIENT_LINUX_MINIDUMP_FORMAT_LINUX_H_
diff --git a/breakpad/linux/minidump_writer.cc b/breakpad/linux/minidump_writer.cc
deleted file mode 100644
index 5252950..0000000
--- a/breakpad/linux/minidump_writer.cc
+++ /dev/null
@@ -1,862 +0,0 @@
-// Copyright (c) 2009, 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.
-
-// This code writes out minidump files:
-// http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
-//
-// Minidumps are a Microsoft format which Breakpad uses for recording crash
-// dumps. This code has to run in a compromised environment (the address space
-// may have received SIGSEGV), thus the following rules apply:
-// * You may not enter the dynamic linker. This means that we cannot call
-// any symbols in a shared library (inc libc). Because of this we replace
-// libc functions in linux_libc_support.h.
-// * You may not call syscalls via the libc wrappers. This rule is a subset
-// of the first rule but it bears repeating. We have direct wrappers
-// around the system calls in linux_syscall_support.h.
-// * You may not malloc. There's an alternative allocator in memory.h and
-// a canonical instance in the LinuxDumper object. We use the placement
-// new form to allocate objects and we don't delete them.
-
-#include "breakpad/linux/minidump_writer.h"
-#include "client/minidump_file_writer-inl.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/ucontext.h>
-#include <sys/user.h>
-#include <sys/utsname.h>
-
-#include "client/minidump_file_writer.h"
-#include "google_breakpad/common/minidump_format.h"
-#include "google_breakpad/common/minidump_cpu_amd64.h"
-#include "google_breakpad/common/minidump_cpu_x86.h"
-
-#include "breakpad/linux/exception_handler.h"
-#include "breakpad/linux/line_reader.h"
-#include "breakpad/linux/linux_dumper.h"
-#include "breakpad/linux/linux_libc_support.h"
-#include "breakpad/linux/linux_syscall_support.h"
-#include "breakpad/linux/minidump_format_linux.h"
-
-// Minidump defines register structures which are different from the raw
-// structures which we get from the kernel. These are platform specific
-// functions to juggle the ucontext and user structures into minidump format.
-#if defined(__i386)
-typedef MDRawContextX86 RawContextCPU;
-
-// Write a uint16_t to memory
-// out: memory location to write to
-// v: value to write.
-static void U16(void* out, uint16_t v) {
- memcpy(out, &v, sizeof(v));
-}
-
-// Write a uint32_t to memory
-// out: memory location to write to
-// v: value to write.
-static void U32(void* out, uint32_t v) {
- memcpy(out, &v, sizeof(v));
-}
-
-// Juggle an x86 user_(fp|fpx|)regs_struct into minidump format
-// out: the minidump structure
-// info: the collection of register structures.
-static void CPUFillFromThreadInfo(MDRawContextX86 *out,
- const google_breakpad::ThreadInfo &info) {
- out->context_flags = MD_CONTEXT_X86_ALL;
-
- out->dr0 = info.dregs[0];
- out->dr1 = info.dregs[1];
- out->dr2 = info.dregs[2];
- out->dr3 = info.dregs[3];
- // 4 and 5 deliberatly omitted because they aren't included in the minidump
- // format.
- out->dr6 = info.dregs[6];
- out->dr7 = info.dregs[7];
-
- out->gs = info.regs.xgs;
- out->fs = info.regs.xfs;
- out->es = info.regs.xes;
- out->ds = info.regs.xds;
-
- out->edi = info.regs.edi;
- out->esi = info.regs.esi;
- out->ebx = info.regs.ebx;
- out->edx = info.regs.edx;
- out->ecx = info.regs.ecx;
- out->eax = info.regs.eax;
-
- out->ebp = info.regs.ebp;
- out->eip = info.regs.eip;
- out->cs = info.regs.xcs;
- out->eflags = info.regs.eflags;
- out->esp = info.regs.esp;
- out->ss = info.regs.xss;
-
- out->float_save.control_word = info.fpregs.cwd;
- out->float_save.status_word = info.fpregs.swd;
- out->float_save.tag_word = info.fpregs.twd;
- out->float_save.error_offset = info.fpregs.fip;
- out->float_save.error_selector = info.fpregs.fcs;
- out->float_save.data_offset = info.fpregs.foo;
- out->float_save.data_selector = info.fpregs.fos;
-
- // 8 registers * 10 bytes per register.
- memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8);
-
- // This matches the Intel fpsave format.
- U16(out->extended_registers + 0, info.fpregs.cwd);
- U16(out->extended_registers + 2, info.fpregs.swd);
- U16(out->extended_registers + 4, info.fpregs.twd);
- U16(out->extended_registers + 6, info.fpxregs.fop);
- U32(out->extended_registers + 8, info.fpxregs.fip);
- U16(out->extended_registers + 12, info.fpxregs.fcs);
- U32(out->extended_registers + 16, info.fpregs.foo);
- U16(out->extended_registers + 20, info.fpregs.fos);
- U32(out->extended_registers + 24, info.fpxregs.mxcsr);
-
- memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128);
- memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128);
-}
-
-// Juggle an x86 ucontext into minidump format
-// out: the minidump structure
-// info: the collection of register structures.
-static void CPUFillFromUContext(MDRawContextX86 *out, const ucontext *uc,
- const struct _libc_fpstate* fp) {
- const greg_t* regs = uc->uc_mcontext.gregs;
-
- out->context_flags = MD_CONTEXT_X86_FULL |
- MD_CONTEXT_X86_FLOATING_POINT;
-
- out->gs = regs[REG_GS];
- out->fs = regs[REG_FS];
- out->es = regs[REG_ES];
- out->ds = regs[REG_DS];
-
- out->edi = regs[REG_EDI];
- out->esi = regs[REG_ESI];
- out->ebx = regs[REG_EBX];
- out->edx = regs[REG_EDX];
- out->ecx = regs[REG_ECX];
- out->eax = regs[REG_EAX];
-
- out->ebp = regs[REG_EBP];
- out->eip = regs[REG_EIP];
- out->cs = regs[REG_CS];
- out->eflags = regs[REG_EFL];
- out->esp = regs[REG_UESP];
- out->ss = regs[REG_SS];
-
- out->float_save.control_word = fp->cw;
- out->float_save.status_word = fp->sw;
- out->float_save.tag_word = fp->tag;
- out->float_save.error_offset = fp->ipoff;
- out->float_save.error_selector = fp->cssel;
- out->float_save.data_offset = fp->dataoff;
- out->float_save.data_selector = fp->datasel;
-
- // 8 registers * 10 bytes per register.
- memcpy(out->float_save.register_area, fp->_st, 10 * 8);
-}
-
-#elif defined(__x86_64)
-typedef MDRawContextAMD64 RawContextCPU;
-
-static void CPUFillFromThreadInfo(MDRawContextAMD64 *out,
- const google_breakpad::ThreadInfo &info) {
- out->context_flags = MD_CONTEXT_AMD64_FULL |
- MD_CONTEXT_AMD64_SEGMENTS;
-
- out->cs = info.regs.cs;
-
- out->ds = info.regs.ds;
- out->es = info.regs.es;
- out->fs = info.regs.fs;
- out->gs = info.regs.gs;
-
- out->ss = info.regs.ss;
- out->eflags = info.regs.eflags;
-
- out->dr0 = info.dregs[0];
- out->dr1 = info.dregs[1];
- out->dr2 = info.dregs[2];
- out->dr3 = info.dregs[3];
- // 4 and 5 deliberatly omitted because they aren't included in the minidump
- // format.
- out->dr6 = info.dregs[6];
- out->dr7 = info.dregs[7];
-
- out->rax = info.regs.rax;
- out->rcx = info.regs.rcx;
- out->rdx = info.regs.rdx;
- out->rbx = info.regs.rbx;
-
- out->rsp = info.regs.rsp;
-
- out->rbp = info.regs.rbp;
- out->rsi = info.regs.rsi;
- out->rdi = info.regs.rdi;
- out->r8 = info.regs.r8;
- out->r9 = info.regs.r9;
- out->r10 = info.regs.r10;
- out->r11 = info.regs.r11;
- out->r12 = info.regs.r12;
- out->r13 = info.regs.r13;
- out->r14 = info.regs.r14;
- out->r15 = info.regs.r15;
-
- out->rip = info.regs.rip;
-
- out->flt_save.control_word = info.fpregs.cwd;
- out->flt_save.status_word = info.fpregs.swd;
- out->flt_save.tag_word = info.fpregs.ftw;
- out->flt_save.error_opcode = info.fpregs.fop;
- out->flt_save.error_offset = info.fpregs.rip;
- out->flt_save.error_selector = 0; // We don't have this.
- out->flt_save.data_offset = info.fpregs.rdp;
- out->flt_save.data_selector = 0; // We don't have this.
- out->flt_save.mx_csr = info.fpregs.mxcsr;
- out->flt_save.mx_csr_mask = info.fpregs.mxcr_mask;
- memcpy(&out->flt_save.float_registers, &info.fpregs.st_space, 8 * 16);
- memcpy(&out->flt_save.xmm_registers, &info.fpregs.xmm_space, 16 * 16);
-}
-
-static void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc,
- const struct _libc_fpstate* fpregs) {
- const greg_t* regs = uc->uc_mcontext.gregs;
-
- out->context_flags = MD_CONTEXT_AMD64_FULL;
-
- out->cs = regs[REG_CSGSFS] & 0xffff;
-
- out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
- out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
-
- out->eflags = regs[REG_EFL];
-
- out->rax = regs[REG_RAX];
- out->rcx = regs[REG_RCX];
- out->rdx = regs[REG_RDX];
- out->rbx = regs[REG_RBX];
-
- out->rsp = regs[REG_RSP];
- out->rbp = regs[REG_RBP];
- out->rsi = regs[REG_RSI];
- out->rdi = regs[REG_RDI];
- out->r8 = regs[REG_R8];
- out->r9 = regs[REG_R9];
- out->r10 = regs[REG_R10];
- out->r11 = regs[REG_R11];
- out->r12 = regs[REG_R12];
- out->r13 = regs[REG_R13];
- out->r14 = regs[REG_R14];
- out->r15 = regs[REG_R15];
-
- out->rip = regs[REG_RIP];
-
- out->flt_save.control_word = fpregs->cwd;
- out->flt_save.status_word = fpregs->swd;
- out->flt_save.tag_word = fpregs->ftw;
- out->flt_save.error_opcode = fpregs->fop;
- out->flt_save.error_offset = fpregs->rip;
- out->flt_save.data_offset = fpregs->rdp;
- out->flt_save.error_selector = 0; // We don't have this.
- out->flt_save.data_selector = 0; // We don't have this.
- out->flt_save.mx_csr = fpregs->mxcsr;
- out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
- memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
- memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
-}
-
-#else
-#error "This code has not been ported to your platform yet."
-#endif
-
-namespace google_breakpad {
-
-class MinidumpWriter {
- public:
- MinidumpWriter(const char* filename,
- pid_t crashing_pid,
- const ExceptionHandler::CrashContext* context)
- : filename_(filename),
- siginfo_(&context->siginfo),
- ucontext_(&context->context),
- float_state_(&context->float_state),
- crashing_tid_(context->tid),
- dumper_(crashing_pid) {
- }
-
- bool Init() {
- return dumper_.Init() && minidump_writer_.Open(filename_) &&
- dumper_.ThreadsSuspend();
- }
-
- ~MinidumpWriter() {
- minidump_writer_.Close();
- dumper_.ThreadsResume();
- }
-
- bool Dump() {
- // A minidump file contains a number of tagged streams. This is the number
- // of stream which we write.
- static const unsigned kNumWriters = 11;
-
- TypedMDRVA<MDRawHeader> header(&minidump_writer_);
- TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
- if (!header.Allocate())
- return false;
- if (!dir.AllocateArray(kNumWriters))
- return false;
- memset(header.get(), 0, sizeof(MDRawHeader));
-
- header.get()->signature = MD_HEADER_SIGNATURE;
- header.get()->version = MD_HEADER_VERSION;
- header.get()->time_date_stamp = time(NULL);
- header.get()->stream_count = kNumWriters;
- header.get()->stream_directory_rva = dir.position();
-
- unsigned dir_index = 0;
- MDRawDirectory dirent;
-
- if (!WriteThreadListStream(&dirent))
- return false;
- dir.CopyIndex(dir_index++, &dirent);
-
- if (!WriteMappings(&dirent))
- return false;
- dir.CopyIndex(dir_index++, &dirent);
-
- if (!WriteExceptionStream(&dirent))
- return false;
- dir.CopyIndex(dir_index++, &dirent);
-
- if (!WriteSystemInfoStream(&dirent))
- return false;
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_CPU_INFO;
- if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_PROC_STATUS;
- if (!WriteProcFile(&dirent.location, crashing_tid_, "status"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_LSB_RELEASE;
- if (!WriteFile(&dirent.location, "/etc/lsb-release"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_CMD_LINE;
- if (!WriteProcFile(&dirent.location, crashing_tid_, "cmdline"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_ENVIRON;
- if (!WriteProcFile(&dirent.location, crashing_tid_, "environ"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_AUXV;
- if (!WriteProcFile(&dirent.location, crashing_tid_, "auxv"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_AUXV;
- if (!WriteProcFile(&dirent.location, crashing_tid_, "maps"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- // If you add more directory entries, don't forget to update kNumWriters,
- // above.
-
- dumper_.ThreadsResume();
- return true;
- }
-
- // Write information about the threads.
- bool WriteThreadListStream(MDRawDirectory* dirent) {
- const unsigned num_threads = dumper_.threads().size();
-
- TypedMDRVA<uint32_t> list(&minidump_writer_);
- if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
- return false;
-
- dirent->stream_type = MD_THREAD_LIST_STREAM;
- dirent->location = list.location();
-
- *list.get() = num_threads;
-
- for (unsigned i = 0; i < num_threads; ++i) {
- MDRawThread thread;
- my_memset(&thread, 0, sizeof(thread));
- thread.thread_id = dumper_.threads()[i];
- // We have a different source of information for the crashing thread. If
- // we used the actual state of the thread we would find it running in the
- // signal handler with the alternative stack, which would be deeply
- // unhelpful.
- if (thread.thread_id == crashing_tid_) {
- const void* stack;
- size_t stack_len;
- if (!dumper_.GetStackInfo(&stack, &stack_len, GetStackPointer()))
- return false;
- UntypedMDRVA memory(&minidump_writer_);
- if (!memory.Allocate(stack_len))
- return false;
- uint8_t* stack_copy = (uint8_t*) dumper_.allocator()->Alloc(stack_len);
- dumper_.CopyFromProcess(stack_copy, thread.thread_id, stack, stack_len);
- memory.Copy(stack_copy, stack_len);
- thread.stack.start_of_memory_range = (uintptr_t) (stack);
- thread.stack.memory = memory.location();
- TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
- if (!cpu.Allocate())
- return false;
- my_memset(cpu.get(), 0, sizeof(RawContextCPU));
- CPUFillFromUContext(cpu.get(), ucontext_, float_state_);
- thread.thread_context = cpu.location();
- crashing_thread_context_ = cpu.location();
- } else {
- ThreadInfo info;
- if (!dumper_.ThreadInfoGet(dumper_.threads()[i], &info))
- return false;
- UntypedMDRVA memory(&minidump_writer_);
- if (!memory.Allocate(info.stack_len))
- return false;
- uint8_t* stack_copy =
- (uint8_t*) dumper_.allocator()->Alloc(info.stack_len);
- dumper_.CopyFromProcess(stack_copy, thread.thread_id, info.stack,
- info.stack_len);
- memory.Copy(stack_copy, info.stack_len);
- thread.stack.start_of_memory_range = (uintptr_t)(info.stack);
- thread.stack.memory = memory.location();
- TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
- if (!cpu.Allocate())
- return false;
- my_memset(cpu.get(), 0, sizeof(RawContextCPU));
- CPUFillFromThreadInfo(cpu.get(), info);
- thread.thread_context = cpu.location();
- }
-
- list.CopyIndexAfterObject(i, &thread, sizeof(thread));
- }
-
- return true;
- }
-
- static bool ShouldIncludeMapping(const MappingInfo& mapping) {
- if (mapping.name[0] == 0 || // we only want modules with filenames.
- mapping.offset || // we only want to include one mapping per shared lib.
- mapping.size < 4096) { // too small to get a signature for.
- return false;
- }
-
- return true;
- }
-
- // Write information about the mappings in effect. Because we are using the
- // minidump format, the information about the mappings is pretty limited.
- // Because of this, we also include the full, unparsed, /proc/$x/maps file in
- // another stream in the file.
- bool WriteMappings(MDRawDirectory* dirent) {
- const unsigned num_mappings = dumper_.mappings().size();
- unsigned num_output_mappings = 0;
-
- for (unsigned i = 0; i < dumper_.mappings().size(); ++i) {
- const MappingInfo& mapping = *dumper_.mappings()[i];
- if (ShouldIncludeMapping(mapping))
- num_output_mappings++;
- }
-
- TypedMDRVA<uint32_t> list(&minidump_writer_);
- if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
- return false;
-
- dirent->stream_type = MD_MODULE_LIST_STREAM;
- dirent->location = list.location();
- *list.get() = num_output_mappings;
-
- for (unsigned i = 0, j = 0; i < num_mappings; ++i) {
- const MappingInfo& mapping = *dumper_.mappings()[i];
- if (!ShouldIncludeMapping(mapping))
- continue;
-
- MDRawModule mod;
- my_memset(&mod, 0, MD_MODULE_SIZE);
- mod.base_of_image = mapping.start_addr;
- mod.size_of_image = mapping.size;
- const size_t filepath_len = my_strlen(mapping.name);
-
- // Figure out file name from path
- const char* filename_ptr = mapping.name + filepath_len - 1;
- while (filename_ptr >= mapping.name) {
- if (*filename_ptr == '/')
- break;
- filename_ptr--;
- }
- filename_ptr++;
- const size_t filename_len = mapping.name + filepath_len - filename_ptr;
-
- uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
- uint8_t* cv_ptr = cv_buf;
- UntypedMDRVA cv(&minidump_writer_);
- if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1))
- return false;
-
- const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
- memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
- cv_ptr += sizeof(cv_signature);
-
- {
- // We XOR the first page of the file to get a signature for it.
- uint8_t xor_buf[sizeof(MDGUID)];
- size_t done = 0;
- uint8_t* signature = cv_ptr;
- cv_ptr += sizeof(xor_buf);
-
- my_memset(signature, 0, sizeof(xor_buf));
- while (done < 4096) {
- dumper_.CopyFromProcess(xor_buf, crashing_tid_,
- (void *) (mod.base_of_image + done),
- sizeof(xor_buf));
- for (unsigned i = 0; i < sizeof(xor_buf); ++i)
- signature[i] ^= xor_buf[i];
- done += sizeof(xor_buf);
- }
- my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux.
- cv_ptr += sizeof(uint32_t);
- }
-
- // Write pdb_file_name
- memcpy(cv_ptr, filename_ptr, filename_len + 1);
- cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1);
-
- mod.cv_record = cv.location();
-
- MDLocationDescriptor ld;
- if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld))
- return false;
- mod.module_name_rva = ld.rva;
-
- list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
- }
-
- return true;
- }
-
- bool WriteExceptionStream(MDRawDirectory* dirent) {
- TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
- if (!exc.Allocate())
- return false;
- my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
-
- dirent->stream_type = MD_EXCEPTION_STREAM;
- dirent->location = exc.location();
-
- exc.get()->thread_id = crashing_tid_;
- exc.get()->exception_record.exception_code = siginfo_->si_signo;
- exc.get()->exception_record.exception_address =
- (uintptr_t) siginfo_->si_addr;
- exc.get()->thread_context = crashing_thread_context_;
-
- return true;
- }
-
- bool WriteSystemInfoStream(MDRawDirectory* dirent) {
- TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
- if (!si.Allocate())
- return false;
- my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
-
- dirent->stream_type = MD_SYSTEM_INFO_STREAM;
- dirent->location = si.location();
-
- WriteCPUInformation(si.get());
- WriteOSInformation(si.get());
-
- return true;
- }
-
- private:
-#if defined(__i386)
- uintptr_t GetStackPointer() {
- return ucontext_->uc_mcontext.gregs[REG_ESP];
- }
-#elif defined(__x86_64)
- uintptr_t GetStackPointer() {
- return ucontext_->uc_mcontext.gregs[REG_RSP];
- }
-#else
-#error "This code has not been ported to your platform yet."
-#endif
-
- void NullifyDirectoryEntry(MDRawDirectory* dirent) {
- dirent->stream_type = 0;
- dirent->location.data_size = 0;
- dirent->location.rva = 0;
- }
-
- bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
- char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
- static const char vendor_id_name[] = "vendor_id";
- static const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1;
-
- struct CpuInfoEntry {
- const char* info_name;
- int value;
- bool found;
- } cpu_info_table[] = {
- { "processor", -1, false },
- { "model", 0, false },
- { "stepping", 0, false },
- { "cpu family", 0, false },
- };
-
- // processor_architecture should always be set, do this first
- sys_info->processor_architecture =
-#if defined(__i386)
- MD_CPU_ARCHITECTURE_X86;
-#elif defined(__x86_64)
- MD_CPU_ARCHITECTURE_AMD64;
-#else
-#error "Unknown CPU arch"
-#endif
-
- const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
- if (fd < 0)
- return false;
-
- {
- PageAllocator allocator;
- LineReader* const line_reader = new(allocator) LineReader(fd);
- const char* line;
- unsigned line_len;
- while (line_reader->GetNextLine(&line, &line_len)) {
- for (size_t i = 0;
- i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
- i++) {
- CpuInfoEntry* entry = &cpu_info_table[i];
- if (entry->found)
- continue;
- if (!strncmp(line, entry->info_name, strlen(entry->info_name))) {
- const char* value = strchr(line, ':');
- if (!value)
- continue;
-
- // the above strncmp only matches the prefix, it might be the wrong
- // line. i.e. we matched "model name" instead of "model".
- // check and make sure there is only spaces between the prefix and
- // the colon.
- const char* space_ptr = line + strlen(entry->info_name);
- for (; space_ptr < value; space_ptr++) {
- if (!isspace(*space_ptr)) {
- break;
- }
- }
- if (space_ptr != value)
- continue;
-
- sscanf(++value, " %d", &(entry->value));
- entry->found = true;
- }
- }
-
- // special case for vendor_id
- if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
- const char* value = strchr(line, ':');
- if (!value)
- goto popline;
-
- // skip ':" and all the spaces that follows
- do {
- value++;
- } while (isspace(*value));
-
- if (*value) {
- size_t length = strlen(value);
- if (length == 0)
- goto popline;
- // we don't want the trailing newline
- if (value[length - 1] == '\n')
- length--;
- // ensure we have space for the value
- if (length < sizeof(vendor_id))
- strncpy(vendor_id, value, length);
- }
- }
-
-popline:
- line_reader->PopLine(line_len);
- }
- sys_close(fd);
- }
-
- // make sure we got everything we wanted
- for (size_t i = 0;
- i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
- i++) {
- if (!cpu_info_table[i].found) {
- return false;
- }
- }
- // /proc/cpuinfo contains cpu id, change it into number by adding one.
- cpu_info_table[0].value++;
-
- sys_info->number_of_processors = cpu_info_table[0].value;
- sys_info->processor_level = cpu_info_table[3].value;
- sys_info->processor_revision = cpu_info_table[1].value << 8 |
- cpu_info_table[2].value;
-
- if (vendor_id[0] != '\0') {
- memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
- sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
- }
- return true;
- }
-
- bool WriteFile(MDLocationDescriptor* result, const char* filename) {
- const int fd = sys_open(filename, O_RDONLY, 0);
- if (fd < 0)
- return false;
-
- // We can't stat the files because several of the files that we want to
- // read are kernel seqfiles, which always have a length of zero. So we have
- // to read as much as we can into a buffer.
- static const unsigned kMaxFileSize = 1024;
- uint8_t* data = (uint8_t*) dumper_.allocator()->Alloc(kMaxFileSize);
-
- size_t done = 0;
- while (done < kMaxFileSize) {
- ssize_t r;
- do {
- r = sys_read(fd, data + done, kMaxFileSize - done);
- } while (r == -1 && errno == EINTR);
-
- if (r < 1)
- break;
- done += r;
- }
- sys_close(fd);
-
- if (!done)
- return false;
-
- UntypedMDRVA memory(&minidump_writer_);
- if (!memory.Allocate(done))
- return false;
- memory.Copy(data, done);
- *result = memory.location();
- return true;
- }
-
- bool WriteOSInformation(MDRawSystemInfo* sys_info) {
- sys_info->platform_id = MD_OS_LINUX;
-
- struct utsname uts;
- if (uname(&uts))
- return false;
-
- static const size_t buf_len = 512;
- char buf[buf_len] = {0};
- size_t space_left = buf_len - 1;
- const char* info_table[] = {
- uts.sysname,
- uts.release,
- uts.version,
- uts.machine,
- NULL
- };
- bool first_item = true;
- for (const char** cur_info = info_table; *cur_info; cur_info++) {
- static const char* separator = " ";
- size_t separator_len = strlen(separator);
- size_t info_len = strlen(*cur_info);
- if (info_len == 0)
- continue;
-
- if (space_left < info_len + (first_item ? 0 : separator_len))
- break;
-
- if (!first_item) {
- strcat(buf, separator);
- space_left -= separator_len;
- }
-
- first_item = false;
- strcat(buf, *cur_info);
- space_left -= info_len;
- }
-
- MDLocationDescriptor location;
- if (!minidump_writer_.WriteString(buf, 0, &location))
- return false;
- sys_info->csd_version_rva = location.rva;
-
- return true;
- }
-
- bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
- const char* filename) {
- char buf[80];
- memcpy(buf, "/proc/", 6);
- const unsigned pid_len = my_int_len(pid);
- my_itos(buf + 6, pid, pid_len);
- buf[6 + pid_len] = '/';
- memcpy(buf + 6 + pid_len + 1, filename, my_strlen(filename) + 1);
- return WriteFile(result, buf);
- }
-
- const char* const filename_; // output filename
- const siginfo_t* const siginfo_; // from the signal handler (see sigaction)
- const struct ucontext* const ucontext_; // also from the signal handler
- const struct _libc_fpstate* const float_state_; // ditto
- const pid_t crashing_tid_; // the process which actually crashed
- LinuxDumper dumper_;
- MinidumpFileWriter minidump_writer_;
- MDLocationDescriptor crashing_thread_context_;
-};
-
-bool WriteMinidump(const char* filename, pid_t crashing_process,
- const void* blob, size_t blob_size) {
- if (blob_size != sizeof(ExceptionHandler::CrashContext))
- return false;
- const ExceptionHandler::CrashContext* context =
- reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
- MinidumpWriter writer(filename, crashing_process, context);
- if (!writer.Init())
- return false;
- return writer.Dump();
-}
-
-} // namespace google_breakpad
diff --git a/breakpad/linux/minidump_writer.h b/breakpad/linux/minidump_writer.h
deleted file mode 100644
index b2303f7..0000000
--- a/breakpad/linux/minidump_writer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#ifndef CLIENT_LINUX_HANDLER_MINIDUMP_WRITER_H_
-#define CLIENT_LINUX_HANDLER_MINIDUMP_WRITER_H_
-
-#include <stdint.h>
-#include <unistd.h>
-
-namespace google_breakpad {
-
-// Write a minidump to the filesystem. This function does not malloc nor use
-// libc functions which may. Thus, it can be used in contexts where the state
-// of the heap may be corrupt.
-// filename: the filename to write to. This is opened O_EXCL and fails if
-// open fails.
-// crashing_process: the pid of the crashing process. This must be trusted.
-// blob: a blob of data from the crashing process. See exception_handler.h
-// blob_size: the length of |blob|, in bytes
-//
-// Returns true iff successful.
-bool WriteMinidump(const char* filename, pid_t crashing_process,
- const void* blob, size_t blob_size);
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_HANDLER_MINIDUMP_WRITER_H_
diff --git a/breakpad/linux/minidump_writer_unittest.cc b/breakpad/linux/minidump_writer_unittest.cc
deleted file mode 100644
index 1f0eac3..0000000
--- a/breakpad/linux/minidump_writer_unittest.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2009, 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.
-
-#include <unistd.h>
-#include <sys/syscall.h>
-
-#include "base/eintr_wrapper.h"
-#include "breakpad/linux/exception_handler.h"
-#include "breakpad/linux/minidump_writer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using namespace google_breakpad;
-
-namespace {
-typedef testing::Test MinidumpWriterTest;
-}
-
-TEST(MinidumpWriterTest, Setup) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- ExceptionHandler::CrashContext context;
- memset(&context, 0, sizeof(context));
-
- char templ[] = "/tmp/minidump-writer-unittest-XXXXXX";
- mktemp(templ);
- ASSERT_TRUE(WriteMinidump(templ, child, &context, sizeof(context)));
- struct stat st;
- ASSERT_EQ(stat(templ, &st), 0);
- ASSERT_GT(st.st_size, 0u);
- unlink(templ);
-
- close(fds[1]);
-}