Skip to content

Commit 6eb9dc1

Browse files
committed
Add new unit tests for the gdb api
This adds new unit tests for gdb_apit. The tests compile a test file test.c and then run gdb on it (via gdb_apit).
1 parent 7269ba9 commit 6eb9dc1

File tree

3 files changed

+160
-180
lines changed

3 files changed

+160
-180
lines changed

unit/memory-analyzer/gdb_api.cpp

Lines changed: 130 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ Author: Malte Mues <[email protected]>
1616
defined(__unix__) || \
1717
defined(__CYGWIN__) || \
1818
defined(__MACH__)
19+
#define RUN_GDB_API_TESTS
20+
#endif
1921
// clang-format on
2022

23+
#ifdef RUN_GDB_API_TESTS
24+
2125
#include <cstdio>
2226
#include <cstdlib>
2327
#include <regex>
@@ -27,232 +31,178 @@ Author: Malte Mues <[email protected]>
2731
#include <iostream>
2832

2933
#include <memory-analyzer/gdb_api.cpp>
30-
#include <string>
3134

32-
SCENARIO(
33-
"gdb_apit uses regex as expected for memory",
34-
"[core][memory-analyzer]")
35+
void compile_test_file()
3536
{
36-
gdb_apit gdb_api("");
37-
GIVEN("The result of a struct pointer")
38-
{
39-
const std::string line = "$2 = (struct cycle_buffer *) 0x601050 <buffer>";
40-
THEN("the result matches the memory address in the output")
41-
{
42-
REQUIRE(gdb_api.extract_memory(line) == "0x601050");
43-
}
44-
THEN("adding '(gdb) ' to the line doesn't have an influence")
45-
{
46-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x601050");
47-
}
48-
}
37+
std::string test_file("memory-analyzer/test.c");
4938

50-
GIVEN("The result of a typedef pointer")
51-
{
52-
const std::string line = "$4 = (cycle_buffer_entry_t *) 0x602010";
53-
THEN("the result matches the memory address in the output")
54-
{
55-
REQUIRE(gdb_api.extract_memory(line) == "0x602010");
56-
}
57-
THEN("adding '(gdb) ' to the line doesn't have an influence")
58-
{
59-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x602010");
60-
}
61-
}
39+
std::string cmd("gcc -g -o test ");
40+
cmd += test_file;
6241

63-
GIVEN("The result of a char pointer")
64-
{
65-
const std::string line = "$5 = 0x400734 \"snow\"";
66-
THEN("the result matches the memory address in the output")
67-
{
68-
REQUIRE(gdb_api.extract_memory(line) == "0x400734");
69-
}
70-
THEN("adding '(gdb) ' to the line doesn't have an influence")
71-
{
72-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x400734");
73-
}
74-
}
42+
const int r = system(cmd.c_str());
43+
REQUIRE(!r);
44+
}
7545

76-
GIVEN("The result of a null pointer")
46+
class gdb_api_testt : public gdb_apit
47+
{
48+
explicit gdb_api_testt(const char *binary) : gdb_apit(binary)
7749
{
78-
const std::string line = "$2 = 0x0";
79-
THEN("the result matches the memory address in the output")
80-
{
81-
REQUIRE(gdb_api.extract_memory(line) == "0x0");
82-
}
83-
THEN("adding '(gdb) ' to the line doesn't have an influence")
84-
{
85-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x0");
86-
}
8750
}
8851

89-
GIVEN("The result of a char pointer at very low address")
90-
{
91-
const std::string line = "$34 = 0x007456 \"snow\"";
92-
THEN("the result matches the memory address and not nullpointer")
93-
{
94-
REQUIRE(gdb_api.extract_memory(line) == "0x007456");
95-
}
96-
THEN("adding '(gdb) ' to the line doesn't have an influence")
97-
{
98-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x007456");
99-
}
100-
}
52+
friend void gdb_api_internals_test();
53+
};
10154

