4 * Babeltrace SO info tests
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>
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.
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.
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.
24 #define BT_LOG_OUTPUT_LEVEL BT_LOG_WARNING
25 #define BT_LOG_TAG "TEST/BIN-INFO"
26 #include "logging/log.h"
34 #include "common/macros.h"
35 #include "common/assert.h"
36 #include <lttng-utils/debug-info/bin-info.h>
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
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"
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
60 #define BUILD_ID_HEX_LEN 20
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
;
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
];
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",
91 {"debug-info-dir", 0, 0, G_OPTION_ARG_STRING
, &opt_debug_info_dir
,
92 "Debug info directory", NULL
},
96 int build_id_to_bin(void)
104 len
= strnlen(opt_build_id
, BUILD_ID_HEX_LEN
* 2);
105 if (len
!= (BUILD_ID_HEX_LEN
* 2)) {
109 for (i
= 0; i
< (len
/ 2); i
++) {
110 ret
= sscanf(opt_build_id
+ 2 * i
, "%02hhx", &build_id
[i
]);
116 if (i
!= BUILD_ID_HEX_LEN
) {
126 void subtest_has_address(struct bin_info
*bin
, uint64_t addr
)
130 ret
= bin_info_has_address(bin
, SO_LOW_ADDR
- 1);
131 ok(ret
== 0, "bin_info_has_address - address under SO's range");
133 ret
= bin_info_has_address(bin
, SO_LOW_ADDR
);
134 ok(ret
== 1, "bin_info_has_address - lower bound of SO's range");
136 ret
= bin_info_has_address(bin
, addr
);
137 ok(ret
== 1, "bin_info_has_address - address in SO's range");
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");
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");
147 void subtest_lookup_function_name(struct bin_info
*bin
, uint64_t addr
,
151 char *_func_name
= NULL
;
153 ret
= bin_info_lookup_function_name(bin
, addr
, &_func_name
);
154 ok(ret
== 0, "bin_info_lookup_function_name successful at 0x%" PRIx64
, addr
);
156 ok(strcmp(_func_name
, func_name
) == 0,
157 "bin_info_lookup_function_name - correct function name (%s == %s)",
158 func_name
, _func_name
);
163 "bin_info_lookup_function_name - function name is NULL");
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
,
169 "bin_info_lookup_function_name - fail on invalid addr");
174 void subtest_lookup_source_location(struct bin_info
*bin
, uint64_t addr
,
175 uint64_t line_no
, char *filename
)
178 struct source_location
*src_loc
= NULL
;
180 ret
= bin_info_lookup_source_location(bin
, addr
, &src_loc
);
181 ok(ret
== 0, "bin_info_lookup_source_location successful at 0x%" PRIx64
,
184 ok(src_loc
->line_no
== line_no
,
185 "bin_info_lookup_source_location - correct line_no (%" PRIu64
" == %" PRIu64
")",
186 line_no
, src_loc
->line_no
);
187 ok(strcmp(src_loc
->filename
, filename
) == 0,
188 "bin_info_lookup_source_location - correct filename (%s == %s)",
189 filename
, src_loc
->filename
);
190 source_location_destroy(src_loc
);
193 fail("bin_info_lookup_source_location - src_loc is NULL");
194 fail("bin_info_lookup_source_location - src_loc is NULL");
197 /* Test source location lookup - erroneous address */
198 ret
= bin_info_lookup_source_location(bin
, SO_INV_ADDR
, &src_loc
);
199 ok(ret
== -1 && !src_loc
,
200 "bin_info_lookup_source_location - fail on invalid addr");
202 source_location_destroy(src_loc
);
207 void test_bin_info_build_id(const char *bin_info_dir
)
210 char *data_dir
, *bin_path
;
211 struct bin_info
*bin
= NULL
;
212 struct bt_fd_cache fdc
;
213 uint8_t invalid_build_id
[BUILD_ID_HEX_LEN
] = {
214 0xa3, 0xfd, 0x8b, 0xff, 0x45, 0xe1, 0xa9, 0x32, 0x15, 0xdd,
215 0x6d, 0xaa, 0xd5, 0x53, 0x98, 0x7e, 0xaf, 0xd4, 0x0c, 0xbb
218 diag("bin-info tests - separate DWARF via build ID");
220 data_dir
= g_build_filename(bin_info_dir
, BUILDID_DIR_NAME
, NULL
);
222 g_build_filename(bin_info_dir
, BUILDID_DIR_NAME
, SO_NAME
, NULL
);
224 if (!data_dir
|| !bin_path
) {
228 ret
= bt_fd_cache_init(&fdc
, BT_LOG_OUTPUT_LEVEL
);
230 diag("Failed to initialize FD cache");
234 bin
= bin_info_create(&fdc
, bin_path
, SO_LOW_ADDR
, SO_MEMSZ
, true,
235 data_dir
, NULL
, BT_LOG_OUTPUT_LEVEL
, NULL
);
236 ok(bin
, "bin_info_create successful (%s)", bin_path
);
238 /* Test setting invalid build_id */
239 ret
= bin_info_set_build_id(bin
, invalid_build_id
, BUILD_ID_HEX_LEN
);
240 ok(ret
== -1, "bin_info_set_build_id fail on invalid build_id");
242 /* Test setting correct build_id */
243 ret
= bin_info_set_build_id(bin
, build_id
, BUILD_ID_HEX_LEN
);
244 ok(ret
== 0, "bin_info_set_build_id successful");
246 /* Test bin_info_has_address */
247 subtest_has_address(bin
, func_foo_printf_addr
);
249 /* Test function name lookup (with DWARF) */
250 subtest_lookup_function_name(bin
, func_foo_printf_addr
,
251 func_foo_printf_name
);
253 /* Test source location lookup */
254 subtest_lookup_source_location(bin
, func_foo_printf_addr
,
255 opt_func_foo_printf_line_no
,
258 bin_info_destroy(bin
);
259 bt_fd_cache_fini(&fdc
);
265 void test_bin_info_debug_link(const char *bin_info_dir
)
268 char *data_dir
, *bin_path
;
269 struct bin_info
*bin
= NULL
;
270 struct bt_fd_cache fdc
;
272 diag("bin-info tests - separate DWARF via debug link");
274 data_dir
= g_build_filename(bin_info_dir
, DEBUGLINK_DIR_NAME
, NULL
);
275 bin_path
= g_build_filename(bin_info_dir
, DEBUGLINK_DIR_NAME
, SO_NAME
,
278 if (!data_dir
|| !bin_path
) {
282 ret
= bt_fd_cache_init(&fdc
, BT_LOG_OUTPUT_LEVEL
);
284 diag("Failed to initialize FD cache");
288 bin
= bin_info_create(&fdc
, bin_path
, SO_LOW_ADDR
, SO_MEMSZ
, true,
289 data_dir
, NULL
, BT_LOG_OUTPUT_LEVEL
, NULL
);
290 ok(bin
, "bin_info_create successful (%s)", bin_path
);
292 /* Test setting debug link */
293 ret
= bin_info_set_debug_link(bin
, DEBUG_NAME
, opt_debug_link_crc
);
294 ok(ret
== 0, "bin_info_set_debug_link successful");
296 /* Test bin_info_has_address */
297 subtest_has_address(bin
, func_foo_printf_addr
);
299 /* Test function name lookup (with DWARF) */
300 subtest_lookup_function_name(bin
, func_foo_printf_addr
,
301 func_foo_printf_name
);
303 /* Test source location lookup */
304 subtest_lookup_source_location(bin
, func_foo_printf_addr
,
305 opt_func_foo_printf_line_no
,
308 bin_info_destroy(bin
);
309 bt_fd_cache_fini(&fdc
);
315 void test_bin_info_elf(const char *bin_info_dir
)
318 char *data_dir
, *bin_path
;
319 struct bin_info
*bin
= NULL
;
320 struct source_location
*src_loc
= NULL
;
321 struct bt_fd_cache fdc
;
323 diag("bin-info tests - ELF only");
325 data_dir
= g_build_filename(bin_info_dir
, ELF_DIR_NAME
, NULL
);
326 bin_path
= g_build_filename(bin_info_dir
, ELF_DIR_NAME
, SO_NAME
, NULL
);
328 if (!data_dir
|| !bin_path
) {
332 ret
= bt_fd_cache_init(&fdc
, BT_LOG_OUTPUT_LEVEL
);
334 diag("Failed to initialize FD cache");
338 bin
= bin_info_create(&fdc
, bin_path
, SO_LOW_ADDR
, SO_MEMSZ
, true,
339 data_dir
, NULL
, BT_LOG_OUTPUT_LEVEL
, NULL
);
340 ok(bin
, "bin_info_create successful (%s)", bin_path
);
342 /* Test bin_info_has_address */
343 subtest_has_address(bin
, func_foo_printf_addr
);
345 /* Test function name lookup (with ELF) */
346 subtest_lookup_function_name(bin
, func_foo_printf_addr
,
347 func_foo_printf_name
);
349 /* Test source location location - should fail on ELF only file */
350 ret
= bin_info_lookup_source_location(bin
, func_foo_printf_addr
,
353 "bin_info_lookup_source_location - fail on ELF only file");
355 source_location_destroy(src_loc
);
356 bin_info_destroy(bin
);
357 bt_fd_cache_fini(&fdc
);
363 void test_bin_info_bundled(const char *bin_info_dir
)
366 char *data_dir
, *bin_path
;
367 struct bin_info
*bin
= NULL
;
368 struct bt_fd_cache fdc
;
370 diag("bin-info tests - DWARF bundled in SO file");
372 data_dir
= g_build_filename(bin_info_dir
, DWARF_DIR_NAME
, NULL
);
374 g_build_filename(bin_info_dir
, DWARF_DIR_NAME
, SO_NAME
, NULL
);
376 if (!data_dir
|| !bin_path
) {
380 ret
= bt_fd_cache_init(&fdc
, BT_LOG_OUTPUT_LEVEL
);
382 diag("Failed to initialize FD cache");
386 bin
= bin_info_create(&fdc
, bin_path
, SO_LOW_ADDR
, SO_MEMSZ
, true,
387 data_dir
, NULL
, BT_LOG_OUTPUT_LEVEL
, NULL
);
388 ok(bin
, "bin_info_create successful (%s)", bin_path
);
390 /* Test bin_info_has_address */
391 subtest_has_address(bin
, func_foo_printf_addr
);
393 /* Test function name lookup (with DWARF) */
394 subtest_lookup_function_name(bin
, func_foo_printf_addr
,
395 func_foo_printf_name
);
397 /* Test source location lookup */
398 subtest_lookup_source_location(bin
, func_foo_printf_addr
,
399 opt_func_foo_printf_line_no
,
402 /* Test source location lookup - inlined function */
403 subtest_lookup_source_location(bin
, func_foo_tp_addr
,
404 opt_func_foo_tp_line_no
,
407 bin_info_destroy(bin
);
408 bt_fd_cache_fini(&fdc
);
413 int main(int argc
, char **argv
)
416 GError
*error
= NULL
;
417 GOptionContext
*context
;
419 context
= g_option_context_new("- bin info test");
420 g_option_context_add_main_entries(context
, entries
, NULL
);
421 if (!g_option_context_parse(context
, &argc
, &argv
, &error
)) {
422 fprintf(stderr
, "option parsing failed: %s\n", error
->message
);
426 g_snprintf(func_foo_printf_name
, FUNC_FOO_NAME_LEN
,
427 FUNC_FOO_PRINTF_NAME_FMT
, opt_func_foo_printf_offset
);
428 func_foo_printf_addr
=
429 SO_LOW_ADDR
+ opt_func_foo_addr
+ opt_func_foo_printf_offset
;
431 SO_LOW_ADDR
+ opt_func_foo_addr
+ opt_func_foo_tp_offset
;
433 if (build_id_to_bin()) {
434 fprintf(stderr
, "Failed to parse / missing build id\n");
438 plan_tests(NR_TESTS
);
440 ret
= bin_info_init(BT_LOG_OUTPUT_LEVEL
, NULL
);
441 ok(ret
== 0, "bin_info_init successful");
443 test_bin_info_elf(opt_debug_info_dir
);
444 test_bin_info_bundled(opt_debug_info_dir
);
445 test_bin_info_build_id(opt_debug_info_dir
);
446 test_bin_info_debug_link(opt_debug_info_dir
);