Missing test cases for jit-reader interface

Message ID 87k2z8ydq4.fsf@igalia.com
State New, archived
Headers

Commit Message

Andy Wingo Feb. 23, 2015, 1:11 p.m. UTC
  Hi,

On Mon 23 Feb 2015 11:23, Andy Wingo <wingo@igalia.com> writes:

> In this thread:
>
>   http://thread.gmane.org/gmane.comp.gdb.patches/80671/focus=82555
>
> There were tests for the jit-reader interface that were to be added to
> the repo, but they didn't seem to make it in:
>
>   $ git show --stat 675921c059dbaddd02ab2eb8a1eaf77b3ac727dd
>   commit 675921c059dbaddd02ab2eb8a1eaf77b3ac727dd
>   Author: Sanjoy Das <sanjoyd@sourceware.org>
>   Date:   Thu Jan 17 14:21:46 2013 +0000
>
>       gdb/testsuite
>       
>        * gdb.base/jit-reader.exp: New file. Test case for the jit-reader
>          interface.
>        * gdb.base/jithost.c: New file.
>        * gdb.base/jithost.h: New file.
>        * gdb.base/jitreader.c : New file.
>        * gdb.base/jit-protocol.h: New file.
>
>    gdb/testsuite/ChangeLog | 9 +++++++++
>    1 file changed, 9 insertions(+)
>
> Could it be Jan that you forgot to add the new files when you committed
> Sanjoy's patch?

I think it was Sanjoy who forgot to commit these.  Anyway, here is an
updated version of the same patch, which passes tests for me.  WDYT?
  

Comments

Sanjoy Das Feb. 25, 2015, 7:37 a.m. UTC | #1
This is definitely my fault, I missed actually adding the files when
making the checkin.

Unfortunately I neither have the necessary context in my head to
review this change nor the right SSH keys to check this in.  It will
probably be best if a gdb maintainer takes a look at this.

Thanks,
-- Sanjoy

On Mon, Feb 23, 2015 at 5:11 AM, Andy Wingo <wingo@igalia.com> wrote:
> Hi,
>
> On Mon 23 Feb 2015 11:23, Andy Wingo <wingo@igalia.com> writes:
>
>> In this thread:
>>
>>   http://thread.gmane.org/gmane.comp.gdb.patches/80671/focus=82555
>>
>> There were tests for the jit-reader interface that were to be added to
>> the repo, but they didn't seem to make it in:
>>
>>   $ git show --stat 675921c059dbaddd02ab2eb8a1eaf77b3ac727dd
>>   commit 675921c059dbaddd02ab2eb8a1eaf77b3ac727dd
>>   Author: Sanjoy Das <sanjoyd@sourceware.org>
>>   Date:   Thu Jan 17 14:21:46 2013 +0000
>>
>>       gdb/testsuite
>>
>>        * gdb.base/jit-reader.exp: New file. Test case for the jit-reader
>>          interface.
>>        * gdb.base/jithost.c: New file.
>>        * gdb.base/jithost.h: New file.
>>        * gdb.base/jitreader.c : New file.
>>        * gdb.base/jit-protocol.h: New file.
>>
>>    gdb/testsuite/ChangeLog | 9 +++++++++
>>    1 file changed, 9 insertions(+)
>>
>> Could it be Jan that you forgot to add the new files when you committed
>> Sanjoy's patch?
>
> I think it was Sanjoy who forgot to commit these.  Anyway, here is an
> updated version of the same patch, which passes tests for me.  WDYT?
>
  
Yao Qi Feb. 25, 2015, 3:50 p.m. UTC | #2
Andy Wingo <wingo@igalia.com> writes:

> I think it was Sanjoy who forgot to commit these.  Anyway, here is an
> updated version of the same patch, which passes tests for me.  WDYT?
>

Yes, we should add them back since they were reviewed and approved.

> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/jit-protocol.h
> @@ -0,0 +1,54 @@
> +/* Copyright (C) 2009-2013 Free Software Foundation, Inc.

It should be 2009-2013.


> diff --git a/gdb/testsuite/gdb.base/jit-reader.exp b/gdb/testsuite/gdb.base/jit-reader.exp
> new file mode 100644
> index 0000000..6080564
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/jit-reader.exp
> @@ -0,0 +1,80 @@
> +# Copyright 2012 Free Software Foundation, Inc.

Likewise.

> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +standard_testfile jithost.c
> +
> +if { (![istarget x86_64-*-*] && ![istarget i?86-*-*]) || ![is_lp64_target] } {
> +    return -1;
> +}

I don't see any reason why this test is arch specific.  We can remove
such checking, IMO.

> +
> +if {[skip_shlib_tests]} {
> +    return -1
> +}
> +
> +if { ![isnative] } {
> +    return -1
> +}

and remove it too.

> +
> +if {[get_compiler_info]} {
> +    untested "could not get compiler info"
> +    return 1
> +}
> +
> +set jit_host_src ${srcfile}
> +set jit_host_bin ${binfile}
> +
> +# We inject the complete path to jit-reader.h into the source file
> +# lest we end up (incorrectly) building against a system-installed
> +# version.
> +set jit_reader_header [standard_output_file "../../../gdb/jit-reader.h"]
> +set jit_reader_flag "-DJIT_READER_H=\"$jit_reader_header\""
> +
> +if  { [gdb_compile "${srcdir}/${subdir}/${jit_host_src}" "${jit_host_bin}" \
> +       executable  [list debug additional_flags=$jit_reader_flag]] != "" } {
> +    untested jit-reader.exp
> +    return -1
> +}
> +
> +set jit_reader jitreader
> +set jit_reader_src ${jit_reader}.c
> +set jit_reader_bin [standard_output_file ${jit_reader}.so]
> +
> +if { [gdb_compile_shlib "${srcdir}/${subdir}/${jit_reader_src}" "${jit_reader_bin}" \
> +	  [list debug additional_flags=$jit_reader_flag]] != "" } {
> +    untested jit-reader.exp
> +    return -1
> +}
> +
> +gdb_load_shlibs "${jit_reader_bin}"
> +

It should be moved into jit_reader_test, after clean_restart, otherwise,
we'll get the following errors if I run it with --target_board=native-gdbserver.

ERROR: tcl error sourcing /home/yao/SourceCode/gnu/gdb/git/gdb/testsuite/gdb.base/jit-reader.exp.
ERROR: can't read "use_gdb_stub": no such variable
    while executing
"if {$use_gdb_stub
	&& [regexp -nocase {^\s*(r|run|star|start|at|att|atta|attac|attach)\M}  $command]} {
	error "gdbserver does not support $command wi..."
    (procedure "gdb_test_multiple" line 21)
    invoked from within
"gdb_test_multiple $command $message {
	-re "\[\r\n\]*($pattern)\[\r\n\]+$gdb_prompt $" {
	    if ![string match "" $message] then {
		pass "$message"
..."
    (procedure "gdb_test" line 22)
    invoked from within
  
Andy Wingo Feb. 25, 2015, 4:23 p.m. UTC | #3
On Wed 25 Feb 2015 16:50, Yao Qi <qiyaoltc@gmail.com> writes:

>> +if { (![istarget x86_64-*-*] && ![istarget i?86-*-*]) || ![is_lp64_target] } {
>> +    return -1;
>> +}
>
> I don't see any reason why this test is arch specific.  We can remove
> such checking, IMO.

The test is arch-specific because it has a simple x86 "jit".  See
jithost.c.

>> +if { ![isnative] } {
>> +    return -1
>> +}
>
> and remove it too.

Does it not need to be this way?  If you are debugging from a big-endian
host, you will read the addresses wrong from the inferior, as the
jit-reader .so reads the values directly.  (Seems to me anyway.)

>> +gdb_load_shlibs "${jit_reader_bin}"
>> +
>
> It should be moved into jit_reader_test, after clean_restart, otherwise,
> we'll get the following errors if I run it with --target_board=native-gdbserver.

ACK.  Will update.

Thanks for the review,

Andy
  
Yao Qi Feb. 25, 2015, 10:38 p.m. UTC | #4
On 02/25/2015 04:23 PM, Andy Wingo wrote:
> The test is arch-specific because it has a simple x86 "jit".  See
> jithost.c.
> 

If jithost.c has arch-specific stuff, let us move all arch-specific
stuff there, like,

#if defined __x86_64__
  code[0] = 0xcc; /* SIGTRAP  */
  code[1] = 0xc3; /* RET  */
