2 * SPDX-License-Identifier: GPL-2.0-only
4 * Copyright (C) 2015 EfficiOS Inc. and Linux Foundation
5 * Copyright (C) 2015 Antoine Busque <abusque@efficios.com>
6 * Copyright (C) 2019 Michael Jeanson <mjeanson@efficios.com>
8 * Babeltrace SO info tests
11 #define BT_LOG_OUTPUT_LEVEL BT_LOG_WARNING
12 #define BT_LOG_TAG "TEST/BIN-INFO"
13 #include "logging/log.h"
21 #include "common/macros.h"
22 #include "common/assert.h"
23 #include <lttng-utils/debug-info/bin-info.h>
29 #define SO_NAME "libhello_so"
30 #define DEBUG_NAME "libhello_so.debug"
31 #define FUNC_FOO_FILENAME "./libhello.c"
32 #define FUNC_FOO_PRINTF_NAME_FMT "foo+0x%" PRIx64
33 #define FUNC_FOO_NAME_LEN 64
35 #define DWARF_DIR_NAME "dwarf_full"
36 #define ELF_DIR_NAME "elf_only"
37 #define BUILDID_DIR_NAME "build_id"
38 #define DEBUGLINK_DIR_NAME "debug_link"
40 /* Lower bound of PIC address mapping */
41 #define SO_LOW_ADDR 0x400000
42 /* Size of PIC address mapping */
43 #define SO_MEMSZ 0x800000
44 /* An address outside the PIC mapping */
45 #define SO_INV_ADDR 0x200000
47 #define BUILD_ID_HEX_LEN 20
49 static uint64_t opt_func_foo_addr
;
50 static uint64_t opt_func_foo_printf_offset
;
51 static uint64_t opt_func_foo_printf_line_no
;
52 static uint64_t opt_func_foo_tp_offset
;
53 static uint64_t opt_func_foo_tp_line_no
;
54 static uint64_t opt_debug_link_crc
;
55 static gchar
*opt_build_id
;
56 static gchar
*opt_debug_info_dir
;
58 static uint64_t func_foo_printf_addr
;
59 static uint64_t func_foo_tp_addr
;
60 static char func_foo_printf_name
[FUNC_FOO_NAME_LEN
];
61 static uint8_t build_id
[BUILD_ID_HEX_LEN
];
63 static GOptionEntry entries
[] = {
64 {"foo-addr", 0, 0, G_OPTION_ARG_INT64
, &opt_func_foo_addr
,
65 "Offset to printf in foo", "0xX"},
66 {"printf-offset", 0, 0, G_OPTION_ARG_INT64
, &opt_func_foo_printf_offset
,
67 "Offset to printf in foo", "0xX"},
68 {"printf-lineno", 0, 0, G_OPTION_ARG_INT64
,
69 &opt_func_foo_printf_line_no
, "Line number to printf in foo", "N"},
70 {"tp-offset", 0, 0, G_OPTION_ARG_INT64
, &opt_func_foo_tp_offset
,
71 "Offset to tp in foo", "0xX"},
72 {"tp-lineno", 0, 0, G_OPTION_ARG_INT64
, &opt_func_foo_tp_line_no
,
73 "Line number to tp in foo", "N"},
74 {"debug-link-crc", 0, 0, G_OPTION_ARG_INT64
, &opt_debug_link_crc
,
75 "Debug link CRC", "0xX"},
76 {"build-id", 0, 0, G_OPTION_ARG_STRING
, &opt_build_id
, "Build ID",
78 {"debug-info-dir", 0, 0, G_OPTION_ARG_STRING
, &opt_debug_info_dir
,
79 "Debug info directory", NULL
},
80 {NULL
, 0, 0, G_OPTION_ARG_NONE
, NULL
, NULL
, NULL
}};
83 int build_id_to_bin(void)
91 len
= strnlen(opt_build_id
, BUILD_ID_HEX_LEN
* 2);
92 if (len
!= (BUILD_ID_HEX_LEN
* 2)) {
96 for (i
= 0; i
< (len
/ 2); i
++) {
97 ret
= sscanf(opt_build_id
+ 2 * i
, "%02hhx", &build_id
[i
]);
103 if (i
!= BUILD_ID_HEX_LEN
) {
113 void subtest_has_address(struct bin_info
*bin
, uint64_t addr
)
117 ret
= bin_info_has_address(bin
, SO_LOW_ADDR
- 1);
118 ok(ret
== 0, "bin_info_has_address - address under SO's range");
120 ret
= bin_info_has_address(bin
, SO_LOW_ADDR
);
121 ok(ret
== 1, "bin_info_has_address - lower bound of SO's range");
123 ret
= bin_info_has_address(bin
, addr
);
124 ok(ret
== 1, "bin_info_has_address - address in SO's range");
126 ret
= bin_info_has_address(bin
, SO_LOW_ADDR
+ SO_MEMSZ
- 1);
127 ok(ret
== 1, "bin_info_has_address - upper bound of SO's range");
129 ret
= bin_info_has_address(bin
, SO_LOW_ADDR
+ SO_MEMSZ
);
130 ok(ret
== 0, "bin_info_has_address - address above SO's range");
134 void subtest_lookup_function_name(struct bin_info
*bin
, uint64_t addr
,
138 char *_func_name
= NULL
;
140 ret
= bin_info_lookup_function_name(bin
, addr
, &_func_name
);
141 ok(ret
== 0, "bin_info_lookup_function_name successful at 0x%" PRIx64
, addr
);
143 ok(strcmp(_func_name
, func_name
) == 0,
144 "bin_info_lookup_function_name - correct function name (%s == %s)",
145 func_name
, _func_name
);
150 "bin_info_lookup_function_name - function name is NULL");
153 /* Test function name lookup - erroneous address */
154 ret
= bin_info_lookup_function_name(bin
, SO_INV_ADDR
, &_func_name
);
155 ok(ret
== -1 && !_func_name
,
156 "bin_info_lookup_function_name - fail on invalid addr");
161 void subtest_lookup_source_location(struct bin_info
*bin
, uint64_t addr
,
162 uint64_t line_no
, const char *filename
)
165 struct source_location
*src_loc
= NULL
;
167 ret
= bin_info_lookup_source_location(bin
, addr
, &src_loc
);
168 ok(ret
== 0, "bin_info_lookup_source_location successful at 0x%" PRIx64
,
171 ok(src_loc
->line_no
== line_no
,
172 "bin_info_lookup_source_location - correct line_no (%" PRIu64
" == %" PRIu64
")",
173 line_no
, src_loc
->line_no
);
174 ok(strcmp(src_loc
->filename
, filename
) == 0,
175 "bin_info_lookup_source_location - correct filename (%s == %s)",
176 filename
, src_loc
->filename
);
177 source_location_destroy(src_loc
);
180 fail("bin_info_lookup_source_location - src_loc is NULL");
181 fail("bin_info_lookup_source_location - src_loc is NULL");
184 /* Test source location lookup - erroneous address */
185 ret
= bin_info_lookup_source_location(bin
, SO_INV_ADDR
, &src_loc
);
186 ok(ret
== -1 && !src_loc
,
187 "bin_info_lookup_source_location - fail on invalid addr");
189 source_location_destroy(src_loc
);
194 void test_bin_info_build_id(const char *bin_info_dir
)
197 char *data_dir
, *bin_path
;
198 struct bin_info
*bin
= NULL
;
199 struct bt_fd_cache fdc
;
200 uint8_t invalid_build_id
[BUILD_ID_HEX_LEN
] = {
201 0xa3, 0xfd, 0x8b, 0xff, 0x45, 0xe1, 0xa9, 0x32, 0x15, 0xdd,
202 0x6d, 0xaa, 0xd5, 0x53, 0x98, 0x7e, 0xaf, 0xd4, 0x0c, 0xbb
205 diag("bin-info tests - separate DWARF via build ID");
207 data_dir
= g_build_filename(bin_info_dir
, BUILDID_DIR_NAME
, NULL
);
209 g_build_filename(bin_info_dir
, BUILDID_DIR_NAME
, SO_NAME
, NULL
);
211 if (!data_dir
|| !bin_path
) {
215 ret
= bt_fd_cache_init(&fdc
, BT_LOG_OUTPUT_LEVEL
);
217 diag("Failed to initialize FD cache");
221 bin
= bin_info_create(&fdc
, bin_path
, SO_LOW_ADDR
, SO_MEMSZ
, true,
222 data_dir
, NULL
, BT_LOG_OUTPUT_LEVEL
, NULL
);
223 ok(bin
, "bin_info_create successful (%s)", bin_path
);
225 /* Test setting invalid build_id */
226 ret
= bin_info_set_build_id(bin
, invalid_build_id
, BUILD_ID_HEX_LEN
);
227 ok(ret
== -1, "bin_info_set_build_id fail on invalid build_id");
229 /* Test setting correct build_id */
230 ret
= bin_info_set_build_id(bin
, build_id
, BUILD_ID_HEX_LEN
);
231 ok(ret
== 0, "bin_info_set_build_id successful");
233 /* Test bin_info_has_address */
234 subtest_has_address(bin
, func_foo_printf_addr
);
236 /* Test function name lookup (with DWARF) */
237 subtest_lookup_function_name(bin
, func_foo_printf_addr
,
238 func_foo_printf_name
);
240 /* Test source location lookup */
241 subtest_lookup_source_location(bin
, func_foo_printf_addr
,
242 opt_func_foo_printf_line_no
,
245 bin_info_destroy(bin
);
246 bt_fd_cache_fini(&fdc
);
252 void test_bin_info_debug_link(const char *bin_info_dir
)
255 char *data_dir
, *bin_path
;
256 struct bin_info
*bin
= NULL
;
257 struct bt_fd_cache fdc
;
259 diag("bin-info tests - separate DWARF via debug link");
261 data_dir
= g_build_filename(bin_info_dir
, DEBUGLINK_DIR_NAME
, NULL
);
262 bin_path
= g_build_filename(bin_info_dir
, DEBUGLINK_DIR_NAME
, SO_NAME
,
265 if (!data_dir
|| !bin_path
) {
269 ret
= bt_fd_cache_init(&fdc
, BT_LOG_OUTPUT_LEVEL
);
271 diag("Failed to initialize FD cache");
275 bin
= bin_info_create(&fdc
, bin_path
, SO_LOW_ADDR
, SO_MEMSZ
, true,
276 data_dir
, NULL
, BT_LOG_OUTPUT_LEVEL
, NULL
);
277 ok(bin
, "bin_info_create successful (%s)", bin_path
);
279 /* Test setting debug link */
280 ret
= bin_info_set_debug_link(bin
, DEBUG_NAME
, opt_debug_link_crc
);
281 ok(ret
== 0, "bin_info_set_debug_link successful");
283 /* Test bin_info_has_address */
284 subtest_has_address(bin
, func_foo_printf_addr
);
286 /* Test function name lookup (with DWARF) */
287 subtest_lookup_function_name(bin
, func_foo_printf_addr
,
288 func_foo_printf_name
);
290 /* Test source location lookup */
291 subtest_lookup_source_location(bin
, func_foo_printf_addr
,
292 opt_func_foo_printf_line_no
,
295 bin_info_destroy(bin
);
296 bt_fd_cache_fini(&fdc
);
302 void test_bin_info_elf(const char *bin_info_dir
)
305 char *data_dir
, *bin_path
;
306 struct bin_info
*bin
= NULL
;
307 struct source_location
*src_loc
= NULL
;
308 struct bt_fd_cache fdc
;
310 diag("bin-info tests - ELF only");
312 data_dir
= g_build_filename(bin_info_dir
, ELF_DIR_NAME
, NULL
);
313 bin_path
= g_build_filename(bin_info_dir
, ELF_DIR_NAME
, SO_NAME
, NULL
);
315 if (!data_dir
|| !bin_path
) {
319 ret
= bt_fd_cache_init(&fdc
, BT_LOG_OUTPUT_LEVEL
);
321 diag("Failed to initialize FD cache");
325 bin
= bin_info_create(&fdc
, bin_path
, SO_LOW_ADDR
, SO_MEMSZ
, true,
326 data_dir
, NULL
, BT_LOG_OUTPUT_LEVEL
, NULL
);
327 ok(bin
, "bin_info_create successful (%s)", bin_path
);
329 /* Test bin_info_has_address */
330 subtest_has_address(bin
, func_foo_printf_addr
);
332 /* Test function name lookup (with ELF) */
333 subtest_lookup_function_name(bin
, func_foo_printf_addr
,
334 func_foo_printf_name
);
336 /* Test source location location - should fail on ELF only file */
337 ret
= bin_info_lookup_source_location(bin
, func_foo_printf_addr
,
340 "bin_info_lookup_source_location - fail on ELF only file");
342 source_location_destroy(src_loc
);
343 bin_info_destroy(bin
);
344 bt_fd_cache_fini(&fdc
);
350 void test_bin_info_bundled(const char *bin_info_dir
)
353 char *data_dir
, *bin_path
;
354 struct bin_info
*bin
= NULL
;
355 struct bt_fd_cache fdc
;
357 diag("bin-info tests - DWARF bundled in SO file");
359 data_dir
= g_build_filename(bin_info_dir
, DWARF_DIR_NAME
, NULL
);
361 g_build_filename(bin_info_dir
, DWARF_DIR_NAME
, SO_NAME
, NULL
);
363 if (!data_dir
|| !bin_path
) {
367 ret
= bt_fd_cache_init(&fdc
, BT_LOG_OUTPUT_LEVEL
);
369 diag("Failed to initialize FD cache");
373 bin
= bin_info_create(&fdc
, bin_path
, SO_LOW_ADDR
, SO_MEMSZ
, true,
374 data_dir
, NULL
, BT_LOG_OUTPUT_LEVEL
, NULL
);
375 ok(bin
, "bin_info_create successful (%s)", bin_path
);
377 /* Test bin_info_has_address */
378 subtest_has_address(bin
, func_foo_printf_addr
);
380 /* Test function name lookup (with DWARF) */
381 subtest_lookup_function_name(bin
, func_foo_printf_addr
,
382 func_foo_printf_name
);
384 /* Test source location lookup */
385 subtest_lookup_source_location(bin
, func_foo_printf_addr
,
386 opt_func_foo_printf_line_no
,
389 /* Test source location lookup - inlined function */
390 subtest_lookup_source_location(bin
, func_foo_tp_addr
,
391 opt_func_foo_tp_line_no
,
394 bin_info_destroy(bin
);
395 bt_fd_cache_fini(&fdc
);
400 int main(int argc
, char **argv
)
403 GError
*error
= NULL
;
404 GOptionContext
*context
;
407 plan_tests(NR_TESTS
);
409 context
= g_option_context_new("- bin info test");
410 g_option_context_add_main_entries(context
, entries
, NULL
);
411 if (!g_option_context_parse(context
, &argc
, &argv
, &error
)) {
412 fprintf(stderr
, "option parsing failed: %s\n", error
->message
);
413 status
= EXIT_FAILURE
;
417 g_snprintf(func_foo_printf_name
, FUNC_FOO_NAME_LEN
,
418 FUNC_FOO_PRINTF_NAME_FMT
, opt_func_foo_printf_offset
);
419 func_foo_printf_addr
=
420 SO_LOW_ADDR
+ opt_func_foo_addr
+ opt_func_foo_printf_offset
;
422 SO_LOW_ADDR
+ opt_func_foo_addr
+ opt_func_foo_tp_offset
;
424 if (build_id_to_bin()) {
425 fprintf(stderr
, "Failed to parse / missing build id\n");
426 status
= EXIT_FAILURE
;
430 ret
= bin_info_init(BT_LOG_OUTPUT_LEVEL
, NULL
);
431 ok(ret
== 0, "bin_info_init successful");
433 test_bin_info_elf(opt_debug_info_dir
);
434 test_bin_info_bundled(opt_debug_info_dir
);
435 test_bin_info_build_id(opt_debug_info_dir
);
436 test_bin_info_debug_link(opt_debug_info_dir
);
438 status
= exit_status();
441 g_option_context_free(context
);