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