#else
  #error "don't know what instructions to generate"
#endif

in jit-reader.exp, if jithost.c is compiled successfully, do the tests,
otherwise, emit UNSUPPORTED and return.  In this way, once some one
wants to extend jit-reader.exp for other targets, he or she needs
to change this part in jithost.c to generate corresponding instructions,
breakpoint instruction and return instruction, right?

jitreader.c needs the same treatment too, but I am fine to leave it
as-is now.

>>> >> +if { ![isnative] } {
>>> >> +    return -1
>>> >> +}
>> >
>> > and remove it too.
> Does it not need to be this way?  If you are debugging from a big-endian
> host, you will read the addresses wrong from the inferior, as the
> jit-reader .so reads the values directly.  (Seems to me anyway.)
> 

My understanding is that jitreader accesses inferior through GDB, no?
  
Andy Wingo Feb. 26, 2015, 9:02 a.m. UTC | #5
On Wed 25 Feb 2015 23:38, Yao Qi <qiyaoltc@gmail.com> writes:

>>>> >> +if { ![isnative] } {
>>>> >> +    return -1
>>>> >> +}
>>> >
>>> > and remove it too.
>> Does it not need to be this way?  If you are debugging from a big-endian
>> host, you will read the addresses wrong from the inferior, as the
>> jit-reader .so reads the values directly.  (Seems to me anyway.)
>> 
>
> My understanding is that jitreader accesses inferior through GDB, no?

Yes, but it does so through a straw, so to speak -- the only interface
it has is "read these bytes of memory", nothing about pointer sizes,
endianness, etc.  And as an exception, the symfile itself is pre-copied
into the address space of the .so, but without any kind of conversion.

Andy
  
Pedro Alves June 17, 2016, 6:56 p.m. UTC | #6
The subject of missing jit reader tests came up again:

 https://sourceware.org/ml/gdb-patches/2016-06/msg00202.html

I've now pushed this in, with a couple trivial modifications mentioned
below.

I left the test arch specific as it was, thinking that it can always
be cleaned up with follow up patches.

On 02/25/2015 03:50 PM, Yao Qi wrote:
> Andy Wingo <wingo@igalia.com> writes:
> 
>> I think it was Sanjoy who forgot to commit these.  Anyway, here is an
>> updated version of the same patch, which passes tests for me.  WDYT?
>>
> 
> Yes, we should add them back since they were reviewed and approved.


> It should be moved into jit_reader_test, after clean_restart, otherwise,
> we'll get the following errors if I run it with --target_board=native-gdbserver.

I did this.

> 
> ERROR: tcl error sourcing /home/yao/SourceCode/gnu/gdb/git/gdb/testsuite/gdb.base/jit-reader.exp.
> ERROR: can't read "use_gdb_stub": no such variable

(...)

and also adjusted the number of "../"'s in :

> set jit_reader_header [standard_output_file "../../../gdb/jit-reader.h"]

since the standard output directory moved under testsuite/outputs/ meanwhile.

Thanks,
Pedro Alves
  

Patch

From e62775ce538a089af4dfb6ef69114633e9694554 Mon Sep 17 00:00:00 2001
From: Sanjoy Das <sanjoy@playingwithpointers.com>
Date: Tue, 18 Sep 2012 08:52:07 +0530
Subject: [PATCH] Add a test case for the jit-reader interface.

Originally intended to be committed on 2013-01-17 in
675921c059dbaddd02ab2eb8a1eaf77b3ac727dd, but by mistake the files were
not added.  Fortunately they still work.

gdb/testsuite/ChangeLog:
2015-02-23  Sanjoy Das <sanjoy@playingwithpointers.com>

	* gdb.base/jit-reader.exp: New file. Test case for the jit-reader
	interface.
	* gdb.base/jithost.c: New file.
	* gdb.base/jithost.h: New file.
	* gdb.base/jitreader.c : New file.
	* gdb.base/jit-protocol.h: New file.