102-
GIVEN("The result of a char pointer with some more whitespaces")
103-
{
104-
const std::string line = "$12 = 0x400752 \"thunder storm\"\n";
105-
THEN("the result matches the memory address in the output")
106-
{
107-
REQUIRE(gdb_api.extract_memory(line) == "0x400752");
108-
}
109-
THEN("adding '(gdb) ' to the line doesn't have an influence")
110-
{
111-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x400752");
112-
}
113-
}
55+
void gdb_api_internals_test()
56+
{
57+
compile_test_file();
11458

115-
GIVEN("The result of an array pointer")
59+
SECTION("parse gdb output record")
11660
{
117-
const std::string line = "$5 = (struct a_sub_type_t (*)[4]) 0x602080";
118-
THEN("the result matches the memory address in the output")
119-
{
120-
REQUIRE(gdb_api.extract_memory(line) == "0x602080");
121-
}
122-
THEN("adding '(gdb) ' to the line doesn't have an influence")
123-
{
124-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x602080");
125-
}
126-
}
61+
gdb_api_testt gdb_api("test");
12762

128-
GIVEN("A constant struct pointer pointing to 0x0")
129-
{
130-
const std::string line = "$3 = (const struct name *) 0x0";
131-
THEN("the returned memory address should be 0x0")
132-
{
133-
REQUIRE(gdb_api.extract_memory(line) == "0x0");
134-
}
135-
}
63+
gdb_api_testt::gdb_output_recordt gor;
13664

137-
GIVEN("An enum address")
138-
{
139-
const std::string line = "$2 = (char *(*)[5]) 0x7e5500 <abc>";
140-
THEN("the returned address is the address of the enum")
141-
{
142-
REQUIRE(gdb_api.extract_memory(line) == "0x7e5500");
143-
}
65+
gor = gdb_api.parse_gdb_output_record(
66+
"a = \"1\", b = \"2\", c = {1, 2}, d = [3, 4], e=\"0x0\"");
67+
68+
REQUIRE(gor["a"] == "1");
69+
REQUIRE(gor["b"] == "2");
70+
REQUIRE(gor["c"] == "{1, 2}");
71+
REQUIRE(gor["d"] == "[3, 4]");
72+
REQUIRE(gor["e"] == "0x0");
14473
}
14574

146-
GIVEN("The result of an int pointer")
75+
SECTION("read a line from an input stream")
14776
{
148-
const std::string line = "$1 = (int *) 0x601088 <e>\n";
149-
THEN("the result is the value of memory address of the int pointer")
150-
{
151-
REQUIRE(gdb_api.extract_memory(line) == "0x601088");
152-
}
153-
THEN("adding '(gdb) ' to the line doesn't have an influence")
154-
{
155-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x601088");
156-
}
77+
gdb_api_testt gdb_api("test");
78+
79+
FILE *f = fopen("memory-analyzer/input.txt", "r");
80+
gdb_api.input_stream = f;
81+
82+
std::string line;
83+
84+
line = gdb_api.read_next_line();
85+
REQUIRE(line == "abc\n");
86+
87+
line = gdb_api.read_next_line();
88+
REQUIRE(line == std::string(1120, 'a') + "\n");
89+
90+
line = gdb_api.read_next_line();
91+
REQUIRE(line == "xyz");
15792
}
15893

159-
GIVEN("Non matching result")
94+
SECTION("start and exit gdb")
16095
{
161-
const std::string line = "Something that must not match 0x605940";
162-
THEN("an exception is thrown")
163-
{
164-
REQUIRE_THROWS_AS(
165-
gdb_api.extract_memory(line), gdb_interaction_exceptiont);
166-
}
96+
gdb_api_testt gdb_api("test");
97+
98+
gdb_api.create_gdb_process();
99+
100+
// check input and output streams
101+
REQUIRE(!ferror(gdb_api.input_stream));
102+
REQUIRE(!ferror(gdb_api.output_stream));
103+
104+
gdb_api.terminate_gdb_process();
167105
}
168106
}
169107

170-
SCENARIO(
171-
"gdb_apit uses regex as expected for value extraction",
172-
"[core][memory-analyzer]")
108+
#endif
109+
110+
TEST_CASE("gdb api internals test", "[core][memory-analyzer]")
173111
{
174-
gdb_apit gdb_api("");
175-
GIVEN("An integer value")
176-
{
177-
const std::string line = "$90 = 100";
178-
THEN("the result schould be '100'")
179-
{
180-
REQUIRE(gdb_api.extract_value(line) == "100");
181-
}
182-
}
112+
#ifdef RUN_GDB_API_TESTS
113+
gdb_api_internals_test();
114+
#endif
115+
}
183116

