Skip to content

Commit 55fbebb

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 18aee0c commit 55fbebb

File tree

4 files changed

+125
-187
lines changed

4 files changed

+125
-187
lines changed

src/memory-analyzer/gdb_api.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class gdb_apit
2222
std::string get_value(const std::string &variable);
2323
std::string get_memory(const std::string &variable);
2424

25-
private:
25+
protected:
2626
const char *binary_name;
2727
FILE *input_stream;
2828
FILE *output_stream;

unit/memory-analyzer/gdb_api.cpp

Lines changed: 94 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -2,235 +2,143 @@
22
#include <testing-utils/use_catch.h>
33

44
#ifdef __linux__
5-
// \file Test that the regex expression used work as expected.
6-
#define private public
7-
#include <memory-analyzer/gdb_api.cpp>
5+
6+
#include <cstdio>
7+
#include <cstdlib>
8+
#include <regex>
89
#include <string>
910

10-
SCENARIO(
11-
"gdb_apit uses regex as expected for memory",
12-
"[core][memory-analyzer]")
11+
#include <fstream>
12+
#include <iostream>
13+
14+
#include <memory-analyzer/gdb_api.cpp>
15+
16+
void compile_test_file()
1317
{
14-
gdb_apit gdb_api("");
15-
GIVEN("The result of a struct pointer")
16-
{
17-
const std::string line = "$2 = (struct cycle_buffer *) 0x601050 <buffer>";
18-
THEN("the result matches the memory address in the output")
19-
{
20-
REQUIRE(gdb_api.extract_memory(line) == "0x601050");
21-
}
22-
THEN("adding '(gdb) ' to the line doesn't have an influence")
23-
{
24-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x601050");
25-
}
26-
}
18+
std::string test_file("memory-analyzer/test.c");
2719

28-
GIVEN("The result of a typedef pointer")
29-
{
30-
const std::string line = "$4 = (cycle_buffer_entry_t *) 0x602010";
31-
THEN("the result matches the memory address in the output")
32-
{
33-
REQUIRE(gdb_api.extract_memory(line) == "0x602010");
34-
}
35-
THEN("adding '(gdb) ' to the line doesn't have an influence")
36-
{
37-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x602010");
38-
}
39-
}
20+
std::string cmd("gcc -g -o test ");
21+
cmd += test_file;
4022

41-
GIVEN("The result of a char pointer")
42-
{
43-
const std::string line = "$5 = 0x400734 \"snow\"";
44-
THEN("the result matches the memory address in the output")
45-
{
46-
REQUIRE(gdb_api.extract_memory(line) == "0x400734");
47-
}
48-
THEN("adding '(gdb) ' to the line doesn't have an influence")
49-
{
50-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x400734");
51-
}
52-
}
23+
const int r = system(cmd.c_str());
24+
REQUIRE(!r);
25+
}
5326

54-
GIVEN("The result of a null pointer")
27+
class gdb_api_testt : public gdb_apit
28+
{
29+
gdb_api_testt(const char *binary) : gdb_apit(binary)
5530
{
56-
const std::string line = "$2 = 0x0";
57-
THEN("the result matches the memory address in the output")
58-
{
59-
REQUIRE(gdb_api.extract_memory(line) == "0x0");
60-
}
61-
THEN("adding '(gdb) ' to the line doesn't have an influence")
62-
{
63-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x0");
64-
}
6531
}
6632

67-
GIVEN("The result of a char pointer at very low address")
68-
{
69-
const std::string line = "$34 = 0x007456 \"snow\"";
70-
THEN("the result matches the memory address and not nullpointer")
71-
{
72-
REQUIRE(gdb_api.extract_memory(line) == "0x007456");
73-
}
74-
THEN("adding '(gdb) ' to the line doesn't have an influence")
75-
{
76-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x007456");
77-
}
78-
}
33+
friend void gdb_api_internals_test();
34+
};
7935

