Skip to content
This repository has been archived by the owner on Apr 13, 2021. It is now read-only.

Commit

Permalink
Add source code for the Windows DynamoRIO debug client
Browse files Browse the repository at this point in the history
  • Loading branch information
cblichmann committed Mar 17, 2016
1 parent aa24afd commit fa6509f
Show file tree
Hide file tree
Showing 16 changed files with 3,029 additions and 0 deletions.
15 changes: 15 additions & 0 deletions debug/client/windynamorio/AbstractCommandReader.cc
@@ -0,0 +1,15 @@
// Copyright 2011-2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "AbstractCommandReader.h"
30 changes: 30 additions & 0 deletions debug/client/windynamorio/AbstractCommandReader.h
@@ -0,0 +1,30 @@
//// Copyright 2011-2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Defines the interface that must be implemented by classes that want to
// receive IPC commands from the broker.
#ifndef ABSTRACTCOMMANDREADER_H_
#define ABSTRACTCOMMANDREADER_H_

#include <memory>

#include "drdebug.pb.h"

class AbstractCommandReader {
public:
virtual std::unique_ptr<security::drdebug::Command> WaitForCommand() = 0;
virtual bool SendResponse(const security::drdebug::Response& response) = 0;
};

#endif // ABSTRACTCOMMANDREADER_H_
94 changes: 94 additions & 0 deletions debug/client/windynamorio/BitReference.h
@@ -0,0 +1,94 @@
//// Copyright 2011-2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Provides BitReference class, which allows user to create a reference
// to selected range of bits in a variable.
#ifndef BITREFERENCE_H_
#define BITREFERENCE_H_

#include <cassert>

// Creates a reference to bits [first_bit_pos; first_bit_pos + bit_size - 1]
// from source variable
//
// Bit position X corresponds to the bit with value 2^X (X-th from the right,
// counting from 0)
//
// It doesn't free source pointer in destructor
//
// T should be an unsigned integer type (unsigned is needed because we can
// underflow in BitMask() method.
template <class T>
class BitReference {
public:
// Same as BitReference(source, 0, sizeof(T)*8)
explicit BitReference(T* source);

BitReference(T* source, int first_bit_pos, int bit_size);

void SetReference(T* source, int first_bit_pos, int bit_size);

T value() const;
void set_value(T val);

private:
T* source_;
int first_bit_pos_;
int bit_size_;

// Creates a bitmask with lowest bit_cnt bits set to 1
static T BitMask(int bit_cnt);
};

template <class T>
BitReference<T>::BitReference(T* source) {
SetReference(source, 0, sizeof(T) * 8);
}

template <class T>
BitReference<T>::BitReference(T* source, int first_bit_pos, int bit_size) {
SetReference(source, first_bit_pos, bit_size);
}

template <class T>
void BitReference<T>::SetReference(T* source, int first_bit_pos, int bit_size) {
assert(first_bit_pos >= 0 && first_bit_pos < sizeof(T) * 8);
assert(first_bit_pos + bit_size <= sizeof(T) * 8);
source_ = source;
first_bit_pos_ = first_bit_pos;
bit_size_ = bit_size;
}

template <class T>
T BitReference<T>::value() const {
return ((*source_) >> first_bit_pos_) & BitMask(bit_size_);
}

template <class T>
void BitReference<T>::set_value(T val) {
T val_mask = BitMask(bit_size_);
T mask = ~(val_mask << first_bit_pos_);
(*source_) = (((*source_) & mask) | ((val & val_mask) << first_bit_pos_));
}

template <class T>
T BitReference<T>::BitMask(int bit_cnt) {
// We need it to solve the problem with bit_cnt >= 32 (1 << 32 == 1)
if (bit_cnt >= sizeof(T) * 8)
return (T)0 - 1;
else
return ((T)1 << bit_cnt) - 1;
}

#endif // BITREFERENCE_H_
55 changes: 55 additions & 0 deletions debug/client/windynamorio/BreakpointInfo.h
@@ -0,0 +1,55 @@
// Copyright 2011-2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Provides BreakpointInfo, which holds breakpoint's parameters.
#ifndef BREAKPOINTINFO_H_
#define BREAKPOINTINFO_H_

#include <functional>
#include <memory>

#include "common.h"

// Note that instances of this class define an operator== that only takes the
// breakpoint id into account and ignores other fields.
class BreakpointInfo {
public:
BreakpointInfo(breakpoint_id_t id, bool auto_resume, bool send_registers) :
: id_(id), auto_resume_(auto_resume), send_registers_(send_registers) {}

breakpoint_id_t id() const { return id_; }
bool auto_resume() const { return auto_resume_; }
bool send_registers() const { return send_registers_; }

bool operator==(const BreakpointInfo& other) const {
return id_ == other.id_;
}

typedef std::function<bool(const std::unique_ptr<BreakpointInfo>&)>
BreakpointComparator;

// Returns a function which matches the thread with a given id.
// Intended for use with STL functions, e.g. std::remove_if.
static BreakpointComparator MakeBreakpointIdComparator(breakpoint_id_t id) {
return [id](const std::unique_ptr<BreakpointInfo>& t)
-> bool { return t->id() == id; };
}

private:
breakpoint_id_t id_;
bool auto_resume_;
bool send_registers_;
};

