Logging: pass dynamic log level to common functions and subsystems
[babeltrace.git] / tests / plugins / flt.lttng-utils.debug-info / test_bin_info.c
1 /*
2 * test_bin_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 * Copyright (c) 2019 Michael Jeanson <mjeanson@efficios.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; under version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 #define BT_LOG_OUTPUT_LEVEL BT_LOG_WARN
25 #define BT_LOG_TAG "TEST/BIN-INFO"
26 #include "logging/log.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <inttypes.h>
32 #include <glib.h>
33
34 #include "common/macros.h"
35 #include "common/assert.h"
36 #include <lttng-utils/debug-info/bin-info.h>
37
38 #include "tap/tap.h"
39
40 #define NR_TESTS 57
41
42 #define SO_NAME "libhello_so"
43 #define DEBUG_NAME "libhello_so.debug"
44 #define FUNC_FOO_FILENAME "./libhello.c"
45 #define FUNC_FOO_PRINTF_NAME_FMT "foo+0x%" PRIx64
46 #define FUNC_FOO_NAME_LEN 64
47
48 #define DWARF_DIR_NAME "dwarf_full"
49 #define ELF_DIR_NAME "elf_only"
50 #define BUILDID_DIR_NAME "build_id"
51 #define DEBUGLINK_DIR_NAME "debug_link"
52
53 /* Lower bound of PIC address mapping */
54 #define SO_LOW_ADDR 0x400000
55 /* Size of PIC address mapping */
56 #define SO_MEMSZ 0x800000
57 /* An address outside the PIC mapping */
58 #define SO_INV_ADDR 0x200000
59
60 #define BUILD_ID_HEX_LEN 20
61
62 static uint64_t opt_func_foo_addr;
63 static uint64_t opt_func_foo_printf_offset;
64 static uint64_t opt_func_foo_printf_line_no;
65 static uint64_t opt_func_foo_tp_offset;
66 static uint64_t opt_func_foo_tp_line_no;
67 static uint64_t opt_debug_link_crc;
68 static gchar *opt_build_id;
69 static gchar *opt_debug_info_dir;
70
71 static uint64_t func_foo_printf_addr;
72 static uint64_t func_foo_tp_addr;
73 static char func_foo_printf_name[FUNC_FOO_NAME_LEN];
74 static uint8_t build_id[BUILD_ID_HEX_LEN];
75
76 static GOptionEntry entries[] = {
77 {"foo-addr", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_addr,
78 "Offset to printf in foo", "0xX"},
79 {"printf-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_printf_offset,
80 "Offset to printf in foo", "0xX"},
81 {"printf-lineno", 0, 0, G_OPTION_ARG_INT64,
82 &opt_func_foo_printf_line_no, "Line number to printf in foo", "N"},
83 {"tp-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_offset,
84 "Offset to tp in foo", "0xX"},
85 {"tp-lineno", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_line_no,
86 "Line number to tp in foo", "N"},
87 {"debug-link-crc", 0, 0, G_OPTION_ARG_INT64, &opt_debug_link_crc,
88 "Debug link CRC", "0xX"},
89 {"build-id", 0, 0, G_OPTION_ARG_STRING, &opt_build_id, "Build ID",
90 "XXXXXXXXXXXXXXX"},
91 {"debug-info-dir", 0, 0, G_OPTION_ARG_STRING, &opt_debug_info_dir,
92 "Debug info directory", NULL},
93 {NULL}};
94
95 static
96 int build_id_to_bin(void)
97 {
98 int ret, len, i;
99
100 if (opt_build_id == NULL) {
101 goto error;
102 }
103
104 len = strnlen(opt_build_id, BUILD_ID_HEX_LEN * 2);
105 if (len != (BUILD_ID_HEX_LEN * 2)) {
106 goto error;
107 }
108
109 for (i = 0; i < (len / 2); i++) {
110 ret = sscanf(opt_build_id + 2 * i, "%02hhx", &build_id[i]);
111 if (ret != 1) {
112 goto error;
113 }
114 }
115
116 if (i != BUILD_ID_HEX_LEN) {
117 goto error;
118 }
119
120 return 0;
121 error:
122 return -1;
123 }
124
125 static
126 void subtest_has_address(struct bin_info *bin, uint64_t addr)
127 {
128 int ret;
129
130 ret = bin_info_has_address(bin, SO_LOW_ADDR - 1);
131 ok(ret == 0, "bin_info_has_address - address under SO's range");
132
133 ret = bin_info_has_address(bin, SO_LOW_ADDR);
134 ok(ret == 1, "bin_info_has_address - lower bound of SO's range");
135
136 ret = bin_info_has_address(bin, addr);
137 ok(ret == 1, "bin_info_has_address - address in SO's range");
138
139 ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ - 1);
140 ok(ret == 1, "bin_info_has_address - upper bound of SO's range");
141
142 ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ);
143 ok(ret == 0, "bin_info_has_address - address above SO's range");
144 }
145
146 static
147 void subtest_lookup_function_name(struct bin_info *bin, uint64_t addr,
148 char *func_name)
149 {
150 int ret;
151 char *_func_name = NULL;
152
153 ret = bin_info_lookup_function_name(bin, addr, &_func_name);
154 ok(ret == 0, "bin_info_lookup_function_name successful at 0x%x", addr);
155 if (_func_name) {
156 ok(strcmp(_func_name, func_name) == 0,
157 "bin_info_lookup_function_name - correct function name (%s == %s)",
158 func_name, _func_name);
159 free(_func_name);
160 _func_name = NULL;
161 } else {
162 skip(1,
163 "bin_info_lookup_function_name - function name is NULL");
164 }
165
166 /* Test function name lookup - erroneous address */
167 ret = bin_info_lookup_function_name(bin, SO_INV_ADDR, &_func_name);
168 ok(ret == -1 && _func_name == NULL,
169 "bin_info_lookup_function_name - fail on invalid addr");
170 if (_func_name) {
171 free(_func_name);
172 }
173 }
174
175 static
176 void subtest_lookup_source_location(struct bin_info *bin, uint64_t addr,
177 uint64_t line_no, char *filename)
178 {
179 int ret;
180 struct source_location *src_loc = NULL;
181
182 ret = bin_info_lookup_source_location(bin, addr, &src_loc);
183 ok(ret == 0, "bin_info_lookup_source_location successful at 0x%x",
184 addr);
185 if (src_loc) {
186 ok(src_loc->line_no == line_no,
187 "bin_info_lookup_source_location - correct line_no (%d == %d)",
188 line_no, src_loc->line_no);
189 ok(strcmp(src_loc->filename, filename) == 0,
190 "bin_info_lookup_source_location - correct filename (%s == %s)",
191 filename, src_loc->filename);
192 source_location_destroy(src_loc);
193 src_loc = NULL;
194 } else {
195 fail("bin_info_lookup_source_location - src_loc is NULL");
196 fail("bin_info_lookup_source_location - src_loc is NULL");
197 }
198
199 /* Test source location lookup - erroneous address */
200 ret = bin_info_lookup_source_location(bin, SO_INV_ADDR, &src_loc);
201 ok(ret == -1 && src_loc == NULL,
202 "bin_info_lookup_source_location - fail on invalid addr");
203 if (src_loc) {
204 source_location_destroy(src_loc);
205 }
206 }
207
208 static
209 void test_bin_info_build_id(const char *bin_info_dir)
210 {
211 int ret;
212 char *data_dir, *bin_path;
213 struct bin_info *bin = NULL;
214 struct bt_fd_cache fdc;
215 uint8_t invalid_build_id[BUILD_ID_HEX_LEN] = {
216 0xa3, 0xfd, 0x8b, 0xff, 0x45, 0xe1, 0xa9, 0x32, 0x15, 0xdd,
217 0x6d, 0xaa, 0xd5, 0x53, 0x98, 0x7e, 0xaf, 0xd4, 0x0c, 0xbb
218 };
219
220 diag("bin-info tests - separate DWARF via build ID");
221
222 data_dir = g_build_filename(bin_info_dir, BUILDID_DIR_NAME, NULL);
223 bin_path =
224 g_build_filename(bin_info_dir, BUILDID_DIR_NAME, SO_NAME, NULL);
225
226 if (data_dir == NULL || bin_path == NULL) {
227 exit(EXIT_FAILURE);
228 }
229
230 ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL);
231 if (ret != 0) {
232 diag("Failed to initialize FD cache");
233 exit(EXIT_FAILURE);
234 }
235
236 bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true,
237 data_dir, NULL);
238 ok(bin != NULL, "bin_info_create successful (%s)", bin_path);
239
240 /* Test setting invalid build_id */
241 ret = bin_info_set_build_id(bin, invalid_build_id, BUILD_ID_HEX_LEN);
242 ok(ret == -1, "bin_info_set_build_id fail on invalid build_id");
243
244 /* Test setting correct build_id */
245 ret = bin_info_set_build_id(bin, build_id, BUILD_ID_HEX_LEN);
246 ok(ret == 0, "bin_info_set_build_id successful");
247
248 /* Test bin_info_has_address */
249 subtest_has_address(bin, func_foo_printf_addr);
250
251 /* Test function name lookup (with DWARF) */
252 subtest_lookup_function_name(bin, func_foo_printf_addr,
253 func_foo_printf_name);
254
255 /* Test source location lookup */
256 subtest_lookup_source_location(bin, func_foo_printf_addr,
257 opt_func_foo_printf_line_no,
258 FUNC_FOO_FILENAME);
259
260 bin_info_destroy(bin);
261 bt_fd_cache_fini(&fdc);
262 g_free(data_dir);
263 g_free(bin_path);
264 }
265
266 static
267 void test_bin_info_debug_link(const char *bin_info_dir)
268 {
269 int ret;
270 char *data_dir, *bin_path;
271 struct bin_info *bin = NULL;
272 struct bt_fd_cache fdc;
273
274 diag("bin-info tests - separate DWARF via debug link");
275
276 data_dir = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, NULL);
277 bin_path = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, SO_NAME,
278 NULL);
279
280 if (data_dir == NULL || bin_path == NULL) {
281 exit(EXIT_FAILURE);
282 }
283
284 ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL);
285 if (ret != 0) {
286 diag("Failed to initialize FD cache");
287 exit(EXIT_FAILURE);
288 }
289
290 bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true,
291 data_dir, NULL);
292 ok(bin != NULL, "bin_info_create successful (%s)", bin_path);
293
294 /* Test setting debug link */
295 ret = bin_info_set_debug_link(bin, DEBUG_NAME, opt_debug_link_crc);
296 ok(ret == 0, "bin_info_set_debug_link successful");
297
298 /* Test bin_info_has_address */
299 subtest_has_address(bin, func_foo_printf_addr);
300
301 /* Test function name lookup (with DWARF) */
302 subtest_lookup_function_name(bin, func_foo_printf_addr,
303 func_foo_printf_name);
304
305 /* Test source location lookup */
306 subtest_lookup_source_location(bin, func_foo_printf_addr,
307 opt_func_foo_printf_line_no,
308 FUNC_FOO_FILENAME);
309
310 bin_info_destroy(bin);
311 bt_fd_cache_fini(&fdc);
312 g_free(data_dir);
313 g_free(bin_path);
314 }
315
316 static
317 void test_bin_info_elf(const char *bin_info_dir)
318 {
319 int ret;
320 char *data_dir, *bin_path;
321 struct bin_info *bin = NULL;
322 struct source_location *src_loc = NULL;
323 struct bt_fd_cache fdc;
324
325 diag("bin-info tests - ELF only");
326
327 data_dir = g_build_filename(bin_info_dir, ELF_DIR_NAME, NULL);
328 bin_path = g_build_filename(bin_info_dir, ELF_DIR_NAME, SO_NAME, NULL);
329
330 if (data_dir == NULL || bin_path == NULL) {
331 exit(EXIT_FAILURE);
332 }
333
334 ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL);
335 if (ret != 0) {
336 diag("Failed to initialize FD cache");
337 exit(EXIT_FAILURE);
338 }
339
340 bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true,
341 data_dir, NULL);
342 ok(bin != NULL, "bin_info_create successful (%s)", bin_path);
343
344 /* Test bin_info_has_address */
345 subtest_has_address(bin, func_foo_printf_addr);
346
347 /* Test function name lookup (with ELF) */
348 subtest_lookup_function_name(bin, func_foo_printf_addr,
349 func_foo_printf_name);
350
351 /* Test source location location - should fail on ELF only file */
352 ret = bin_info_lookup_source_location(bin, func_foo_printf_addr,
353 &src_loc);
354 ok(ret == -1,
355 "bin_info_lookup_source_location - fail on ELF only file");
356
357 source_location_destroy(src_loc);
358 bin_info_destroy(bin);
359 bt_fd_cache_fini(&fdc);
360 g_free(data_dir);
361 g_free(bin_path);
362 }
363
364 static
365 void test_bin_info_bundled(const char *bin_info_dir)
366 {
367 int ret;
368 char *data_dir, *bin_path;
369 struct bin_info *bin = NULL;
370 struct bt_fd_cache fdc;
371
372 diag("bin-info tests - DWARF bundled in SO file");
373
374 data_dir = g_build_filename(bin_info_dir, DWARF_DIR_NAME, NULL);
375 bin_path =
376 g_build_filename(bin_info_dir, DWARF_DIR_NAME, SO_NAME, NULL);
377
378 if (data_dir == NULL || bin_path == NULL) {
379 exit(EXIT_FAILURE);
380 }
381
382 ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL);
383 if (ret != 0) {
384 diag("Failed to initialize FD cache");
385 exit(EXIT_FAILURE);
386 }
387
388 bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true,
389 data_dir, NULL);
390 ok(bin != NULL, "bin_info_create successful (%s)", bin_path);
391
392 /* Test bin_info_has_address */
393 subtest_has_address(bin, func_foo_printf_addr);
394
395 /* Test function name lookup (with DWARF) */
396 subtest_lookup_function_name(bin, func_foo_printf_addr,
397 func_foo_printf_name);
398
399 /* Test source location lookup */
400 subtest_lookup_source_location(bin, func_foo_printf_addr,
401 opt_func_foo_printf_line_no,
402 FUNC_FOO_FILENAME);
403
404 /* Test source location lookup - inlined function */
405 subtest_lookup_source_location(bin, func_foo_tp_addr,
406 opt_func_foo_tp_line_no,
407 FUNC_FOO_FILENAME);
408
409 bin_info_destroy(bin);
410 bt_fd_cache_fini(&fdc);
411 g_free(data_dir);
412 g_free(bin_path);
413 }
414
415 int main(int argc, char **argv)
416 {
417 int ret;
418 GError *error = NULL;
419 GOptionContext *context;
420
421 context = g_option_context_new("- bin info test");
422 g_option_context_add_main_entries(context, entries, NULL);
423 if (!g_option_context_parse(context, &argc, &argv, &error)) {
424 fprintf(stderr, "option parsing failed: %s\n", error->message);
425 exit(EXIT_FAILURE);
426 }
427
428 g_snprintf(func_foo_printf_name, FUNC_FOO_NAME_LEN,
429 FUNC_FOO_PRINTF_NAME_FMT, opt_func_foo_printf_offset);
430 func_foo_printf_addr =
431 SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_printf_offset;
432 func_foo_tp_addr =
433 SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_tp_offset;
434
435 if (build_id_to_bin()) {
436 fprintf(stderr, "Failed to parse / missing build id\n");
437 exit(EXIT_FAILURE);
438 }
439
440 plan_tests(NR_TESTS);
441
442 ret = bin_info_init();
443 ok(ret == 0, "bin_info_init successful");
444
445 test_bin_info_elf(opt_debug_info_dir);
446 test_bin_info_bundled(opt_debug_info_dir);
447 test_bin_info_build_id(opt_debug_info_dir);
448 test_bin_info_debug_link(opt_debug_info_dir);
449
450 return EXIT_SUCCESS;
451 }
This page took 0.038913 seconds and 5 git commands to generate.