Commit | Line | Data |
---|---|---|
394fd13b AB |
1 | /* |
2 | * test_so_info.c | |
3 | * | |
4 | * Babeltrace SO info tests | |
5 | * | |
6 | * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation | |
7 | * Copyright (c) 2015 Antoine Busque <abusque@efficios.com> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; under version 2 of the License. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License along | |
19 | * with this program; if not, write to the Free Software Foundation, Inc., | |
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
22 | ||
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <babeltrace/so-info.h> | |
27 | #include "tap/tap.h" | |
28 | ||
29 | #define NR_TESTS 36 | |
30 | #define SO_NAME "libhello.so" | |
31 | #define SO_NAME_ELF "libhello_elf.so" | |
32 | #define SO_NAME_BUILD_ID "libhello_build_id.so" | |
33 | #define SO_NAME_DEBUG_LINK "libhello_debug_link.so" | |
34 | #define SO_LOW_ADDR 0x400000 | |
35 | #define SO_MEMSZ 0x400000 | |
36 | #define FUNC_FOO_ADDR 0x4014ee | |
37 | #define FUNC_FOO_LINE_NO 8 | |
38 | #define FUNC_FOO_FILENAME "/efficios/libhello.c" | |
39 | #define FUNC_FOO_TP_ADDR 0x4014d3 | |
40 | #define FUNC_FOO_TP_LINE_NO 7 | |
41 | #define FUNC_FOO_TP_FILENAME "/efficios/libhello.c" | |
42 | #define FUNC_FOO_ADDR_ELF 0x4013ef | |
43 | #define FUNC_FOO_ADDR_DBG_LINK 0x40148e | |
44 | #define FUNC_FOO_NAME "foo" | |
45 | #define FUNC_FOO_NAME_ELF "foo+0x24" | |
46 | #define BUILD_ID_LEN 20 | |
47 | ||
3be1e3c9 | 48 | char *opt_debug_info_dir; |
394fd13b AB |
49 | |
50 | static | |
51 | void test_so_info_build_id(const char *data_dir) | |
52 | { | |
53 | int ret; | |
54 | char path[PATH_MAX]; | |
55 | char *func_name = NULL; | |
56 | struct so_info *so = NULL; | |
57 | struct source_location *src_loc = NULL; | |
58 | uint8_t build_id[BUILD_ID_LEN] = { | |
59 | 0xcd, 0xd9, 0x8c, 0xdd, 0x87, 0xf7, 0xfe, 0x64, 0xc1, 0x3b, | |
60 | 0x6d, 0xaa, 0xd5, 0x53, 0x98, 0x7e, 0xaf, 0xd4, 0x0c, 0xbb | |
61 | }; | |
62 | ||
63 | diag("so-info tests - separate DWARF via build ID"); | |
64 | ||
65 | snprintf(path, PATH_MAX, "%s/%s", data_dir, SO_NAME_BUILD_ID); | |
66 | ||
67 | so = so_info_create(path, SO_LOW_ADDR, SO_MEMSZ); | |
68 | ok(so != NULL, "so_info_create succesful"); | |
69 | ||
70 | /* Test setting build_id */ | |
71 | ret = so_info_set_build_id(so, build_id, BUILD_ID_LEN); | |
72 | ok(ret == 0, "so_info_set_build_id succesful"); | |
73 | ||
74 | /* Test function name lookup (with DWARF) */ | |
75 | ret = so_info_lookup_function_name(so, FUNC_FOO_ADDR, &func_name); | |
76 | ok(ret == 0, "so_info_lookup_function_name succesful"); | |
77 | ok(strcmp(func_name, FUNC_FOO_NAME) == 0, | |
78 | "so_info_lookup_function_name - correct func_name value"); | |
79 | free(func_name); | |
80 | ||
81 | /* Test source location lookup */ | |
82 | ret = so_info_lookup_source_location(so, FUNC_FOO_ADDR, &src_loc); | |
83 | ok(ret == 0, "so_info_lookup_source_location succesful"); | |
84 | ok(src_loc->line_no == FUNC_FOO_LINE_NO, | |
85 | "so_info_lookup_source_location - correct line_no"); | |
86 | ok(strcmp(src_loc->filename, FUNC_FOO_FILENAME) == 0, | |
87 | "so_info_lookup_source_location - correct filename"); | |
88 | source_location_destroy(src_loc); | |
89 | ||
90 | so_info_destroy(so); | |
91 | } | |
92 | ||
93 | static | |
94 | void test_so_info_debug_link(const char *data_dir) | |
95 | { | |
96 | int ret; | |
97 | char path[PATH_MAX]; | |
98 | char *func_name = NULL; | |
99 | struct so_info *so = NULL; | |
100 | struct source_location *src_loc = NULL; | |
101 | char *dbg_filename = "libhello_debug_link.so.debug"; | |
102 | uint32_t crc = 0xe55c2b98; | |
103 | ||
104 | diag("so-info tests - separate DWARF via debug link"); | |
105 | ||
106 | snprintf(path, PATH_MAX, "%s/%s", data_dir, SO_NAME_DEBUG_LINK); | |
107 | ||
108 | so = so_info_create(path, SO_LOW_ADDR, SO_MEMSZ); | |
109 | ok(so != NULL, "so_info_create succesful"); | |
110 | ||
111 | /* Test setting debug link */ | |
112 | ret = so_info_set_debug_link(so, dbg_filename, crc); | |
113 | ok(ret == 0, "so_info_set_debug_link succesful"); | |
114 | ||
115 | /* Test function name lookup (with DWARF) */ | |
116 | ret = so_info_lookup_function_name(so, FUNC_FOO_ADDR_DBG_LINK, | |
117 | &func_name); | |
118 | ok(ret == 0, "so_info_lookup_function_name succesful"); | |
119 | ok(strcmp(func_name, FUNC_FOO_NAME) == 0, | |
120 | "so_info_lookup_function_name - correct func_name value"); | |
121 | free(func_name); | |
122 | ||
123 | /* Test source location lookup */ | |
124 | ret = so_info_lookup_source_location(so, FUNC_FOO_ADDR_DBG_LINK, | |
125 | &src_loc); | |
126 | ok(ret == 0, "so_info_lookup_source_location succesful"); | |
127 | ok(src_loc->line_no == FUNC_FOO_LINE_NO, | |
128 | "so_info_lookup_source_location - correct line_no"); | |
129 | ok(strcmp(src_loc->filename, FUNC_FOO_FILENAME) == 0, | |
130 | "so_info_lookup_source_location - correct filename"); | |
131 | source_location_destroy(src_loc); | |
132 | ||
133 | so_info_destroy(so); | |
134 | } | |
135 | ||
136 | static | |
137 | void test_so_info_elf(const char *data_dir) | |
138 | { | |
139 | int ret; | |
140 | char path[PATH_MAX]; | |
141 | char *func_name = NULL; | |
142 | struct so_info *so = NULL; | |
143 | struct source_location *src_loc = NULL; | |
144 | ||
145 | diag("so-info tests - ELF only"); | |
146 | ||
147 | snprintf(path, PATH_MAX, "%s/%s", data_dir, SO_NAME_ELF); | |
148 | ||
149 | so = so_info_create(path, SO_LOW_ADDR, SO_MEMSZ); | |
150 | ok(so != NULL, "so_info_create succesful"); | |
151 | ||
152 | /* Test function name lookup (with ELF) */ | |
153 | ret = so_info_lookup_function_name(so, FUNC_FOO_ADDR_ELF, &func_name); | |
154 | ok(ret == 0, "so_info_lookup_function_name succesful"); | |
155 | ok(strcmp(func_name, FUNC_FOO_NAME_ELF) == 0, | |
156 | "so_info_lookup_function_name - correct func_name value"); | |
157 | free(func_name); | |
158 | func_name = NULL; | |
159 | ||
160 | /* Test function name lookup - erroneous address */ | |
161 | ret = so_info_lookup_function_name(so, 0, &func_name); | |
162 | ok(ret == -1 && func_name == NULL, | |
163 | "so_info_lookup_function_name - fail on addr not found"); | |
164 | ||
165 | /* Test source location location - should fail on ELF only file */ | |
166 | ret = so_info_lookup_source_location(so, FUNC_FOO_ADDR_ELF, &src_loc); | |
167 | ok(ret == -1, "so_info_lookup_source_location - fail on ELF only file"); | |
168 | ||
169 | source_location_destroy(src_loc); | |
170 | so_info_destroy(so); | |
171 | } | |
172 | ||
173 | static | |
174 | void test_so_info(const char *data_dir) | |
175 | { | |
176 | int ret; | |
177 | char path[PATH_MAX]; | |
178 | char *func_name = NULL; | |
179 | struct so_info *so = NULL; | |
180 | struct source_location *src_loc = NULL; | |
181 | ||
182 | diag("so-info tests - DWARF bundled with SO file"); | |
183 | ||
184 | snprintf(path, PATH_MAX, "%s/%s", data_dir, SO_NAME); | |
185 | ||
186 | so = so_info_create(path, SO_LOW_ADDR, SO_MEMSZ); | |
187 | ok(so != NULL, "so_info_create succesful"); | |
188 | ||
189 | /* Test so_info_has_address */ | |
190 | ret = so_info_has_address(so, 0); | |
191 | ok(ret == 0, "so_info_has_address - address under so's range"); | |
192 | ret = so_info_has_address(so, SO_LOW_ADDR); | |
193 | ok(ret == 1, "so_info_has_address - lower bound of so's range"); | |
194 | ret = so_info_has_address(so, FUNC_FOO_ADDR); | |
195 | ok(ret == 1, "so_info_has_address - address in so's range"); | |
196 | ret = so_info_has_address(so, SO_LOW_ADDR + SO_MEMSZ - 1); | |
197 | ok(ret == 1, "so_info_has_address - upper bound of so's range"); | |
198 | ret = so_info_has_address(so, SO_LOW_ADDR + SO_MEMSZ); | |
199 | ok(ret == 0, "so_info_has_address - address above so's range"); | |
200 | ||
201 | /* Test function name lookup (with DWARF) */ | |
202 | ret = so_info_lookup_function_name(so, FUNC_FOO_ADDR, &func_name); | |
203 | ok(ret == 0, "so_info_lookup_function_name succesful"); | |
204 | ok(strcmp(func_name, FUNC_FOO_NAME) == 0, | |
205 | "so_info_lookup_function_name - correct func_name value"); | |
206 | free(func_name); | |
207 | func_name = NULL; | |
208 | ||
209 | /* Test function name lookup - erroneous address */ | |
210 | ret = so_info_lookup_function_name(so, 0, &func_name); | |
211 | ok(ret == -1 && func_name == NULL, | |
212 | "so_info_lookup_function_name - fail on addr not found"); | |
213 | ||
214 | /* Test source location lookup */ | |
215 | ret = so_info_lookup_source_location(so, FUNC_FOO_ADDR, &src_loc); | |
216 | ok(ret == 0, "so_info_lookup_source_location succesful"); | |
217 | ok(src_loc->line_no == FUNC_FOO_LINE_NO, | |
218 | "so_info_lookup_source_location - correct line_no"); | |
219 | ok(strcmp(src_loc->filename, FUNC_FOO_FILENAME) == 0, | |
220 | "so_info_lookup_source_location - correct filename"); | |
221 | source_location_destroy(src_loc); | |
222 | src_loc = NULL; | |
223 | ||
224 | /* Test source location lookup - inlined function */ | |
225 | ret = so_info_lookup_source_location(so, FUNC_FOO_TP_ADDR, &src_loc); | |
226 | ok(ret == 0, | |
227 | "so_info_lookup_source_location (inlined func) succesful"); | |
228 | ok(src_loc->line_no == FUNC_FOO_TP_LINE_NO, | |
229 | "so_info_lookup_source_location (inlined func) - correct line_no"); | |
230 | ok(strcmp(src_loc->filename, FUNC_FOO_TP_FILENAME) == 0, | |
231 | "so_info_lookup_source_location (inlined func) - correct filename"); | |
232 | source_location_destroy(src_loc); | |
233 | src_loc = NULL; | |
234 | ||
235 | /* Test source location lookup - erroneous address */ | |
236 | ret = so_info_lookup_source_location(so, 0, &src_loc); | |
237 | ok(ret == -1 && src_loc == NULL, | |
238 | "so_info_lookup_source_location - fail on addr not found"); | |
239 | ||
240 | so_info_destroy(so); | |
241 | } | |
242 | ||
243 | int main(int argc, char **argv) | |
244 | { | |
245 | int ret; | |
246 | ||
247 | plan_tests(NR_TESTS); | |
248 | ||
249 | if (argc != 2) { | |
250 | return EXIT_FAILURE; | |
251 | } else { | |
3be1e3c9 | 252 | opt_debug_info_dir = argv[1]; |
394fd13b AB |
253 | } |
254 | ||
255 | ret = so_info_init(); | |
256 | ok(ret == 0, "so_info_init succesful"); | |
257 | ||
3be1e3c9 JG |
258 | test_so_info(opt_debug_info_dir); |
259 | test_so_info_elf(opt_debug_info_dir); | |
260 | test_so_info_build_id(opt_debug_info_dir); | |
261 | test_so_info_debug_link(opt_debug_info_dir); | |
394fd13b AB |
262 | |
263 | return EXIT_SUCCESS; | |
264 | } |