aboutsummaryrefslogtreecommitdiff
path: root/src/processor/network_source_line_server_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/processor/network_source_line_server_unittest.cc')
-rw-r--r--src/processor/network_source_line_server_unittest.cc955
1 files changed, 955 insertions, 0 deletions
diff --git a/src/processor/network_source_line_server_unittest.cc b/src/processor/network_source_line_server_unittest.cc
new file mode 100644
index 00000000..5e969ccf
--- /dev/null
+++ b/src/processor/network_source_line_server_unittest.cc
@@ -0,0 +1,955 @@
+// 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));
+};
+
+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_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();
+}