diff options
author | ted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2011-07-07 20:53:52 +0000 |
---|---|---|
committer | ted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2011-07-07 20:53:52 +0000 |
commit | 69607b678fabd81ce7e77bd50cec0fa343e73b3e (patch) | |
tree | e176c234b585aa6e8ac336e85fce6671d5584637 /src/processor | |
parent | Add some unit tests for Linux WriteSymbolFile (diff) | |
download | breakpad-69607b678fabd81ce7e77bd50cec0fa343e73b3e.tar.xz |
Remove NetworkSourceLine{Resolver,Server} and related code. It never wound up being useful enough to use in production, so let's drop the maintenence burden
R=jessicag at http://breakpad.appspot.com/292001/show
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@795 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/processor')
-rw-r--r-- | src/processor/network_interface.h | 62 | ||||
-rw-r--r-- | src/processor/network_source_line_protocol.h | 162 | ||||
-rw-r--r-- | src/processor/network_source_line_resolver.cc | 455 | ||||
-rw-r--r-- | src/processor/network_source_line_resolver_server_unittest.cc | 195 | ||||
-rw-r--r-- | src/processor/network_source_line_resolver_unittest.cc | 535 | ||||
-rw-r--r-- | src/processor/network_source_line_server.cc | 435 | ||||
-rw-r--r-- | src/processor/network_source_line_server.h | 136 | ||||
-rw-r--r-- | src/processor/network_source_line_server_unittest.cc | 963 | ||||
-rw-r--r-- | src/processor/source_daemon.cc | 127 | ||||
-rw-r--r-- | src/processor/udp_network.cc | 187 | ||||
-rw-r--r-- | src/processor/udp_network.h | 73 |
11 files changed, 0 insertions, 3330 deletions
diff --git a/src/processor/network_interface.h b/src/processor/network_interface.h deleted file mode 100644 index 3871b4f5..00000000 --- a/src/processor/network_interface.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// NetworkInterface is an abstract interface for network connections. -// Its purpose is to make the network portion of certain classes -// easier to mock for testing. A concrete implementation of this -// interface can be found in udp_network.h. - -#ifndef GOOGLE_BREAKPAD_PROCESSOR_NETWORK_INTERFACE_H_ -#define GOOGLE_BREAKPAD_PROCESSOR_NETWORK_INTERFACE_H_ -namespace google_breakpad { - -class NetworkInterface { - public: - // Prepare a network connection. - // If listen is true, prepare the socket to listen for incoming - // connections. - // Returns true for success, false for failure. - virtual bool Init(bool listen) = 0; - - // Send length bytes of data to the current address. - // Returns true for success, false for failure. - virtual bool Send(const char *data, size_t length) = 0; - - // Wait at most timeout milliseconds, returning when data is available or - // time has expired. - // Returns true if data is available, false if a timeout or error occurred. - virtual bool WaitToReceive(int timeout) = 0; - - // Read data into buffer. received will contain the number of bytes received. - // Returns true for success, false for failure. - virtual bool Receive(char *buffer, size_t buffer_size, ssize_t &received) = 0; -}; - -} // namespace google_breakpad -#endif // GOOGLE_BREAKPAD_PROCESSOR_NETWORK_INTERFACE_H_ diff --git a/src/processor/network_source_line_protocol.h b/src/processor/network_source_line_protocol.h deleted file mode 100644 index b9744a8a..00000000 --- a/src/processor/network_source_line_protocol.h +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This file contains constants used in the network source line server -// protocol. - -// Brief protocol description: -// -// Requests are sent via UDP. All requests begin with a sequence number -// that is prepended to the response. The sequence number is opaque -// to the server, it is provided for client tracking of requests. -// -// In this file, request and response fields will be described as: -// <foo:N>, which should be read as "foo, an N byte unsigned integer -// in network byte order". Strings will be described as <foo:S>. -// -// A client request looks like: -// <seq:2><command:1><command data> -// Where <seq> is a sequence number as described above, <command> -// is one of the commands listed below, and <command data> is arbitrary -// data, defined per-command. -// -// A server response looks like: -// <seq:2><status:1><data> -// Where <seq> is the same sequence number from the request, -// <status> is one of the OK or ERROR values defined below, -// with OK signifying that the request was formatted properly and -// the response contains data, and ERROR signifying that the request -// was malformed in some way. <data> is arbitrary data, defined -// per-command below. -// -// Strings are sent as a 2-byte integer encoding the length, followed -// by <length> bytes. -// -// Valid Commands: -//================================================== -// <HAS:1><module name:S><debug file:S><debug identifier:S> -// example: <HAS><0x8>test.dll<0x8>test.pdb<0xA>0123456789 -// -// Query whether the module with this filename and debug information -// has been previously loaded. -// -// Server Response: -// <loaded:1> -// Where <loaded> is one of MODULE_LOADED or MODULE_NOT_LOADED -// -//================================================== -// <LOAD:1><module name:S><debug file:S><debug identifier:S> -// example: <LOAD><0x8>test.dll<0x8>test.pdb<0xA>0123456789 -// -// Request that the server find and load symbols for this module. -// -// Server Response: -// <result:1> -// Where <result> is one of: -// LOAD_NOT_FOUND -// - Symbols not found -// LOAD_INTERRUPT -// - Processing should be interrupted, symbols may be available later -// LOAD_FAIL -// - Found symbols, but failed to load them -// LOAD_OK -// - Found and loaded symbols successfully -// -//================================================== -// <GET:1><module name:S><debug file:S><debug identifier:S><module base address:8><instruction address:8> -// example: <GET><0x8>test.dll<0x8>test.pdb<0x9>0123456789<0x0000000000010000><0x0000000000011A2B> -// -// Look up source line info for this module, loaded at this base address, -// for the code at this instruction address. -// -// Server Response: -// <function:S><func_base:8><source_file:S><source_line:4><source_line_base:8> -// - As many fields as available are filled in. Fields that are not available -// will contain an empty string, or a zero for numeric values. - -//================================================== -// <GETSTACKWIN:1><module name:S><debug file:S><debug identifier:S><module base address:8><instruction address:8> -// example: <GETSTACKWIN><0x8>test.dll<0x8>test.pdb<0x9>0123456789<0x0000000000010000><0x0000000000011A2B> -// -// Look up Windows stack frame info for this module, loaded at this base -// address, for the code at this instruction address. -// -// Server Response: -// <stack:S> -// The stack info is formatted as in the symbol file format, with -// "STACK " omitted, as documented at: -// http://code.google.com/p/google-breakpad/wiki/SymbolFiles -// If no Windows stack frame info is available, an empty string is returned. - -//================================================== -// <GETSTACKCFI:1><module name:S><debug file:S><debug identifier:S><module base address:8><instruction address:8> -// example: <GETSTACKCFI><0x8>test.dll<0x8>test.pdb<0x9>0123456789<0x0000000000010000><0x0000000000011A2B> -// -// Look up CFI stack frame info for this module, loaded at this base -// address, for the code at this instruction address. -// -// Server Response: -// <stack:S> -// The stack info is formatted as in the symbol file format, with -// "STACK " omitted, as documented at: -// http://code.google.com/p/google-breakpad/wiki/SymbolFiles -// If no CFI stack frame info is available, an empty string is returned. - -#ifndef GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_PROTOCOL_H_ -#define GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_PROTOCOL_H_ - -#include "google_breakpad/common/breakpad_types.h" - -namespace google_breakpad { -namespace source_line_protocol { - -// Response status codes -const u_int8_t OK = 1; -const u_int8_t ERROR = 0; - -// Commands -const u_int8_t HAS = 1; -const u_int8_t LOAD = 2; -const u_int8_t GET = 3; -const u_int8_t GETSTACKWIN = 4; -const u_int8_t GETSTACKCFI = 5; - -// HAS responses -const u_int8_t MODULE_NOT_LOADED = 0; -const u_int8_t MODULE_LOADED = 1; - -// LOAD responses -const u_int8_t LOAD_NOT_FOUND = 0; -const u_int8_t LOAD_INTERRUPT = 1; -const u_int8_t LOAD_FAIL = 2; -const u_int8_t LOAD_OK = 3; - -} // namespace source_line_protocol -} // namespace google_breakpad -#endif // GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_PROTOCOL_H_ diff --git a/src/processor/network_source_line_resolver.cc b/src/processor/network_source_line_resolver.cc deleted file mode 100644 index 86c939f9..00000000 --- a/src/processor/network_source_line_resolver.cc +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "google_breakpad/processor/network_source_line_resolver.h" - -#include <assert.h> -#include <stdlib.h> -#include <string.h> - -#include <sstream> -#include <vector> - -#include "google_breakpad/processor/stack_frame.h" -#include "processor/binarystream.h" -#include "processor/cfi_frame_info.h" -#include "processor/network_interface.h" -#include "processor/network_source_line_protocol.h" -#include "processor/logging.h" -#include "processor/scoped_ptr.h" -#include "processor/udp_network.h" -#include "processor/windows_frame_info.h" - -namespace google_breakpad { - -using std::string; -using std::vector; -using std::dec; -using std::hex; -// Style guide forbids "using namespace", so at least shorten it. -namespace P = source_line_protocol; - -NetworkSourceLineResolver::NetworkSourceLineResolver(const string &server, - unsigned short port, - int wait_milliseconds) - : wait_milliseconds_(wait_milliseconds), - initialized_(false), - sequence_(0), - net_(new UDPNetwork(server, port)) { - if (net_->Init(false)) - initialized_ = true; -} - -NetworkSourceLineResolver::NetworkSourceLineResolver(NetworkInterface *net, - int wait_milliseconds) - : wait_milliseconds_(wait_milliseconds), - initialized_(false), - sequence_(0), - net_(net) { - if (net_ && net->Init(false)) - initialized_ = true; -} - -NetworkSourceLineResolver::~NetworkSourceLineResolver() { - initialized_ = false; -} - -bool NetworkSourceLineResolver::LoadModule(const CodeModule *module, - const string &map_file) { - // Just lie here and say it was loaded. The server always loads - // symbols immediately when they're found, since clients always - // will want to load them after finding them anyway. Since this class - // acts as both the symbol supplier and source line resolver, - // it's just a little optimization. - return true; -} - -bool NetworkSourceLineResolver::LoadModuleUsingMapBuffer( - const CodeModule *module, - const string &map_buffer) { - // see above - return true; -} - -bool NetworkSourceLineResolver::LoadModuleUsingMemoryBuffer( - const CodeModule *module, - char *memory_buffer) { - // see above - return true; -} - -void NetworkSourceLineResolver::UnloadModule(const CodeModule *module) { - // no-op -} - -bool NetworkSourceLineResolver::HasModule(const CodeModule *module) { - if (!initialized_ || !module) - return false; - - // cache seen modules so the network round trip can be skipped - if (module_cache_.find(module->code_file()) != module_cache_.end()) - return true; - - // also cache modules for which symbols aren't found - if (no_symbols_cache_.find(module->debug_file() + module->debug_identifier()) - != no_symbols_cache_.end()) - return false; - - binarystream message; - message << P::HAS - << module->code_file() - << module->debug_file() - << module->debug_identifier(); - binarystream response; - bool got_response = SendMessageGetResponse(message, response); - u_int8_t response_data; - response >> response_data; - - bool found = false; - if (got_response && !response.eof() && response_data == P::MODULE_LOADED) { - module_cache_.insert(module->code_file()); - found = true; - } - return found; -} - -void NetworkSourceLineResolver::FillSourceLineInfo( - StackFrame *frame) { - if (!initialized_) - return; - - // if don't this module isn't loaded, can't fill source line info - if (!frame->module || - module_cache_.find(frame->module->code_file()) == module_cache_.end()) - return; - - // if this frame has already been seen, return the cached copy - if (FindCachedSourceLineInfo(frame)) { - BPLOG(INFO) << "Using cached source line info"; - return; - } - - binarystream message; - message << P::GET - << frame->module->code_file() - << frame->module->debug_file() - << frame->module->debug_identifier() - << frame->module->base_address() - << frame->instruction; - binarystream response; - bool got_response = SendMessageGetResponse(message, response); - if (!got_response) - return; - - string function_name, source_file; - u_int32_t source_line; - u_int64_t function_base, source_line_base; - response >> function_name >> function_base - >> source_file >> source_line >> source_line_base; - - if (response.eof()) { - BPLOG(ERROR) << "GET response malformed"; - return; - } else { - BPLOG(INFO) << "GET response: " << function_name << " " - << hex << function_base << " " << source_file << " " - << dec << source_line << " " << hex - << source_line_base; - } - - frame->function_name = function_name; - frame->function_base = function_base; - frame->source_file_name = source_file; - frame->source_line = source_line; - frame->source_line_base = source_line_base; - - CacheSourceLineInfo(frame); -} - -WindowsFrameInfo* -NetworkSourceLineResolver::FindWindowsFrameInfo(const StackFrame *frame) { - if (!initialized_) - return NULL; - - // if this module isn't loaded, can't get frame info - if (!frame->module || - module_cache_.find(frame->module->code_file()) == module_cache_.end()) - return NULL; - - // check the cache first - string stack_info; - - if (FindCachedFrameInfo(frame, kWindowsFrameInfo, &stack_info)) { - BPLOG(INFO) << "Using cached windows frame info"; - } else { - binarystream message; - message << P::GETSTACKWIN - << frame->module->code_file() - << frame->module->debug_file() - << frame->module->debug_identifier() - << frame->module->base_address() - << frame->instruction; - binarystream response; - if (SendMessageGetResponse(message, response)) { - response >> stack_info; - CacheFrameInfo(frame, kWindowsFrameInfo, stack_info); - } - } - - WindowsFrameInfo *info = NULL; - if (!stack_info.empty()) { - int type; - u_int64_t rva, code_size; - info = WindowsFrameInfo::ParseFromString(stack_info, - type, - rva, - code_size); - } - - return info; -} - -CFIFrameInfo* -NetworkSourceLineResolver::FindCFIFrameInfo(const StackFrame *frame) -{ - if (!initialized_) - return NULL; - - // if this module isn't loaded, can't get frame info - if (!frame->module || - module_cache_.find(frame->module->code_file()) == module_cache_.end()) - return NULL; - - string stack_info; - - if (FindCachedFrameInfo(frame, kCFIFrameInfo, &stack_info)) { - BPLOG(INFO) << "Using cached CFI frame info"; - } else { - binarystream message; - message << P::GETSTACKCFI - << frame->module->code_file() - << frame->module->debug_file() - << frame->module->debug_identifier() - << frame->module->base_address() - << frame->instruction; - binarystream response; - if (SendMessageGetResponse(message, response)) { - response >> stack_info; - CacheFrameInfo(frame, kCFIFrameInfo, stack_info); - } - } - - if (!stack_info.empty()) { - scoped_ptr<CFIFrameInfo> info(new CFIFrameInfo()); - CFIFrameInfoParseHandler handler(info.get()); - CFIRuleParser parser(&handler); - if (parser.Parse(stack_info)) - return info.release(); - } - - return NULL; -} - -SymbolSupplier::SymbolResult -NetworkSourceLineResolver::GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file) { - BPLOG_IF(ERROR, !symbol_file) << "NetworkSourceLineResolver::GetSymbolFile " - "requires |symbol_file|"; - assert(symbol_file); - - if (!initialized_) - return NOT_FOUND; - - if (no_symbols_cache_.find(module->debug_file() + module->debug_identifier()) - != no_symbols_cache_.end()) - return NOT_FOUND; - - binarystream message; - message << P::LOAD - << module->code_file() - << module->debug_file() - << module->debug_identifier(); - binarystream response; - bool got_response = SendMessageGetResponse(message, response); - if (!got_response) { - // Didn't get a response, which is the same as not having symbols. - // Don't cache this, though, to force a retry if the client asks for - // symbols for the same file again. - return NOT_FOUND; - } - u_int8_t response_data; - response >> response_data; - - if (response.eof()) { - BPLOG(ERROR) << "Malformed LOAD response"; - return NOT_FOUND; - } - - if (response_data == P::LOAD_NOT_FOUND || response_data == P::LOAD_FAIL) { - // Received NOT or FAIL, symbols not present or failed to load them. - // Same problem to the client any way you look at it. - // Cache this module to avoid pointless retry. - no_symbols_cache_.insert(module->debug_file() + module->debug_identifier()); - return NOT_FOUND; - } else if (response_data == P::LOAD_INTERRUPT) { - return INTERRUPT; - } - - // otherwise, OK - module_cache_.insert(module->code_file()); - *symbol_file = "<loaded on server>"; - return FOUND; -} - -SymbolSupplier::SymbolResult -NetworkSourceLineResolver::GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data) { - if(symbol_data) - symbol_data->clear(); - return GetSymbolFile(module, system_info, symbol_file); -} - -SymbolSupplier::SymbolResult -NetworkSourceLineResolver::GetCStringSymbolData( - const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data) { - if (symbol_data) - delete *symbol_data; - - return GetSymbolFile(module, system_info, symbol_file); -} - -bool NetworkSourceLineResolver::SendMessageGetResponse( - const binarystream &message, - binarystream &response) { - binarystream sequence_stream; - u_int16_t sent_sequence = sequence_; - sequence_stream << sequence_; - ++sequence_; - string message_string = sequence_stream.str(); - message_string.append(message.str()); - BPLOG(INFO) << "Sending " << message_string.length() << " bytes"; - if (!net_->Send(message_string.c_str(), message_string.length())) - return false; - - bool done = false; - while (!done) { - if (!net_->WaitToReceive(wait_milliseconds_)) - return false; - - vector<char> buffer(1024); - ssize_t received_bytes; - if (!net_->Receive(&buffer[0], buffer.size(), received_bytes)) - return false; - - BPLOG(INFO) << "received " << received_bytes << " bytes"; - buffer.resize(received_bytes); - - response.str(string(&buffer[0], buffer.size())); - response.rewind(); - u_int16_t read_sequence; - u_int8_t status; - response >> read_sequence >> status; - if (response.eof()) { - BPLOG(ERROR) << "malformed response, missing sequence number or status"; - return false; - } - if (read_sequence < sent_sequence) // old packet - continue; - - if (read_sequence != sent_sequence) { - // not expecting this packet, just error - BPLOG(ERROR) << "error, got sequence number " << read_sequence - << ", expected " << sent_sequence; - return false; - } - - // This is the expected packet, so even if it's an error this loop is done - done = true; - - if (status != P::OK) { - BPLOG(ERROR) << "received an ER response packet"; - return false; - } - // the caller will process the rest of response - } - return true; -} - -bool NetworkSourceLineResolver::FindCachedSourceLineInfo(StackFrame *frame) - const -{ - SourceCache::const_iterator iter = - source_line_info_cache_.find(frame->instruction); - if (iter == source_line_info_cache_.end()) - return false; - - const StackFrame &f = iter->second; - frame->function_name = f.function_name; - frame->function_base = f.function_base; - frame->source_file_name = f.source_file_name; - frame->source_line = f.source_line; - frame->source_line_base = f.source_line_base; - return true; -} - -bool NetworkSourceLineResolver::FindCachedFrameInfo( - const StackFrame *frame, - FrameInfoType type, - string *info) const -{ - FrameInfoCache::const_iterator iter = - frame_info_cache_[type].find(frame->instruction); - if (iter == frame_info_cache_[type].end()) - return false; - - *info = iter->second; - return true; -} - -void NetworkSourceLineResolver::CacheSourceLineInfo(const StackFrame *frame) { - StackFrame f(*frame); - // can't hang onto this pointer, the caller owns it - f.module = NULL; - source_line_info_cache_[frame->instruction] = f; -} - -void NetworkSourceLineResolver::CacheFrameInfo( - const StackFrame *frame, - FrameInfoType type, - const string &info) { - frame_info_cache_[type][frame->instruction] = info; -} - -} // namespace google_breakpad diff --git a/src/processor/network_source_line_resolver_server_unittest.cc b/src/processor/network_source_line_resolver_server_unittest.cc deleted file mode 100644 index 0e84536c..00000000 --- a/src/processor/network_source_line_resolver_server_unittest.cc +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Full system test for NetworkSourceLineResolver / NetworkSourceLineServer. -// Forks a background process to run a NetworkSourceLineServer, then -// instantiates a MinidumpProcessor with a NetworkSourceLineResolver to -// connect to the background server and process a minidump. - -#include <string> - -#include <signal.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "breakpad_googletest_includes.h" -#include "google_breakpad/processor/basic_source_line_resolver.h" -#include "google_breakpad/processor/call_stack.h" -#include "google_breakpad/processor/minidump_processor.h" -#include "google_breakpad/processor/process_state.h" -#include "google_breakpad/processor/network_source_line_resolver.h" -#include "processor/simple_symbol_supplier.h" -#include "processor/network_source_line_server.h" -#include "processor/simple_symbol_supplier.h" -#include "processor/udp_network.h" - -namespace { - -using std::string; -using google_breakpad::BasicSourceLineResolver; -using google_breakpad::CallStack; -using google_breakpad::MinidumpProcessor; -using google_breakpad::NetworkSourceLineResolver; -using google_breakpad::NetworkSourceLineServer; -using google_breakpad::ProcessState; -using google_breakpad::SimpleSymbolSupplier; -using google_breakpad::UDPNetwork; - -static const char *kSystemInfoOS = "Windows NT"; -static const char *kSystemInfoOSShort = "windows"; -static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2"; -static const char *kSystemInfoCPU = "x86"; -static const char *kSystemInfoCPUInfo = - "GenuineIntel family 6 model 13 stepping 8"; - -bool exitProcess = false; - -void signal_handler(int signal) { - if (signal == SIGINT) - exitProcess = true; -} - -void RunSourceLineServer(int fd) { - // Set a signal handler so the parent process - // can signal this process to end. - signal(SIGINT, signal_handler); - - BasicSourceLineResolver resolver; - SimpleSymbolSupplier supplier(string(getenv("srcdir") ? - getenv("srcdir") : ".") + - "/src/processor/testdata/symbols/"); - UDPNetwork net("localhost", - 0, // pick a free port - true); // IPv4 only - - NetworkSourceLineServer server(&supplier, &resolver, &net, - 0); // no source line limit - unsigned short port = -1; - bool initialized = server.Initialize(); - if (initialized) - port = net.port(); - - // send port number back to parent - ssize_t written = write(fd, &port, sizeof(port)); - close(fd); - - if (!initialized || written != sizeof(port)) - return; - - while (!exitProcess) { - server.RunOnce(100); - } -} - -TEST(NetworkSourceLineResolverServer, SystemTest) { - int fds[2]; - ASSERT_EQ(0, pipe(fds)); - // Fork a background process to run the server. - pid_t pid = fork(); - if (pid == 0) { - close(fds[0]); - RunSourceLineServer(fds[1]); - exit(0); - } - ASSERT_NE(-1, pid); - // Wait for the background process to return info about the port. - close(fds[1]); - unsigned short port; - ssize_t nbytes = read(fds[0], &port, sizeof(port)); - ASSERT_EQ(sizeof(port), nbytes); - ASSERT_NE(-1, port); - - NetworkSourceLineResolver resolver("localhost", port, - 5000); // wait at most 5 seconds for reply - MinidumpProcessor processor(&resolver, &resolver); - // this is all copied from minidump_processor_unittest.cc - string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") + - "/src/processor/testdata/minidump2.dmp"; - - ProcessState state; - ASSERT_EQ(processor.Process(minidump_file, &state), - google_breakpad::PROCESS_OK); - EXPECT_EQ(state.system_info()->os, kSystemInfoOS); - EXPECT_EQ(state.system_info()->os_short, kSystemInfoOSShort); - EXPECT_EQ(state.system_info()->os_version, kSystemInfoOSVersion); - EXPECT_EQ(state.system_info()->cpu, kSystemInfoCPU); - EXPECT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo); - ASSERT_TRUE(state.crashed()); - EXPECT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION_WRITE"); - EXPECT_EQ(state.crash_address(), 0x45U); - ASSERT_EQ(state.threads()->size(), size_t(1)); - ASSERT_EQ(state.requesting_thread(), 0); - - CallStack *stack = state.threads()->at(0); - ASSERT_TRUE(stack); - ASSERT_EQ(stack->frames()->size(), 4U); - - // Can now only set non-empty/zero values for function_name, source_file_name - // and source line on certain platforms (ie. windows), so those are untested. - ASSERT_TRUE(stack->frames()->at(0)->module); - EXPECT_EQ(stack->frames()->at(0)->module->base_address(), 0x400000U); - EXPECT_EQ(stack->frames()->at(0)->module->code_file(), "c:\\test_app.exe"); - - ASSERT_TRUE(stack->frames()->at(1)->module); - EXPECT_EQ(stack->frames()->at(1)->module->base_address(), 0x400000U); - EXPECT_EQ(stack->frames()->at(1)->module->code_file(), "c:\\test_app.exe"); - - // This comes from the CRT - ASSERT_TRUE(stack->frames()->at(2)->module); - EXPECT_EQ(stack->frames()->at(2)->module->base_address(), 0x400000U); - EXPECT_EQ(stack->frames()->at(2)->module->code_file(), "c:\\test_app.exe"); - - // OS frame, kernel32.dll - ASSERT_TRUE(stack->frames()->at(3)->module); - EXPECT_EQ(stack->frames()->at(3)->module->base_address(), 0x7c800000U); - EXPECT_EQ(stack->frames()->at(3)->module->code_file(), - "C:\\WINDOWS\\system32\\kernel32.dll"); - - ASSERT_EQ(state.modules()->module_count(), 13U); - ASSERT_TRUE(state.modules()->GetMainModule()); - EXPECT_EQ(state.modules()->GetMainModule()->code_file(), "c:\\test_app.exe"); - EXPECT_FALSE(state.modules()->GetModuleForAddress(0)); - EXPECT_EQ(state.modules()->GetMainModule(), - state.modules()->GetModuleForAddress(0x400000)); - EXPECT_EQ(state.modules()->GetModuleForAddress(0x7c801234)->debug_file(), - "kernel32.pdb"); - EXPECT_EQ(state.modules()->GetModuleForAddress(0x77d43210)->version(), - "5.1.2600.2622"); - - // Kill background process - kill(pid, SIGINT); - ASSERT_EQ(pid, waitpid(pid, NULL, 0)); -} - -} - -int main(int argc, char *argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/processor/network_source_line_resolver_unittest.cc b/src/processor/network_source_line_resolver_unittest.cc deleted file mode 100644 index bf0aae78..00000000 --- a/src/processor/network_source_line_resolver_unittest.cc +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// Unit tests for NetworkSourceLineResolver. - -#include <string> - -#include "breakpad_googletest_includes.h" -#include "google_breakpad/processor/network_source_line_resolver.h" -#include "google_breakpad/processor/stack_frame.h" -#include "google_breakpad/processor/symbol_supplier.h" -#include "processor/basic_code_module.h" -#include "processor/binarystream.h" -#include "processor/cfi_frame_info.h" -#include "processor/network_interface.h" -#include "processor/network_source_line_protocol.h" -#include "processor/windows_frame_info.h" - -namespace google_breakpad { -class MockNetwork : public NetworkInterface { - public: - MockNetwork() {} - - MOCK_METHOD1(Init, bool(bool listen)); - MOCK_METHOD2(Send, bool(const char *data, size_t length)); - MOCK_METHOD1(WaitToReceive, bool(int timeout)); - MOCK_METHOD3(Receive, bool(char *buffer, size_t buffer_size, - ssize_t &received)); -}; -} - -namespace { -using std::string; -using google_breakpad::binarystream; -using google_breakpad::BasicCodeModule; -using google_breakpad::CFIFrameInfo; -using google_breakpad::MockNetwork; -using google_breakpad::NetworkSourceLineResolver; -using google_breakpad::StackFrame; -using google_breakpad::SymbolSupplier; -using google_breakpad::WindowsFrameInfo; -using ::testing::_; -using ::testing::Invoke; -using ::testing::Return; -using namespace google_breakpad::source_line_protocol; - -class TestNetworkSourceLineResolver : public ::testing::Test { -public: - TestNetworkSourceLineResolver() : resolver(NULL) {} - - void SetUp() { - EXPECT_CALL(net, Init(false)).WillOnce(Return(true)); - resolver = new NetworkSourceLineResolver(&net, 0); - } - - NetworkSourceLineResolver *resolver; - MockNetwork net; -}; - -bool GeneratePositiveHasResponse(char *buffer, size_t buffer_size, - ssize_t &received) { - binarystream stream; - stream << u_int16_t(0) << OK << MODULE_LOADED; - string s = stream.str(); - received = s.length(); - memcpy(buffer, s.c_str(), s.length()); - return true; -} - -bool GenerateNegativeHasResponse(char *buffer, size_t buffer_size, - ssize_t &received) { - binarystream stream; - stream << u_int16_t(1) << OK << MODULE_NOT_LOADED; - string s = stream.str(); - received = s.length(); - memcpy(buffer, s.c_str(), s.length()); - return true; -} - -TEST_F(TestNetworkSourceLineResolver, TestHasMessages) { - EXPECT_CALL(net, Send(_,_)) - .WillOnce(Return(true)) - .WillOnce(Return(true)); - EXPECT_CALL(net, WaitToReceive(0)) - .WillOnce(Return(true)) - .WillOnce(Return(true)); - EXPECT_CALL(net, Receive(_,_,_)) - .WillOnce(Invoke(GeneratePositiveHasResponse)) - .WillOnce(Invoke(GenerateNegativeHasResponse)); - ASSERT_NE(resolver, (NetworkSourceLineResolver*)NULL); - BasicCodeModule module(0x0, 0x0, "test.dll", "test.pdb", "ABCD", "", ""); - EXPECT_TRUE(resolver->HasModule(&module)); - BasicCodeModule module2(0x0, 0x0, "test2.dll", "test2.pdb", "FFFF", "", ""); - EXPECT_FALSE(resolver->HasModule(&module2)); - // calling again should hit the cache, and not the network - EXPECT_TRUE(resolver->HasModule(&module)); -} - -bool GenerateErrorResponse(char *buffer, size_t buffer_size, - ssize_t &received) { - binarystream stream; - stream << u_int16_t(0) << ERROR; - string s = stream.str(); - received = s.length(); - memcpy(buffer, s.c_str(), s.length()); - return true; -} - -TEST_F(TestNetworkSourceLineResolver, TestHasErrorResponse) { - EXPECT_CALL(net, Send(_,_)) - .WillOnce(Return(true)); - EXPECT_CALL(net, WaitToReceive(0)) - .WillOnce(Return(true)); - EXPECT_CALL(net, Receive(_,_,_)) - .WillOnce(Invoke(GenerateErrorResponse)); - ASSERT_NE(resolver, (NetworkSourceLineResolver*)NULL); - BasicCodeModule module(0x0, 0x0, "test.dll", "test.pdb", "ABCD", "", ""); - // error packet should function as a not found - EXPECT_FALSE(resolver->HasModule(&module)); -} - -// GenerateLoadResponse will generate (LOAD_NOT_FOUND, LOAD_INTERRUPT, -// LOAD_FAIL, LOAD_OK) in order. -class LoadHelper { - public: - LoadHelper() : response(LOAD_NOT_FOUND), sequence(0) {} - bool GenerateLoadResponse(char *buffer, size_t buffer_size, - ssize_t &received) { - binarystream stream; - stream << sequence << OK << response; - string s = stream.str(); - received = s.length(); - memcpy(buffer, s.c_str(), s.length()); - ++sequence; - ++response; - return true; - } - u_int8_t response; - u_int16_t sequence; -}; - -TEST_F(TestNetworkSourceLineResolver, TestLoadMessages) { - EXPECT_CALL(net, Send(_,_)) - .Times(4) - .WillRepeatedly(Return(true)); - EXPECT_CALL(net, WaitToReceive(0)) - .Times(4) - .WillRepeatedly(Return(true)); - LoadHelper helper; - EXPECT_CALL(net, Receive(_,_,_)) - .Times(4) - .WillRepeatedly(Invoke(&helper, &LoadHelper::GenerateLoadResponse)); - ASSERT_NE(resolver, (NetworkSourceLineResolver*)NULL); - BasicCodeModule module(0x0, 0x0, "test.dll", "test.pdb", "ABCD", "", ""); - string s; - EXPECT_EQ(SymbolSupplier::NOT_FOUND, - resolver->GetSymbolFile(&module, NULL, &s)); - BasicCodeModule module2(0x0, 0x0, "test2.dll", "test2.pdb", "FFFF", "", ""); - EXPECT_EQ(SymbolSupplier::INTERRUPT, - resolver->GetSymbolFile(&module2, NULL, &s)); - BasicCodeModule module3(0x0, 0x0, "test3.dll", "test3.pdb", "0000", "", ""); - // a FAIL result from the network should come back as NOT_FOUND - EXPECT_EQ(SymbolSupplier::NOT_FOUND, - resolver->GetSymbolFile(&module3, NULL, &s)); - BasicCodeModule module4(0x0, 0x0, "test4.dll", "test4.pdb", "1010", "", ""); - EXPECT_EQ(SymbolSupplier::FOUND, - resolver->GetSymbolFile(&module4, NULL, &s)); - // calling this should hit the cache, and not the network - EXPECT_TRUE(resolver->HasModule(&module4)); -} - -TEST_F(TestNetworkSourceLineResolver, TestLoadErrorResponse) { - EXPECT_CALL(net, Send(_,_)) - .WillOnce(Return(true)); - EXPECT_CALL(net, WaitToReceive(0)) - .WillOnce(Return(true)); - EXPECT_CALL(net, Receive(_,_,_)) - .WillOnce(Invoke(GenerateErrorResponse)); - ASSERT_NE(resolver, (NetworkSourceLineResolver*)NULL); - BasicCodeModule module(0x0, 0x0, "test.dll", "test.pdb", "ABCD", "", ""); - string s; - // error packet should function as NOT_FOUND response - EXPECT_EQ(SymbolSupplier::NOT_FOUND, - resolver->GetSymbolFile(&module, NULL, &s)); -} - -class GetHelper { - public: - GetHelper() : sequence(1) {} - bool GenerateGetResponse(char *buffer, size_t buffer_size, - ssize_t &received) { - binarystream stream; - stream << sequence << OK; - switch(sequence) { - case 1: - // return full info - stream << string("test()") << u_int64_t(0x1000) << string("test.c") - << u_int32_t(1) << u_int64_t(0x1010); - break; - case 2: - // return full info - stream << string("test2()") << u_int64_t(0x2000) << string("test2.c") - << u_int32_t(2) << u_int64_t(0x2020); - break; - case 3: - // return just function name - stream << string("test3()") << u_int64_t(0x4000) << string("") - << u_int32_t(0) << u_int64_t(0); - break; - } - string s = stream.str(); - received = s.length(); - memcpy(buffer, s.c_str(), s.length()); - ++sequence; - return true; - } - u_int16_t sequence; -}; - -TEST_F(TestNetworkSourceLineResolver, TestGetMessages) { - EXPECT_CALL(net, Send(_,_)) - .Times(4) - .WillRepeatedly(Return(true)); - EXPECT_CALL(net, WaitToReceive(0)) - .Times(4) - .WillRepeatedly(Return(true)); - GetHelper helper; - EXPECT_CALL(net, Receive(_,_,_)) - .Times(4) - .WillOnce(Invoke(GeneratePositiveHasResponse)) - .WillRepeatedly(Invoke(&helper, &GetHelper::GenerateGetResponse)); - BasicCodeModule module(0x0, 0x0, "test.dll", "test.pdb", "ABCD", "", ""); - // The resolver has to think the module is loaded before it will respond - // to GET requests for that module. - EXPECT_TRUE(resolver->HasModule(&module)); - StackFrame frame; - frame.module = &module; - frame.instruction = 0x1010; - resolver->FillSourceLineInfo(&frame); - EXPECT_EQ("test()", frame.function_name); - EXPECT_EQ(0x1000, frame.function_base); - EXPECT_EQ("test.c", frame.source_file_name); - EXPECT_EQ(1, frame.source_line); - EXPECT_EQ(0x1010, frame.source_line_base); - - StackFrame frame2; - frame2.module = &module; - frame2.instruction = 0x2020; - resolver->FillSourceLineInfo(&frame2); - EXPECT_EQ("test2()", frame2.function_name); - EXPECT_EQ(0x2000, frame2.function_base); - EXPECT_EQ("test2.c", frame2.source_file_name); - EXPECT_EQ(2, frame2.source_line); - EXPECT_EQ(0x2020, frame2.source_line_base); - - StackFrame frame3; - frame3.module = &module; - frame3.instruction = 0x4040; - resolver->FillSourceLineInfo(&frame3); - EXPECT_EQ("test3()", frame3.function_name); - EXPECT_EQ(0x4000, frame3.function_base); - EXPECT_EQ("", frame3.source_file_name); - EXPECT_EQ(0, frame3.source_line); - EXPECT_EQ(0, frame3.source_line_base); - - // this should come from the cache and not hit the network - StackFrame frame4; - frame4.module = &module; - frame4.instruction = 0x1010; - resolver->FillSourceLineInfo(&frame4); - EXPECT_EQ("test()", frame4.function_name); - EXPECT_EQ(0x1000, frame4.function_base); - EXPECT_EQ("test.c", frame4.source_file_name); - EXPECT_EQ(1, frame4.source_line); - EXPECT_EQ(0x1010, frame4.source_line_base); - - // this should also be cached - StackFrame frame5; - frame5.module = &module; - frame5.instruction = 0x4040; - resolver->FillSourceLineInfo(&frame5); - EXPECT_EQ("test3()", frame5.function_name); - EXPECT_EQ(0x4000, frame5.function_base); - EXPECT_EQ("", frame5.source_file_name); - EXPECT_EQ(0, frame5.source_line); - EXPECT_EQ(0, frame5.source_line_base); -} - -class GetStackWinHelper { - public: - GetStackWinHelper() : sequence(1) {} - bool GenerateGetStackWinResponse(char *buffer, size_t buffer_size, - ssize_t &received) { - binarystream stream; - stream << sequence << OK; - switch(sequence) { - case 1: - // return full info including program string - stream << string("0 0 0 1 2 3 a ff f00 1 x y ="); - break; - case 2: - // return full info, no program string - stream << string("0 0 0 1 2 3 a ff f00 0 1"); - break; - case 3: - // return empty string - stream << string(""); - break; - } - string s = stream.str(); - received = s.length(); - memcpy(buffer, s.c_str(), s.length()); - ++sequence; - return true; - } - u_int16_t sequence; -}; - -TEST_F(TestNetworkSourceLineResolver, TestGetStackWinMessages) { - EXPECT_CALL(net, Send(_,_)) - .Times(4) - .WillRepeatedly(Return(true)); - EXPECT_CALL(net, WaitToReceive(0)) - .Times(4) - .WillRepeatedly(Return(true)); - GetStackWinHelper helper; - EXPECT_CALL(net, Receive(_,_,_)) - .Times(4) - .WillOnce(Invoke(GeneratePositiveHasResponse)) - .WillRepeatedly(Invoke(&helper, - &GetStackWinHelper::GenerateGetStackWinResponse)); - - BasicCodeModule module(0x0, 0x0, "test.dll", "test.pdb", "ABCD", "", ""); - // The resolver has to think the module is loaded before it will respond - // to GETSTACKWIN requests for that module. - EXPECT_TRUE(resolver->HasModule(&module)); - StackFrame frame; - frame.module = &module; - frame.instruction = 0x1010; - WindowsFrameInfo *info = resolver->FindWindowsFrameInfo(&frame); - ASSERT_NE((WindowsFrameInfo*)NULL, info); - EXPECT_EQ(0x1, info->prolog_size); - EXPECT_EQ(0x2, info->epilog_size); - EXPECT_EQ(0x3, info->parameter_size); - EXPECT_EQ(0xa, info->saved_register_size); - EXPECT_EQ(0xff, info->local_size); - EXPECT_EQ(0xf00, info->max_stack_size); - EXPECT_EQ("x y =", info->program_string); - delete info; - - StackFrame frame2; - frame2.module = &module; - frame2.instruction = 0x2020; - info = resolver->FindWindowsFrameInfo(&frame2); - ASSERT_NE((WindowsFrameInfo*)NULL, info); - EXPECT_EQ(0x1, info->prolog_size); - EXPECT_EQ(0x2, info->epilog_size); - EXPECT_EQ(0x3, info->parameter_size); - EXPECT_EQ(0xa, info->saved_register_size); - EXPECT_EQ(0xff, info->local_size); - EXPECT_EQ(0xf00, info->max_stack_size); - EXPECT_EQ("", info->program_string); - EXPECT_EQ(true, info->allocates_base_pointer); - delete info; - - StackFrame frame3; - frame3.module = &module; - frame3.instruction = 0x4040; - info = resolver->FindWindowsFrameInfo(&frame3); - EXPECT_EQ((WindowsFrameInfo*)NULL, info); - - // this should come from the cache and not hit the network - StackFrame frame4; - frame4.module = &module; - frame4.instruction = 0x1010; - info = resolver->FindWindowsFrameInfo(&frame4); - ASSERT_NE((WindowsFrameInfo*)NULL, info); - EXPECT_EQ(0x1, info->prolog_size); - EXPECT_EQ(0x2, info->epilog_size); - EXPECT_EQ(0x3, info->parameter_size); - EXPECT_EQ(0xa, info->saved_register_size); - EXPECT_EQ(0xff, info->local_size); - EXPECT_EQ(0xf00, info->max_stack_size); - EXPECT_EQ("x y =", info->program_string); - delete info; - - // this should also be cached - StackFrame frame5; - frame5.module = &module; - frame5.instruction = 0x4040; - info = resolver->FindWindowsFrameInfo(&frame5); - EXPECT_EQ((WindowsFrameInfo*)NULL, info); -} - -class GetStackCFIHelper { - public: - GetStackCFIHelper() : sequence(1) {} - bool GenerateGetStackCFIResponse(char *buffer, size_t buffer_size, - ssize_t &received) { - binarystream stream; - stream << sequence << OK; - switch(sequence) { - case 1: - // return .cfa, .ra, registers - stream << string(".cfa: 1234 .ra: .cfa 5 + r0: abc xyz r2: 10 10"); - break; - case 2: - // return just .cfa - stream << string(".cfa: xyz"); - break; - case 3: - // return empty string - stream << string(""); - break; - } - string s = stream.str(); - received = s.length(); - memcpy(buffer, s.c_str(), s.length()); - ++sequence; - return true; - } - u_int16_t sequence; -}; - -TEST_F(TestNetworkSourceLineResolver, TestGetStackCFIMessages) { - EXPECT_CALL(net, Send(_,_)) - .Times(4) - .WillRepeatedly(Return(true)); - EXPECT_CALL(net, WaitToReceive(0)) - .Times(4) - .WillRepeatedly(Return(true)); - GetStackCFIHelper helper; - EXPECT_CALL(net, Receive(_,_,_)) - .Times(4) - .WillOnce(Invoke(GeneratePositiveHasResponse)) - .WillRepeatedly(Invoke(&helper, - &GetStackCFIHelper::GenerateGetStackCFIResponse)); - - BasicCodeModule module(0x0, 0x0, "test.dll", "test.pdb", "ABCD", "", ""); - // The resolver has to think the module is loaded before it will respond - // to GETSTACKCFI requests for that module. - EXPECT_TRUE(resolver->HasModule(&module)); - StackFrame frame; - frame.module = &module; - frame.instruction = 0x1010; - CFIFrameInfo *info = resolver->FindCFIFrameInfo(&frame); - ASSERT_NE((CFIFrameInfo*)NULL, info); - // Ostensibly we would check the internal data structure, but - // we'd have to either mock out some other classes or get internal access, - // so this is easier. - EXPECT_EQ(".cfa: 1234 .ra: .cfa 5 + r0: abc xyz r2: 10 10", - info->Serialize()); - delete info; - - StackFrame frame2; - frame2.module = &module; - frame2.instruction = 0x2020; - info = resolver->FindCFIFrameInfo(&frame2); - ASSERT_NE((CFIFrameInfo*)NULL, info); - EXPECT_EQ(".cfa: xyz", info->Serialize()); - delete info; - - StackFrame frame3; - frame3.module = &module; - frame3.instruction = 0x4040; - info = resolver->FindCFIFrameInfo(&frame3); - EXPECT_EQ((CFIFrameInfo*)NULL, info); - - // this should come from the cache and not hit the network - StackFrame frame4; - frame4.module = &module; - frame4.instruction = 0x1010; - info = resolver->FindCFIFrameInfo(&frame4); - ASSERT_NE((CFIFrameInfo*)NULL, info); - EXPECT_EQ(".cfa: 1234 .ra: .cfa 5 + r0: abc xyz r2: 10 10", - info->Serialize()); - delete info; - - // this should also be cached - StackFrame frame5; - frame5.module = &module; - frame5.instruction = 0x4040; - info = resolver->FindCFIFrameInfo(&frame5); - EXPECT_EQ((CFIFrameInfo*)NULL, info); -} - -TEST_F(TestNetworkSourceLineResolver, TestBogusData) { - EXPECT_FALSE(resolver->HasModule(NULL)); - - StackFrame frame; - frame.module = NULL; - frame.instruction = 0x1000; - resolver->FillSourceLineInfo(&frame); - EXPECT_EQ("", frame.function_name); - EXPECT_EQ(0x0, frame.function_base); - EXPECT_EQ("", frame.source_file_name); - EXPECT_EQ(0, frame.source_line); - EXPECT_EQ(0x0, frame.source_line_base); - - EXPECT_EQ((WindowsFrameInfo*)NULL, resolver->FindWindowsFrameInfo(&frame)); -} - -} // namespace - -int main(int argc, char *argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/processor/network_source_line_server.cc b/src/processor/network_source_line_server.cc deleted file mode 100644 index 1a6ea31b..00000000 --- a/src/processor/network_source_line_server.cc +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <arpa/inet.h> -#include <netinet/in.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/types.h> - -#include <algorithm> -#include <iostream> -#include <sstream> - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "google_breakpad/processor/code_module.h" -#include "google_breakpad/processor/stack_frame.h" -#include "processor/basic_code_module.h" -#include "processor/binarystream.h" -#include "processor/cfi_frame_info.h" -#include "processor/logging.h" -#include "processor/network_source_line_protocol.h" -#include "processor/network_source_line_server.h" -#include "processor/tokenize.h" -#include "processor/windows_frame_info.h" - -namespace google_breakpad { - -using std::dec; -using std::find; -using std::hex; -// Style guide forbids "using namespace", so at least shorten it. -namespace P = source_line_protocol; - -bool NetworkSourceLineServer::Initialize() { - if (net_->Init(true)) - initialized_ = true; - return initialized_; -} - -bool NetworkSourceLineServer::RunForever() { - if (!initialized_ && !Initialize()) - return false; - - BPLOG(INFO) << "Running forever..."; - while (true) { - RunOnce(5000); - } - // not reached - return true; -} - -bool NetworkSourceLineServer::RunOnce(int wait_milliseconds) { - if (!initialized_ && !Initialize()) - return false; - - if (!net_->WaitToReceive(wait_milliseconds)) - return false; - //TODO(ted): loop, processing packets until wait_milliseconds - // is actually exhausted? - - vector<char> buffer(1024); - ssize_t received_bytes; - if (!net_->Receive(&buffer[0], buffer.size(), received_bytes)) - return false; - buffer.resize(received_bytes); - - binarystream request(&buffer[0], buffer.size()); - binarystream response; - if (!HandleRequest(request, response)) - return false; - - string response_string = response.str(); - if (!net_->Send(response_string.c_str(), response_string.length())) - return false; - return true; -} - -bool NetworkSourceLineServer::HandleRequest(binarystream &request, - binarystream &response) { - u_int16_t sequence_number; - u_int8_t command; - request >> sequence_number >> command; - if (request.eof()) { - BPLOG(ERROR) << "Malformed request, missing sequence number or command"; - return false; - } - - response.rewind(); - response << sequence_number; - switch(command) { - case P::HAS: - HandleHas(request, response); - break; - case P::LOAD: - HandleLoad(request, response); - break; - case P::GET: - HandleGet(request, response); - break; - case P::GETSTACKWIN: - HandleGetStackWin(request, response); - break; - case P::GETSTACKCFI: - HandleGetStackCFI(request, response); - break; - default: - BPLOG(ERROR) << "Unknown command " << int(command); - response << P::ERROR; - break; - } - return true; -} - -void NetworkSourceLineServer::HandleHas(binarystream &message, - binarystream &response) { - string module_name, debug_file, debug_id; - message >> module_name >> debug_file >> debug_id; - if (message.eof()) { - BPLOG(ERROR) << "HAS message malformed"; - response << P::ERROR; - return; - } - BPLOG(INFO) << "Received message HAS " << module_name - << " " << debug_file - << " " << debug_id; - // Need to lie about the module name here, since BasicSourceLineResolver - // uses only the module name for unique modules, but we want to allow - // multiple versions of the same named module in here. - BasicCodeModule module((u_int64_t)0, (u_int64_t)0, - module_name + "|" + debug_file + "|" + debug_id, "", - debug_file, debug_id, ""); - u_int8_t data; - if (resolver_) { - data = resolver_->HasModule(&module) - ? P::MODULE_LOADED : P::MODULE_NOT_LOADED; - } else { - data = P::MODULE_NOT_LOADED; - } - response << P::OK << data; -} - -void NetworkSourceLineServer::HandleLoad(binarystream &message, - binarystream &response) { - string module_name, debug_file, debug_id; - message >> module_name >> debug_file >> debug_id; - if (message.eof()) { - BPLOG(ERROR) << "LOAD message malformed"; - response << P::ERROR; - return; - } - BPLOG(INFO) << "Received message LOAD " << module_name - << " " << debug_file - << " " << debug_id; - - u_int8_t reply; - // stub out the bare minimum here - BasicCodeModule module((u_int64_t)0, (u_int64_t)0, - module_name + "|" + debug_file + "|" + debug_id, "", - debug_file, debug_id, ""); - if (resolver_->HasModule(&module)) { - // just short-circuit the rest of this, since it's already loaded - BPLOG(INFO) << "Got LOAD for already loaded " << module_name; - UsedModule(module); - reply = P::LOAD_OK; - } else { - BPLOG(INFO) << "Looking up symbols for (" << module_name << ", " - << debug_file << ", " << debug_id << ")"; - string symbol_data, symbol_file; - SymbolSupplier::SymbolResult symbol_result; - if (supplier_) { - symbol_result = supplier_->GetSymbolFile(&module, NULL, - &symbol_file, &symbol_data); - } else { - symbol_result = SymbolSupplier::NOT_FOUND; - } - - switch (symbol_result) { - case SymbolSupplier::FOUND: { - BPLOG(INFO) << "Found symbols for " << module_name; - reply = P::LOAD_OK; - // also go ahead and load the symbols while we're here, - // since the client is just going to ask us to do this right away - // and we already have |symbol_data| here. - int numlines = CountNewlines(symbol_data); - if (!resolver_->LoadModuleUsingMapBuffer(&module, - symbol_data)) { - BPLOG(INFO) << "Failed to load symbols for " << module_name; - reply = P::LOAD_FAIL; - } else { - // save some info about this module - symbol_lines_ += numlines; - UsedModule(module); - module_symbol_lines_[module.code_file()] = numlines; - - BPLOG(INFO) << "Loaded symbols for " << module_name - << " (" << dec << numlines << " lines, " - << symbol_lines_ << " total)"; - - if (max_symbol_lines_ != 0 && symbol_lines_ > max_symbol_lines_) { - // try unloading some modules to reclaim memory - // (but not the one that was just loaded) - BPLOG(INFO) << "Exceeded limit of " << dec << max_symbol_lines_ - << " symbol lines loaded, trying to unload modules"; - TryUnloadModules(module); - } - } - } - break; - case SymbolSupplier::NOT_FOUND: - BPLOG(INFO) << "Symbols not found for " << module_name; - reply = P::LOAD_NOT_FOUND; - break; - case SymbolSupplier::INTERRUPT: - BPLOG(INFO) << "Symbol provider returned interrupt for " << module_name; - reply = P::LOAD_INTERRUPT; - break; - } - } - response << P::OK << reply; -} - -void NetworkSourceLineServer::HandleGet(binarystream &message, - binarystream &response) { - string module_name, debug_file, debug_id; - u_int64_t module_base, instruction; - message >> module_name >> debug_file >> debug_id - >> module_base >> instruction; - if (message.eof()) { - BPLOG(ERROR) << "GET message malformed"; - response << P::ERROR; - return; - } - - BPLOG(INFO) << "Received message GET " << module_name << " " - << debug_file << " " << debug_id << " " - << hex << module_base << " " << instruction; - - StackFrame frame; - if (resolver_) { - BasicCodeModule module(module_base, (u_int64_t)0, - module_name + "|" + debug_file + "|" + debug_id, "", - debug_file, debug_id, ""); - frame.module = &module; - frame.instruction = instruction; - resolver_->FillSourceLineInfo(&frame); - UsedModule(module); - } - - response << P::OK << frame.function_name << frame.function_base - << frame.source_file_name << u_int32_t(frame.source_line) - << frame.source_line_base; - BPLOG(INFO) << "Sending GET response: " << frame.function_name << " " - << hex << frame.function_base << " " - << frame.source_file_name << " " - << dec << frame.source_line << " " - << hex << frame.source_line_base; -} - -void NetworkSourceLineServer::HandleGetStackWin(binarystream &message, - binarystream &response) { - string module_name, debug_file, debug_id; - u_int64_t module_base, instruction; - message >> module_name >> debug_file >> debug_id - >> module_base >> instruction; - if (message.eof()) { - BPLOG(ERROR) << "GETSTACKWIN message malformed"; - response << P::ERROR; - return; - } - - BPLOG(INFO) << "Received message GETSTACKWIN " << module_name << " " - << debug_file << " " << debug_id << " " - << hex << module_base << " " << instruction; - - - WindowsFrameInfo *frame_info = NULL; - if (resolver_) { - StackFrame frame; - BasicCodeModule module(module_base, (u_int64_t)0, - module_name + "|" + debug_file + "|" + debug_id, "", - debug_file, debug_id, ""); - frame.module = &module; - frame.instruction = instruction; - frame_info = resolver_->FindWindowsFrameInfo(&frame); - UsedModule(module); - } - - response << P::OK << FormatWindowsFrameInfo(frame_info); - BPLOG(INFO) << "Sending GETSTACKWIN response: " - << FormatWindowsFrameInfo(frame_info); - delete frame_info; -} - -string NetworkSourceLineServer::FormatWindowsFrameInfo( - WindowsFrameInfo *frame_info) { - if (frame_info == NULL) - return ""; - - std::ostringstream stream; - // Put "0" as the type, rva and code size because the client doesn't - // actually care what these values are, but it's easier to keep the - // format consistent with the symbol files so the parsing code can be - // shared. - stream << "0 0 0 " << hex - << frame_info->prolog_size << " " - << frame_info->epilog_size << " " - << frame_info->parameter_size << " " - << frame_info->saved_register_size << " " - << frame_info->local_size << " " - << frame_info->max_stack_size << " "; - if (!frame_info->program_string.empty()) { - stream << 1 << " " << frame_info->program_string; - } else { - stream << 0 << " " << frame_info->allocates_base_pointer; - } - return stream.str(); -} - -void NetworkSourceLineServer::HandleGetStackCFI(binarystream &message, - binarystream &response) { - string module_name, debug_file, debug_id; - u_int64_t module_base, instruction; - message >> module_name >> debug_file >> debug_id - >> module_base >> instruction; - if (message.eof()) { - BPLOG(ERROR) << "GETSTACKCFI message malformed"; - response << P::ERROR; - return; - } - - BPLOG(INFO) << "Received message GETSTACKCFI " << module_name << " " - << debug_file << " " << debug_id << " " - << hex << module_base << " " << instruction; - - - CFIFrameInfo *frame_info = NULL; - if (resolver_) { - StackFrame frame; - BasicCodeModule module(module_base, (u_int64_t)0, - module_name + "|" + debug_file + "|" + debug_id, "", - debug_file, debug_id, ""); - frame.module = &module; - frame.instruction = instruction; - frame_info = resolver_->FindCFIFrameInfo(&frame); - UsedModule(module); - } - - string frame_info_string; - if (frame_info != NULL) - frame_info_string = frame_info->Serialize(); - response << P::OK << frame_info_string; - BPLOG(INFO) << "Sending GETSTACKCFI response: " - << frame_info_string; - delete frame_info; -} - -int NetworkSourceLineServer::CountNewlines(const string &str) { - int count = 0; - string::const_iterator iter = str.begin(); - while (iter != str.end()) { - if (*iter == '\n') - count++; - iter++; - } - return count; -} - -void NetworkSourceLineServer::UsedModule(const CodeModule &module) { - list<string>::iterator iter = find(modules_used_.begin(), - modules_used_.end(), - module.code_file()); - if (iter == modules_used_.end()) { - modules_used_.push_front(module.code_file()); - } else { - modules_used_.splice(modules_used_.begin(), - modules_used_, - iter); - } -} - -void NetworkSourceLineServer::TryUnloadModules( - const CodeModule &just_loaded_module) { - if (!resolver_) - return; - - while (symbol_lines_ > max_symbol_lines_) { - // never unload just_loaded_module - if (modules_used_.back() == just_loaded_module.code_file()) - break; - - string module_to_unload = modules_used_.back(); - modules_used_.pop_back(); - BasicCodeModule module(0, 0, module_to_unload, "", "", "", ""); - BPLOG(INFO) << "Unloading module " << module_to_unload; - resolver_->UnloadModule(&module); - - // reduce the symbol line count - map<string, int>::iterator iter = - module_symbol_lines_.find(module_to_unload); - if (iter != module_symbol_lines_.end()) { - symbol_lines_ -= iter->second; - module_symbol_lines_.erase(iter); - } - } -} - -} // namespace google_breakpad diff --git a/src/processor/network_source_line_server.h b/src/processor/network_source_line_server.h deleted file mode 100644 index 6ea4bba8..00000000 --- a/src/processor/network_source_line_server.h +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// NetworkSourceLineServer implements a UDP-based network protocol -// to allow clients to query for source line information. -// -// A brief protocol description can be found in network_source_line_protocol.h - -#ifndef GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_SERVER_H_ -#define GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_SERVER_H_ - -#include <list> -#include <string> -#include <vector> - -#include "google_breakpad/common/breakpad_types.h" -#include "google_breakpad/processor/basic_source_line_resolver.h" -#include "google_breakpad/processor/symbol_supplier.h" -#include "processor/binarystream.h" -#include "processor/network_interface.h" -#include "processor/udp_network.h" - -namespace google_breakpad { - -using std::list; -using std::string; -using std::vector; - -class NetworkSourceLineServer { - public: - explicit NetworkSourceLineServer(SymbolSupplier *supplier, - SourceLineResolverInterface *resolver, - unsigned short listen_port, - bool ip4only, - const string &listen_address, - u_int64_t max_symbol_lines) - : initialized_(false), - net_(new UDPNetwork(listen_address, listen_port, ip4only)), - resolver_(resolver), - supplier_(supplier), - max_symbol_lines_(max_symbol_lines), - symbol_lines_(0) {}; - - NetworkSourceLineServer(SymbolSupplier *supplier, - SourceLineResolverInterface *resolver, - NetworkInterface *net, - u_int64_t max_symbol_lines = 0) - : initialized_(false), - net_(net), - resolver_(resolver), - supplier_(supplier), - max_symbol_lines_(max_symbol_lines), - symbol_lines_(0) {}; - - // Initialize network connection. Will be called automatically by - // RunOnce or RunForever if not already initialized. - // Returns false if network setup fails. - bool Initialize(); - - // Run forever serving connections. - // Returns false only if network setup fails. - bool RunForever(); - - // Look for incoming connections and serve them. - // Wait at most |wait_milliseconds| before returning. Return true - // if any connections were served, and false otherwise. - bool RunOnce(int wait_milliseconds); - - private: - bool initialized_; - NetworkInterface *net_; - SourceLineResolverInterface *resolver_; - SymbolSupplier *supplier_; - // Maximum number of symbol lines to store in memory. - // The number of lines in a symbol file is used as a rough - // proxy for memory usage when parsed and loaded. When - // this limit is surpassed, modules will be unloaded until - // the sum of currently loaded modules is again lower - // than this limit. - const u_int64_t max_symbol_lines_; - // Current number of symbol lines loaded - u_int64_t symbol_lines_; - // List of modules loaded, in most-to-least recently used order - list<string> modules_used_; - // Number of symbol lines loaded, per module. - map<string, int> module_symbol_lines_; - - void HandleHas(binarystream &message, binarystream &response); - void HandleLoad(binarystream &message, binarystream &response); - void HandleGet(binarystream &message, binarystream &response); - void HandleGetStackWin(binarystream &message, binarystream &response); - void HandleGetStackCFI(binarystream &message, binarystream &response); - string FormatWindowsFrameInfo(WindowsFrameInfo *frame_info); - - int CountNewlines(const string &str); - - // Move this module to the front of the used list. - void UsedModule(const CodeModule &module); - // Try to unload some modules to reclaim memory. - // Do not unload the module passed in, as this was just loaded. - void TryUnloadModules(const CodeModule &just_loaded_module); - - protected: - // protected so we can easily unit test it - bool HandleRequest(binarystream &request, binarystream &response); -}; - -} // namespace google_breakpad - -#endif // GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_SERVER_H_ diff --git a/src/processor/network_source_line_server_unittest.cc b/src/processor/network_source_line_server_unittest.cc deleted file mode 100644 index c45f19cc..00000000 --- a/src/processor/network_source_line_server_unittest.cc +++ /dev/null @@ -1,963 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Unit tests for NetworkSourceLineServer. - -#include <ios> -#include <set> -#include <string> - -#include "breakpad_googletest_includes.h" -#include "google_breakpad/processor/code_module.h" -#include "google_breakpad/processor/source_line_resolver_interface.h" -#include "google_breakpad/processor/stack_frame.h" -#include "google_breakpad/processor/symbol_supplier.h" -#include "processor/binarystream.h" -#include "processor/cfi_frame_info.h" -#include "processor/network_source_line_server.h" -#include "processor/network_source_line_protocol.h" -#include "processor/windows_frame_info.h" - -namespace { -using std::ios_base; -using std::set; -using std::string; -using google_breakpad::CFIFrameInfo; -using google_breakpad::CodeModule; -using google_breakpad::binarystream; -using google_breakpad::NetworkInterface; -using google_breakpad::NetworkSourceLineServer; -using google_breakpad::SourceLineResolverInterface; -using google_breakpad::StackFrame; -using google_breakpad::SymbolSupplier; -using google_breakpad::SystemInfo; -using google_breakpad::WindowsFrameInfo; -using ::testing::_; -using ::testing::DoAll; -using ::testing::Invoke; -using ::testing::Property; -using ::testing::Return; -using ::testing::SetArgumentPointee; -// Style guide forbids "using namespace", so at least shorten it. -namespace P = google_breakpad::source_line_protocol; - -class MockNetwork : public NetworkInterface { - public: - MockNetwork() {} - - MOCK_METHOD1(Init, bool(bool listen)); - MOCK_METHOD2(Send, bool(const char *data, size_t length)); - MOCK_METHOD1(WaitToReceive, bool(int timeout)); - MOCK_METHOD3(Receive, bool(char *buffer, size_t buffer_size, - ssize_t &received)); -}; - -class MockSymbolSupplier : public SymbolSupplier { -public: - MockSymbolSupplier() {} - - MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file)); - MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data)); - MOCK_METHOD4(GetCStringSymbolData, SymbolResult(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data)); - MOCK_METHOD1(FreeSymbolData, void(const CodeModule *module)); -}; - -class MockSourceLineResolver : public SourceLineResolverInterface { - public: - MockSourceLineResolver() {} - virtual ~MockSourceLineResolver() {} - - MOCK_METHOD2(LoadModule, bool(const CodeModule *module, - const string &map_file)); - MOCK_METHOD2(LoadModuleUsingMapBuffer, bool(const CodeModule *module, - const string &map_buffer)); - MOCK_METHOD2(LoadModuleUsingMemoryBuffer, bool(const CodeModule *module, - char *memory_buffer)); - MOCK_METHOD0(ShouldDeleteMemoryBufferAfterLoadModule, bool()); - MOCK_METHOD1(UnloadModule, void(const CodeModule *module)); - MOCK_METHOD1(HasModule, bool(const CodeModule *module)); - MOCK_METHOD1(FillSourceLineInfo, void(StackFrame *frame)); - MOCK_METHOD1(FindWindowsFrameInfo, - WindowsFrameInfo*(const StackFrame *frame)); - MOCK_METHOD1(FindCFIFrameInfo, - CFIFrameInfo*(const StackFrame *frame)); -}; - -class TestNetworkSourceLineServer : public NetworkSourceLineServer { - public: - // Override visibility for testing. It's a lot easier to just - // call into this method and verify the result than it would be - // to mock out the calls to the NetworkInterface, even though - // that would ostensibly be more correct and test the code more - // thoroughly. Perhaps if someone has time and figures out a - // clean way to do it this could be changed. - using NetworkSourceLineServer::HandleRequest; - - TestNetworkSourceLineServer(SymbolSupplier *supplier, - SourceLineResolverInterface *resolver, - NetworkInterface *net, - u_int64_t max_symbol_lines = 0) - : NetworkSourceLineServer(supplier, resolver, net, max_symbol_lines) - - {} -}; - -class NetworkSourceLineServerTest : public ::testing::Test { - public: - MockSymbolSupplier supplier; - MockSourceLineResolver resolver; - MockNetwork net; - TestNetworkSourceLineServer *server; - - NetworkSourceLineServerTest() : server(NULL) {} - - void SetUp() { - server = new TestNetworkSourceLineServer(&supplier, &resolver, &net); - } -}; - -TEST_F(NetworkSourceLineServerTest, TestInit) { - EXPECT_CALL(net, Init(true)).WillOnce(Return(true)); - EXPECT_CALL(net, WaitToReceive(0)).WillOnce(Return(false)); - ASSERT_TRUE(server->Initialize()); - EXPECT_FALSE(server->RunOnce(0)); -} - -TEST_F(NetworkSourceLineServerTest, TestMalformedRequest) { - binarystream request; - // send a request without a full sequence number - request << u_int8_t(1); - binarystream response; - EXPECT_FALSE(server->HandleRequest(request, response)); - request.rewind(); - // send a request without a command - request << u_int16_t(1); - EXPECT_FALSE(server->HandleRequest(request, response)); -} - -TEST_F(NetworkSourceLineServerTest, TestUnknownCommand) { - binarystream request; - // send a request with an unknown command - request << u_int16_t(1) << u_int8_t(100); - binarystream response; - ASSERT_TRUE(server->HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status; - response >> response_sequence >> response_status; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(u_int16_t(1), response_sequence); - EXPECT_EQ(P::ERROR, int(response_status)); -} - -TEST_F(NetworkSourceLineServerTest, TestHasBasic) { - EXPECT_CALL(resolver, HasModule(_)) - .WillOnce(Return(false)) - .WillOnce(Return(true)); - - binarystream request; - const u_int16_t sequence = 0xA0A0; - // first request should come back as not loaded - request << sequence << P::HAS << string("test.dll") << string("test.pdb") - << string("ABCD1234"); - binarystream response; - ASSERT_TRUE(server->HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status, response_data; - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ(P::MODULE_NOT_LOADED, int(response_data)); - // second request should come back as loaded - binarystream request2; - request2 << sequence << P::HAS << string("loaded.dll") << string("loaded.pdb") - << string("ABCD1234"); - ASSERT_TRUE(server->HandleRequest(request2, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ(P::MODULE_LOADED, int(response_data)); -} - -TEST_F(NetworkSourceLineServerTest, TestMalformedHasRequest) { - binarystream request; - // send request with just command, missing all data - const u_int16_t sequence = 0xA0A0; - request << sequence << P::HAS; - binarystream response; - ASSERT_TRUE(server->HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status; - response >> response_sequence >> response_status; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::ERROR, int(response_status)); - // send request with just module name - binarystream request2; - request2 << sequence << P::HAS << string("test.dll"); - ASSERT_TRUE(server->HandleRequest(request2, response)); - response >> response_sequence >> response_status; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::ERROR, int(response_status)); - // send request with module name, debug file, missing debug id - binarystream request3; - request3 << sequence << P::HAS << string("test.dll") << string("test.pdb"); - ASSERT_TRUE(server->HandleRequest(request3, response)); - response >> response_sequence >> response_status; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::ERROR, int(response_status)); -} - -TEST_F(NetworkSourceLineServerTest, TestHasLoad) { - EXPECT_CALL(resolver, HasModule(_)) - .WillOnce(Return(false)) - .WillOnce(Return(false)) - .WillOnce(Return(true)); - EXPECT_CALL(resolver, LoadModuleUsingMapBuffer(_,_)) - .WillOnce(Return(true)); - EXPECT_CALL(supplier, GetSymbolFile(_,_,_,_)) - .WillOnce(Return(SymbolSupplier::FOUND)); - - // verify that the module is not loaded, with a HAS request - binarystream request; - const u_int16_t sequence = 0xA0A0; - request << sequence << P::HAS << string("found.dll") << string("found.pdb") - << string("ABCD1234"); - binarystream response; - ASSERT_TRUE(server->HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status, response_data; - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(P::MODULE_NOT_LOADED, int(response_data)); - // now send a load request for this module - binarystream request2; - const u_int16_t sequence2 = 0xB0B0; - request2 << sequence2 << P::LOAD << string("found.dll") << string("found.pdb") - << string("ABCD1234"); - ASSERT_TRUE(server->HandleRequest(request2, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - // sending another HAS message should now show it as loaded - binarystream request3; - const u_int16_t sequence3 = 0xC0C0; - request3 << sequence3 << P::HAS << string("found.dll") << string("found.pdb") - << string("ABCD1234"); - ASSERT_TRUE(server->HandleRequest(request3, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence3, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ(P::MODULE_LOADED, int(response_data)); -} - -TEST_F(NetworkSourceLineServerTest, TestLoad) { - EXPECT_CALL(resolver, HasModule(_)) - .Times(3) - .WillRepeatedly(Return(false)); - EXPECT_CALL(resolver, LoadModuleUsingMapBuffer(_,_)) - .WillOnce(Return(false)); - EXPECT_CALL(supplier, GetSymbolFile(_,_,_,_)) - .WillOnce(Return(SymbolSupplier::NOT_FOUND)) - .WillOnce(Return(SymbolSupplier::INTERRUPT)) - .WillOnce(Return(SymbolSupplier::FOUND)); - - // notfound.dll should return LOAD_NOT_FOUND - binarystream request; - const u_int16_t sequence = 0xA0A0; - request << sequence << P::LOAD << string("notfound.dll") - << string("notfound.pdb") << string("ABCD1234"); - binarystream response; - ASSERT_TRUE(server->HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status, response_data; - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ(int(P::LOAD_NOT_FOUND), int(response_data)); - // interrupt.dll should return LOAD_INTERRUPT - binarystream request2; - const u_int16_t sequence2 = 0xB0B0; - request2 << sequence2 << P::LOAD << string("interrupt.dll") - << string("interrupt.pdb") << string("0000"); - ASSERT_TRUE(server->HandleRequest(request2, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ(int(P::LOAD_INTERRUPT), int(response_data)); - // fail.dll should return LOAD_FAIL - binarystream request3; - const u_int16_t sequence3 = 0xC0C0; - request3 << sequence3 << P::LOAD << string("fail.dll") << string("fail.pdb") - << string("FFFFFFFF"); - ASSERT_TRUE(server->HandleRequest(request3, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence3, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ(int(P::LOAD_FAIL), int(response_data)); -} - -TEST_F(NetworkSourceLineServerTest, TestMalformedLoadRequest) { - binarystream request; - // send request with just command, missing all data - const u_int16_t sequence = 0xA0A0; - request << sequence << P::LOAD; - binarystream response; - ASSERT_TRUE(server->HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status; - response >> response_sequence >> response_status; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::ERROR, int(response_status)); - // send request with just module name - binarystream request2; - request2 << sequence << P::LOAD << string("test.dll"); - ASSERT_TRUE(server->HandleRequest(request2, response)); - response >> response_sequence >> response_status; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::ERROR, int(response_status)); - // send request with module name, debug file, missing debug id - binarystream request3; - request3 << sequence << P::LOAD << string("test.dll") << string("test.pdb"); - ASSERT_TRUE(server->HandleRequest(request3, response)); - response >> response_sequence >> response_status; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::ERROR, int(response_status)); -} - -void FillFullSourceLineInfo(StackFrame *frame) { - frame->function_name = "function1"; - frame->function_base = 0x1200; - frame->source_file_name = "function1.cc"; - frame->source_line = 1; - frame->source_line_base = 0x1230; -} - -void FillPartialSourceLineInfo(StackFrame *frame) { - frame->function_name = "function2"; - frame->function_base = 0xFFF0; -} - -TEST_F(NetworkSourceLineServerTest, TestGet) { - EXPECT_CALL(resolver, FillSourceLineInfo(_)) - .WillOnce(Invoke(FillFullSourceLineInfo)) - .WillOnce(Invoke(FillPartialSourceLineInfo)); - - binarystream request; - const u_int16_t sequence = 0xA0A0; - request << sequence << P::GET << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0x1234); - binarystream response; - ASSERT_TRUE(server->HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status; - string function, source_file; - u_int32_t source_line; - u_int64_t function_base, source_line_base; - response >> response_sequence >> response_status >> function - >> function_base >> source_file >> source_line >> source_line_base; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ("function1", function); - EXPECT_EQ(0x1200, function_base); - EXPECT_EQ("function1.cc", source_file); - EXPECT_EQ(1, source_line); - EXPECT_EQ(0x1230, source_line_base); - - binarystream request2; - const u_int16_t sequence2 = 0xC0C0; - request2 << sequence2 << P::GET << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0xFFFF); - ASSERT_TRUE(server->HandleRequest(request2, response)); - response >> response_sequence >> response_status >> function - >> function_base >> source_file >> source_line >> source_line_base; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ("function2", function); - EXPECT_EQ(0xFFF0, function_base); - EXPECT_EQ("", source_file); - EXPECT_EQ(0, source_line); - EXPECT_EQ(0, source_line_base); -} - -WindowsFrameInfo* GetFullWindowsFrameInfo(const StackFrame *frame) { - // return frame info with program string - return new WindowsFrameInfo(1, 2, 3, 0xA, 0xFF, 0xF00, - true, - "x y ="); -} - -WindowsFrameInfo* GetPartialWindowsFrameInfo(const StackFrame *frame) { - // return frame info, no program string - return new WindowsFrameInfo(1, 2, 3, 4, 5, 6, true, ""); -} - -TEST_F(NetworkSourceLineServerTest, TestGetStackWin) { - EXPECT_CALL(resolver, FindWindowsFrameInfo(_)) - .WillOnce(Invoke(GetFullWindowsFrameInfo)) - .WillOnce(Invoke(GetPartialWindowsFrameInfo)) - .WillOnce(Return((WindowsFrameInfo*)NULL)); - - binarystream request; - const u_int16_t sequence = 0xA0A0; - request << sequence << P::GETSTACKWIN << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0x1234); - binarystream response; - ASSERT_TRUE(server->HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status; - string stack_info; - response >> response_sequence >> response_status - >> stack_info; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ("0 0 0 1 2 3 a ff f00 1 x y =", stack_info); - - binarystream request2; - const u_int16_t sequence2 = 0xB0B0; - request2 << sequence2 << P::GETSTACKWIN << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0xABCD); - ASSERT_TRUE(server->HandleRequest(request2, response)); - response >> response_sequence >> response_status - >> stack_info; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ("0 0 0 1 2 3 4 5 6 0 1", stack_info); - - binarystream request3; - const u_int16_t sequence3 = 0xC0C0; - request3 << sequence3 << P::GETSTACKWIN << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0xFFFF); - ASSERT_TRUE(server->HandleRequest(request3, response)); - response >> response_sequence >> response_status - >> stack_info; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence3, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ("", stack_info); -} - - -CFIFrameInfo* GetCFIFrameInfoJustCFA(const StackFrame *frame) { - CFIFrameInfo* cfi = new CFIFrameInfo(); - cfi->SetCFARule("12345678"); - return cfi; -} - -CFIFrameInfo* GetCFIFrameInfoCFARA(const StackFrame *frame) { - CFIFrameInfo* cfi = new CFIFrameInfo(); - cfi->SetCFARule("12345678"); - cfi->SetRARule("abcdefgh"); - return cfi; -} - -CFIFrameInfo* GetCFIFrameInfoLots(const StackFrame *frame) { - CFIFrameInfo* cfi = new CFIFrameInfo(); - cfi->SetCFARule("12345678"); - cfi->SetRARule("abcdefgh"); - cfi->SetRegisterRule("r0", "foo bar"); - cfi->SetRegisterRule("b0", "123 abc +"); - return cfi; -} - -TEST_F(NetworkSourceLineServerTest, TestGetStackCFI) { - EXPECT_CALL(resolver, FindCFIFrameInfo(_)) - .WillOnce(Return((CFIFrameInfo*)NULL)) - .WillOnce(Invoke(GetCFIFrameInfoJustCFA)) - .WillOnce(Invoke(GetCFIFrameInfoCFARA)) - .WillOnce(Invoke(GetCFIFrameInfoLots)); - - binarystream request; - const u_int16_t sequence = 0xA0A0; - request << sequence << P::GETSTACKCFI << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0x1234); - binarystream response; - ASSERT_TRUE(server->HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status; - string stack_info; - response >> response_sequence >> response_status - >> stack_info; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ("", stack_info); - - binarystream request2; - const u_int16_t sequence2 = 0xB0B0; - request2 << sequence2 << P::GETSTACKCFI << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0xABCD); - ASSERT_TRUE(server->HandleRequest(request2, response)); - response >> response_sequence >> response_status - >> stack_info; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ(".cfa: 12345678", stack_info); - - binarystream request3; - const u_int16_t sequence3 = 0xC0C0; - request3 << sequence3 << P::GETSTACKCFI << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0xFFFF); - ASSERT_TRUE(server->HandleRequest(request3, response)); - response >> response_sequence >> response_status - >> stack_info; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence3, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ(".cfa: 12345678 .ra: abcdefgh", stack_info); - - binarystream request4; - const u_int16_t sequence4 = 0xD0D0; - request4 << sequence4 << P::GETSTACKCFI << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0xFFFF); - ASSERT_TRUE(server->HandleRequest(request4, response)); - response >> response_sequence >> response_status - >> stack_info; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence4, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ(".cfa: 12345678 .ra: abcdefgh b0: 123 abc + r0: foo bar", - stack_info); -} - -TEST_F(NetworkSourceLineServerTest, TestMalformedGetRequest) { - //TODO -} - -TEST(TestMissingMembers, TestServerWithoutSymbolSupplier) { - // Should provide reasonable responses without a SymbolSupplier - MockSourceLineResolver resolver; - MockNetwork net; - TestNetworkSourceLineServer server(NULL, &resolver, &net); - - // All LOAD requests should return LOAD_NOT_FOUND - binarystream request; - binarystream response; - const u_int16_t sequence = 0xB0B0; - u_int16_t response_sequence; - u_int8_t response_status, response_data; - request << sequence << P::LOAD << string("found.dll") << string("found.pdb") - << string("ABCD1234"); - ASSERT_TRUE(server.HandleRequest(request, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_NOT_FOUND), int(response_data)); -} - -TEST(TestMissingMembers, TestServerWithoutResolver) { - // Should provide reasonable responses without a SourceLineResolver - MockSymbolSupplier supplier; - MockNetwork net; - TestNetworkSourceLineServer server(&supplier, NULL, &net); - - // GET requests should return empty info - binarystream request; - binarystream response; - const u_int16_t sequence = 0xA0A0; - u_int16_t response_sequence; - u_int8_t response_status; - request << sequence << P::GET << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0x1234); - ASSERT_TRUE(server.HandleRequest(request, response)); - string function, source_file; - u_int32_t source_line; - u_int64_t function_base, source_line_base; - response >> response_sequence >> response_status >> function - >> function_base >> source_file >> source_line >> source_line_base; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ("", function); - EXPECT_EQ(0x0, function_base); - EXPECT_EQ("", source_file); - EXPECT_EQ(0, source_line); - EXPECT_EQ(0x0, source_line_base); - - // GETSTACKWIN requests should return an empty string - binarystream request2; - const u_int16_t sequence2 = 0xB0B0; - request << sequence2 << P::GETSTACKWIN << string("loaded.dll") - << string("loaded.pdb") << string("ABCD1234") - << u_int64_t(0x1000) << u_int64_t(0x1234); - ASSERT_TRUE(server.HandleRequest(request, response)); - string response_string; - response >> response_sequence >> response_status >> response_string; - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - EXPECT_EQ("", response_string); -} - -class TestModuleManagement : public ::testing::Test { -public: - MockSymbolSupplier supplier; - MockSourceLineResolver resolver; - MockNetwork net; - TestNetworkSourceLineServer server; - - // Init server with symbol line limit of 25 - TestModuleManagement() : server(&supplier, &resolver, &net, 25) {} -}; - -TEST_F(TestModuleManagement, TestModuleUnloading) { - EXPECT_CALL(supplier, GetSymbolFile(_,_,_,_)) - .Times(3) - .WillRepeatedly(DoAll(SetArgumentPointee<3>(string("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n")), - Return(SymbolSupplier::FOUND))); - EXPECT_CALL(resolver, HasModule(_)) - .Times(3) - .WillRepeatedly(Return(false)); - EXPECT_CALL(resolver, LoadModuleUsingMapBuffer(_,_)) - .Times(3) - .WillRepeatedly(Return(true)); - EXPECT_CALL(resolver, UnloadModule(Property(&CodeModule::code_file, - string("one.dll|one.pdb|1111")))) - .Times(1); - - // load three modules, each with 10 lines of symbols. - // the third module will overflow the server's symbol line limit, - // and should cause the first module to be unloaded. - binarystream request; - const u_int16_t sequence = 0x1010; - request << sequence << P::LOAD << string("one.dll") << string("one.pdb") - << string("1111"); - binarystream response; - ASSERT_TRUE(server.HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status, response_data; - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - - binarystream request2; - const u_int16_t sequence2 = 0x2020; - request2 << sequence2 << P::LOAD << string("two.dll") << string("two.pdb") - << string("2222"); - ASSERT_TRUE(server.HandleRequest(request2, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - - binarystream request3; - const u_int16_t sequence3 = 0x3030; - request3 << sequence3 << P::LOAD << string("three.dll") << string("three.pdb") - << string("3333"); - ASSERT_TRUE(server.HandleRequest(request3, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence3, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); -} - -TEST_F(TestModuleManagement, TestSymbolLimitTooLow) { - // load module with symbol count > limit, - // ensure that it doesn't get unloaded even though it's the only module - EXPECT_CALL(supplier, GetSymbolFile(_,_,_,_)) - .WillOnce(DoAll(SetArgumentPointee<3>(string("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n")), - Return(SymbolSupplier::FOUND))); - EXPECT_CALL(resolver, HasModule(_)) - .WillOnce(Return(false)); - EXPECT_CALL(resolver, LoadModuleUsingMapBuffer(_,_)) - .WillOnce(Return(true)); - EXPECT_CALL(resolver, UnloadModule(_)) - .Times(0); - - binarystream request; - const u_int16_t sequence = 0x1010; - request << sequence << P::LOAD << string("one.dll") << string("one.pdb") - << string("1111"); - binarystream response; - ASSERT_TRUE(server.HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status, response_data; - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); -} - -TEST_F(TestModuleManagement, TestModuleLoadLRU) { - // load 2 modules, then re-load the first one, - // then load a third one, causing the second one to be unloaded - EXPECT_CALL(supplier, GetSymbolFile(_,_,_,_)) - .Times(3) - .WillRepeatedly(DoAll(SetArgumentPointee<3>(string("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n")), - Return(SymbolSupplier::FOUND))); - EXPECT_CALL(resolver, HasModule(_)) - .WillOnce(Return(false)) // load module 1 - .WillOnce(Return(false)) // load module 2 - .WillOnce(Return(true)) // module 1 already loaded - .WillOnce(Return(false)); // load module 3 - EXPECT_CALL(resolver, LoadModuleUsingMapBuffer(_,_)) - .Times(3) - .WillRepeatedly(Return(true)); - EXPECT_CALL(resolver, UnloadModule(Property(&CodeModule::code_file, - string("two.dll|two.pdb|2222")))) - .Times(1); - - binarystream request; - const u_int16_t sequence = 0x1010; - request << sequence << P::LOAD << string("one.dll") << string("one.pdb") - << string("1111"); - binarystream response; - ASSERT_TRUE(server.HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status, response_data; - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - - binarystream request2; - const u_int16_t sequence2 = 0x2020; - request2 << sequence2 << P::LOAD << string("two.dll") << string("two.pdb") - << string("2222"); - ASSERT_TRUE(server.HandleRequest(request2, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - - binarystream request3; - const u_int16_t sequence3 = 0x3030; - request3 << sequence3 << P::LOAD << string("one.dll") << string("one.pdb") - << string("1111"); - ASSERT_TRUE(server.HandleRequest(request3, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence3, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - - binarystream request4; - const u_int16_t sequence4 = 0x4040; - request4 << sequence4 << P::LOAD << string("three.dll") << string("three.pdb") - << string("3333"); - ASSERT_TRUE(server.HandleRequest(request4, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence4, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); -} - -TEST_F(TestModuleManagement, TestModuleGetLRU) { - // load 2 modules, then issue a GET for the first one, - // then load a third one, causing the second one to be unloaded - EXPECT_CALL(supplier, GetSymbolFile(_,_,_,_)) - .Times(3) - .WillRepeatedly(DoAll(SetArgumentPointee<3>(string("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n")), - Return(SymbolSupplier::FOUND))); - EXPECT_CALL(resolver, HasModule(_)) - .Times(3) - .WillRepeatedly(Return(false)); - EXPECT_CALL(resolver, LoadModuleUsingMapBuffer(_,_)) - .Times(3) - .WillRepeatedly(Return(true)); - EXPECT_CALL(resolver, FillSourceLineInfo(_)) - .Times(1); - EXPECT_CALL(resolver, UnloadModule(Property(&CodeModule::code_file, - string("two.dll|two.pdb|2222")))) - .Times(1); - - binarystream request; - const u_int16_t sequence = 0x1010; - request << sequence << P::LOAD << string("one.dll") << string("one.pdb") - << string("1111"); - binarystream response; - ASSERT_TRUE(server.HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status, response_data; - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - - binarystream request2; - const u_int16_t sequence2 = 0x2020; - request2 << sequence2 << P::LOAD << string("two.dll") << string("two.pdb") - << string("2222"); - ASSERT_TRUE(server.HandleRequest(request2, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - - binarystream request3; - const u_int16_t sequence3 = 0x3030; - request3 << sequence3 << P::GET << string("one.dll") - << string("one.pdb") << string("1111") - << u_int64_t(0x1000) << u_int64_t(0x1234); - ASSERT_TRUE(server.HandleRequest(request3, response)); - string function, source_file; - u_int32_t source_line; - u_int64_t function_base, source_line_base; - response >> response_sequence >> response_status >> function - >> function_base >> source_file >> source_line >> source_line_base; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence3, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - // Don't care about the rest of the response, really. - - binarystream request4; - const u_int16_t sequence4 = 0x4040; - request4 << sequence4 << P::LOAD << string("three.dll") << string("three.pdb") - << string("3333"); - ASSERT_TRUE(server.HandleRequest(request4, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence4, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); -} - -TEST_F(TestModuleManagement, TestModuleGetStackWinLRU) { - // load 2 modules, then issue a GETSTACKWIN for the first one, - // then load a third one, causing the second one to be unloaded - EXPECT_CALL(supplier, GetSymbolFile(_,_,_,_)) - .Times(3) - .WillRepeatedly(DoAll(SetArgumentPointee<3>(string("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n")), - Return(SymbolSupplier::FOUND))); - EXPECT_CALL(resolver, HasModule(_)) - .Times(3) - .WillRepeatedly(Return(false)); - EXPECT_CALL(resolver, LoadModuleUsingMapBuffer(_,_)) - .Times(3) - .WillRepeatedly(Return(true)); - EXPECT_CALL(resolver, FindWindowsFrameInfo(_)) - .WillOnce(Return((WindowsFrameInfo*)NULL)); - EXPECT_CALL(resolver, UnloadModule(Property(&CodeModule::code_file, - string("two.dll|two.pdb|2222")))) - .Times(1); - - binarystream request; - const u_int16_t sequence = 0x1010; - request << sequence << P::LOAD << string("one.dll") << string("one.pdb") - << string("1111"); - binarystream response; - ASSERT_TRUE(server.HandleRequest(request, response)); - u_int16_t response_sequence; - u_int8_t response_status, response_data; - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - - binarystream request2; - const u_int16_t sequence2 = 0x2020; - request2 << sequence2 << P::LOAD << string("two.dll") << string("two.pdb") - << string("2222"); - ASSERT_TRUE(server.HandleRequest(request2, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence2, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); - - binarystream request3; - const u_int16_t sequence3 = 0x3030; - request3 << sequence3 << P::GETSTACKWIN << string("one.dll") - << string("one.pdb") << string("1111") - << u_int64_t(0x1000) << u_int64_t(0x1234); - ASSERT_TRUE(server.HandleRequest(request3, response)); - string stack_info; - response >> response_sequence >> response_status - >> stack_info; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence3, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - // Don't care about the rest of the response, really. - - binarystream request4; - const u_int16_t sequence4 = 0x4040; - request4 << sequence4 << P::LOAD << string("three.dll") << string("three.pdb") - << string("3333"); - ASSERT_TRUE(server.HandleRequest(request4, response)); - response >> response_sequence >> response_status >> response_data; - ASSERT_FALSE(response.eof()); - EXPECT_EQ(sequence4, response_sequence); - EXPECT_EQ(P::OK, int(response_status)); - ASSERT_EQ(int(P::LOAD_OK), int(response_data)); -} - -} // namespace - -int main(int argc, char *argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/processor/source_daemon.cc b/src/processor/source_daemon.cc deleted file mode 100644 index f47b1f3f..00000000 --- a/src/processor/source_daemon.cc +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// source_daemon.cc: Listen for incoming UDP requests for source line -// info, load symbol files and respond with source info. -// -// Author: Ted Mielczarek - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <string> -#include <vector> - -#include "google_breakpad/processor/basic_source_line_resolver.h" -#include "processor/logging.h" -#include "processor/network_source_line_server.h" -#include "processor/scoped_ptr.h" -#include "processor/simple_symbol_supplier.h" - -using std::string; -using std::vector; -using google_breakpad::BasicSourceLineResolver; -using google_breakpad::NetworkSourceLineServer; -using google_breakpad::scoped_ptr; -using google_breakpad::SimpleSymbolSupplier; - -void usage(char *progname) { - printf("Usage: %s [-p port] [-a listen address] " - "[-m maximum symbol lines to keep in memory] " - "<symbol paths>\n", progname); -} - -int main(int argc, char **argv) { - BPLOG_INIT(&argc, &argv); - - unsigned short listen_port = 0; - char listen_address[1024] = ""; - u_int64_t max_symbol_lines = 0; - int arg; - while((arg = getopt(argc, argv, "p:a:m:")) != -1) { - switch(arg) { - case 'p': { - int port_arg = atoi(optarg); - if (port_arg > -1 && port_arg < 65535) { - listen_port = port_arg; - } else { - fprintf(stderr, "Invalid port number for -p!\n"); - usage(argv[0]); - return 1; - } - } - break; - case 'a': - strncpy(listen_address, optarg, sizeof(listen_address)); - break; - case 'm': - max_symbol_lines = atoll(optarg); - break; - case '?': - fprintf(stderr, "Option -%c requires an argument\n", (char)optopt); - usage(argv[0]); - break; - default: - fprintf(stderr, "Unknown option: -%c\n", (char)arg); - usage(argv[0]); - return 1; - } - } - - if (optind >= argc) { - usage(argv[0]); - return 1; - } - - vector<string> symbol_paths; - for (int argi = optind; argi < argc; ++argi) - symbol_paths.push_back(argv[argi]); - - scoped_ptr<SimpleSymbolSupplier> symbol_supplier; - if (!symbol_paths.empty()) { - symbol_supplier.reset(new SimpleSymbolSupplier(symbol_paths)); - } - BasicSourceLineResolver resolver; - - NetworkSourceLineServer server(symbol_supplier.get(), &resolver, listen_port, - // default to IPv4 if no listen address - // is specified - listen_address[0] == '\0', - listen_address, - max_symbol_lines); - if (!server.Initialize()) { - BPLOG(ERROR) << "Failed to initialize server."; - return 1; - } - - server.RunForever(); - // not reached - return 0; -} diff --git a/src/processor/udp_network.cc b/src/processor/udp_network.cc deleted file mode 100644 index 0cb911e0..00000000 --- a/src/processor/udp_network.cc +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "processor/udp_network.h" - -#include <arpa/inet.h> -#include <errno.h> -#include <netdb.h> -#include <netinet/in.h> -#include <stdio.h> -#include <string.h> -#include <sys/socket.h> - -#include <string> - -#include "processor/logging.h" - -namespace google_breakpad { -using std::string; -using std::dec; - -UDPNetwork::~UDPNetwork() { - if (socket_ != -1) { - close(socket_); - socket_ = -1; - } -} - -bool UDPNetwork::Init(bool listen) { - struct addrinfo hints; - struct addrinfo *results; - memset(&hints, 0, sizeof(hints)); - if (ip4only_) - hints.ai_family = AF_INET; - else - // don't care if it's IPv4 or IPv6 - hints.ai_family = AF_UNSPEC; - // want a UDP socket - hints.ai_socktype = SOCK_DGRAM; - if (listen) - hints.ai_flags = AI_PASSIVE; - - const char *hostname = NULL; - if (!server_.empty()) - hostname = server_.c_str(); - char portname[6]; - sprintf(portname, "%u", port_); - if (!listen) { - BPLOG(INFO) << "Initializing network connection to " << server_ - << ":" << dec << port_; - } - if (getaddrinfo(hostname, portname, &hints, &results) != 0) { - BPLOG(ERROR) << "failed to get address info for address " << server_ - << ": " << strerror(errno); - return false; - } - // save the address of the first result. - //TODO(ted): could support multiple DNS entries, round-robin them for - // fail-over etc - memcpy(&address_, results->ai_addr, GET_SA_LEN(results->ai_addr)); - - socket_ = socket(results->ai_family, results->ai_socktype, - results->ai_protocol); - freeaddrinfo(results); - - if (socket_ == -1) { - BPLOG(ERROR) << "failed to create socket: " << strerror(errno); - return false; - } - - if (listen) { - char address_string[INET_ADDRSTRLEN]; - void *addr = NULL; - if (((struct sockaddr*)&address_)->sa_family == AF_INET) - addr = &((struct sockaddr_in*)&address_)->sin_addr; - else if (((struct sockaddr*)&address_)->sa_family == AF_INET6) - addr = &((struct sockaddr_in6*)&address_)->sin6_addr; - if (inet_ntop(((struct sockaddr*)&address_)->sa_family, addr, - address_string, sizeof(address_string)) != NULL) - BPLOG(INFO) << "Listening on address " << address_string; - - if (bind(socket_, - (struct sockaddr *)&address_, - GET_SA_LEN(address_)) == -1) { - BPLOG(ERROR) << "Failed to bind socket"; - close(socket_); - return false; - } - socklen_t bound_addr_len = GET_SA_LEN(address_); - if (getsockname(socket_, (struct sockaddr *)&address_, &bound_addr_len) - == 0) { - if (((struct sockaddr*)&address_)->sa_family == AF_INET) - port_ = ntohs(((struct sockaddr_in*)&address_)->sin_port); - else if (((struct sockaddr*)&address_)->sa_family == AF_INET6) - port_ = ntohs(((struct sockaddr_in6*)&address_)->sin6_port); - } - BPLOG(INFO) << "Listening on port " << port_; - } - return true; -} - -bool UDPNetwork::Send(const char *data, size_t length) { - int total_sent = 0; - while (total_sent < length) { - int bytes_sent = sendto(socket_, - data + total_sent, - length - total_sent, - 0, - (struct sockaddr *)&address_, - GET_SA_LEN(address_)); - if (bytes_sent < 0) { - BPLOG(ERROR) << "error sending message: " - << strerror(errno) << " (" << errno << ")"; - break; - } - total_sent += bytes_sent; - } - return total_sent == length; -} - -bool UDPNetwork::WaitToReceive(int wait_time) { - fd_set readfds; - FD_ZERO(&readfds); - FD_SET(socket_, &readfds); - struct timeval timeout; - - timeout.tv_sec = wait_time / 1000; - timeout.tv_usec = (wait_time % 1000) * 1000; - int ret = select(socket_+1, &readfds, NULL, NULL, &timeout); - if (ret == 0) { - return false; - } else if (ret == -1) { - if (errno != EINTR) - BPLOG(ERROR) << "error in select(): " << strerror(errno); - return false; - } else if (!FD_ISSET(socket_, &readfds)) { - BPLOG(ERROR) << "select returned, but our socket isn't ready?"; - return false; - } - - return true; -} - -bool UDPNetwork::Receive(char *buffer, size_t buffer_size, ssize_t &received) { - socklen_t fromlen = GET_SA_LEN(address_); - received = recvfrom(socket_, buffer, buffer_size, 0, - (struct sockaddr *)&address_, - &fromlen); - - if (received == -1) { - BPLOG(ERROR) << "Error in recvfrom reading response: " - << strerror(errno); - } - return received != -1; -} - -} // namespace google_breakpad diff --git a/src/processor/udp_network.h b/src/processor/udp_network.h deleted file mode 100644 index 6e8488bc..00000000 --- a/src/processor/udp_network.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// UDPNetwork implements NetworkInterface using UDP sockets. - -#ifndef _GOOGLE_BREAKPAD_PROCESSOR_UDP_NETWORK_H_ -#define _GOOGLE_BREAKPAD_PROCESSOR_UDP_NETWORK_H_ - -#include <sys/socket.h> - -#include <string> - -#include "processor/network_interface.h" - -namespace google_breakpad { - -class UDPNetwork : public NetworkInterface { - public: - // Initialize a UDP Network socket at this address and port. - // address can be empty to indicate that any local address is acceptable. - UDPNetwork(const std::string address, - unsigned short port, - bool ip4only = false) - : server_(address), - port_(port), - ip4only_(ip4only), - socket_(-1) {}; - - ~UDPNetwork(); - - virtual bool Init(bool listen); - virtual bool Send(const char *data, size_t length); - virtual bool WaitToReceive(int timeout); - virtual bool Receive(char *buffer, size_t buffer_size, ssize_t &received); - - unsigned short port() { return port_; } - - private: - std::string server_; - unsigned short port_; - bool ip4only_; - struct sockaddr_storage address_; - int socket_; -}; - -} // namespace google_breakpad -#endif // GOOGLE_BREAKPAD_PROCESSOR_UDP_NETWORK_H_ |