diff options
author | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-02 01:55:06 +0000 |
---|---|---|
committer | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-02 01:55:06 +0000 |
commit | b07fc5114ccce26011ec2312eee3397134739f9a (patch) | |
tree | 1570e3652386e2b314e1be8067e7e44a00f49b75 /breakpad | |
parent | 74f34b094a7b21f0c057f493abee5db30b988592 (diff) | |
download | chromium_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')
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]); -} |