Browse Source

Initial commit

pull/3/head
Eyck Jentzsch 2 years ago
commit
3f7f3b425f
37 changed files with 6119 additions and 0 deletions
  1. +54
    -0
      CMakeLists.txt
  2. +29
    -0
      LICENSE
  3. +42
    -0
      README.md
  4. +82
    -0
      cmake/CPackConfig.cmake
  5. +1
    -0
      cmake/issConfig.cmake
  6. +48
    -0
      incl/iss/arch/traits.h
  7. +149
    -0
      incl/iss/arch_if.h
  8. +161
    -0
      incl/iss/debugger/cmdhandler.h
  9. +82
    -0
      incl/iss/debugger/encoderdecoder.h
  10. +99
    -0
      incl/iss/debugger/gdb_session.h
  11. +410
    -0
      incl/iss/debugger/serialized_connection.h
  12. +130
    -0
      incl/iss/debugger/server.h
  13. +81
    -0
      incl/iss/debugger/server_base.h
  14. +159
    -0
      incl/iss/debugger/server_if.h
  15. +98
    -0
      incl/iss/debugger/target_adapter_base.h
  16. +284
    -0
      incl/iss/debugger/target_adapter_if.h
  17. +68
    -0
      incl/iss/debugger_if.h
  18. +58
    -0
      incl/iss/iss.h
  19. +139
    -0
      incl/iss/jit/MCJIThelper.h
  20. +507
    -0
      incl/iss/vm_base.h
  21. +109
    -0
      incl/iss/vm_if.h
  22. +172
    -0
      incl/iss/vm_types.h
  23. +52
    -0
      incl/util/assert.h
  24. +201
    -0
      incl/util/bit_field.h
  25. +72
    -0
      incl/util/ities.h
  26. +204
    -0
      incl/util/logging.h
  27. +209
    -0
      incl/util/range_lut.h
  28. +87
    -0
      incl/util/sparse_array.h
  29. +117
    -0
      incl/util/thread_syncronizer.h
  30. +41
    -0
      src/CMakeLists.txt
  31. +277
    -0
      src/MCJIThelper.cpp
  32. +849
    -0
      src/cmdhandler.cpp
  33. +91
    -0
      src/dbgsrvbase.cpp
  34. +499
    -0
      src/encoderdecoder.cpp
  35. +316
    -0
      src/gdb_session.cpp
  36. +91
    -0
      src/target_adapter_base.cpp
  37. +51
    -0
      src/vm_base.cpp

+ 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
*/