80-
GIVEN("The result of a char pointer with some more whitespaces")
81-
{
82-
const std::string line = "$12 = 0x400752 \"thunder storm\"\n";
83-
THEN("the result matches the memory address in the output")
84-
{
85-
REQUIRE(gdb_api.extract_memory(line) == "0x400752");
86-
}
87-
THEN("adding '(gdb) ' to the line doesn't have an influence")
88-
{
89-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x400752");
90-
}
91-
}
36+
void gdb_api_internals_test()
37+
{
38+
compile_test_file();
9239

93-
GIVEN("The result of an array pointer")
40+
SECTION("parse gdb output record")
9441
{
95-
const std::string line = "$5 = (struct a_sub_type_t (*)[4]) 0x602080";
96-
THEN("the result matches the memory address in the output")
97-
{
98-
REQUIRE(gdb_api.extract_memory(line) == "0x602080");
99-
}
100-
THEN("adding '(gdb) ' to the line doesn't have an influence")
101-
{
102-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x602080");
103-
}
104-
}
42+
gdb_api_testt gdb_api("test");
10543

106-
GIVEN("A constant struct pointer pointing to 0x0")
107-
{
108-
const std::string line = "$3 = (const struct name *) 0x0";
109-
THEN("the returned memory address should be 0x0")
110-
{
111-
REQUIRE(gdb_api.extract_memory(line) == "0x0");
112-
}
113-
}
44+
gdb_api_testt::gdb_output_recordt gor;
11445

115-
GIVEN("An enum address")
116-
{
117-
const std::string line = "$2 = (char *(*)[5]) 0x7e5500 <abc>";
118-
THEN("the returned address is the address of the enum")
119-
{
120-
REQUIRE(gdb_api.extract_memory(line) == "0x7e5500");
121-
}
46+
gor = gdb_api.parse_gdb_output_record(
47+
"a = \"1\", b = \"2\", c = {1, 2}, d = [3, 4], e=\"0x0\"");
48+
49+
REQUIRE(gor["a"] == "1");
50+
REQUIRE(gor["b"] == "2");
51+
REQUIRE(gor["c"] == "{1, 2}");
52+
REQUIRE(gor["d"] == "[3, 4]");
53+
REQUIRE(gor["e"] == "0x0");
12254
}
12355

124-
GIVEN("The result of an int pointer")
56+
SECTION("read a line from an input stream")
12557
{
126-
const std::string line = "$1 = (int *) 0x601088 <e>\n";
127-
THEN("the result is the value of memory address of the int pointer")
128-
{
129-
REQUIRE(gdb_api.extract_memory(line) == "0x601088");
130-
}
131-
THEN("adding '(gdb) ' to the line doesn't have an influence")
132-
{
133-
REQUIRE(gdb_api.extract_memory("(gdb) " + line) == "0x601088");
134-
}
58+
gdb_api_testt gdb_api("test");
59+
60+
FILE *f = fopen("memory-analyzer/input.txt", "r");
61+
gdb_api.input_stream = f;
62+
63+
std::string line;
64+
65+
line = gdb_api.read_next_line();
66+
REQUIRE(line == "abc\n");
67+
68+
line = gdb_api.read_next_line();
69+
REQUIRE(line == std::string(1120, 'a') + "\n");
70+
71+
line = gdb_api.read_next_line();
72+
REQUIRE(line == "xyz");
13573
}
13674

137-
GIVEN("Non matching result")
75+
SECTION("start and exit gdb")
13876
{
139-
const std::string line = "Something that must not match 0x605940";
140-
THEN("an exception is thrown")
141-
{
142-
REQUIRE_THROWS_AS(
143-
gdb_api.extract_memory(line), gdb_interaction_exceptiont);
144-
}
77+
gdb_api_testt gdb_api("test");
78+
79+
gdb_api.create_gdb_process();
80+
81+
// check input and output streams
82+
REQUIRE(!ferror(gdb_api.input_stream));
83+
REQUIRE(!ferror(gdb_api.output_stream));
84+
85+
gdb_api.terminate_gdb_process();
14586
}
14687
}
14788

148-
SCENARIO(
149-
"gdb_apit uses regex as expected for value extraction",
150-
"[core][memory-analyzer]")
89+
TEST_CASE("gdb api internals test")
15190
{
152-
gdb_apit gdb_api("");
153-
GIVEN("An integer value")
154-
{
155-
const std::string line = "$90 = 100";
156-
THEN("the result schould be '100'")
157-
{
158-
REQUIRE(gdb_api.extract_value(line) == "100");
159-
}
160-
}
91+
gdb_api_internals_test();
92+
}
16193