#endif // BREAKPOINTINFO_H_
59 changes: 59 additions & 0 deletions debug/client/windynamorio/CMakeLists.txt
@@ -0,0 +1,59 @@
# Copyright 2011-2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

cmake_minimum_required (VERSION 2.8)
# Make file for Dynamorio debugger client DLL.
project(dynamorio_client)

# Find dynamoRIO and set global options.
include(FindProtobuf)
find_package(Protobuf REQUIRED)
find_package(DynamoRIO REQUIRED)

include_directories(${PROTOBUF_INCLUDE_DIR})

set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")

PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS drdebug.proto)

foreach(PROTO_HDR ${PROTO_HDRS})
get_filename_component(HDR_DIR ${PROTO_HDR} DIRECTORY)
include_directories(${HDR_DIR})
endforeach(PROTO_HDR)

# Makes dynamic libraries (e.g. dr. memory) known to clients without having to
# copy them to the bin32 directory.
set(DynamoRIO_RPATH ON)

add_library(dynamorio_client SHARED
dynamorio_client.cc
common.h
WinPipeCommandReader.cc
WinPipeCommandReader.h
AbstractCommandReader.cc
AbstractCommandReader.h
BitReference.h
DebugState.h
DebugState.cc
ScopedLocker.h
BreakpointInfo.cc
BreakpointInfo.h
${PROTO_HDRS}
${PROTO_SRCS})

target_link_libraries(dynamorio_client ${PROTOBUF_LIBRARIES})

# Configure dynamorio_client client.
configure_DynamoRIO_client(dynamorio_client)
45 changes: 45 additions & 0 deletions debug/client/windynamorio/DebugState.cc
@@ -0,0 +1,45 @@
// Copyright 2011-2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "DebugState.h"

DebugState::DebugState() : state_(NOT_SET) {
mutex_ = dr_mutex_create();
}

DebugState::~DebugState() {
dr_mutex_destroy(mutex_);
}

void DebugState::Lock() {
dr_mutex_lock(mutex_);
}

void DebugState::Unlock() {
dr_mutex_unlock(mutex_);
}

security::drdebug::ExceptionAction DebugState::GetExceptionAction(
exception_code_t exc_code) {
auto it = exception_actions_.find(exc_code);
if (it == exception_actions_.end()) {
return security::drdebug::ExceptionAction::HALT;
}
return it->second;
}

void DebugState::SetExceptionAction(exception_code_t exc_code,
security::drdebug::ExceptionAction action) {
exception_actions_[exc_code] = action;
}
92 changes: 92 additions & 0 deletions debug/client/windynamorio/DebugState.h
@@ -0,0 +1,92 @@
//// Copyright 2011-2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Provides DebugState, holds current debugger state and manages state
// transitions. It holds only the part of debugger state that is shared
// between DynamoRIO callbacks and debugger loop, thus needs access
// synchronization.
#ifndef DEBUGSTATE_H_
#define DEBUGSTATE_H_

#include <map>
#include <memory>
#include <set>
#include <vector>

#include "BreakpointInfo.h"
#include "common.h"
#include "dr_api.h"
#include "drdebug.pb.h"

class DebugState {
public:
enum State {
NOT_SET, // Default value after DebugState construction.
RUNNING, // Debuggee is currently running.
WAITING, // Waiting after BP hit/exception.
HALTED, // Halted by user, waiting for resume.
EXITING, // After receiving exit_event, but before termination.
};

DebugState();
~DebugState();

// Acquire internal mutex
void Lock();

// Free internal mutex
void Unlock();

security::drdebug::ExceptionAction GetExceptionAction(
exception_code_t exc_code);
void SetExceptionAction(exception_code_t exc_code,
security::drdebug::ExceptionAction action);

// Getters/setters
State state() const { return state_; }

void set_state(State new_state) { state_ = new_state; }

std::set<app_pc>& breakpoint_addresses() { return breakpoint_addresses_; }

std::map<app_pc, std::vector<std::unique_ptr<BreakpointInfo>>>&
breakpoints() {
return breakpoints_;
}

std::vector<thread_id_t>& debuggee_threads() { return debugee_threads_; }

// No copy/assignment
DebugState(const DebugState&) = delete;
DebugState& operator =(const DebugState&) = delete;

private:
// Mutex for accessing fields
void* mutex_;
// Current state of debugged process
State state_;
// All debuggee addresses with breakpoints
std::set<app_pc> breakpoint_addresses_;
// Maps debuggee adress to a list of breakpoints id set on it
// We need a pointer, not an object, because we rely on that the info struct
// address won't change (we pass it in clean call to BPHit handler)
std::map<app_pc, std::vector<std::unique_ptr<BreakpointInfo>>> breakpoints_;
// Maps exception codes to its handling action
std::map<exception_code_t, security::drdebug::ExceptionAction>
exception_actions_;
// List of all debugee threads
std::vector<thread_id_t> debugee_threads_;
};

#endif // DEBUGSTATE_H_

0 comments on commit fa6509f

Please sign in to comment.