+/* Size of PIC address mapping */
+#define SO_MEMSZ 0x800000
+/* An address outside the PIC mapping */
+#define SO_INV_ADDR 0x200000
+
+#define BUILD_ID_HEX_LEN 20
+
+static uint64_t opt_func_foo_addr;
+static uint64_t opt_func_foo_printf_offset;
+static uint64_t opt_func_foo_printf_line_no;
+static uint64_t opt_func_foo_tp_offset;
+static uint64_t opt_func_foo_tp_line_no;
+static uint64_t opt_debug_link_crc;
+static gchar *opt_build_id;
+static gchar *opt_debug_info_dir;
+
+static uint64_t func_foo_printf_addr;
+static uint64_t func_foo_tp_addr;
+static char func_foo_printf_name[FUNC_FOO_NAME_LEN];
+static uint8_t build_id[BUILD_ID_HEX_LEN];
+
+static GOptionEntry entries[] = {
+ {"foo-addr", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_addr,
+ "Offset to printf in foo", "0xX"},
+ {"printf-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_printf_offset,
+ "Offset to printf in foo", "0xX"},
+ {"printf-lineno", 0, 0, G_OPTION_ARG_INT64,
+ &opt_func_foo_printf_line_no, "Line number to printf in foo", "N"},
+ {"tp-offset", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_offset,
+ "Offset to tp in foo", "0xX"},
+ {"tp-lineno", 0, 0, G_OPTION_ARG_INT64, &opt_func_foo_tp_line_no,
+ "Line number to tp in foo", "N"},
+ {"debug-link-crc", 0, 0, G_OPTION_ARG_INT64, &opt_debug_link_crc,
+ "Debug link CRC", "0xX"},
+ {"build-id", 0, 0, G_OPTION_ARG_STRING, &opt_build_id, "Build ID",
+ "XXXXXXXXXXXXXXX"},
+ {"debug-info-dir", 0, 0, G_OPTION_ARG_STRING, &opt_debug_info_dir,
+ "Debug info directory", NULL},
+ {NULL}};
+
+static
+int build_id_to_bin(void)
+{
+ int ret, len, i;
+
+ if (opt_build_id == NULL) {
+ goto error;
+ }
+
+ len = strnlen(opt_build_id, BUILD_ID_HEX_LEN * 2);
+ if (len != (BUILD_ID_HEX_LEN * 2)) {
+ goto error;
+ }
+
+ for (i = 0; i < (len / 2); i++) {
+ ret = sscanf(opt_build_id + 2 * i, "%02hhx", &build_id[i]);
+ if (ret != 1) {
+ goto error;
+ }
+ }
+
+ if (i != BUILD_ID_HEX_LEN) {
+ goto error;
+ }
+
+ return 0;
+error:
+ return -1;
+}
+
+static
+void subtest_has_address(struct bin_info *bin, uint64_t addr)
+{
+ int ret;
+
+ ret = bin_info_has_address(bin, SO_LOW_ADDR - 1);
+ ok(ret == 0, "bin_info_has_address - address under SO's range");
+
+ ret = bin_info_has_address(bin, SO_LOW_ADDR);
+ ok(ret == 1, "bin_info_has_address - lower bound of SO's range");
+
+ ret = bin_info_has_address(bin, addr);
+ ok(ret == 1, "bin_info_has_address - address in SO's range");
+
+ ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ - 1);
+ ok(ret == 1, "bin_info_has_address - upper bound of SO's range");
+
+ ret = bin_info_has_address(bin, SO_LOW_ADDR + SO_MEMSZ);
+ ok(ret == 0, "bin_info_has_address - address above SO's range");
+}
+
+static
+void subtest_lookup_function_name(struct bin_info *bin, uint64_t addr,
+ char *func_name)
+{
+ int ret;
+ char *_func_name = NULL;
+
+ ret = bin_info_lookup_function_name(bin, addr, &_func_name);
+ ok(ret == 0, "bin_info_lookup_function_name successful at 0x%x", addr);
+ if (_func_name) {
+ ok(strcmp(_func_name, func_name) == 0,
+ "bin_info_lookup_function_name - correct function name (%s == %s)",
+ func_name, _func_name);
+ free(_func_name);
+ _func_name = NULL;
+ } else {
+ skip(1,
+ "bin_info_lookup_function_name - function name is NULL");
+ }
+
+ /* Test function name lookup - erroneous address */
+ ret = bin_info_lookup_function_name(bin, SO_INV_ADDR, &_func_name);
+ ok(ret == -1 && _func_name == NULL,
+ "bin_info_lookup_function_name - fail on invalid addr");
+ if (_func_name) {
+ free(_func_name);
+ }
+}
+
+static
+void subtest_lookup_source_location(struct bin_info *bin, uint64_t addr,
+ uint64_t line_no, char *filename)
+{
+ int ret;
+ struct source_location *src_loc = NULL;
+
+ ret = bin_info_lookup_source_location(bin, addr, &src_loc);
+ ok(ret == 0, "bin_info_lookup_source_location successful at 0x%x",
+ addr);
+ if (src_loc) {
+ ok(src_loc->line_no == line_no,
+ "bin_info_lookup_source_location - correct line_no (%d == %d)",
+ line_no, src_loc->line_no);
+ ok(strcmp(src_loc->filename, filename) == 0,
+ "bin_info_lookup_source_location - correct filename (%s == %s)",
+ filename, src_loc->filename);
+ source_location_destroy(src_loc);
+ src_loc = NULL;
+ } else {
+ fail("bin_info_lookup_source_location - src_loc is NULL");
+ fail("bin_info_lookup_source_location - src_loc is NULL");
+ }
+
+ /* Test source location lookup - erroneous address */
+ ret = bin_info_lookup_source_location(bin, SO_INV_ADDR, &src_loc);
+ ok(ret == -1 && src_loc == NULL,
+ "bin_info_lookup_source_location - fail on invalid addr");
+ if (src_loc) {
+ source_location_destroy(src_loc);
+ }
+}