Browse Source

Initial commit

pull/3/head
Eyck Jentzsch 2 years ago
commit
3f7f3b425f

+ 54
- 0
CMakeLists.txt View File

@@ -0,0 +1,54 @@
cmake_minimum_required(VERSION 2.8)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) # main (top) cmake dir
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # project specific cmake dir
set(CMAKE_CXX_STANDARD 14) # tODO move up to a general cmake config for all sub projects ?

# CMake useful variables
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")

# Set the name of your project here
project("iss")

# Set the version number of your project here (format is MAJOR.MINOR.PATCHLEVEL - e.g. 1.0.0)
set(VERSION_MAJOR "0")
set(VERSION_MINOR "0")
set(VERSION_PATCH "1")
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})

include(Common)

## Git (and its revision)
find_package(Git QUIET) # if we don't find git or FindGit.cmake is not on the system we ignore it.
## The Git module will trigger a reconfiguration for each pull that will bring a new revision on the local repository
set (VCS_REVISION "-1")
if(GIT_FOUND)
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
message(STATUS "GIT branch ${GIT_REFSPEC}")
message(STATUS "GIT revision ${GIT_SHA1}")
set (VCS_REVISION ${GIT_SHA1})
endif()

if(DEFINED ENV{LLVM_HOME})
find_path (LLVM_DIR LLVM-Config.cmake $ENV{LLVM_HOME}/lib/cmake/llvm)
message(STATUS "LLVM_DIR = ${LLVM_DIR}")
endif(DEFINED ENV{LLVM_HOME})

find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")

# This sets the include directory for the reference project. This is the -I flag in gcc.
include_directories(
${PROJECT_SOURCE_DIR}/incl
${PROJECT_SOURCE_DIR}/../external/easyloggingpp/src
${LLVM_INCLUDE_DIRS}
)

add_dependent_header(util)

add_definitions(${LLVM_DEFINITIONS})

add_subdirectory(src)

+ 29
- 0
LICENSE View File

@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2016, MINRES Technologies GmbH
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 the copyright holder 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 HOLDER 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.

+ 42
- 0
README.md View File

@@ -0,0 +1,42 @@
# JIT-ISS
A versatile Just-in-time (JIT) compiling instruction set simulator (ISS)

**JIT-ISS README**

This is currently a proof of concept and work in progress, so use at your own risk. It is currently set-up as an Eclipse CDT project and based on LLVM. To build it you need latest LLVM and Eclipse CDT version 4.6 aka Neon.

To build with SystemC the define WITH_SYSTEMC needs to be set. Then a simple proof-of-concept system is created. Mainly missing are platform peripherals and interrupt handling. It reaches about 5 MIPS in lock-step mode on a MacBook Pro (Core i7-4870HQ@2.5GHz) running in a Docker container.

JIT-ISS uses libGIS (https://github.com/vsergeev/libGIS) as well as ELFIO (http://elfio.sourceforge.net/), both under MIT license

**What's missing**

* only AVR instruction set implemented but not verified

**Planned features**

* add platform peripherals
* timers
* gpio
* ext interrupt registers and functionality
* and more

**Quick start**

* you need to have a decent compiler, make and cmake installed
* install LLVM 3.9 or 4.0 according to http://apt.llvm.org/
* download and install SystemC from http://accellera.org/downloads/standards/systemc
* optionally download and install SystemC Verification Library (SCV) from Accelera into the same location
* checkout source from git
* start an out-of-source build like so (e.g. when using LLVM 3.9 and bash)
```
cd JIT-ISS
mkdir build
cd build
LLVM_HOME=/usr/lib/llvm-3.9 cmake ..
make
```
* if the SystemC installation is not to be found be cmake you can optionally specify the location by either setting the following environment variables pointing to the installation
- SYSTEMC_HOME
- SYSTEMC_PREFIX

+ 82
- 0
cmake/CPackConfig.cmake View File

@@ -0,0 +1,82 @@
# @author Barthélémy von Haller

# General CPack configuration
# Info: http://www.itk.org/Wiki/CMake:Component_Install_With_CPack
# _____________________________________________________________________________

set(CPACK_PACKAGE_NAME "iss")

if(APPLE)
set(CPACK_PACKAGE_VENDOR "Organisation") # PackageMaker doesn't like http://
else()
set(CPACK_PACKAGE_VENDOR "http://example.com") # deb lintian insists on URL
endif()

set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Example project")
set(CPACK_PACKAGE_CONTACT "Person name <name@example.com>")
set(CPACK_PACKAGE_VERSION ${VERSION})
set(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH})
set(CPACK_RPM_PACKAGE_DEBUG 0)

# Select package generator
if(MSVC)
set(CPACK_GENERATOR "NSIS")
endif(MSVC)

if(APPLE)
set(CPACK_GENERATOR "PackageMaker")
set(CPACK_SET_DESTDIR ON)
endif(APPLE)

if (${CMAKE_SYSTEM_NAME} MATCHES Linux)
find_program(RPM_EXE rpmbuild)
if(${RPM_EXE} MATCHES RPM_EXE-NOTFOUND)
set(CPACK_GENERATOR "TGZ;DEB")
else()
set(CPACK_GENERATOR "TGZ;DEB;RPM")
endif()
endif(${CMAKE_SYSTEM_NAME} MATCHES Linux)

# Components
# See www.cmake.org/Wiki/CMake:Component_Install_With_CPack#Controlling_Differents_Ways_of_packaging_components
# _____________________________________________________________________________
set(CPACK_COMPONENT_INSTALL ON)
set(CPACK_COMPONENTS_ALL libs devel doc)

set(CPACK_COMPONENT_LIBS_DISPLAY_NAME "Libraries")
set(CPACK_COMPONENT_LIBS_DESCRIPTION "Runtime libraries.")
set(CPACK_COMPONENT_LIBS_GROUP "Runtime")
# express component dependencies this way, it will translate into package dependencies where applicable
set(CPACK_COMPONENT_LIBS_DEPENDS doc)

set(CPACK_COMPONENT_DOCS_DISPLAY_NAME "Documents")
set(CPACK_COMPONENT_DOCS_DESCRIPTION "User Documentation")
set(CPACK_COMPONENT_DOCS_GROUP "Documentation")

