Skip to content

Commit 53255ba

Browse files
author
dmi3
committed
Project:
+ cpp src files + py files /gdb-py/ + file 'path' + Makefile + submodule /modules/
0 parents  commit 53255ba

17 files changed

+934
-0
lines changed

.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
py-gdb-api_demo.txt
3+
\.project
4+
\.cproject
5+
Debug/
6+
\.settings/
7+
\.vscode
8+
**/__pycache__/

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "modules"]
2+
path = modules
3+
url =

gdb-py/gdb_launch.py

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import gdb
2+
import os.path
3+
4+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
5+
6+
sys.path.append('../') # For import /modules/
7+
from modules.gdb_connection import BeginSession
8+
from modules.gdb_connection import Shutdown
9+
from modules.gdb_connection import Output
10+
#from modules.memory import DumpMemory
11+
#from modules.memory import AppendMemory
12+
#from modules.memory import RestoreMemory
13+
from modules.memory import ReadMemory
14+
#from modules.memory import WriteMemory
15+
#from modules.call_method import CallMethod
16+
17+
def main():
18+
print(f'GDB-client version = {gdb.VERSION}\n')
19+
20+
# Elf-file taken as argument of gdb-client
21+
elf = gdb.objfiles()[0]
22+
if elf == None:
23+
raise gdb.GdbError('Elf-file is not found.')
24+
elf = elf.filename
25+
print(f'Elf-file = {elf}\n')
26+
27+
# Preparing:
28+
BeginSession.invoke(elf, False) # CLI: (gdb) begin <path-to-elf>
29+
# State: stop at _start
30+
31+
# Breakpoint on trap for exception/interrupt
32+
gdb.Breakpoint('trap')
33+
34+
# Start execution:
35+
gdb.Breakpoint('main')
36+
gdb.execute('continue')
37+
# State: stop at main()
38+
39+
# Get register value:
40+
pc = gdb.parse_and_eval('$pc')
41+
print(f'\npc = {pc}\n')
42+
43+
# Inside main():
44+
frame = gdb.selected_frame()
45+
gdb.execute('frame') # Print stack-frame information
46+
47+
# Set breakpoint at (main + 3 lines):
48+
bp = gdb.Breakpoint('+3')
49+
bp.silent = True
50+
gdb.execute('continue')
51+
# State: stop at (main + 3 lines)
52+
53+
# Get object information:
54+
val_obj = gdb.parse_and_eval('exampleObj')
55+
print(f'\n{frame.function()}: Object of <{val_obj.type}> allocated at address {val_obj.address}')
56+
print(f'{frame.function()}: exampleObj.indexMax = {val_obj["indexMax"]}\n')
57+
58+
# Set watchpoint on local variable 'isErr':
59+
wp = gdb.Breakpoint('isErr', gdb.BP_WATCHPOINT)
60+
wp.silent = True
61+
gdb.execute('continue')
62+
# State: stop at watchpoint on isErr
63+
64+
# Get array value:
65+
val_dstY = gdb.parse_and_eval('dstY')
66+
print(f'\n{frame.function()}: array <{val_dstY.type}> dstY = {val_dstY}')
67+
ReadMemory.invoke(f'/tmp/tmp.bin dstY {val_dstY.type.sizeof}', False) # Dump to file
68+
69+
# Get local variable:
70+
var_isErr = frame.read_var('isErr')
71+
print(f'\n{frame.function()}: err flag <{var_isErr.type}> isErr = {var_isErr}\n')
72+
73+
# Set finish breakpoint for main():
74+
gdb.execute('set backtrace past-main on')
75+
fbp_main = gdb.FinishBreakpoint()
76+
gdb.execute('continue')
77+
# State: stop at finish breakpoint after main()
78+
79+
# Return value from main():
80+
print(f'\nmain() returns value <{fbp_main.return_value.type}> = {fbp_main.return_value}\n')
81+
82+
# Output text message to GDB-console:
83+
if fbp_main.return_value == 0:
84+
Output.invoke('Ok: Result is Ok!', False)
85+
else:
86+
Output.invoke('Err: Result is Failure!', False)
87+
88+
# End:
89+
Output.invoke(f'Info: {" End of python-GDB-script ":*^80}', False)
90+
Shutdown.invoke('', False) # CLI: (gdb) shutdown
91+
92+
93+
if __name__ == "__main__":
94+
main()

gdb-py/gdb_unit_tests.py