---
 gdb/testsuite/ChangeLog               |   9 ++
 gdb/testsuite/gdb.base/jit-protocol.h |  54 ++++++++++++
 gdb/testsuite/gdb.base/jit-reader.exp |  80 +++++++++++++++++
 gdb/testsuite/gdb.base/jithost.c      |  61 +++++++++++++
 gdb/testsuite/gdb.base/jithost.h      |  27 ++++++
 gdb/testsuite/gdb.base/jitreader.c    | 156 ++++++++++++++++++++++++++++++++++
 6 files changed, 387 insertions(+)
 create mode 100644 gdb/testsuite/gdb.base/jit-protocol.h
 create mode 100644 gdb/testsuite/gdb.base/jit-reader.exp
 create mode 100644 gdb/testsuite/gdb.base/jithost.c
 create mode 100644 gdb/testsuite/gdb.base/jithost.h
 create mode 100644 gdb/testsuite/gdb.base/jitreader.c

diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index ddc9df4..0008005 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,12 @@ 
+2015-02-23  Sanjoy Das <sanjoy@playingwithpointers.com>
+
+	* gdb.base/jit-reader.exp: New file. Test case for the jit-reader
+	interface.
+	* gdb.base/jithost.c: New file.
+	* gdb.base/jithost.h: New file.
+	* gdb.base/jitreader.c : New file.
+	* gdb.base/jit-protocol.h: New file.
+
 2015-02-20  Andy Wingo  <wingo@igalia.com>
 
 	* gdb.guile/scm-frame.exp: Add frame-read-register tests, modelled
