How to integrate GDBFrontend with your Makefile?
GDBFrontend has very powerful APIs on different protocols that allow you to extend and integrate your debugger into very large scale of possibilities.
First think you start your debugger:
gdbfrontend
If you are not specifying a port, the default port is 5550
.
You can specify the port with -p PORT
parameter.
If you want to start multiple GDBFrontend sessions, you should specify different ports and terminal IDs for each debugger.
Just like:
gdbfrontend # debugger one, default port: 5550 and default terminal ID: gdb-frontend
gdbfrontend -p 5551 -t gdb-frontend-2 # second debugger
Load the executable to debugger
When we load the executable, it will reload it when you re-build it.
Just click to Load Executable
button on top left side.
Let's add a debug recipe to call GDBFrontend HTTP API
We are going to use GDBFrontend's HTTP API in our Makefile
.
We should send a request to this:
curl http://127.0.0.1:5550/api/runtime/run
Before integration, the Makefile
looks like this:
CC = gcc
CFLAGS = -std=c99 -I../../ -O3 -g
JSONIC_SOURCES = $(filter-out $(shell find ../../ -path "*/examples/*"), $(shell find ../../ -name "*.c"))
JSONIC_HEADERS = $(filter-out $(shell find ../../ -path "*/examples/*"), $(shell find ../../ -name "*.h"))
JSONIC_OBJ = $(JSONIC_SOURCES:.c=.o)
SOURCE = heroes.c
EXECUTABLE = $(SOURCE:.c=.exe)
ifeq ($(OS), Windows_NT)
RM = rm -rf
else
RM = rm -rf
endif
$(EXECUTABLE): $(JSONIC_OBJ)
$(CC) -o $@ $(SOURCE) $< $(CFLAGS)
clean:
$(RM) $(EXECUTABLE)
We are going to add a debug
recipe to our Makefile
:
debug: $(EXECUTABLE)
@curl http://127.0.0.1:5550/api/runtime/run
Finally the Makefile
will look like this:
CC = gcc
CFLAGS = -std=c99 -I../../ -O3 -g
JSONIC_SOURCES = $(filter-out $(shell find ../../ -path "*/examples/*"), $(shell find ../../ -name "*.c"))
JSONIC_HEADERS = $(filter-out $(shell find ../../ -path "*/examples/*"), $(shell find ../../ -name "*.h"))
JSONIC_OBJ = $(JSONIC_SOURCES:.c=.o)
SOURCE = heroes.c
EXECUTABLE = $(SOURCE:.c=.exe)
ifeq ($(OS), Windows_NT)
RM = rm -rf
else
RM = rm -rf
endif
$(EXECUTABLE): $(JSONIC_OBJ)
$(CC) -o $@ $(SOURCE) $< $(CFLAGS)
clean:
$(RM) $(EXECUTABLE)
debug: $(EXECUTABLE)
@curl http://127.0.0.1:5550/api/runtime/run
Let's use our debug recipe
We added a debug recipe into the Makefile
. Now we can use it like this:
make clean; make debug
This will build your application and start your application on GDBFrontend.
Getting a variable for a specific testing
For an example to special debugger integration requirements, let's see this example.
Don't forget to apply URL encoding:
For example sending a parameter:
http://127.0.0.1:5550/api/frame/variable?expression="jsonic_object_get(json_string, root, "squadName")->val"
Should be like this:
http://127.0.0.1:5550/api/frame/variable?expression="jsonic_object_get(json_string%2C%20root%2C%20%22squadName%22)-%3Eval"
Just add this to the Makefile
recipe:
debug: $(EXECUTABLE)
@curl http://127.0.0.1:5550/api/runtime/run
$(info Waiting debugger to interrupt...)
@sleep 5
$(info Value for expression: "jsonic_object_get(json_string, root, "squadName")->val")
@eval echo "$$(curl http://127.0.0.1:5550/api/frame/variable?expression="jsonic_object_get(json_string%2C%20root%2C%20%22squadName%22)-%3Eval")"
You will an output like this:
root@milkyway:/mnt/c/proje/jsonic/examples/heroes# make debug
Waiting debugger to interrupt...
Value for expression: "jsonic_object_get(json_string, root, "squadName")->val"
{"ok": true}{ok: true, variable: {is_global: false, name: val, expression: jsonic_object_get(json_string, root, "squadName")->val, is_pointer: true, is_optimized_out: false, address: 0x55555555ac78, value: Super "hero" squad, is_nts: true, type: {alignof: 8, code: 1, name: null, sizeof: 8, tag: null, is_pointer: true, terminal: {alignof: 1, code: 8, name: char, sizeof: 1, tag: null, is_pointer: false}}, type_tree: [{alignof: 8, code: 1, name: null, sizeof: 8, tag: null, is_pointer: true}, {alignof: 1, code: 8, name: char, sizeof: 1, tag: null, is_pointer: false}], members: []}}
root@milkyway:/mnt/c/proje/jsonic/examples/heroes#
You may be noticed that we've added sleep 5
to wait the debugger to start and interrupt application. This is a bad approach of course, you can write your own script and use GDBFrontend's WebSocket API to listen events like stop
event and do your jobs on events.
What's now?
Possibilities are infinite. You can follow Plugin Development Tutorial to make your own complex integrations.
By writing your own GDBFrontend plugin, you can make your own Python, HTTP and WebSocket APIs and you can communicate to them from other platforms.
Some ideas for integrations
For special development and debuggin requirements you can do something like these with your own plugin:
- Restarting debugging
- Adding breakpoints
- Writing your own GDBFrontendd plugin to use it for special debugging requirements and integrations
- Writing your own WebSocket client to listen debugging events
- Spawning an evaluater window
- Make your own custom data visualizer and trigger them from your integrations
- Using terminal API for special requirements
Happy debugging! ❤️