+249
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
import gdb
2+
import os.path
3+
import time
4+
5+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
6+
7+
sys.path.append('../') # For import /modules/
8+
from modules.gdb_connection import BeginSession
9+
from modules.gdb_connection import Shutdown
10+
from modules.gdb_connection import Output
11+
12+
from xmethod import ExampleClassMatcher
13+
14+
import unittest
15+
16+
hp = 0 # Heap pointer
17+
18+
19+
def setUpModule():
20+
print(f'GDB-client version = {gdb.VERSION}\n')
21+
22+
# Elf-file taken as argument of gdb-client
23+
elf = gdb.objfiles()[0]
24+
if elf == None:
25+
raise gdb.GdbError('Elf-file is not found.')
26+
elf = elf.filename
27+
print(f'Elf-file = {elf}\n')
28+
29+
# Preparing:
30+
BeginSession.invoke(elf, False)
31+
# State: stop at _start
32+
33+
# Breakpoint on trap for exception/interrupt
34+
gdb.Breakpoint('trap')
35+
36+
# Start execution:
37+
gdb.Breakpoint('main')
38+
gdb.execute('continue')
39+
# State: stop at main()
40+
41+
# Heap pointer:
42+
global hp
43+
hp = int(gdb.parse_and_eval('$sp')) + 0x130 #0x100f0100
44+
45+
#********************************************************************************
46+
47+
class TestComputeDual(unittest.TestCase):
48+
'''Tests for function computeDual(int32_t val)'''
49+
50+
def setUp(self):
51+
'''For each test-method'''
52+
if (int(gdb.parse_and_eval('$pc')) == int(gdb.parse_and_eval('trap').address)):
53+
self.skipTest('Skip due to exception that was earlier')
54+
55+
def test_computeDual_0(self):
56+
'''Test for function computeDual(int32_t val)'''
57+
result = int(gdb.parse_and_eval('computeDual(0)'))
58+
self.assertEqual(result, 0)
59+
60+
def test_computeDual_neg(self):
61+
'''Test for function computeDual(int32_t val)'''
62+
result = int(gdb.parse_and_eval('computeDual(-5)'))
63+
self.assertEqual(result, -10)
64+
65+
def test_computeDual_pos(self):
66+
'''Test for function computeDual(int32_t val)'''
67+
result = int(gdb.parse_and_eval('computeDual(6)'))
68+
self.assertEqual(result, 12)
69+
70+
#********************************************************************************
71+
72+
class TestExampleClass(unittest.TestCase):
73+
'''Tests for methods of ExampleClass without creating class object'''
74+
75+
class_addr = int(gdb.lookup_global_symbol('ExampleClass::ExampleClass').value().address)
76+
77+
def setUp(self):
78+
'''For each test-method'''
79+
if (int(gdb.parse_and_eval('$pc')) == int(gdb.parse_and_eval('trap').address)):
80+
self.skipTest('Skip due to exception that was earlier')
81+
82+
def test_computeFactorial_0(self):
83+
'''Test for method ExampleClass::computeFactorial(uint32_t n)'''
84+
result = int(gdb.parse_and_eval(f'((ExampleClass*){self.class_addr})->computeFactorial(0)'))
85+
self.assertEqual(result, 1)
86+
87+
def test_computeFactorial_1(self):
88+
'''Test for method ExampleClass::computeFactorial(uint32_t n)'''
89+
result = int(gdb.parse_and_eval(f'((ExampleClass*){self.class_addr})->computeFactorial(4)'))
90+
self.assertEqual(result, 24)
91+
92+
def test_findIndexMaxElement(self):
93+
'''Test for method ExampleClass::findIndexMaxElement(uint32_t len, int32_t* src)'''
94+
array = b"\x00\x00\x00\x00\x04\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00" #{0, 4, 7, 2, 2}
95+
length = 5
96+
inferior = gdb.selected_inferior()
97+
inferior.write_memory(hp, array, length*4) #Address = heap = start sp + 0x100
98+
99+
result = int( gdb.parse_and_eval(f'((ExampleClass*){self.class_addr})->\
100+
findIndexMaxElement({length}, (int*){hp})') ) #ret value
101+
self.assertEqual(result, 2)
102+
103+
def test_computeAxpy(self):
104+
'''Test for method ExampleClass::computeAxpy(uint32_t len, int32_t* dstY, int32_t a, int32_t* srcX, int32_t* srcY).
105+
Method ExampleClass::computeAxpy(...) contains nested call this->findIndexMaxElement(...)'''
106+
resultY = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #{0, 0, 0, 0}
107+
a = 2
108+
arrayX = b"\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00" #{1, 1, 1, 1}
109+
arrayY = b"\x00\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00" #{0, 3, 1, 2}
110+
length = 4
111+
inferior = gdb.selected_inferior()
112+
inferior.write_memory(hp, resultY, length*4)
113+
inferior.write_memory(hp+0x100, arrayX, length*4)
114+
inferior.write_memory(hp+0x200, arrayY, length*4)
115+
116+
result = int( gdb.parse_and_eval(f'((ExampleClass*){self.class_addr})->\
117+
computeAxpy({length}, (int*){hp}, {a}, (int*){hp+0x100}, (int*){hp+0x200})') ) #ret value
118+
resultY = inferior.read_memory(hp, length*4).tobytes() #Computed resultY == {2, 5, 3, 4}
119+
120+
self.assertEqual(result, 1)
121+
self.assertEqual(resultY, b'\x02\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00')
122+
123+
def test_0read_init_mask(self):
124+
'''Read initial value of static field ExampleClass::mask'''
125+
result = int(gdb.parse_and_eval('ExampleClass::mask'))
126+
self.assertEqual(result, 0xff)
127+
128+
def test_applyMask(self):
129+
'''Test for static method ExampleClass::applyMask(uint32_t val)'''
130+
mask_val = 0x01f0
131+
132+
gdb.parse_and_eval(f'ExampleClass::mask = {mask_val}')
133+
mask_field = int(gdb.parse_and_eval('ExampleClass::mask'))
134+
135+
result = int(gdb.parse_and_eval('ExampleClass::applyMask(0x237e)')) #0x170
136+
self.assertEqual(mask_field, mask_val)
137+
self.assertEqual(result, 0x0170)
138+
139+
#********************************************************************************
140+
141+
class TestExampleClassObject(unittest.TestCase):
142+
'''Tests for object exampleObj of ExampleClass'''
143+
144+
@classmethod
145+
def setUpClass(cls):
146+
'''Setup for test-class TestExampleClassObject.
147+
Execute C++ code created object exampleObj'''
148+
print('\n')
149+
if (int(gdb.parse_and_eval('$pc')) != int(gdb.parse_and_eval('trap').address)): #If not at exception trap now
150+
# Set breakpoint at (main + 3 lines):
151+
gdb.Breakpoint('+3')
152+
gdb.execute('continue')
153+
# State: stop at (main + 3 lines)
154+
#Register Xmethod for tests with xmethods
155+
gdb.xmethod.register_xmethod_matcher(None, ExampleClassMatcher())
156+
157+
def setUp(self):
158+
'''For each test-method'''
159+
if (int(gdb.parse_and_eval('$pc')) == int(gdb.parse_and_eval('trap').address)):
160+
self.skipTest('Skip due to exception that was earlier')
161+
162+
def test_Xmethod_mustException(self):
163+
'''Tests with Xmethod: replace method exampleObj.mustException(...)'''
164+
'''Original method exampleObj.mustException(...) causes to exception'''
165+
result = int(gdb.parse_and_eval('exampleObj.mustException(2)'))
166+
self.assertEqual(result, 20)
167+
168+
def test_xmethod_getFieldIndexMax(self):
169+
'''Tests with Xmethod: add new xmethod exampleObj.getFieldIndexMax(...)'''
170+
'''Original object exampleObj do not contains method .getFieldIndexMax(...)'''
171+
value = 0x2b
172+
gdb.parse_and_eval(f'exampleObj.indexMax = {value}')
173+
174+
result = int(gdb.parse_and_eval('exampleObj.getFieldIndexMax()'))
175+
self.assertEqual(result, value)
176+
177+
def test_computeFactorial_0(self):
178+
'''Test for object method exampleObj.computeFactorial(uint32_t n)'''
179+
result = int(gdb.parse_and_eval('exampleObj.computeFactorial(0)'))
180+
self.assertEqual(result, 1)
181+
182+
def test_computeFactorial_1(self):
183+
'''Test for object method exampleObj.computeFactorial(uint32_t n)'''
184+
result = int(gdb.parse_and_eval('exampleObj.computeFactorial(5)'))
185+
self.assertEqual(result, 120)
186+
187+
def test_findIndexMaxElement(self):
188+
'''Test for object method exampleObj.findIndexMaxElement(uint32_t len, int32_t* src)'''
189+
array = b"\x00\x00\x00\x00\x04\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00" #{0, 4, 7, 2, 2}
190+
length = 5
191+
inferior = gdb.selected_inferior()
192+
inferior.write_memory(hp, array, length*4) #Address = heap = start sp + 0x100
193+
194+
result = int(gdb.parse_and_eval(f'exampleObj.findIndexMaxElement({length}, (int*){hp})'))
195+
self.assertEqual(result, 2)
196+
197+
def test_computeAxpy(self):
198+
'''Test for object method exampleObj.computeAxpy(uint32_t len, int32_t* dstY, int32_t a, int32_t* srcX, int32_t* srcY).
199+
Method ExampleClass::computeAxpy(...) contains nested call this->findIndexMaxElement(...)'''
200+
resultY = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #{0, 0, 0, 0}
201+
a = 2
202+
arrayX = b"\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00" #{1, 1, 1, 1}
203+
arrayY = b"\x00\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00" #{0, 3, 1, 2}
204+
length = 4
205+
inferior = gdb.selected_inferior()
206+
inferior.write_memory(hp, resultY, length*4)
207+
inferior.write_memory(hp+0x100, arrayX, length*4)
208+
inferior.write_memory(hp+0x200, arrayY, length*4)
209+
210+
result = int(gdb.parse_and_eval(f'exampleObj.computeAxpy({length}, (int*){hp}, {a}, (int*){hp+0x100}, (int*){hp+0x200})'))
211+
resultY = inferior.read_memory(hp, length*4).tobytes() #Computed resultY == {2, 5, 3, 4}
212+
213+
self.assertEqual(result, 1)
214+
self.assertEqual(resultY, b'\x02\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00')
215+
216+
def test_applyMask(self):
217+
'''Test for static method ExampleClass::applyMask(uint32_t val) of object exampleObj'''
218+
obj = gdb.parse_and_eval('exampleObj')
219+
mask_val = 0x01f0
220+
221+
gdb.parse_and_eval(f'exampleObj.mask = {mask_val}')
222+
mask_field = int(obj['mask'])
223+
224+
result = int(gdb.parse_and_eval('exampleObj.applyMask(0x237e)')) #0x170
225+
self.assertEqual(mask_field, mask_val)
226+
self.assertEqual(result, 0x0170)
227+
228+
def test_objectField(self):
229+
'''Test for access object field exampleObj.indexMax'''
230+
obj = gdb.parse_and_eval('exampleObj')
231+
init_field_val = int(obj['indexMax'])
232+
233+
value = 0x1a
234+
gdb.parse_and_eval(f'exampleObj.indexMax = {value}')
235+
result = int(obj['indexMax'])
236+
237+
self.assertEqual(init_field_val, 0xcf)
238+
self.assertEqual(result, value)
239+
240+
#********************************************************************************
241+
242+
if __name__ == "__main__":
243+
unittest.main(exit=False, verbosity=2, catchbreak=True)
244+
245+
# Finish GDB-session:
246+
time.sleep(2) #For unittest output finishing
247+
print('\n')
248+
Output.invoke(f'Info: {" End of python-GDB-script ":*^80}', False)
249+
Shutdown.invoke('', False)

gdb-py/openocd_gdb_launch.sh

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/bash
2+
3+
source ../paths
4+
5+
ELF="$1"
6+
7+
8+
OPENOCD_LAUNCH="$OPENOCD -f $OPENOCD_CFG_HW"
9+
GDB_LAUNCH="$GDB -x $GDB_SCRIPT --silent $ELF"
10+
11+
12+
#Launch: Hardware + OpenOCD + GDB
13+
xfce4-terminal \
14+
--tab --title=OpenOCD -e "$OPENOCD_LAUNCH" \
15+
--tab --title=GDB --hold -e "$GDB_LAUNCH"
16+
17+
exit 0

gdb-py/riscpoa.cfg

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# interface
2+
interface jlink
3+
transport select jtag
4+
adapter_khz 1000
5+
6+
# target
7+
8+
set _CHIPNAME riscv
9+
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00000ccd
10+
11+
set _TARGETNAME $_CHIPNAME.cpu
12+
13+
target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME
14+
$_TARGETNAME.0 configure -work-area-phys 0x10000000 -work-area-size 0x800000 -work-area-backup 1
15+
16+
echo "Ready for Remote Connections"

0 commit comments

Comments
 (0)