set(CPACK_COMPONENT_DEV_DISPLAY_NAME "Development files")
set(CPACK_COMPONENT_DEV_DESCRIPTION "Development header files and libraries, as well as cmake config files.")
set(CPACK_COMPONENT_DEV_GROUP "Development")
set(CPACK_COMPONENT_DEV_DEPENDS libs)

# Debian specific configuration (minimum)
# _____________________________________________________________________________

set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_CONTACT}")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.1-6), libboost-test-dev")
SET(CPACK_DEBIAN_PACKAGE_CONFLICTS "Hello0-apps")

# RPM specific configuration (minimum)
# _____________________________________________________________________________
set(CPACK_RPM_PACKAGE_LICENSE "Proprietary")
set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries")
set(CPACK_RPM_PACKAGE_VERSION ${VERSION})
set(CPACK_RPM_COMPONENT_INSTALL ON) # necessary even if CPACK_COMPONENT_INSTALL set to ON. A bug in my opinion.

# OS X PackageMaker
# _____________________________________________________________________________
set(CPACK_OSX_PACKAGE_VERSION "10.5")

include (InstallRequiredSystemLibraries)
include (CPack)

+ 1
- 0
cmake/issConfig.cmake View File

@@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/issTargets.cmake")

+ 48
- 0
incl/iss/arch/traits.h View File

@@ -0,0 +1,48 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _TRAITS_H_
#define _TRAITS_H_

namespace iss {
namespace arch {

template<typename ARCH>
struct traits {

};
}
}

#endif /* _TRAITS_H_ */

+ 149
- 0
incl/iss/arch_if.h View File

@@ -0,0 +1,149 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _ARCH_IF_H_
#define _ARCH_IF_H_

#include "vm_types.h"

#include <vector>
#include <algorithm>

namespace iss {
/**
* exception to be thrown if the architecture encounters a synchronous trap
*/
struct trap_access {
trap_access(unsigned id, uint64_t addr) : id(id), addr(addr) {}
const unsigned id;
const uint64_t addr;
};

/**
* architecture interface
*/
struct arch_if {
/* deprecated */
enum operations {
NOP,
AND, OR, XOR,
ADD, ADC, SUB, SUBC, MUL, DIV,
ADDL, ADCL, SUBL, SUBCL, MULL, DIVL,
};
/**
* execution phases: instruction start and end
*/
enum exec_phase {ISTART, IEND};
/**
* reset the core
* @param address where to start from
*/
virtual void reset(uint64_t address)=0;
/**
* preload memories from file
* @param name name of th efile to load
* @param type of file, implementation dependent
*/
virtual void load_file(std::string name, int type =-1) = 0;
/**
* notify the core about the execution phase (if needed)
* @param the actual phase the vm is in
*/
virtual void notify_phase(exec_phase) =0;
/**
* get the pointer to the register array
* @return pointer to the registers
*/
virtual uint8_t* get_regs_base_ptr() = 0;
/* deprecated */
virtual void get_reg(short idx, std::vector<uint8_t>& value){};
virtual void set_reg(short idx, const std::vector<uint8_t>& value){};
/* deprecated */
virtual bool get_flag(int flag){return false;};
virtual void set_flag(int flag, bool value){};
virtual void update_flags(operations op, uint64_t opr1, uint64_t opr2){};
/**
* read from addresses
* @param addr address to read from, contains access type, address space and address
* @param length length of th edata to read
* @param data pointer to the memory to read into
* @return success or failure of access
*/
virtual iss::status read(const addr_t& addr, unsigned length, uint8_t* const data)=0;
/**
* write to addresses
* @param addr address to read from, contains access type, address space and address
* @param length length of the data to write
* @param data pointer to the memory to write from
* @return success or failure of access
*/
virtual iss::status write(const addr_t& addr, unsigned length, const uint8_t* const data)=0;
/**
* vm encountered a trap (exception, interrupt), process accordingly in core
* @param flags trap flags
* @return new (virtual) address to continue from
*/
virtual uint64_t enter_trap(uint64_t flags){return 0;}
/**
* vm encountered a trap (exception, interrupt), process accordingly in core
* @param flags trap flags
* @param addr address where the trap enountered
* @return new (virtual) address to continue from
*/
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr){return 0;}
/**
* vm decoded the instruction to return from trap (exception, interrupt), process accordingly in core
* @param flags trap flags
* @return new (virtual) address to continue from
*/
virtual uint64_t leave_trap(uint64_t flags){return 0;}
/**
* wait until condition indicated by flags becomes true
* @param flags indicating the condition
*/
virtual void wait_until(uint64_t flags){}
/**
* destructor
*/
virtual ~arch_if() {}
/**
* retrieve information to augment the disassembly
* @return string containing the core status in text form
*/
virtual std::string get_additional_disass_info(){ return "";};
};

}

#endif /* _ARCH_IF_H_ */

+ 161
- 0
incl/iss/debugger/cmdhandler.h View File

@@ -0,0 +1,161 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _CMDHANDLER_H_
#define _CMDHANDLER_H_

#include "encoderdecoder.h"
#include <unordered_map>

#include "server_if.h"
#include "target_adapter_if.h"