diff --git a/gdb/testsuite/gdb.base/jit-protocol.h b/gdb/testsuite/gdb.base/jit-protocol.h
new file mode 100644
index 0000000..f7f9285
--- /dev/null
+++ b/gdb/testsuite/gdb.base/jit-protocol.h
@@ -0,0 +1,54 @@ 
+/* Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef JIT_H
+#error "We don't include jit.h directly since we'd like the jit-reader unit  \
+        tests to break if we make ABI incompatible changes to the structures \
+        re-declared here."
+#endif
+
+#ifndef JIT_PROTOCOL_H
+#define JIT_PROTOCOL_H
+
+#include <stdint.h>
+
+typedef enum
+{
+  JIT_NOACTION = 0,
+  JIT_REGISTER,
+  JIT_UNREGISTER
+} jit_actions_t;
+
+
+struct jit_code_entry
+{
+  struct jit_code_entry *next_entry;
+  struct jit_code_entry *prev_entry;
+  void *symfile_addr;
+  uint64_t symfile_size;
+};
+
+
+struct jit_descriptor
+{
+  uint32_t version;
+  uint32_t action_flag;
+  struct jit_code_entry *relevant_entry;
+  struct jit_code_entry *first_entry;
+};
+
+#endif /* JIT_PROTOCOL_H */
diff --git a/gdb/testsuite/gdb.base/jit-reader.exp b/gdb/testsuite/gdb.base/jit-reader.exp
new file mode 100644
index 0000000..6080564
--- /dev/null
+++ b/gdb/testsuite/gdb.base/jit-reader.exp
@@ -0,0 +1,80 @@ 
+# Copyright 2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile jithost.c
+
+if { (![istarget x86_64-*-*] && ![istarget i?86-*-*]) || ![is_lp64_target] } {
+    return -1;
+}
+
+if {[skip_shlib_tests]} {
+    return -1
+}
+
+if { ![isnative] } {
+    return -1
+}
+
+if {[get_compiler_info]} {
+    untested "could not get compiler info"
+    return 1
+}
+
+set jit_host_src ${srcfile}
+set jit_host_bin ${binfile}
+
+# We inject the complete path to jit-reader.h into the source file
+# lest we end up (incorrectly) building against a system-installed
+# version.
+set jit_reader_header [standard_output_file "../../../gdb/jit-reader.h"]
+set jit_reader_flag "-DJIT_READER_H=\"$jit_reader_header\""
+
+if  { [gdb_compile "${srcdir}/${subdir}/${jit_host_src}" "${jit_host_bin}" \
+       executable  [list debug additional_flags=$jit_reader_flag]] != "" } {
+    untested jit-reader.exp
+    return -1
+}
+
+set jit_reader jitreader
+set jit_reader_src ${jit_reader}.c
+set jit_reader_bin [standard_output_file ${jit_reader}.so]
+
+if { [gdb_compile_shlib "${srcdir}/${subdir}/${jit_reader_src}" "${jit_reader_bin}" \
+	  [list debug additional_flags=$jit_reader_flag]] != "" } {
+    untested jit-reader.exp
+    return -1
+}
+
+gdb_load_shlibs "${jit_reader_bin}"
+
+proc jit_reader_test {} {
+    global jit_host_bin
+    global jit_reader_bin
+    global verbose
+
+    clean_restart $jit_host_bin
+
+    if {$verbose > 0} {
+	gdb_test_no_output "set debug jit 1"
+    }
+
+    gdb_test_no_output "jit-reader-load ${jit_reader_bin}" "jit-reader-load"
+    gdb_run_cmd
+    gdb_test "" "Program received signal SIGTRAP, .*" "expect SIGTRAP"
+
+    gdb_test "bt" "jit_function_00.*"
+}
+
+jit_reader_test
diff --git a/gdb/testsuite/gdb.base/jithost.c b/gdb/testsuite/gdb.base/jithost.c
new file mode 100644
index 0000000..413c4cd
--- /dev/null
+++ b/gdb/testsuite/gdb.base/jithost.c
@@ -0,0 +1,61 @@ 
+/* Copyright (C) 2009-2012 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#include JIT_READER_H  /* Please see jit-reader.exp for an explanation.  */
+#include "jithost.h"
+#include "jit-protocol.h"
+
+void __attribute__((noinline)) __jit_debug_register_code () { }
+
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+struct jit_code_entry only_entry;
+
+typedef void (jit_function_t) ();
+
+int main (int argc, char **argv)
+{
+  char *code = mmap (NULL, getpagesize (), PROT_WRITE | PROT_EXEC,
+		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  jit_function_t *function = (jit_function_t *) code;
+
+  code[0] = 0xcc; /* SIGTRAP  */
+  code[1] = 0xc3; /* RET  */
+
+  struct jithost_abi *symfile = malloc (sizeof (struct jithost_abi));
+  symfile->begin = code;
+  symfile->end = code + 2;
+
+  only_entry.symfile_addr = symfile;
+  only_entry.symfile_size = sizeof (struct jithost_abi);
+
+  __jit_debug_descriptor.first_entry = &only_entry;
+  __jit_debug_descriptor.relevant_entry = &only_entry;
+  __jit_debug_descriptor.action_flag = JIT_REGISTER;
+  __jit_debug_descriptor.version = 1;
+  __jit_debug_register_code ();
+
+  function ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/jithost.h b/gdb/testsuite/gdb.base/jithost.h
new file mode 100644
index 0000000..52ca87a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/jithost.h
@@ -0,0 +1,27 @@ 
+/* Copyright (C) 2009-2012 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef JITHOST_H
+#define JITHOST_H
+
+struct jithost_abi
+{
+  const char *begin;
+  const char *end;
+};
+
+#endif /* JITHOST_H */
diff --git a/gdb/testsuite/gdb.base/jitreader.c b/gdb/testsuite/gdb.base/jitreader.c
new file mode 100644
index 0000000..0c935c4
--- /dev/null
+++ b/gdb/testsuite/gdb.base/jitreader.c
@@ -0,0 +1,156 @@ 
+/* Copyright (C) 2009-2012 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include JIT_READER_H  /* Please see jit-reader.exp for an explanation.  */
+#include "jithost.h"
+
+GDB_DECLARE_GPL_COMPATIBLE_READER;
+
+enum register_mapping
+{
+  AMD64_RA = 16,
+  AMD64_RSP = 7,
+};
+
+struct reader_state
+{
+  uintptr_t code_begin;
+  uintptr_t code_end;
+};
+
+static enum gdb_status
+read_debug_info (struct gdb_reader_funcs *self,
+		 struct gdb_symbol_callbacks *cbs,
+                 void *memory, long memory_sz)
+{
+  struct jithost_abi *symfile = memory;
+  struct gdb_object *object = cbs->object_open (cbs);
+  struct gdb_symtab *symtab = cbs->symtab_open (cbs, object, "");
+  GDB_CORE_ADDR begin = (GDB_CORE_ADDR) symfile->begin;
+  GDB_CORE_ADDR end = (GDB_CORE_ADDR) symfile->end;
+
+  cbs->block_open (cbs, symtab, NULL, begin, end, "jit_function_00");
+
+  cbs->symtab_close (cbs, symtab);
+  cbs->object_close (cbs, object);
+  return GDB_SUCCESS;
+}
+
+static void
+free_reg_value (struct gdb_reg_value *value)
+{
+  free (value);
+}
+
+static void
+write_register (struct gdb_unwind_callbacks *callbacks, int dw_reg,
+                uintptr_t value)
+{
+  const int size = sizeof (uintptr_t);
+  struct gdb_reg_value *reg_val =
+    malloc (sizeof (struct gdb_reg_value) + size - 1);
+  reg_val->defined = 1;
+  reg_val->free = free_reg_value;
+
+  memcpy (reg_val->value, &value, size);
+  callbacks->reg_set (callbacks, dw_reg, reg_val);
+}
+
+static int
+read_register (struct gdb_unwind_callbacks *callbacks, int dw_reg,
+	       uintptr_t *value)
+{
+  const int size = sizeof (uintptr_t);
+  struct gdb_reg_value *reg_val = callbacks->reg_get (callbacks, dw_reg);
+  if (reg_val->size != size || !reg_val->defined)
+    {
+      reg_val->free (reg_val);
+      return 0;
+    }
+  memcpy (value, reg_val->value, size);
+  reg_val->free (reg_val);
+  return 1;
+}
+
+static enum gdb_status
+unwind_frame (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs)
+{
+  const int word_size = sizeof (uintptr_t);
+  uintptr_t this_sp, this_ip, prev_ip, prev_sp;
+  struct reader_state *state = (struct reader_state *) self->priv_data;
+
+  if (!read_register (cbs, AMD64_RA, &this_ip))
+    return GDB_FAIL;
+
+  if (this_ip >= state->code_end || this_ip < state->code_begin)
+    return GDB_FAIL;
+
+  if (!read_register (cbs, AMD64_RSP, &this_sp))
+    return GDB_FAIL;
+
+  if (cbs->target_read (this_sp, &prev_ip, word_size) == GDB_FAIL)
+    return GDB_FAIL;
+
+  prev_sp = this_sp + word_size;
+  write_register (cbs, AMD64_RA, prev_ip);
+  write_register (cbs, AMD64_RSP, prev_sp);
+  return GDB_SUCCESS;
+}
+
+static struct gdb_frame_id
+get_frame_id (struct gdb_reader_funcs *self, struct gdb_unwind_callbacks *cbs)
+{
+  struct reader_state *state = (struct reader_state *) self->priv_data;
+  struct gdb_frame_id frame_id;
+
+  uintptr_t sp;
+  read_register (cbs, AMD64_RSP, &sp);
+
+  frame_id.code_address = (GDB_CORE_ADDR) state->code_begin;
+  frame_id.stack_address = (GDB_CORE_ADDR) sp;
+
+  return frame_id;
+}
+
+static void
+destroy_reader (struct gdb_reader_funcs *self)
+{
+  free (self->priv_data);
+  free (self);
+}
+
+extern struct gdb_reader_funcs *
+gdb_init_reader (void)
+{
+  struct reader_state *state = malloc (sizeof (struct reader_state));
+  struct gdb_reader_funcs *reader_funcs =
+    malloc (sizeof (struct gdb_reader_funcs));
+
+  reader_funcs->reader_version = GDB_READER_INTERFACE_VERSION;
+  reader_funcs->priv_data = state;
+  reader_funcs->read = read_debug_info;
+  reader_funcs->unwind = unwind_frame;
+  reader_funcs->get_frame_id = get_frame_id;
+  reader_funcs->destroy = destroy_reader;
+
+  return reader_funcs;
+}
-- 
2.1.4