Add example demonstrating how to inject code into a debugee
authorJan Vrany <jan.vrany@labware.com>
Sat, 27 Mar 2021 07:05:45 +0000
changeset 227 044104319ea4
parent 226 f6c09fa9424e
child 228 04ce643219ce
Add example demonstrating how to inject code into a debugee
tests/GDBDebuggerExamples.st
tests/c/Makefile
tests/c/fatshell.c
--- a/tests/GDBDebuggerExamples.st	Wed Mar 17 12:44:56 2021 +0000
+++ b/tests/GDBDebuggerExamples.st	Sat Mar 27 07:05:45 2021 +0000
@@ -77,6 +77,76 @@
 
 !GDBDebuggerExamples methodsFor:'examples'!
 
+example01_inject_code_riscv
+    "
+    This example demonstrates how to use libgdbs to dynamically
+    inject code into a debugee. This example uses RISC-V as a target 
+    architecture.
+
+    At any point, you may open a VDB on debugger instance by evaluating
+
+        VDBDebuggerApplication openFor: gdb
+    "
+
+    | fatshell nzone code exit |
+
+    "First, we need a 'fatshell'. On Debian, you may compile it by
+
+         cd .../jv/libgdbs/tests/c
+         make make CC=riscv64-linux-gnu-gcc BUILD_TARGET=riscv64-unknown-linux-gnu
+
+    To see fatshell source, inspect:
+
+        ((Smalltalk getPackageDirectoryForPackage:'jv:libgdbs/tests') / 'c' / 'fatshell.c') asFilename contents asString
+
+    "
+    fatshell := (Smalltalk getPackageDirectoryForPackage:'jv:libgdbs/tests') / 'c' / 'riscv64-unknown-linux-gnu' / 'fatshell'.
+
+    self skipIf: fatshell exists not 
+         description: 'fatshell for RISC-V does not exists'.
+    self skipIf: (OperatingSystem pathOfCommand: 'qemu-riscv64-static') isNil 
+         description: 'QEMU not found'.
+
+    "First, start QEMU: "
+    TerminalView 
+        openOnCommand:'qemu-riscv64-static -g 1234 ', fatshell pathName, ' 1 2 3 4'
+        onExit:[:vt | vt topView close ]. 
+
+    "...then create a new GDB and connect to QEMU: "
+    gdb := GDBDebugger new.
+    gdb executable: fatshell.
+    gdb targetConnect: 'remote' parameters: #('localhost:1234').
+
+    "Now let's determine where the nzone is: "
+    nzone := ((gdb evaluate: '(void*)&nzone') valueFormatted: GDBOutputFormat signedDecimal) asInteger.
+
+    "Now, let's generate some code, Following might be generated on
+     the fly by smalltalk code (or anything else), but here we will
+     just use a simple static code:"
+    code := ByteArray fromHexStringWithSeparators: 
+            '93 07 05 00',    "/ mv      a5,a0
+            '13 05 10 00',    "/ li      a0,1
+            '93 06 10 00',    "/ li      a3,1
+            '63 8a a7 00',    "/ beq     a5,a0,+20 ---------+
+            '13 87 07 00',    "/ mv      a4,a5     <---+    |
+            '9b 87 f7 ff',    "/ addiw   a5,a5,-1      |    |
+            '3b 05 a7 02',    "/ mulw    a0,a4,a0      |    |
+            'e3 9a d7 fe',    "/ bne     a5,a3,-12 ----+    |
+            '67 80 00 00'.    "/ ret               <--------+
+
+    "Now inject the code into debuggee by owerwriting nzone: "
+    gdb selectedInferior memoryAt: nzone put: code.
+
+    "Finally, run the inferior"
+    exit := gdb send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
+
+    "This is here so you can place a breakpoint on this line :-)"
+    exit yourself.
+
+    "Created: / 24-03-2021 / 12:40:17 / Jan Vrany <jan.vrany@labware.com>"
+    "Modified: / 27-03-2021 / 07:01:57 / Jan Vrany <jan.vrany@labware.com>"
+!
+
 example_README
     "
     This is an example from libgdb's README.md.
--- a/tests/c/Makefile	Wed Mar 17 12:44:56 2021 +0000
+++ b/tests/c/Makefile	Sat Mar 27 07:05:45 2021 +0000
@@ -55,7 +55,7 @@
 	 	-o $@ -c $<
 
 $(BUILD_TARGET)/%$(EXE): %.c
-	$(CC) \
+	$(CC) -static \
 		$(shell if grep CFLAGS $< > /dev/null; then grep CFLAGS $< | sed -e 's/^.*CFLAGS=//g'; else echo "$(CFLAGS_BIN)"; fi) \
 		-o $@ $<
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/c/fatshell.c	Sat Mar 27 07:05:45 2021 +0000
@@ -0,0 +1,21 @@
+#include <stdio.h>
+
+#define NZONE_SIZE 1024*1024
+
+__asm__(
+	"                                  \n"
+	".section .nzone,\"awx\", @progbits\n"
+	"nzone:                            \n"
+	".space 1024*1024                  \n"
+	"                                  \n"
+	".section text                     \n"
+);
+
+extern unsigned char nzone[NZONE_SIZE];
+
+typedef int (*entry_func)(int argc, char ** argv);
+static entry_func entry = (entry_func)(&nzone);
+
+int main(int argc, char **argv) {
+	return entry(argc, argv);
+}
\ No newline at end of file