namespace iss {
namespace debugger {

enum {
MAX_DATABYTES = 0x10000, /* Size of data buffer */
INOUTBUF_SIZE =2*MAX_DATABYTES+32,
TARGET_SIGNAL0=0,
DBG_PRINTBUF_SIZE=400,
MAXARGS=4
};

enum signals {
/* Signal types */
HANGUP = 1,
INTERRUPT = 2,
QUIT = 3,
ILLEGAL_INSTRUCTION = 4,
TRAP = 5,
ABORTED = 6,
BUS_ERROR = 7,
FLOATING_POINT_EXCEPTION = 8,
KILLED = 9,
SEGMENT_VIOLATION = 11,
TERMINATED = 15,
STK_FLT = 16
};

/* Remote command */
#define GEN_ENTRY(name, hlp) {#name, &cmd_handler::rcmd_##name, hlp}

struct cmd_handler {
/* Table entry definition */
struct my_custom_command {
/* command name */
const char *name;
/* command function */
int (cmd_handler::*function)(int, char **, out_func, data_func);
/* one line of help text */
const char *help;
};

cmd_handler(iss::debugger::server_if& server)
:s(server)
, t(s.get_target())
, extended_protocol(false)
, can_restart(false)
{}

void attach();

std::string search_memory(const std::string in_buf);
std::string threads(const std::string in_buf);
std::string read_registers(const std::string in_buf);
std::string write_registers(const std::string in_buf);
std::string read_single_register(const std::string in_buf);
std::string write_single_register(const std::string in_buf);
std::string read_memory(const std::string in_buf);
std::string write_memory(const std::string in_buf);
std::string running(const std::string in_buf);
int kill(const std::string in_buf, std::string& out_buf);
std::string thread_alive(const std::string in_buf);
void interrupt_target();
int restart_target(const std::string in_buf, std::string& out_buf);
std::string detach(const std::string in_buf);
std::string query(const std::string in_buf);
std::string set(const std::string in_buf);
std::string handle_extended(const std::string in_buf);
std::string breakpoint(const std::string in_buf);
int rcmd(const char * const in_buf, out_func of, data_func df);
// TODO: change calls
int rcmd_help(int argc, char *argv[], out_func of, data_func df);
int rcmd_set(int argc, char *argv[], out_func of, data_func df);

/* Encode return value */
const char* to_string(int ret){
switch (ret){
case iss::Ok:
return "OK";
case iss::Err:
return "E00";
case iss::NotSupported:
return "";
default:
assert(0);
return nullptr;
}
}
const char* to_string(iss::status ret){
switch (ret){
case iss::Ok:
return "OK";
case iss::Err:
return "E00";
case iss::NotSupported:
return "";
default:
assert(0);
return nullptr;
}
}

iss::debugger::server_if& s;
std::shared_ptr<target_adapter_if> t;
encoder_decoder encdec;
bool extended_protocol;
bool can_restart;
std::unordered_map<uint64_t, unsigned> bp_map;
const my_custom_command rp_remote_commands[3] = {/* Table of commands */
GEN_ENTRY(help, "This help text"),
GEN_ENTRY(set, "Set debug level"),
{ nullptr, nullptr, nullptr } //sentinel, end of table marker
};
};

} // namespace debugger
} // namspace iss

#endif /* _CMDHANDLER_H_ */

+ 82
- 0
incl/iss/debugger/encoderdecoder.h View File

@@ -0,0 +1,82 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/
#ifndef _ENCODERDECODER_H_
#define _ENCODERDECODER_H_
#include <stddef.h>
#include <stdint.h>
#include <iostream>
#include <string>
#include <vector>

#include "target_adapter_if.h"

namespace iss {
namespace debugger {

struct encoder_decoder {
/* Decode/encode functions */
std::vector<uint8_t> dec_data(const char *in);

int dec_reg(const char *in, unsigned int *reg_no);

std::vector<uint8_t> dec_reg_assignment(const char *in, unsigned int *reg_no);
int dec_mem(const char *in, uint64_t *addr, size_t *len);
int dec_process_query(const char *in, unsigned int *mask, rp_thread_ref *ref);
int dec_break(const char *in, int *type, uint64_t *addr, unsigned int *len);
int dec_list_query(const char *in, int *first, size_t *max, rp_thread_ref *arg);
std::string enc_regs(const std::vector<uint8_t>& data, const std::vector<uint8_t>& avail);
std::string enc_data(const unsigned char *data, size_t data_len);
std::string enc_data(const std::vector<uint8_t>& data);
int enc_string(const char *s, char *out, size_t out_size);
std::string enc_process_query_response(unsigned int mask, const rp_thread_ref *ref, const rp_thread_info *info);
std::string enc_list_query_response(size_t count, int done, const rp_thread_ref& arg, const std::vector<rp_thread_ref> found);
int dec_nibble(const char *in, unsigned int *nibble);
int dec_byte(const char *in, unsigned int *byte_ptr);
int dec_4bytes(const char *in, uint32_t *val);
int dec_8bytes(const char *in, uint64_t *val);
int dec_uint32(char const **in, uint32_t *val, char break_char);
int dec_uint64(char const **in, uint64_t *val, char break_char);
void enc_byte(unsigned char val, std::string& out, size_t offset=0);
char enc_byte(unsigned char val, bool highNibble) {
return highNibble?hex[(val >> 4) & 0xf]:hex[val & 0xf];
}

private:
const char* hex = "0123456789abcdef";
void encode_str(std::stringstream& ss, const char* const str);
};

} // namespace debugger
} // namspace iss
#endif /* _ENCODERDECODER_H_ */

+ 99
- 0
incl/iss/debugger/gdb_session.h View File

@@ -0,0 +1,99 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _GDB_SESSION_H_
#define _GDB_SESSION_H_

#include <cstdlib>
#include <iostream>
#include <thread>
#include <chrono>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <iss/debugger/serialized_connection.h>

#include "cmdhandler.h"
#include "serialized_connection.h"
#include "server_if.h"

namespace iss {
namespace debugger {

using boost::asio::ip::tcp;

class gdb_session: public connection<std::string,std::string>::async_listener {
public:
gdb_session(server_if* server_, boost::asio::io_service& io_service)
: server(server_)
, conn_shptr(new connection<std::string,std::string>(io_service))
, handler(*server)
{
}

virtual ~gdb_session() {
}

tcp::socket& socket() {
return conn_shptr->socket();
}

int start();

void receive_completed(const boost::system::error_code& e, std::string* data) override;

void send_completed(const boost::system::error_code& e) override;

bool message_completed(std::vector<char>& buffer)override;
protected:

std::string check_packet(std::string& msg);

void parse_n_execute(std::string& msg);

void respond(const std::string msg){
last_msg=msg;
//std::this_thread::sleep_for(std::chrono::milliseconds(2));
CLOG(TRACE, "connection")<<"Processed message, responding with '"<<last_msg<<"'";
conn_shptr->write_data(&last_msg);
conn_shptr->async_read();
}
private:
server_if* server;
boost::shared_ptr<connection<std::string,std::string> > conn_shptr;
std::string last_msg;
cmd_handler handler;
};
}
}
#endif /* _GDB_SESSION_H_ */

+ 410
- 0
incl/iss/debugger/serialized_connection.h View File

@@ -0,0 +1,410 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _SERIALIZED_CONNECTION_H_
#define _SERIALIZED_CONNECTION_H_

#include <boost/asio.hpp>