162-
GIVEN("A string value")
163-
{
164-
const std::string line = "$5 = 0x602010 \"snow\"";
165-
THEN("the result should be 'snow'")
166-
{
167-
REQUIRE(gdb_api.extract_value(line) == "snow");
168-
}
169-
}
94+
TEST_CASE("gdb api test")
95+
{
96+
compile_test_file();
17097

171-
GIVEN("A string with withe spaces")
172-
{
173-
const std::string line = "$1323 = 0x1243253 \"thunder storm\"\n";
174-
THEN("the result should be 'thunder storm'")
175-
{
176-
REQUIRE(gdb_api.extract_value(line) == "thunder storm");
177-
}
178-
}
98+
gdb_apit gdb_api("test");
17999

180-
GIVEN("A byte value")
181-
{
182-
const std::string line = "$2 = 243 '\363'";
183-
THEN("the result should be 243")
184-
{
185-
REQUIRE(gdb_api.extract_value(line) == "243");
186-
}
187-
}
100+
gdb_api.create_gdb_process();
188101

189-
GIVEN("A negative int value")
102+
SECTION("breakpoint is hit")
190103
{
191-
const std::string line = "$8 = -32";
192-
THEN("the result should be -32")
193-
{
194-
REQUIRE(gdb_api.extract_value(line) == "-32");
195-
}
104+
const bool r = gdb_api.run_gdb_to_breakpoint("checkpoint");
105+
REQUIRE(r);
196106
}
197107

198-
GIVEN("An enum value")
108+
SECTION("breakpoint is not hit")
199109
{
200-
const std::string line = "$1 = INFO";
201-
THEN("the result should be INFO")
202-
{
203-
REQUIRE(gdb_api.extract_value(line) == "INFO");
204-
}
110+
const bool r = gdb_api.run_gdb_to_breakpoint("checkpoint2");
111+
REQUIRE(!r);
205112
}
206113

207-
GIVEN("A void pointer value")
114+
SECTION("breakpoint does not exist")
208115
{
209-
const std::string line = "$6 = (const void *) 0x71";
210-
THEN("the requried result should be 0x71")
211-
{
212-
REQUIRE(gdb_api.extract_value(line) == "0x71");
213-
}
116+
REQUIRE_THROWS_AS(
117+
gdb_api.run_gdb_to_breakpoint("checkpoint3"), gdb_interaction_exceptiont);
214118
}
215119

216-
GIVEN("A gdb response that contains 'cannot access memory'")
120+
SECTION("query memory")
217121
{
218-
const std::string line = "Cannot access memory at address 0x71";
219-
THEN("a gdb_inaccesible_memoryt excepition must be raised")
122+
const bool r = gdb_api.run_gdb_to_breakpoint("checkpoint");
123+
REQUIRE(r);
124+
125+
REQUIRE(gdb_api.get_value("x") == "8");
126+
REQUIRE(gdb_api.get_value("s") == "abc");
127+
128+
const std::regex regex(R"(0x[1-9a-f][0-9a-f]*)");
129+
220130
{
221-
REQUIRE_THROWS_AS(
222-
gdb_api.extract_value(line), gdb_inaccessible_memory_exceptiont);
131+
std::string address = gdb_api.get_memory("p");
132+
REQUIRE(std::regex_match(address, regex));
223133
}
224-
}
225134

226-
GIVEN("A value that must not match")
227-
{
228-
const std::string line = "$90 = must not match 20";
229-
THEN("an exception is raised")
230135
{
231-
REQUIRE_THROWS_AS(
232-
gdb_api.extract_value(line), gdb_interaction_exceptiont);
136+
std::string address = gdb_api.get_memory("vp");
137+
REQUIRE(std::regex_match(address, regex));
233138
}
234139
}
140+
141+
gdb_api.terminate_gdb_process();
235142
}
143+
236144
#endif

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

unit/memory-analyzer/test.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
int x;
2+
char *s = "abc";
3+
int *p;
4+
void *vp;
5+
6+
void checkpoint()
7+
{
8+
}
9+
void checkpoint2()
10+
{
11+
}
12+
13+
void func()
14+
{
15+
checkpoint2();
16+
}
17+
18+
int main()
19+
{
20+
x = 8;
21+
p = &x;
22+
vp = (void *)&x;
23+
24+
checkpoint();
25+
26+
return 0;
27+
}

0 commit comments

Comments
 (0)