Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
gdb 8.1 with Ruby

This work is related to libgdbruby.

How to build and install

$ sudo apt-get install build-essential python3 libpython3-dev texinfo
$ ruby -e 'puts "Hello world"'  # Ruby must be installed before compilation
$ # download gdb-8.1.tar.gz from GNU
$ # download gdbruby.patch attached to this Gist
$ tar zxf gdb-8.1.tar.gz
$ cd gdb-8.1
$ patch -p1 < ../gdbruby.patch
$ mkdir build
$ cd build
$ ../configure --with-python=python3 --with-separate-debug-dir=/usr/lib/debug:/usr/local/lib/debug
$ make
$ sudo make install

Known limitations

  • Using Readline inside Ruby will break gdb's Readline
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 17b71c6..03dd88f 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -412,6 +412,15 @@ SUBDIR_PYTHON_DEPS =
SUBDIR_PYTHON_LDFLAGS =
SUBDIR_PYTHON_CFLAGS =
+SUBDIR_RUBY_SRCS = \
+ ruby/ruby.c
+
+SUBDIR_RUBY_OBS = $(patsubst %.c,%.o,$(SUBDIR_RUBY_SRCS))
+
+SUBDIR_RUBY_DEPS =
+SUBDIR_RUBY_LDFLAGS =
+SUBDIR_RUBY_CFLAGS =
+
SUBDIR_UNITTESTS_SRCS = \
unittests/array-view-selftests.c \
unittests/common-utils-selftests.c \
@@ -522,7 +531,7 @@ CONFIG_INSTALL = @CONFIG_INSTALL@
CONFIG_UNINSTALL = @CONFIG_UNINSTALL@
HAVE_NATIVE_GCORE_TARGET = @HAVE_NATIVE_GCORE_TARGET@
-CONFIG_SRC_SUBDIR = arch cli mi compile tui unittests guile python target
+CONFIG_SRC_SUBDIR = arch cli mi compile tui unittests guile python target ruby
CONFIG_DEP_SUBDIR = $(addsuffix /$(DEPDIR),$(CONFIG_SRC_SUBDIR))
# -I. for config files.
@@ -552,7 +561,7 @@ CXXFLAGS = @CXXFLAGS@
# are sometimes a little generic, we think that the risk of collision
# with other header files is high. If that happens, we try to mitigate
# a bit the consequences by putting the Python includes last in the list.
-INTERNAL_CPPFLAGS = @CPPFLAGS@ @GUILE_CPPFLAGS@ @PYTHON_CPPFLAGS@
+INTERNAL_CPPFLAGS = @CPPFLAGS@ @GUILE_CPPFLAGS@ @PYTHON_CPPFLAGS@ @RUBY_CPPFLAGS@
# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros.
INTERNAL_CFLAGS_BASE = \
@@ -583,7 +592,7 @@ INTERNAL_LDFLAGS = \
# LIBIBERTY appears twice on purpose.
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(ZLIB) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) \
- @LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
+ @LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ @RUBY_LIBS@ \
$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR)
CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
@@ -1609,6 +1618,7 @@ generated_files = \
# Flags needed to compile Python code
PYTHON_CFLAGS = @PYTHON_CFLAGS@
+RUBY_CFLAGS =
all: gdb$(EXEEXT) $(CONFIG_ALL)
@$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do
@@ -1625,6 +1635,8 @@ $(CONFIG_DEP_SUBDIR):
# Python files need special flags.
python/%.o: INTERNAL_CFLAGS += $(PYTHON_CFLAGS)
+ruby/%.o: INTERNAL_CFLAGS += $(RUBY_CFLAGS)
+
# Rules for compiling .c files in the various source subdirectories.
%.o: ${srcdir}/common/%.c
$(COMPILE) $<
diff --git a/gdb/configure b/gdb/configure
index 092893d..183e5a9 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -681,6 +681,8 @@ HAVE_PYTHON_TRUE
PYTHON_LIBS
PYTHON_CPPFLAGS
PYTHON_CFLAGS
+RUBY_LIBS
+RUBY_CPPFLAGS
python_prog_path
LTLIBMPFR
LIBMPFR
@@ -17591,8 +17593,13 @@ done
ac_config_links="$ac_config_links $ac_config_links_1"
-
-
+# add ruby stuffs
+CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_RUBY_OBS)"
+CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_RUBY_SRCS)"
+CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_RUBY_DEPS)"
+ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_RUBY_CFLAGS)"
+RUBY_CPPFLAGS=`ruby ${srcdir}/ruby/config.rb --include`
+RUBY_LIBS=`ruby ${srcdir}/ruby/config.rb --libs`
$as_echo "#define GDB_DEFAULT_HOST_CHARSET \"UTF-8\"" >>confdefs.h
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 4844c86..92cfa7d 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -37,6 +37,8 @@
#include "location.h"
#include "ser-event.h"
+extern void initialize_ruby();
+
/* Declared constants and enum for python stack printing. */
static const char python_excp_none[] = "none";
static const char python_excp_full[] = "full";
@@ -1893,6 +1895,8 @@ message == an error message without a stack will be printed."),
if (!do_start_initialization () && PyErr_Occurred ())
gdbpy_print_stack ();
#endif /* HAVE_PYTHON */
+
+ initialize_ruby();
}
#ifdef HAVE_PYTHON
diff --git a/gdb/ruby/config.rb b/gdb/ruby/config.rb
new file mode 100644
index 0000000..a2bfa1a
--- /dev/null
+++ b/gdb/ruby/config.rb
@@ -0,0 +1,13 @@
+#coding:utf-8
+require "mkmf"
+
+if ARGV.length != 1
+ exit 1
+end
+
+case ARGV[0]
+when "--include"
+ print RbConfig.expand("-I $(rubyarchhdrdir) -I $(rubyhdrdir)")
+when "--libs"
+ print RbConfig.expand(libpathflag + " -l$(RUBY_SO_NAME)")
+end
diff --git a/gdb/ruby/ruby.c b/gdb/ruby/ruby.c
new file mode 100644
index 0000000..edf49f1
--- /dev/null
+++ b/gdb/ruby/ruby.c
@@ -0,0 +1,135 @@
+#include <stdio.h>
+#include <build-gnulib/config.h> // to make gcc happy :P
+#include <string.h>
+#include <string>
+#include "defs.h"
+#include "gdbcmd.h"
+#include <ruby.h>
+
+static VALUE gdbruby_binding;
+static VALUE rb_eGdbError;
+
+static VALUE eval_ruby_internal(VALUE command){
+ RUBY_INIT_STACK;
+
+ return rb_funcall(gdbruby_binding, rb_intern("eval"), 1, command);
+}
+
+static VALUE error_handler(VALUE args, VALUE exception_object){
+ unsigned long i, length;
+ VALUE message;
+ VALUE backtrace;
+ VALUE item;
+ RUBY_INIT_STACK;
+
+ if(NIL_P(exception_object)){
+ puts("error");
+ return Qnil;
+ }
+
+ message = rb_funcall(exception_object, rb_intern("to_s"), 0);
+ backtrace = rb_funcall(exception_object, rb_intern("backtrace"), 0);
+
+ if(NIL_P(message)){
+ printf("%1$s: %1$s\n", rb_obj_classname(exception_object));
+ }else{
+ SafeStringValue(message);
+ printf("%s: %s\n", rb_obj_classname(exception_object), RSTRING_PTR(message));
+ }
+
+ if(NIL_P(backtrace)){
+ return Qnil;
+ }
+
+ length = NUM2LONG(rb_funcall(backtrace, rb_intern("length"), 0));
+ for(i = 0; length > 1 && i < length - 1; i++){
+ item = rb_ary_entry(backtrace, i);
+ if(NIL_P(item)){
+ continue;
+ }
+ SafeStringValue(item);
+ printf(" from %s\n", RSTRING_PTR(item));
+ }
+
+ return Qnil;
+}
+
+static void eval_ruby(const char *script){
+ VALUE command;
+ RUBY_INIT_STACK;
+
+ if(script == NULL){
+ puts("no script given");
+ return;
+ }
+
+ command = rb_str_new2(script);
+ rb_rescue((VALUE (*)(ANYARGS))eval_ruby_internal, command, (VALUE (*)(ANYARGS))error_handler, Qnil);
+}
+
+static VALUE gdb_execute(VALUE self, VALUE arg1){
+ char *code;
+ std::string result;
+ char *result_cstr;
+ VALUE rb_result;
+ RUBY_INIT_STACK;
+
+ SafeStringValue(arg1);
+
+ code = (char *)calloc(1, RSTRING_LEN(arg1) + 1);
+ if(code == NULL){
+ rb_raise(rb_eRuntimeError, "error");
+ }
+ memcpy(code, RSTRING_PTR(arg1), RSTRING_LEN(arg1));
+
+ TRY{
+ result = execute_command_to_string(code, 0);
+ }CATCH(except, RETURN_MASK_ALL){
+ free(code);
+
+ if(except.reason == RETURN_QUIT){
+ rb_raise(rb_eInterrupt, "Interrupt");
+ }else{
+ rb_raise(rb_eGdbError, "%s", except.message);
+ }
+ }END_CATCH
+
+ free(code);
+
+ result_cstr = strdup(result.c_str());
+ if(result_cstr == NULL){
+ rb_raise(rb_eRuntimeError, "error");
+ }
+
+ rb_result = rb_str_new2(result_cstr);
+ free(result_cstr);
+
+ return rb_result;
+}
+
+void initialize_ruby(){
+ int a = 3;
+ const char *args[] = {"ruby", "-e", "", NULL};
+ char **arg = (char **)args;
+ int state;
+
+ /* Initialize Ruby VM */
+ ruby_sysinit(&a, &arg);
+ {
+ RUBY_INIT_STACK;
+
+ ruby_init();
+ ruby_options(a, arg);
+ ruby_script("gdbruby");
+
+ rb_define_global_function("gdb_execute", (VALUE (*)(ANYARGS))gdb_execute, 1);
+
+ gdbruby_binding = rb_funcall(Qnil, rb_intern("binding"), 0);
+ rb_define_readonly_variable("gdbruby_binding", &gdbruby_binding);
+
+ rb_eGdbError = rb_define_class("GdbError", rb_eStandardError);
+ }
+
+ /* Add ruby command to gdb */
+ add_com("ruby", no_class, (void (*)(char const *, int))eval_ruby, "Evaluate a Ruby command.");
+}
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.