#ifdef USE_TEXT
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
typedef boost::archive::text_oarchive oarchive_type;
typedef boost::archive::text_iarchive iarchive_type;
#else
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
typedef boost::archive::binary_oarchive oarchive_type;
typedef boost::archive::binary_iarchive iarchive_type;
#endif
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/tuple/tuple.hpp>
#include <iomanip>
#include <string>
#include <sstream>
#include <vector>
#include <easylogging++.h>


/// The connection class provides serialization primitives on top of a socket.
/**
* Each message sent using this class consists of:
* @li An 8-byte header containing the length of the serialized data in
* hexadecimal.
* @li The serialized data.
*/
template<typename TREQ, typename TRESP>
class connection: public boost::enable_shared_from_this<connection<TREQ, TRESP> > {
public:
typedef boost::shared_ptr<connection<TREQ, TRESP> > ptr;

struct async_listener: public boost::enable_shared_from_this<async_listener>{
virtual void send_completed(const boost::system::error_code& error) = 0;
virtual void receive_completed(const boost::system::error_code& error, TREQ* result) = 0;
};
/// Constructor.
connection(boost::asio::io_service& io_service) : socket_(io_service) {
}
/// Get the underlying socket. Used for making a connection or for accepting
/// an incoming connection.
boost::asio::ip::tcp::socket& socket() {
return socket_;
}
///
void add_listener(boost::shared_ptr<async_listener> l){
listener=l;
}
///
void remove_listener(){
listener.reset();
}
/// Asynchronously write a data structure to the socket.
void async_write(TRESP& t) {
async_write(&t);
}
/// Asynchronously write a data structure to the socket.
void async_write(TRESP* t) {
// Serialize the data first so we know how large it is.
std::ostringstream archive_stream;
oarchive_type archive(archive_stream);
archive << t;
outbound_data_ = archive_stream.str();
#ifdef EXTENDED_TRACE
CLOG(TRACE, "connection")<<"outbound async data with len "<< outbound_data_.size()<<":'"<<outbound_data_<<"'";
#endif
// Format the header.
std::ostringstream header_stream;
header_stream << std::setw(header_length) << std::hex <<std::setfill('0')<< outbound_data_.size();
if (!header_stream || header_stream.str().size() != header_length) {
// Something went wrong, inform the caller.
boost::system::error_code err(boost::asio::error::invalid_argument);
if(listener)listener->send_completed(err);
return;
}
outbound_header_ = header_stream.str();
// Write the serialized data to the socket. We use "gather-write" to send
// both the header and the data in a single write operation.
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(outbound_header_));
buffers.push_back(boost::asio::buffer(outbound_data_));
boost::asio::async_write(socket_, buffers,
boost::bind(&connection::handle_async_write, this->shared_from_this(),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

protected:
/// notify the listener about the finish of the send process
void handle_async_write(const boost::system::error_code& err, size_t /*bytes_transferred*/){
if(listener!=NULL) listener->send_completed(err);
}
public:
/// Asynchronously read a data structure from the socket.
void async_read() {
// Issue a read operation to read exactly the number of bytes in a header.
boost::asio::async_read(socket_, boost::asio::buffer(inbound_header_),
boost::bind(&connection::async_read_header, this, boost::asio::placeholders::error));
}

protected:
/// Handle a completed read of a message header. The handler is passed using
/// a tuple since boost::bind seems to have trouble binding a function object
/// created using boost::bind as a parameter.
void async_read_header(const boost::system::error_code& e) {
if (e) {
if(listener) listener->receive_completed(e, NULL);
} else {
// Determine the length of the serialized data.
std::istringstream is(std::string(inbound_header_, header_length));
std::size_t inbound_data_size = 0;
if (!(is >> std::hex >> inbound_data_size)) {
// Header doesn't seem to be valid. Inform the caller.
boost::system::error_code error(boost::asio::error::invalid_argument);
if(listener) listener->receive_completed(e, NULL);
return;
}
// Start an asynchronous call to receive the data.
inbound_data_.resize(inbound_data_size);
boost::asio::async_read(socket_, boost::asio::buffer(inbound_data_),
boost::bind(&connection::async_read_data, this, boost::asio::placeholders::error));
}
}

/// Handle a completed read of message data.
void async_read_data(const boost::system::error_code& e) {
if (e) {
if(listener) listener->receive_completed(e, NULL);
}else {
// Extract the data structure from the data just received.
try {
std::string archive_data(&inbound_data_[0], inbound_data_.size());
#ifdef EXTENDED_TRACE
CLOG(TRACE, "connection")<<"inbound async data with len "<< inbound_data_.size()<<":'"<<archive_data<<"'";
#endif
std::istringstream archive_stream(archive_data);
iarchive_type archive(archive_stream);
TREQ* t;
archive >> t;
if(listener) listener->receive_completed(e, t);
} catch (std::exception& /* unnamed */) {
// Unable to decode data.
boost::system::error_code err(boost::asio::error::invalid_argument);
if(listener) listener->receive_completed(err, NULL);
return;
}
}
}

public:
///
void write_data(boost::shared_ptr<TRESP>& t){
write_data(t.get());
}

void write_data(TRESP& t){
write_data(&t);
}

void write_data(TRESP* t){
boost::system::error_code ec;
this->write_data(t, ec);
boost::asio::detail::throw_error(ec);
}

void write_data(TRESP* t, boost::system::error_code& ec){
// Serialize the data first so we know how large it is.
std::ostringstream archive_stream;
oarchive_type archive(archive_stream);
archive << t;
outbound_data_ = archive_stream.str();
#ifdef EXTENDED_TRACE
CLOG(TRACE, "connection")<<"outbound sync data with len "<< outbound_data_.size()<<":'"<<outbound_data_<<"'";
#endif // Format the header.
std::ostringstream header_stream;
header_stream << std::setw(header_length) << std::hex << std::setfill('0')<<outbound_data_.size();
if (!header_stream || header_stream.str().size() != header_length) {
// Something went wrong, inform the caller.
ec.assign(boost::asio::error::invalid_argument,boost::system::get_system_category());
return;
}
outbound_header_ = header_stream.str();
// Write the serialized data to the socket. We use "gather-write" to send
// both the header and the data in a single write operation.
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(outbound_header_));
buffers.push_back(boost::asio::buffer(outbound_data_));
boost::asio::write(socket_, buffers);
}

void read_data(boost::shared_ptr<TREQ>& msg){
TREQ* m;
read_data(m);
msg.reset(m);
}

void read_data(TREQ*& t){
boost::system::error_code ec;
this->read_data(t, ec);
boost::asio::detail::throw_error(ec);
}

void read_data(TREQ*& t, boost::system::error_code& ec){
boost::asio::read(socket_, boost::asio::buffer(inbound_header_, header_length), boost::asio::transfer_exactly(header_length));
// Determine the length of the serialized data.
std::istringstream is(std::string(inbound_header_, header_length));
std::size_t inbound_data_size = 0;
if (!(is >> std::hex >> inbound_data_size)) {
// Header doesn't seem to be valid. Inform the caller.
ec.assign(boost::asio::error::invalid_argument,boost::system::get_system_category());
return;
}
// Start an synchronous call to receive the data.
inbound_data_.resize(inbound_data_size);
boost::asio::read(socket_, boost::asio::buffer(inbound_data_, inbound_data_size), boost::asio::transfer_exactly(inbound_data_size));
std::string archive_data(&inbound_data_[0], inbound_data_.size());
#ifdef EXTENDED_TRACE
CLOG(TRACE, "connection")<<"inbound sync data with len "<< inbound_data_.size()<<":'"<<archive_data<<"'";
#endif
std::istringstream archive_stream(archive_data);
iarchive_type archive(archive_stream);
archive >> t;
return;
}

private:
/// The underlying socket.
boost::asio::ip::tcp::socket socket_;
/// The size of a fixed length header.
enum {
header_length = 8
};
/// Holds an outbound header.
std::string outbound_header_;
/// Holds the outbound data.
std::string outbound_data_;
/// Holds an inbound header.
char inbound_header_[header_length];
/// Holds the inbound data.
std::vector<char> inbound_data_;

boost::shared_ptr<async_listener> listener;
};

template<>
class connection<std::string, std::string>: public boost::enable_shared_from_this<connection<std::string, std::string> > {
public:
struct async_listener: public boost::enable_shared_from_this<async_listener>{
virtual void send_completed(const boost::system::error_code& error) = 0;
virtual void receive_completed(const boost::system::error_code& error, std::string* result) = 0;
virtual bool message_completed(std::vector<char>& buffer) {return true;};
};
/// Constructor.
connection(boost::asio::io_service& io_service) : socket_(io_service) {
}
/// Get the underlying socket. Used for making a connection or for accepting
/// an incoming connection.
boost::asio::ip::tcp::socket& socket() {
return socket_;
}
///
void add_listener(boost::shared_ptr<async_listener> l){
listener=l;
}
/// template specialization for std::string to allow plain communication
/// Asynchronously write a string to the socket.
void async_write(const std::string& str) {
// Serialize the data first so we know how large it is.
outbound_data_ = str;
#ifdef EXTENDED_TRACE
LOG(TRACE)<<"outbound async data with len "<< outbound_data_.size()<<":'"<<outbound_data_<<"'";
#endif
// Write the outbound data to the socket. We use "gather-write" to send
// both the header and the data in a single write operation.
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(outbound_data_));
boost::asio::async_write(socket_, buffers,
boost::bind(&connection::handle_async_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

protected:
/// notify the listener about the finish of the send process
void handle_async_write(const boost::system::error_code& err, size_t /*bytes_transferred*/){
if(listener!=NULL) listener->send_completed(err);
}
public:
/// template specialization for std::string to allow plain communication
/// Asynchronously read a string from the socket.
void async_read() {
// Issue a read operation to read exactly the number of bytes in a header.
boost::asio::async_read(socket_, boost::asio::buffer(inbound_buffer_),
boost::bind(&connection::async_read_data, this, boost::asio::placeholders::error));
}
protected:
/// template specialization for std::string to allow plain communication
/// Handle a read of string data.
void async_read_data(const boost::system::error_code& e) {
if (e) {
if(listener) listener->receive_completed(e, NULL);
}else {
// Extract the data structure from the data just received.
try {
inbound_data_.push_back(inbound_buffer_[0]);
if(listener->message_completed(inbound_data_)){
std::string receive_data(&inbound_data_[0], inbound_data_.size());
#ifdef EXTENDED_TRACE
LOG(TRACE)<<"inbound async data with len "<< inbound_data_.size()<<":'"<<receive_data<<"'";
#endif
if(listener) listener->receive_completed(e, &receive_data);
inbound_data_.clear();
} else
boost::asio::async_read(socket_, boost::asio::buffer(inbound_buffer_),
boost::bind(&connection::async_read_data, this, boost::asio::placeholders::error));
} catch (std::exception& /* unnamed */) {
// Unable to decode data.
boost::system::error_code err(boost::asio::error::invalid_argument);
if(listener) listener->receive_completed(err, NULL);
return;
}
}
}
public:
///
void write_data(const std::string* t){
boost::system::error_code ec;
this->write_data(t, ec);
boost::asio::detail::throw_error(ec);
}

void write_data(const std::string* t, boost::system::error_code& ec){
outbound_data_ = *t;
#ifdef EXTENDED_TRACE
LOG(TRACE)<<"outbound sync data with len "<< outbound_data_.size()<<":'"<<outbound_data_<<"'";
#endif // Format the header.
// Write the serialized data to the socket. We use "gather-write" to send
// both the header and the data in a single write operation.
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(outbound_data_));
boost::asio::write(socket_, buffers);
}

void read_data(std::string*& t){
boost::system::error_code ec;
this->read_data(t, ec);
boost::asio::detail::throw_error(ec);
}

void read_data(std::string*& t, boost::system::error_code& ec){
boost::asio::read(socket_, boost::asio::buffer(inbound_buffer_, buffer_length));
t=new std::string(inbound_buffer_);
return;
}

private:
/// The underlying socket.
boost::asio::ip::tcp::socket socket_;
/// The size of a fixed length header.
enum {
buffer_length = 1
};
/// Holds the outbound data.
std::string outbound_data_;
/// Holds an inbound header.
char inbound_buffer_[buffer_length];
/// Holds the inbound data.
std::vector<char> inbound_data_;

boost::shared_ptr<async_listener> listener;
};
#endif /* _SERIALIZED_CONNECTION_H_ */

+ 130
- 0
incl/iss/debugger/server.h View File

@@ -0,0 +1,130 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _SERVER_H_
#define _SERVER_H_

#include <easylogging++.h>
#include <sys/time.h>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include "server_base.h"

namespace iss {
namespace debugger {

template<class SESSION>
class server: public server_base {
public:

static void run_server(iss::debugger_if* vm, unsigned int port) {
if(get()!=NULL) { LOG(FATAL)<< "server already initialized"; }
LOG(DEBUG) << "starting server";
get(new server<SESSION>(vm, port));
}

static server<SESSION>* get(){return get(NULL);}

unsigned short get_port_nr(){
return acceptor.local_endpoint().port();
}

void shutdown() override {
delete work_ctrl;
work_ctrl=nullptr;
// Wait for all threads in the pool to exit.
threads.join_all();
// allow the synchronizer to run
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
}

protected:
static server<SESSION>* get(server<SESSION>* srv){
static server<SESSION>* s = NULL;
if(srv != NULL && s==NULL) s = srv;
return s;
}

server(iss::debugger_if* vm, unsigned short port)
: server_base(vm)
, acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
{
// Create a pool of threads to run all of the io_services.
std::size_t thread_pool_size_ = 2;
work_ctrl = new boost::asio::io_service::work(io_service);
boost::thread::hardware_concurrency();
for (std::size_t i = 0; i < thread_pool_size_; ++i){
threads.create_thread([this]()->void {io_service.run();});
}
createNewSession();
};

void createNewSession(){
boost::shared_ptr<SESSION> new_session(new SESSION(this, acceptor.get_io_service()));
acceptor.async_accept(new_session->socket(),
boost::bind(&server<SESSION>::handle_accept, this, boost::asio::placeholders::error, new_session));
}

void shutDown(){
// request shutdown of simulation
server_base::shutdown();
// stop the io acceptor
acceptor.get_io_service().stop();
}

private:
/// Handle completion of a accept operation by starting a session.
void handle_accept(const boost::system::error_code& e, boost::shared_ptr<SESSION> session) {
if (!e){
// Start an accept operation for a new connection. If it finishes create a new session
if(!session->start()) createNewSession();
} else {
// An error occurred. Log it and return. Since we are not starting a new
// accept operation the io_service will run out of work to do and the
// thread will exit.
LOG(ERROR) << e.message();
}
}
// server related members
boost::asio::io_service io_service;
boost::asio::io_service::work *work_ctrl;
boost::asio::ip::tcp::acceptor acceptor;
boost::thread_group threads;

};

} // namespace debugger
} // namspace iss

#endif /* _SERVER_H_ */

+ 81
- 0
incl/iss/debugger/server_base.h View File

@@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _SERVER_BASE_H_
#define _SERVER_BASE_H_

#include <easylogging++.h>

#include <vector>
#include <list>
#include <deque>
#include <boost/lockfree/queue.hpp>
#include <atomic>
#include <condition_variable>
#include "server_if.h"
#include <iss/debugger_if.h>

namespace iss {
namespace debugger {

struct server_base : public server_if{

server_base(debugger_if* adapter);

~server_base();

unsigned int get_reg_width(int index) const ;

void run(unsigned coreId) override ;

void request_stop(unsigned coreId) override ;

void wait_for_stop() override;

void step(unsigned coreId, unsigned steps=1) override ;

iss::status reset(int coreId);

target_adapter_if* get_target() override { return vm->accquire_target_adapter(this);}

protected:
debugger_if* vm;
int dummy_func();
target_adapter_if* tgt;
};

} // namespace debugger
} // namspace iss

#endif /* _SERVER_BASE_H_ */

+ 159
- 0
incl/iss/debugger/server_if.h View File

@@ -0,0 +1,159 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _SERVER_IF_H_
#define _SERVER_IF_H_

#include <iss/vm_if.h>
#include <util/thread_syncronizer.h>

#include <string>
#include <vector>
#include <deque>
#include <atomic>
#include <type_traits>


namespace iss {

struct debugger_if;

namespace debugger {
// forward declaration
struct target_adapter_if;
/**
* the debug server interface
*/
struct server_if{
friend class iss::debugger_if;
/**
* debugger access type
*/
enum access_type {Read, Write};
/**
* type of breakpoints
*/
enum bp_type {OnExec=0, OnRead=1, OnWrite=2, OnRW=3};
/**
* address type
*/
enum addr_type {Phys, Virt, Log};
/**
* execution mode of debuggee
*/
enum mode_e {MODE_RUN, MODE_BREAK, MODE_STOP};

/**
* destructor
*/
virtual ~server_if(){};
/**
* run the specified core, numeric_limits<unsigned>::max() indicates all cores
* @param coreId the core to let run
*/
virtual void run(unsigned coreId) = 0;
/**
* stop the specified core (non-blocking)
* @param coreId the core to stop
*/
virtual void request_stop(unsigned coreId) = 0;
/**
* check if a core is executing
* @return true if the core runs
*/
virtual bool is_running(){ return mode.load()!=MODE_STOP;}
/**
* wait until request_stop() is processed and the specified core stops
*/
virtual void wait_for_stop() = 0;
/**
* single step the specified core
* @param coreId the core to single step
* @param steps number of steps to execute
*/
virtual void step(unsigned coreId, unsigned steps=1) = 0;
/**
* shut down the simulation and server
*/
virtual void shutdown() = 0;
/**
* reset the core and system
* @param coreId core to reset
* @return result of the operation
*/
virtual status reset(int coreId) = 0;

enum exec_states { initialized=0, running=1, stopped=2, stepping=3};
/**
* get the target adapter for the core being debugged
* @return
*/
virtual target_adapter_if* get_target() = 0;
/**
* check if the simulation can continue
* @param bp_handle the handle of breakpoint condition being met, 0 means no hit
*/
inline
void check_continue(unsigned bp_handle) {
if(bp_handle){
mode.store(MODE_STOP, std::memory_order_release);
last_bp=bp_handle;
}
while(mode.load(std::memory_order_acquire)==MODE_STOP){
syncronizer.executeNext();
}
if(--cycles==0) mode=MODE_STOP;
}
/**
* execute the specified function synchronized in the simulation thread
* @param f function to execute
* @param args arguments of the function
* @return result value of function (if any)
*/
template<class F, class... Args>
typename std::result_of<F(Args...)>::type execute_syncronized(F&& f, Args&&... args) {
return syncronizer.enqueue_and_wait(f, args...);
}

protected:
thread_syncronizer syncronizer;
std::atomic<mode_e> mode{MODE_STOP};
std::atomic<uint64_t> cycles;
unsigned last_bp;
};

} // namespace debugger
} // namspace iss

#endif /* _SERVER_IF_H_ */

+ 98
- 0
incl/iss/debugger/target_adapter_base.h View File

@@ -0,0 +1,98 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _TARGET_ADAPTER_BASE_H_
#define _TARGET_ADAPTER_BASE_H_

#include "target_adapter_if.h"
#include <iss/vm_types.h>
#include <iss/debugger/server_if.h>
#include <util/range_lut.h>

namespace iss {
namespace debugger {

struct target_adapter_base: public target_adapter_if {


target_adapter_base(iss::debugger::server_if* srv)
: srv(srv)
, bp_lut(0)
{

}

void set_server(iss::debugger::server_if* server){srv=server;}

void check_continue(uint64_t pc){
unsigned handle = bp_lut.getEntry(pc);
srv->check_continue(handle);
}

/* return table of remote commands */
const std::vector<target_adapter_if::custom_command>& custom_commands() override { return ccmds;}

void help(const char *prog_name) override;

iss::status open(int argc, char * const agrv[], const char *prog_name, log_func log_fn) override;

void close(void) override;

iss::status connect(std::string& status_string, bool& can_restart) override;

iss::status disconnect(void) override;

void kill(void) override;

iss::status restart(void) override;

void stop(void) override;

iss::status resume_from_current(bool step, int sig) override;

iss::status wait_non_blocking(std::string& status_string, out_func out, bool& running) override;

iss::status wait_blocking(std::string& status_string, out_func out) override;

protected:
iss::debugger::server_if* srv;
util::range_lut<unsigned> bp_lut;
long bp_count=0;
std::vector<target_adapter_if::custom_command> ccmds;
};

} // namespace debugger
} // namspace iss

#endif /* _TARGETADAPTER_H_ */

+ 284
- 0
incl/iss/debugger/target_adapter_if.h View File

@@ -0,0 +1,284 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _TARGET_ADAPTER_IF_H_
#define _TARGET_ADAPTER_IF_H_

#include <iss/vm_types.h>
#include <vector>
#include <string>

namespace iss {
namespace debugger {

/* Function to do console output from wait methods */
typedef void (*out_func)(const char *string);

/* Function to transefer data received as qRcmd response */
typedef void (*data_func)(const char *string);

/* Function to do logging */
typedef void (*log_func)(int level, const char *string, ...);

struct rp_thread_ref
{
uint64_t val;
} ;

struct rp_thread_info {
rp_thread_ref thread_id;
int exists;
char display[256];
char thread_name[32];
char more_display[256];
};

struct target_adapter_if {

/* Table entry definition */
struct custom_command {
/* command name */
const char *name;
/* command function */
int (*function)(int, char **, out_func, data_func);
/* one line of help text */
const char *help;
};

virtual ~target_adapter_if(){}

/* return table of remote commands */
virtual const std::vector<custom_command>& custom_commands() = 0;

/*====================== Help/Debug =======================*/

/* Help, argument is a pointer to itself */
virtual void help(const char *prog_name) = 0;

/*========= Open/Close/Connect/Disconnect ==============*/

/* Start target stub and provide run time parameters
in time tested manner, does not assume actually
connecting to target. */
virtual iss::status open(int argc, char * const agrv[], const char *prog_name, log_func log_fn) = 0;

/* Close target stub: if target is still connected disconnect and
leave it running */
virtual void close(void) = 0;

/* Actually connect to a target and return status string; */
virtual iss::status connect(std::string& status_string, bool& can_restart) = 0;

/* Disconnect from a target a leave it running */
virtual iss::status disconnect(void) = 0;

/*=================== Start/Stop =========================*/

/* Kill target: disconnect from a target and leave it waiting
for a command. Target output is ignored.

Restart: start target all over again.

Stop: break into running target

Note these commands are used in following sequences only

1. kill, close, terminate proxy
2. kill, restart, connect
3. restart, connect
4. stop, wait */

/* Kill target: disconnect from a target and leave it waiting
for a command. It is expected that either close or wait or
connect will follow after kill to get last status_string */
virtual void kill(void) = 0;

/* Restart target and return status string */
virtual iss::status restart(void) = 0;

/* Stop target. E.g. send ^C or BREAK to target - note
it has to be followed either by wait or connect in order to
to get last status_string */
virtual void stop(void) = 0;

/*============== Thread Control ===============================*/

/* Set generic thread */
virtual iss::status set_gen_thread(rp_thread_ref& thread) = 0;

/* Set control thread */
virtual iss::status set_ctrl_thread(rp_thread_ref& thread) = 0;

/* Get thread status */
virtual iss::status is_thread_alive(rp_thread_ref& thread, bool& alive) = 0;

/*============= Register Access ================================*/

/* Read all registers. buf is 4-byte aligned and it is in
target byte order. If register is not available
corresponding bytes in avail_buf are 0, otherwise
avail buf is 1 */
virtual iss::status read_registers(std::vector<uint8_t>& data_buf, std::vector<uint8_t>& avail_buf) = 0;

/* Write all registers. buf is 4-byte aligned and it is in target
byte order */
virtual iss::status write_registers(const std::vector<uint8_t>& buf) = 0;

/* Read one register. buf is 4-byte aligned and it is in
target byte order. If register is not available
corresponding bytes in avail_buf are 0, otherwise
avail buf is 1 */
virtual iss::status read_single_register(unsigned int reg_no, std::vector<uint8_t>& buf, std::vector<uint8_t>& avail_buf) = 0;

/* Write one register. buf is 4-byte aligned and it is in target byte
order */
virtual iss::status write_single_register(unsigned int reg_no, const std::vector<uint8_t>& buf) = 0;

/*=================== Memory Access =====================*/

/* Read memory, buf is 4-bytes aligned and it is in target
byte order */
virtual iss::status read_mem(uint64_t addr, std::vector<uint8_t>& buf) = 0;

/* Write memory, buf is 4-bytes aligned and it is in target
byte order */
virtual iss::status write_mem(uint64_t addr, const std::vector<uint8_t>& buf) = 0;

/*================ Resume/Wait ============================*/

/* Resume from current address, if not supported it has to be figured out by wait */
virtual iss::status resume_from_current(bool step, int sig) = 0;

/* Resume from specified address, if not supported it
has to be figured out by wait */
virtual iss::status resume_from_addr(bool step, int sig, uint64_t addr) = 0;

/* Wait function, wait_partial is called by the proxy with one
tick intervals, so it allows to break into running
target */

/* Check for event and return. It allows proxy server to
check messages from gdb allowing gdb to stop/kill target.
Break and kill commands are generated by a human being so,
the process can wait inside wait_partial with some substantial
timeouts. It seems like 1s time will be highest acceptable value.

In this case return value RP_TARGETRET_NOSUPP means, that
response to previous resume was - 'not supported'. If this operation
is not implemented by target, then it will return OK and
implemeted will be 0.

status_string is unchanged unless return value is OK and
implemented is non 0 */
virtual iss::status wait_non_blocking(std::string& status_string, out_func out, bool& running){
return iss::NotSupported;
}

/* Wait for event, fill (null-terminated) status_string upon successful
return, if there is not enough space for 'TAA... string' use
'SAA' instead, status_sting_len is always > 3

In this case return value RP_TARGETRET_NOSUPP means, that
response to previous resume was - 'not supported'. If this operation
is not implemented by target, then it will return OK and
implemeted will be 0

status_string is unchanged unless return value is OK and
implemented is non 0 */
virtual iss::status wait_blocking(std::string& status_string, out_func out) = 0;

/*============= Queries ===============================*/

/* Bits of mask determine set of information about thread
to be retrieved, results are put into info. */
virtual iss::status process_query(unsigned int& mask, const rp_thread_ref& arg, rp_thread_info& info) = 0;

/* List threads. If first is non-zero then start from the first thread,
otherwise start from arg, result points to array of threads to be
filled out, result size is number of elements in the result,
num points to the actual number of threads found, done is
set if all threads are processed. */
virtual iss::status thread_list_query(int first, const rp_thread_ref& arg, std::vector<rp_thread_ref>& result, size_t max_num, size_t& num, bool& done) = 0;

/* Query current thread id */
virtual iss::status current_thread_query(rp_thread_ref& thread) = 0;

/* Query offset of major sections in memory */
virtual iss::status offsets_query(uint64_t& text, uint64_t& data, uint64_t& bss) = 0;

/* Query crc32 of memory area */
virtual iss::status crc_query(uint64_t addr, size_t len, uint32_t& val) = 0;

/* Raw query, see gdb-XXXX/gdb/remote.c. we got buffer
call this function. It is a responsibility of the target
to fill out out_buf correctly in case of success.

It is planned to have more more specific queries in
the nearest future. */
virtual iss::status raw_query(std::string in_buf, std::string& out_buf) = 0;

/*============ Breakpoints ===========================*/
/**
* add a breakpoint
*
* @param type the type of the breakpoint: 0 - sw exec, 1 - hw exec, 2 - write watchpoint, 3 - access watchpoint
* @param addr address of the breakpoint
* @param length length of the range to check
* @return iss:Ok if successful, iss::Err otherwise
*/
virtual iss::status add_break(int type, uint64_t addr, unsigned int length) = 0;
/**
* remove a breakpoint
*
* @param type the type of the breakpoint: 0 - sw exec, 1 - hw exec, 2 - write watchpoint, 3 - access watchpoint
* @param addr address of the breakpoint
* @param length length of the range to check
* @return iss:Ok if successful, iss::Err otherwise
*/
virtual iss::status remove_break(int type, uint64_t addr, unsigned int length) = 0;

/* Query thread info */
virtual iss::status threadinfo_query(int first, std::string& out_buf) = 0;

/* Query thread extra info */
virtual iss::status threadextrainfo_query(const rp_thread_ref& thread, std::string& out_buf) = 0;

/* Query packet size */
virtual iss::status packetsize_query(std::string& out_buf) = 0;
};

} // namespace debugger
} // namspace iss

#endif /* _TARGET_ADAPTER_H_ */

+ 68
- 0
incl/iss/debugger_if.h View File

@@ -0,0 +1,68 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _DEBUGGER_IF_H_
#define _DEBUGGER_IF_H_

#include "vm_types.h"
#include <vector>
#include "debugger/server_if.h"
#include "debugger/target_adapter_if.h"

namespace iss {

struct debugger_if {
/**
* destructor
*/
virtual ~debugger_if(){};
/**
* check if debugging is enabled
* @return
*/
inline bool debugging_enabled(){return dbg_enabled;}
/**
* return a target adapter for accessing the core to be debugged
* @param server server interface to be used for the target adapter
* @return the target adapter for the core
*/
virtual debugger::target_adapter_if* accquire_target_adapter(debugger::server_if* server) = 0;

protected:
bool dbg_enabled=false;
};
}


#endif /* _DEBUGGER_IF_H_ */

+ 58
- 0
incl/iss/iss.h View File

@@ -0,0 +1,58 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _ISS_H
#define _ISS_H

#include <iss/vm_if.h>
#include <stdint.h>
#include <memory>

namespace iss {

template<typename ARCH>
std::unique_ptr<iss::vm_if> create(std::string inst_name, bool dump=false);

template<typename ARCH>
std::unique_ptr<iss::vm_if> create(std::string inst_name, unsigned short port, bool dump=false);

template<typename ARCH>
std::unique_ptr<iss::vm_if> create(ARCH*, bool dump=false);

template<typename ARCH>
std::unique_ptr<iss::vm_if> create(ARCH*, unsigned short port, bool dump=false);

}

#endif /* _ISS_H */

+ 139
- 0
incl/iss/jit/MCJIThelper.h View File

@@ -0,0 +1,139 @@
/*******************************************************************************
* Copyright (C) 2017, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/

#ifndef _MCJITHELPER_H_
#define _MCJITHELPER_H_

#include <iss/arch/traits.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/Error.h>
#include <iostream>
#include <sstream>

#include <vector>
#include <unordered_map>


namespace iss {
/**
* get the LLVM context
* NOTE: this is a singleton and not threadsave
* @return the cotext