184-
GIVEN("A string value")
185-
{
186-
const std::string line = "$5 = 0x602010 \"snow\"";
187-
THEN("the result should be 'snow'")
188-
{
189-
REQUIRE(gdb_api.extract_value(line) == "snow");
190-
}
191-
}
117+
TEST_CASE("gdb api test", "[core][memory-analyzer]")
118+
{
119+
#ifdef RUN_GDB_API_TESTS
120+
compile_test_file();
192121

193-
GIVEN("A string with withe spaces")
194122
{
195-
const std::string line = "$1323 = 0x1243253 \"thunder storm\"\n";
196-
THEN("the result should be 'thunder storm'")
123+
gdb_apit gdb_api("test", true);
124+
gdb_api.create_gdb_process();
125+
126+
try
197127
{
198-
REQUIRE(gdb_api.extract_value(line) == "thunder storm");
199-
}
200-
}
128+
const bool r = gdb_api.run_gdb_to_breakpoint("checkpoint");
129+
REQUIRE(r);
201130

202-
GIVEN("A byte value")
203-
{
204-
const std::string line = "$2 = 243 '\363'";
205-
THEN("the result should be 243")
131+
gdb_api.terminate_gdb_process();
132+
}
133+
catch(const gdb_interaction_exceptiont &e)
206134
{
207-
REQUIRE(gdb_api.extract_value(line) == "243");
135+
std::cerr << "warning: cannot fully unit test GDB API as program cannot "
136+
<< "be run with gdb\n";
137+
std::cerr << "warning: this may be due to not having the required "
138+
<< "permissions (e.g., to invoke ptrace() or to disable ASLR)"
139+
<< "\n";
140+
std::cerr << "gdb_interaction_exceptiont:" << '\n';
141+
std::cerr << e.what() << '\n';
142+
143+
std::ifstream file("gdb.txt");
144+
CHECK_RETURN(file.is_open());
145+
std::string line;
146+
147+
std::cerr << "=== gdb log begin ===\n";
148+
149+
while(getline(file, line))
150+
{
151+
std::cerr << line << '\n';
152+
}
153+
154+
file.close();
155+
156+
std::cerr << "=== gdb log end ===\n";
157+
158+
gdb_api.terminate_gdb_process();
159+
160+
return;
208161
}
209162
}
210163

211-
GIVEN("A negative int value")
164+
gdb_apit gdb_api("test");
165+
gdb_api.create_gdb_process();
166+
167+
SECTION("breakpoint is hit")
212168
{
213-
const std::string line = "$8 = -32";
214-
THEN("the result should be -32")
215-
{
216-
REQUIRE(gdb_api.extract_value(line) == "-32");
217-
}
169+
const bool r = gdb_api.run_gdb_to_breakpoint("checkpoint");
170+
REQUIRE(r);
218171
}
219172

220-
GIVEN("An enum value")
173+
SECTION("breakpoint is not hit")
221174
{
222-
const std::string line = "$1 = INFO";
223-
THEN("the result should be INFO")
224-
{
225-
REQUIRE(gdb_api.extract_value(line) == "INFO");
226-
}
175+
const bool r = gdb_api.run_gdb_to_breakpoint("checkpoint2");
176+
REQUIRE(!r);
227177
}
228178

229-
GIVEN("A void pointer value")
179+
SECTION("breakpoint does not exist")
230180
{
231-
const std::string line = "$6 = (const void *) 0x71";
232-
THEN("the requried result should be 0x71")
233-
{
234-
REQUIRE(gdb_api.extract_value(line) == "0x71");
235-
}
181+
REQUIRE_THROWS_AS(
182+
gdb_api.run_gdb_to_breakpoint("checkpoint3"), gdb_interaction_exceptiont);
236183
}
237184

238-
GIVEN("A gdb response that contains 'cannot access memory'")
185+
SECTION("query memory")
239186
{
240-
const std::string line = "Cannot access memory at address 0x71";
241-
THEN("a gdb_inaccesible_memoryt excepition must be raised")
187+
const bool r = gdb_api.run_gdb_to_breakpoint("checkpoint");
188+
REQUIRE(r);
189+
190+
REQUIRE(gdb_api.get_value("x") == "8");
191+
REQUIRE(gdb_api.get_value("s") == "abc");
192+
193+
const std::regex regex(R"(0x[1-9a-f][0-9a-f]*)");
194+
242195
{
243-
REQUIRE_THROWS_AS(
244-
gdb_api.extract_value(line), gdb_inaccessible_memory_exceptiont);
196+
std::string address = gdb_api.get_memory("p");
197+
REQUIRE(std::regex_match(address, regex));
245198
}
246-
}
247199

248-
GIVEN("A value that must not match")
249-
{
250-
const std::string line = "$90 = must not match 20";
251-
THEN("an exception is raised")
252200
{
253-
REQUIRE_THROWS_AS(
254-
gdb_api.extract_value(line), gdb_interaction_exceptiont);
201+
std::string address = gdb_api.get_memory("vp");
202+
REQUIRE(std::regex_match(address, regex));
255203
}
256204
}
257-
}
205+
206+
gdb_api.terminate_gdb_process();
258207
#endif
208+
}

unit/memory-analyzer/input.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
abc
2+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
3+
xyz

0 commit comments

Comments
 (0)