Move to kernel style SPDX license identifiers
[babeltrace.git] / tests / plugins / flt.lttng-utils.debug-info / test_bin_info.c
CommitLineData
6ab5bdaa 1/*
0235b0db 2 * SPDX-License-Identifier: GPL-2.0-only
6ab5bdaa 3 *
0235b0db
MJ
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>
6ab5bdaa 7 *
0235b0db 8 * Babeltrace SO info tests
6ab5bdaa
AB
9 */
10
770538dd 11#define BT_LOG_OUTPUT_LEVEL BT_LOG_WARNING
86d8b7b8
PP
12#define BT_LOG_TAG "TEST/BIN-INFO"
13#include "logging/log.h"
14
6ab5bdaa
AB
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
882adb99
MJ
18#include <inttypes.h>
19#include <glib.h>
1e638f98 20
91d81473 21#include "common/macros.h"
578e048b 22#include "common/assert.h"
c283522b 23#include <lttng-utils/debug-info/bin-info.h>
1e638f98 24
6ab5bdaa
AB
25#include "tap/tap.h"
26
882adb99
MJ
27#define NR_TESTS 57
28
24d3147c 29#define SO_NAME "libhello_so"
882adb99
MJ
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
6a284733
MJ
34
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"
39
882adb99 40/* Lower bound of PIC address mapping */
6ab5bdaa 41#define SO_LOW_ADDR 0x400000
882adb99
MJ
42/* Size of PIC address mapping */
43#define SO_MEMSZ 0x800000
44/* An address outside the PIC mapping */
45#define SO_INV_ADDR 0x200000
46
47#define BUILD_ID_HEX_LEN 20
48
49static uint64_t opt_func_foo_addr;
50static uint64_t opt_func_foo_printf_offset;
51static uint64_t opt_func_foo_printf_line_no;
52static uint64_t opt_func_foo_tp_offset;
53static uint64_t opt_func_foo_tp_line_no;
54static uint64_t opt_debug_link_crc;
55static gchar *opt_build_id;
56static gchar *opt_debug_info_dir;
57
58static uint64_t func_foo_printf_addr;
59static uint64_t func_foo_tp_addr;
60static char func_foo_printf_name[FUNC_FOO_NAME_LEN];
61static uint8_t build_id[BUILD_ID_HEX_LEN];
62
63static 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",
77 "XXXXXXXXXXXXXXX"},
78 {"debug-info-dir", 0, 0, G_OPTION_ARG_STRING, &opt_debug_info_dir,
79 "Debug info directory", NULL},
ef5a502c 80 {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}};
882adb99
MJ
81
82static
83int build_id_to_bin(void)
84{
85 int ret, len, i;
86
5084732e 87 if (!opt_build_id) {
882adb99
MJ
88 goto error;
89 }
90
91 len = strnlen(opt_build_id, BUILD_ID_HEX_LEN * 2);
92 if (len != (BUILD_ID_HEX_LEN * 2)) {
93 goto error;
94 }
95
96 for (i = 0; i < (len / 2); i++) {
97 ret = sscanf(opt_build_id + 2 * i, "%02hhx", &build_id[i]);
98 if (ret != 1) {
99 goto error;
100 }
101 }
102
103 if (i != BUILD_ID_HEX_LEN) {
104 goto error;
105 }
106
107 return 0;
108error:
109 return -1;
110}
111
112static
113void subtest_has_address(struct bin_info *bin, uint64_t addr)
114{
115 int ret;
116
117 ret = bin_info_has_address(bin, SO_LOW_ADDR - 1);
118 ok(ret == 0, "bin_info_has_address - address under SO's range");
119
120 ret = bin_info_has_address(bin, SO_LOW_ADDR);
121 ok(ret == 1, "bin_info_has_address - lower bound of SO's range");
122
123 ret = bin_info_has_address(bin, addr);
124 ok(ret == 1, "bin_info_has_address - address in SO's range");
125
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");
128
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");
131}
132
133static
134void subtest_lookup_function_name(struct bin_info *bin, uint64_t addr,
135 char *func_name)
136{
137 int ret;
138 char *_func_name = NULL;
139
140 ret = bin_info_lookup_function_name(bin, addr, &_func_name);
092f9aea 141 ok(ret == 0, "bin_info_lookup_function_name successful at 0x%" PRIx64, addr);
882adb99
MJ
142 if (_func_name) {
143 ok(strcmp(_func_name, func_name) == 0,
144 "bin_info_lookup_function_name - correct function name (%s == %s)",
145 func_name, _func_name);
146 free(_func_name);
147 _func_name = NULL;
148 } else {
149 skip(1,
150 "bin_info_lookup_function_name - function name is NULL");
151 }
152
153 /* Test function name lookup - erroneous address */
154 ret = bin_info_lookup_function_name(bin, SO_INV_ADDR, &_func_name);
5084732e 155 ok(ret == -1 && !_func_name,
882adb99 156 "bin_info_lookup_function_name - fail on invalid addr");
6b934a94 157 free(_func_name);
882adb99
MJ
158}
159
160static
161void subtest_lookup_source_location(struct bin_info *bin, uint64_t addr,
02bb4fcc 162 uint64_t line_no, const char *filename)
882adb99
MJ
163{
164 int ret;
165 struct source_location *src_loc = NULL;
166
167 ret = bin_info_lookup_source_location(bin, addr, &src_loc);
092f9aea 168 ok(ret == 0, "bin_info_lookup_source_location successful at 0x%" PRIx64,
882adb99
MJ
169 addr);
170 if (src_loc) {
171 ok(src_loc->line_no == line_no,
092f9aea 172 "bin_info_lookup_source_location - correct line_no (%" PRIu64 " == %" PRIu64 ")",
882adb99
MJ
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);
178 src_loc = NULL;
179 } else {
180 fail("bin_info_lookup_source_location - src_loc is NULL");
181 fail("bin_info_lookup_source_location - src_loc is NULL");
182 }
183
184 /* Test source location lookup - erroneous address */
185 ret = bin_info_lookup_source_location(bin, SO_INV_ADDR, &src_loc);
5084732e 186 ok(ret == -1 && !src_loc,
882adb99
MJ
187 "bin_info_lookup_source_location - fail on invalid addr");
188 if (src_loc) {
189 source_location_destroy(src_loc);
190 }
191}
6ab5bdaa
AB
192
193static
6a284733 194void test_bin_info_build_id(const char *bin_info_dir)
6ab5bdaa
AB
195{
196 int ret;
6a284733 197 char *data_dir, *bin_path;
d5ddf820 198 struct bin_info *bin = NULL;
1e638f98 199 struct bt_fd_cache fdc;
882adb99
MJ
200 uint8_t invalid_build_id[BUILD_ID_HEX_LEN] = {
201 0xa3, 0xfd, 0x8b, 0xff, 0x45, 0xe1, 0xa9, 0x32, 0x15, 0xdd,
6ab5bdaa
AB
202 0x6d, 0xaa, 0xd5, 0x53, 0x98, 0x7e, 0xaf, 0xd4, 0x0c, 0xbb
203 };
204
d5ddf820 205 diag("bin-info tests - separate DWARF via build ID");
6ab5bdaa 206
6a284733 207 data_dir = g_build_filename(bin_info_dir, BUILDID_DIR_NAME, NULL);
882adb99
MJ
208 bin_path =
209 g_build_filename(bin_info_dir, BUILDID_DIR_NAME, SO_NAME, NULL);
6a284733 210
5084732e 211 if (!data_dir || !bin_path) {
6a284733
MJ
212 exit(EXIT_FAILURE);
213 }
6ab5bdaa 214
86d8b7b8 215 ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL);
7de0939d
MJ
216 if (ret != 0) {
217 diag("Failed to initialize FD cache");
218 exit(EXIT_FAILURE);
219 }
6ab5bdaa 220
882adb99 221 bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true,
91bc8451 222 data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL);
5084732e 223 ok(bin, "bin_info_create successful (%s)", bin_path);
882adb99
MJ
224
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");
228
229 /* Test setting correct build_id */
230 ret = bin_info_set_build_id(bin, build_id, BUILD_ID_HEX_LEN);
4caab45b 231 ok(ret == 0, "bin_info_set_build_id successful");
6ab5bdaa 232
882adb99
MJ
233 /* Test bin_info_has_address */
234 subtest_has_address(bin, func_foo_printf_addr);
235
6ab5bdaa 236 /* Test function name lookup (with DWARF) */
882adb99
MJ
237 subtest_lookup_function_name(bin, func_foo_printf_addr,
238 func_foo_printf_name);
6ab5bdaa
AB
239
240 /* Test source location lookup */
882adb99
MJ
241 subtest_lookup_source_location(bin, func_foo_printf_addr,
242 opt_func_foo_printf_line_no,
243 FUNC_FOO_FILENAME);
6ab5bdaa 244
d5ddf820 245 bin_info_destroy(bin);
1e638f98 246 bt_fd_cache_fini(&fdc);
6a284733
MJ
247 g_free(data_dir);
248 g_free(bin_path);
6ab5bdaa
AB
249}
250
251static
6a284733 252void test_bin_info_debug_link(const char *bin_info_dir)
6ab5bdaa
AB
253{
254 int ret;
6a284733 255 char *data_dir, *bin_path;
d5ddf820 256 struct bin_info *bin = NULL;
1e638f98 257 struct bt_fd_cache fdc;
6ab5bdaa 258
d5ddf820 259 diag("bin-info tests - separate DWARF via debug link");
6ab5bdaa 260
6a284733 261 data_dir = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, NULL);
882adb99
MJ
262 bin_path = g_build_filename(bin_info_dir, DEBUGLINK_DIR_NAME, SO_NAME,
263 NULL);
6a284733 264
5084732e 265 if (!data_dir || !bin_path) {
6a284733
MJ
266 exit(EXIT_FAILURE);
267 }
6ab5bdaa 268
86d8b7b8 269 ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL);
7de0939d
MJ
270 if (ret != 0) {
271 diag("Failed to initialize FD cache");
272 exit(EXIT_FAILURE);
273 }
882adb99
MJ
274
275 bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true,
91bc8451 276 data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL);
5084732e 277 ok(bin, "bin_info_create successful (%s)", bin_path);
6ab5bdaa
AB
278
279 /* Test setting debug link */
882adb99 280 ret = bin_info_set_debug_link(bin, DEBUG_NAME, opt_debug_link_crc);
4caab45b 281 ok(ret == 0, "bin_info_set_debug_link successful");
6ab5bdaa 282
882adb99
MJ
283 /* Test bin_info_has_address */
284 subtest_has_address(bin, func_foo_printf_addr);
285
6ab5bdaa 286 /* Test function name lookup (with DWARF) */
882adb99
MJ
287 subtest_lookup_function_name(bin, func_foo_printf_addr,
288 func_foo_printf_name);
6ab5bdaa
AB
289
290 /* Test source location lookup */
882adb99
MJ
291 subtest_lookup_source_location(bin, func_foo_printf_addr,
292 opt_func_foo_printf_line_no,
293 FUNC_FOO_FILENAME);
6ab5bdaa 294
d5ddf820 295 bin_info_destroy(bin);
1e638f98 296 bt_fd_cache_fini(&fdc);
6a284733
MJ
297 g_free(data_dir);
298 g_free(bin_path);
6ab5bdaa
AB
299}
300
301static
6a284733 302void test_bin_info_elf(const char *bin_info_dir)
6ab5bdaa
AB
303{
304 int ret;
6a284733 305 char *data_dir, *bin_path;
d5ddf820 306 struct bin_info *bin = NULL;
6ab5bdaa 307 struct source_location *src_loc = NULL;
1e638f98 308 struct bt_fd_cache fdc;
6ab5bdaa 309
d5ddf820 310 diag("bin-info tests - ELF only");
6ab5bdaa 311
6a284733
MJ
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);
314
5084732e 315 if (!data_dir || !bin_path) {
6a284733
MJ
316 exit(EXIT_FAILURE);
317 }
6ab5bdaa 318
86d8b7b8 319 ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL);
7de0939d
MJ
320 if (ret != 0) {
321 diag("Failed to initialize FD cache");
322 exit(EXIT_FAILURE);
323 }
6ab5bdaa 324
882adb99 325 bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true,
91bc8451 326 data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL);
5084732e 327 ok(bin, "bin_info_create successful (%s)", bin_path);
6ab5bdaa 328
882adb99
MJ
329 /* Test bin_info_has_address */
330 subtest_has_address(bin, func_foo_printf_addr);
331
332 /* Test function name lookup (with ELF) */
333 subtest_lookup_function_name(bin, func_foo_printf_addr,
334 func_foo_printf_name);
6ab5bdaa
AB
335
336 /* Test source location location - should fail on ELF only file */
882adb99
MJ
337 ret = bin_info_lookup_source_location(bin, func_foo_printf_addr,
338 &src_loc);
339 ok(ret == -1,
340 "bin_info_lookup_source_location - fail on ELF only file");
6ab5bdaa
AB
341
342 source_location_destroy(src_loc);
d5ddf820 343 bin_info_destroy(bin);
1e638f98 344 bt_fd_cache_fini(&fdc);
6a284733
MJ
345 g_free(data_dir);
346 g_free(bin_path);
6ab5bdaa
AB
347}
348
349static
882adb99 350void test_bin_info_bundled(const char *bin_info_dir)
6ab5bdaa
AB
351{
352 int ret;
6a284733 353 char *data_dir, *bin_path;
d5ddf820 354 struct bin_info *bin = NULL;
1e638f98 355 struct bt_fd_cache fdc;
6ab5bdaa 356
882adb99 357 diag("bin-info tests - DWARF bundled in SO file");
1e638f98 358
6a284733 359 data_dir = g_build_filename(bin_info_dir, DWARF_DIR_NAME, NULL);
882adb99
MJ
360 bin_path =
361 g_build_filename(bin_info_dir, DWARF_DIR_NAME, SO_NAME, NULL);
6a284733 362
5084732e 363 if (!data_dir || !bin_path) {
6a284733
MJ
364 exit(EXIT_FAILURE);
365 }
6ab5bdaa 366
86d8b7b8 367 ret = bt_fd_cache_init(&fdc, BT_LOG_OUTPUT_LEVEL);
7de0939d
MJ
368 if (ret != 0) {
369 diag("Failed to initialize FD cache");
370 exit(EXIT_FAILURE);
371 }
882adb99
MJ
372
373 bin = bin_info_create(&fdc, bin_path, SO_LOW_ADDR, SO_MEMSZ, true,
91bc8451 374 data_dir, NULL, BT_LOG_OUTPUT_LEVEL, NULL);
5084732e 375 ok(bin, "bin_info_create successful (%s)", bin_path);
d5ddf820
AB
376
377 /* Test bin_info_has_address */
882adb99 378 subtest_has_address(bin, func_foo_printf_addr);
6ab5bdaa
AB
379
380 /* Test function name lookup (with DWARF) */
882adb99
MJ
381 subtest_lookup_function_name(bin, func_foo_printf_addr,
382 func_foo_printf_name);
6ab5bdaa
AB
383
384 /* Test source location lookup */
882adb99
MJ
385 subtest_lookup_source_location(bin, func_foo_printf_addr,
386 opt_func_foo_printf_line_no,
387 FUNC_FOO_FILENAME);
6ab5bdaa
AB
388
389 /* Test source location lookup - inlined function */
882adb99
MJ
390 subtest_lookup_source_location(bin, func_foo_tp_addr,
391 opt_func_foo_tp_line_no,
392 FUNC_FOO_FILENAME);
6ab5bdaa 393
d5ddf820 394 bin_info_destroy(bin);
1e638f98 395 bt_fd_cache_fini(&fdc);
6a284733
MJ
396 g_free(data_dir);
397 g_free(bin_path);
6ab5bdaa
AB
398}
399
400int main(int argc, char **argv)
401{
402 int ret;
882adb99
MJ
403 GError *error = NULL;
404 GOptionContext *context;
03a71671 405 int status;
6ab5bdaa 406
882adb99
MJ
407 context = g_option_context_new("- bin info test");
408 g_option_context_add_main_entries(context, entries, NULL);
409 if (!g_option_context_parse(context, &argc, &argv, &error)) {
410 fprintf(stderr, "option parsing failed: %s\n", error->message);
03a71671
SM
411 status = EXIT_FAILURE;
412 goto end;
882adb99 413 }
6ab5bdaa 414
882adb99
MJ
415 g_snprintf(func_foo_printf_name, FUNC_FOO_NAME_LEN,
416 FUNC_FOO_PRINTF_NAME_FMT, opt_func_foo_printf_offset);
417 func_foo_printf_addr =
418 SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_printf_offset;
419 func_foo_tp_addr =
420 SO_LOW_ADDR + opt_func_foo_addr + opt_func_foo_tp_offset;
421
422 if (build_id_to_bin()) {
423 fprintf(stderr, "Failed to parse / missing build id\n");
03a71671
SM
424 status = EXIT_FAILURE;
425 goto end;
6ab5bdaa
AB
426 }
427
882adb99
MJ
428 plan_tests(NR_TESTS);
429
91bc8451 430 ret = bin_info_init(BT_LOG_OUTPUT_LEVEL, NULL);
4caab45b 431 ok(ret == 0, "bin_info_init successful");
6ab5bdaa 432
d5ddf820 433 test_bin_info_elf(opt_debug_info_dir);
882adb99 434 test_bin_info_bundled(opt_debug_info_dir);
d5ddf820
AB
435 test_bin_info_build_id(opt_debug_info_dir);
436 test_bin_info_debug_link(opt_debug_info_dir);
6ab5bdaa 437
03a71671
SM
438 status = EXIT_SUCCESS;
439
440end:
441 g_option_context_free(context);
442
443 return status;
6ab5bdaa 444}
This page took 0.083845 seconds and 4 git commands to generate.