From 29f056aa1e20a898cf3f3fabddf9b9c497b147c6 Mon Sep 17 00:00:00 2001 From: Kiko Fernandez-Reyes Date: Wed, 27 Nov 2024 16:22:45 +0100 Subject: [PATCH 1/3] otp: move gdb-tools outside of erlang/otp repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lukas Backström --- .github/dockerfiles/Dockerfile.32-bit | 1 + .github/dockerfiles/Dockerfile.clang | 1 + .github/dockerfiles/Dockerfile.cross-compile | 3 +- .github/dockerfiles/Dockerfile.debian-base | 2 +- .github/workflows/main.yaml | 2 +- erts/etc/common/Makefile.in | 14 +- erts/etc/unix/cerl.src | 34 +- erts/etc/unix/jit-reader.c | 386 ------------------- erts/etc/unix/jit-reader.h | 346 ----------------- make/gdb_tools_link | 1 + make/gdb_tools_vsn | 1 + otp_build | 192 ++++++++- 12 files changed, 225 insertions(+), 758 deletions(-) delete mode 100644 erts/etc/unix/jit-reader.c delete mode 100644 erts/etc/unix/jit-reader.h create mode 100644 make/gdb_tools_link create mode 100644 make/gdb_tools_vsn diff --git a/.github/dockerfiles/Dockerfile.32-bit b/.github/dockerfiles/Dockerfile.32-bit index d14144f74373..7c160515a518 100644 --- a/.github/dockerfiles/Dockerfile.32-bit +++ b/.github/dockerfiles/Dockerfile.32-bit @@ -18,6 +18,7 @@ ENV CFLAGS="-O2 -g -Werror -DwxSTC_DISABLE_MACRO_DEPRECATIONS=1" ## Configure, check that no application are disabled, then make and then build doc chunks RUN ./configure --with-ssl --prefix=/otp && \ if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi && \ + ./otp_build download_gdb_tools && \ make && make install ## Disable -Werror as testcases do not compile with it on diff --git a/.github/dockerfiles/Dockerfile.clang b/.github/dockerfiles/Dockerfile.clang index c35c5b358c21..ed632b4e4f4a 100644 --- a/.github/dockerfiles/Dockerfile.clang +++ b/.github/dockerfiles/Dockerfile.clang @@ -43,6 +43,7 @@ ENV CC=clang CXX=clang++ \ # give us this information such as gcc does... RUN ./configure --with-ssl --with-ssl-lib-subdir=lib/x86_64-linux-gnu --prefix=/otp && \ if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi && \ + ./otp_build download_gdb_tools && \ make && sudo make install && \ make FLAVOR=emu && sudo make install FLAVOR=emu diff --git a/.github/dockerfiles/Dockerfile.cross-compile b/.github/dockerfiles/Dockerfile.cross-compile index d76d333e95fa..ec73802ef189 100644 --- a/.github/dockerfiles/Dockerfile.cross-compile +++ b/.github/dockerfiles/Dockerfile.cross-compile @@ -59,6 +59,7 @@ WORKDIR /buildroot/otp # We cannot use config.guess for --build since its value clashes with the # canonical value of host... RUN ./configure --prefix=/otp/ --host=$HOST --build=x86-pc-linux-gnu && \ + ./otp_build download_gdb_tools && \ OTP_SMALL_BUILD=true V=1 make && \ make install @@ -70,7 +71,7 @@ RUN cd release/tests/test_server && \ -eval "ts:install([{cross,\"yes\"},{crossflags,[{\"host\",\"$HOST\"}]},{crossroot,\"/$ERL_TOP\"}])." \ -s ts compile_testcases -s init stop -FROM debian as install +FROM ghcr.io/erlang/otp/debian-base as install # Install the released application COPY --from=build /otp /otp diff --git a/.github/dockerfiles/Dockerfile.debian-base b/.github/dockerfiles/Dockerfile.debian-base index 578980a16f1d..52ff97409244 100644 --- a/.github/dockerfiles/Dockerfile.debian-base +++ b/.github/dockerfiles/Dockerfile.debian-base @@ -37,7 +37,7 @@ ENV CROSS_LIBS="$INSTALL_LIBS" ## 1. Install build-essential to get access to dpkg-architecture ## 2. Use dpkg-architecture to figure out what we are running on ## 3. If the HOST_TRIP does not equal BUILD_TRIP we should cross compile -RUN apt-get update && apt-get -y upgrade && apt-get install -y build-essential pkg-config && \ +RUN apt-get update && apt-get -y upgrade && apt-get install -y build-essential pkg-config git && \ BUILD_TRIP=`dpkg-architecture -t${HOST_TRIP} -qDEB_BUILD_MULTIARCH` && \ BUILD_ARCH=`dpkg-architecture -t${HOST_TRIP} -qDEB_BUILD_ARCH` && \ if [ "$HOST_TRIP" != "$BUILD_TRIP" ]; then \ diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 89c37c02283e..5314e8a5f515 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -522,7 +522,7 @@ jobs: -e EXTRA_ARGS="-ct_hooks cth_surefire [{path,\"/buildroot/otp/$DIR/make_test_dir/${{ matrix.type }}_junit.xml\"}]" \ -v "$PWD/make_test_dir:/buildroot/otp/$DIR/make_test_dir" \ -v "$PWD/scripts:/buildroot/otp/scripts" \ - otp "make TYPE=${TYPE} && make ${APP}_test TYPE=${TYPE}" + otp "./otp_build download_gdb_tools && make emulator && make TYPE=${TYPE} && make ${APP}_test TYPE=${TYPE}" ## Rename os_mon to debug for debug build if [ "$APP" != "${{ matrix.type }}" ]; then mv make_test_dir/${APP}_test "make_test_dir/${{ matrix.type }}_test" diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in index 42af9c87dca5..2778fb1504d9 100644 --- a/erts/etc/common/Makefile.in +++ b/erts/etc/common/Makefile.in @@ -107,6 +107,8 @@ ERTS_LIB = $(ERL_TOP)/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE EI_LIB = -L$(ERL_TOP)/lib/erl_interface/obj/$(TARGET) -lei $(THR_LIBS) +GDB_TOOLS = $(ETC)/gdb-tools + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -204,7 +206,7 @@ INSTALL_MISC = $(UXETC)/format_man_pages INSTALL_SRC = $(UXETC)/setuid_socket_wrap.c #delivered as an example ERLEXECDIR = . INSTALL_LIBS = -EXTRA_LIBS = $(BINDIR)/jit-reader.so +EXTRA_LIBS = INSTALL_OBJS = INSTALL_INCLUDES = TEXTFILES = Install erl.src @@ -215,15 +217,19 @@ INSTALL_PROGS = \ $(INSTALL_EMBEDDED_PROGS) endif +-include ../unix/gdb-tools/jit-reader.mk + CREATE_DIRS=$(OBJDIR) $(BINDIR) ifneq ($(strip $(CREATE_DIRS)),) _create_dirs := $(shell mkdir -p $(CREATE_DIRS)) endif +.DEFAULT_GOAL := etc .PHONY: etc etc: $(ENTRY_OBJ) $(INSTALL_PROGS) $(EXTRA_LIBS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BIN) + # erlexec needs the erts_internal library... $(ERTS_LIB): $(V_at)cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) @@ -500,12 +506,6 @@ $(BINDIR)/ct_run@EXEEXT@: $(OBJDIR)/ct_run.o $(ERTS_LIB) $(OBJDIR)/ct_run.o: ct_run.c $(RC_GENERATED) $(V_CC) $(CFLAGS) -o $@ -c ct_run.c -$(OBJDIR)/jit-reader.o: $(ETC)/jit-reader.c $(ETC)/jit-reader.h - $(V_CC) $(DED_CFLAGS) -I$(ETC) -o $@ -c $< - -$(BINDIR)/jit-reader.so: $(OBJDIR)/jit-reader.o - $(V_LD) $(DED_LDFLAGS) -o $@ $^ - Install: $(UXETC)/Install.src ../../vsn.mk $(TARGET)/Makefile $(vsn_verbose)sed -e 's;%I_VSN%;$(VSN);' \ -e 's;%EMULATOR%;$(EMULATOR);' \ diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src index 7b707a3345d5..5df77be5cbbb 100644 --- a/erts/etc/unix/cerl.src +++ b/erts/etc/unix/cerl.src @@ -54,6 +54,30 @@ # FIXME For GDB you can also set the break point using "-break FUNCTION". # FIXME For GDB you can also point out your own .gdbini...... +install_gdb_tools () +{ + if [ -z "$(find $ERL_TOP -name jit-reader.c)" ] + then + printf "%s" "Do you want to install gdb-tools? (Y/n) " + read -r confirm + case "$confirm" in + "Y"|"y"|"") + "$ERL_TOP"/otp_build download_gdb_tools + build_gdb_tools + ;; + esac + else + ## Check that correct version is present + "$ERL_TOP"/otp_build download_gdb_tools + build_gdb_tools + fi +} + +build_gdb_tools () +{ + (cd "$ERL_TOP"/erts/etc/common && make) +} + # These are marked for export export ROOTDIR export PROGNAME @@ -435,6 +459,9 @@ if [ "x$GDB" = "x" ]; then exec $EXEC $xargs ${1+"$@"} fi elif [ "x$GDB" = "xgdb" ]; then + + install_gdb_tools + case "x$core" in x) # Get emu args to use from erlexec... @@ -474,7 +501,9 @@ elif [ "x$GDB" = "xegdb" ]; then if [ "x$EMACS" = "x" ]; then EMACS=emacs fi - + + install_gdb_utils + case "x$core" in x) # Get emu args to use from erlexec... @@ -513,6 +542,9 @@ elif [ "x$GDB" = "xegdb" ]; then EVAL="(progn (gdb \"gdb $GDBARGS -x $cmdfile\"))" exec $EMACS --eval "$EVAL" elif [ "x$GDB" = "xdump" ]; then + + install_gdb_tools + cmdfile="/tmp/.cerlgdb.$$" ## Examine the result of "file $core" in case it is not the emulator ## that created the dump diff --git a/erts/etc/unix/jit-reader.c b/erts/etc/unix/jit-reader.c deleted file mode 100644 index 50005a1242a1..000000000000 --- a/erts/etc/unix/jit-reader.c +++ /dev/null @@ -1,386 +0,0 @@ -#include "jit-reader.h" - -#include -#include -#include -#include - -/* Useful links - * - https://pwparchive.wordpress.com/2011/11/20/new-jit-interface-for-gdb/ - * - https://sourceware.org/gdb/current/onlinedocs/gdb/Custom-Debug-Info.html - * - https://github.com/tetzank/asmjit-utilities - * - https://github.com/bminor/binutils-gdb/blob/master/gdb/testsuite/gdb.base/jitreader.c - */ - -GDB_DECLARE_GPL_COMPATIBLE_READER - -#if 0 -#define HARD_DEBUG -static FILE *log = NULL; -#define LOG(...) do { fprintf(log, ##__VA_ARGS__); fflush(log); } while(0) -#else -#define LOG(...) -#endif - -typedef enum { - X64_RBP = 6, /* Frame pointer iff native frames are enabled */ - X64_RSP = 7, /* Stack pointer when using native stack */ - X64_R12 = 12, /* Stack pointer when using non-native stack */ - X64_R13 = 13, /* Current process */ - X64_RIP = 16 -} X64Register; - -typedef enum { - /* Return address only */ - ERTS_FRAME_LAYOUT_RA, - /* Frame pointer, return address */ - ERTS_FRAME_LAYOUT_FP_RA -} ErtsFrameLayout; - -struct emulator_info { - /* 0 = regular, 1 = frame pointers */ - int frame_layout; - const void *normal_exit; -}; - -struct erlang_module_info { - uint64_t base_address; - uint32_t range_count; - uint32_t code_size; - /* Module name, including null terminator. */ - uint16_t name_length; - char name[]; - /* array of range_info structures */ -}; - -struct range_info { - uint32_t start_offset; - uint32_t end_offset; - uint32_t line_count; - /* Range name, including null terminator. */ - uint16_t name_length; - char name[]; - /* array of line_info structures */ -}; - -struct line_info { - uint32_t start_offset; - uint32_t line_number; - /* File name, including null terminator. */ - uint16_t file_length; - char file[]; -}; - -enum debug_info_header { - DEBUG_INFO_HEADER_EMULATOR = 0, - DEBUG_INFO_HEADER_MODULE = 1, -}; - -struct debug_info { - enum debug_info_header header; - union { - struct emulator_info emu; - struct erlang_module_info mod; - } payload; -}; - -typedef struct range { - GDB_CORE_ADDR start; - GDB_CORE_ADDR end; -#ifdef HARD_DEBUG - char *name; -#endif -} range; - -typedef struct priv { - range *ranges; - int num_ranges; - ErtsFrameLayout frame_layout; - const void *normal_exit; -} priv; - -static enum gdb_status read_module_info(struct gdb_reader_funcs *self, - struct gdb_symbol_callbacks *cb, - struct erlang_module_info *module_info) { - struct gdb_object *obj = cb->object_open(cb); - GDB_CORE_ADDR mod_start, mod_end; - char *symfile = (char*)module_info; - priv *priv = self->priv_data; - - symfile += sizeof(*module_info) + module_info->name_length; - - mod_start = module_info->base_address; - mod_end = mod_start + module_info->code_size; - - priv->ranges = realloc(priv->ranges, (priv->num_ranges + 1) * sizeof(range)); - priv->ranges[priv->num_ranges].start = mod_start; - priv->ranges[priv->num_ranges].end = mod_end; -#ifdef HARD_DEBUG - priv->ranges[priv->num_ranges].name = strdup(module_info->name); -#endif - priv->num_ranges += 1; - - LOG("Add module `%s` (0x%lx, 0x%lx)\r\n", - module_info->name, mod_start, mod_end); - - for (int range = 0; range < module_info->range_count; range++) { - struct range_info *range_info; - struct gdb_symtab *symtab; - GDB_CORE_ADDR begin, end; - - range_info = (struct range_info *)symfile; - symfile += sizeof(*range_info) + range_info->name_length; - - begin = mod_start + range_info->start_offset; - end = mod_start + range_info->end_offset; - - LOG("Add range `%s` (0x%lx, 0x%lx), %u lines\r\n", - range_info->name, - begin, end, - range_info->line_count); - - /* A bug in GDB < 9 forces us to open and close the symtab for each - * iteration. */ - symtab = cb->symtab_open(cb, obj, module_info->name); - cb->block_open(cb, symtab, NULL, begin, end, range_info->name); - cb->symtab_close(cb, symtab); - - for (int line = 0; line < range_info->line_count; line++) { - struct gdb_line_mapping line_mapping; - struct line_info *line_info; - - line_info = (struct line_info *)symfile; - symfile += sizeof(*line_info) + line_info->file_length; - - line_mapping.pc = mod_start + line_info->start_offset; - line_mapping.line = line_info->line_number; - - LOG("\t%s:%u\r\n", line_info->file, line_info->line_number); - - /* The symbol table must be opened and closed on every single line - * for file names to work properly, as there is no other way to - * tell GDB that a certain line belongs to a different file than - * the rest of the table. Sigh. */ - symtab = cb->symtab_open(cb, obj, line_info->file); - - cb->block_open(cb, symtab, NULL, line_mapping.pc, end, - range_info->name); - cb->line_mapping_add(cb, symtab, 1, &line_mapping); - cb->symtab_close(cb, symtab); - } - } - - cb->object_close(cb, obj); - - return GDB_SUCCESS; -} - -static enum gdb_status read_emulator_info(struct gdb_reader_funcs *self, - struct gdb_symbol_callbacks *cb, - struct emulator_info *emulator_info) { - priv *priv = self->priv_data; - - priv->frame_layout = emulator_info->frame_layout; - priv->normal_exit = emulator_info->normal_exit; - - LOG("initialize: frame layout = %i\r\n", priv->frame_layout); - - return GDB_SUCCESS; -} - -static enum gdb_status read_debug_info(struct gdb_reader_funcs *self, - struct gdb_symbol_callbacks *cb, - void *memory, long memory_sz) { - struct debug_info *debug_info = memory; - - (void)memory_sz; - - switch (debug_info->header) { - case DEBUG_INFO_HEADER_EMULATOR: - return read_emulator_info(self, cb, &debug_info->payload.emu); - case DEBUG_INFO_HEADER_MODULE: - return read_module_info(self, cb, &debug_info->payload.mod); - } - - return GDB_FAIL; -} - -static void regfree(struct gdb_reg_value *reg) { - free(reg); -} - -static struct range *get_range(priv *priv, GDB_CORE_ADDR rip) { - for (int i = 0; i < priv->num_ranges; i++) { - if (rip >= priv->ranges[i].start && rip < priv->ranges[i].end) { - return &priv->ranges[i]; - } - } - - return NULL; -} - -static enum gdb_status unwind(struct gdb_reader_funcs *self, - struct gdb_unwind_callbacks *cb) { - GDB_CORE_ADDR rbp, rsp, rip; - struct range *range; - priv *priv; - - rbp = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RBP)->value; - rsp = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RSP)->value; - rip = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RIP)->value; - - priv = self->priv_data; - range = get_range(priv, rip); - - /* Check that rip points to one of the addresses that we handle */ - if (range) { - struct gdb_reg_value *prev_rbp, *prev_rsp, *prev_rip; - - prev_rbp = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)); - prev_rsp = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)); - prev_rip = malloc(sizeof(struct gdb_reg_value) + sizeof(char*)); - - LOG("UNWIND match %s: rbp: 0x%lx rsp: 0x%lx rip: 0x%lx \r\n", - range->name, rbp, rsp, rip); - - prev_rbp->free = ®free; - prev_rbp->defined = 1; - prev_rbp->size = sizeof(char*); - prev_rsp->free = ®free; - prev_rsp->defined = 1; - prev_rsp->size = sizeof(char*); - prev_rip->free = ®free; - prev_rip->defined = 1; - prev_rip->size = sizeof(char*); - - if (priv->frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { - /* Frame pointers are enabled, which means that rbp will point to - * where we stored the previous frames rbp. Also the previous - * frames address will be at rbp + 8 and the previous frames rsp - * will be rbp + 16. - * - * 0x00: <- prev_rsp - * 0x08: prev call addr - * 0x10: prev rbp <- curr rbp - * 0x18: current frame - * 0x20: <- curr rip */ - cb->target_read(rbp + 1 * sizeof(char*), &prev_rip->value, - sizeof(char*)); - cb->target_read(rbp + 0 * sizeof(char*), &prev_rbp->value, - sizeof(char*)); - *(GDB_CORE_ADDR*)prev_rsp->value = rbp + sizeof(char*[2]); - } else { - /* Normal frame layout, we need to scan the stack. */ - cb->target_read(rsp, &prev_rip->value, sizeof(char*)); - - for (rsp += sizeof(char*); ; rsp += sizeof(char*)) { - cb->target_read(rsp, &prev_rip->value, sizeof(char*)); - - LOG("rsp: 0x%lx rip: 0x%lx\r\n", - rsp, *(GDB_CORE_ADDR*)prev_rip->value); - - /* Check if it is a cp */ - if ((*(GDB_CORE_ADDR*)prev_rip->value & 0x3) == 0) { - break; - } - } - - *(GDB_CORE_ADDR*)prev_rsp->value = rsp; - *(GDB_CORE_ADDR*)prev_rbp->value = rsp - sizeof(char*); - } - - if (*(GDB_CORE_ADDR*)prev_rip->value == (uintptr_t)priv->normal_exit) { - LOG("Normal exit\r\n"); - *(GDB_CORE_ADDR*)prev_rsp->value = 0; - *(GDB_CORE_ADDR*)prev_rbp->value = 0; - } else { - LOG("UNWIND prev: rbp: 0x%lx rsp: 0x%lx rip: 0x%lx\r\n", - *(GDB_CORE_ADDR*)prev_rbp->value, - *(GDB_CORE_ADDR*)prev_rsp->value, - *(GDB_CORE_ADDR*)prev_rip->value); - } - - cb->reg_set(cb, X64_RIP, prev_rip); - cb->reg_set(cb, X64_RSP, prev_rsp); - cb->reg_set(cb, X64_RBP, prev_rbp); - - return GDB_SUCCESS; - } - - LOG("UNWIND no match: rbp: 0x%lx rsp: 0x%lx rip: 0x%lx\r\n", rbp, rsp, rip); - return GDB_FAIL; -} - -static struct gdb_frame_id get_frame_id(struct gdb_reader_funcs *self, - struct gdb_unwind_callbacks *cb){ - struct gdb_frame_id frame = {0, 0}; - GDB_CORE_ADDR rbp, rsp, rip; - struct range *range; - priv *priv; - - rbp = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RBP)->value; - rsp = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RSP)->value; - rip = *(GDB_CORE_ADDR*)cb->reg_get(cb, X64_RIP)->value; - - priv = self->priv_data; - range = get_range(priv, rip); - - LOG("FRAME: rip: 0x%lx rsp: 0x%lx rbp: 0x%lx \r\n", rip, rsp, rbp); - - if (range) { - frame.code_address = rip; - - if (priv->frame_layout == ERTS_FRAME_LAYOUT_FP_RA) { - frame.stack_address = rbp + sizeof(char*); - } else { - GDB_CORE_ADDR prev_rip; - - for (rsp += sizeof(char*); ; rsp += sizeof(char*)) { - cb->target_read(rsp, &prev_rip, sizeof(char*)); - - LOG("rsp: 0x%lx rip: 0x%lx\r\n", rsp, prev_rip); - - /* Check if it is a cp */ - if ((prev_rip & 0x3) == 0) { - break; - } - } - - frame.stack_address = rsp; - } - } - - LOG("FRAME: code_address: 0x%lx stack_address: 0x%lx\r\n", - frame.code_address, frame.stack_address); - - return frame; -} - -static void destroy(struct gdb_reader_funcs *self){ - free(self); -} - -struct gdb_reader_funcs *gdb_init_reader(void){ - struct gdb_reader_funcs *funcs = malloc(sizeof(struct gdb_reader_funcs)); - priv *priv_data = malloc(sizeof(priv)); - - priv_data->num_ranges = 1; - priv_data->ranges = malloc(sizeof(range)); - priv_data->ranges[0].start = 0; - priv_data->ranges[0].end = 0; - - funcs->reader_version = GDB_READER_INTERFACE_VERSION; - funcs->priv_data = priv_data; - - funcs->read = read_debug_info; - funcs->unwind = unwind; - funcs->get_frame_id = get_frame_id; - funcs->destroy = destroy; - -#ifdef HARD_DEBUG - log = fopen("/tmp/jit-reader.log","w+"); - if (!log) fprintf(stderr,"Could not open /tmp/jit-reader.log"); -#endif - - return funcs; -} diff --git a/erts/etc/unix/jit-reader.h b/erts/etc/unix/jit-reader.h deleted file mode 100644 index 28013858d5e3..000000000000 --- a/erts/etc/unix/jit-reader.h +++ /dev/null @@ -1,346 +0,0 @@ -/* JIT declarations for GDB, the GNU Debugger. - - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#ifndef GDB_JIT_READER_H -#define GDB_JIT_READER_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Versioning information. See gdb_reader_funcs. */ - -#define GDB_READER_INTERFACE_VERSION 1 - -/* Readers must be released under a GPL compatible license. To - declare that the reader is indeed released under a GPL compatible - license, invoke the macro GDB_DECLARE_GPL_COMPATIBLE in a source - file. */ - -#ifdef __cplusplus -#define GDB_DECLARE_GPL_COMPATIBLE_READER \ - extern "C" { \ - extern int plugin_is_GPL_compatible (void); \ - extern int plugin_is_GPL_compatible (void) \ - { \ - return 0; \ - } \ - } - -#else - -#define GDB_DECLARE_GPL_COMPATIBLE_READER \ - extern int plugin_is_GPL_compatible (void); \ - extern int plugin_is_GPL_compatible (void) \ - { \ - return 0; \ - } - -#endif - -/* Represents an address on the target system. */ - -typedef unsigned long GDB_CORE_ADDR; - -/* Return status codes. */ - -enum gdb_status { - GDB_FAIL = 0, - GDB_SUCCESS = 1 -}; - -struct gdb_object; -struct gdb_symtab; -struct gdb_block; -struct gdb_symbol_callbacks; - -/* An array of these are used to represent a map from code addresses to line - numbers in the source file. */ - -struct gdb_line_mapping -{ - int line; - GDB_CORE_ADDR pc; -}; - -/* Create a new GDB code object. Each code object can have one or - more symbol tables, each representing a compiled source file. */ - -typedef struct gdb_object *(gdb_object_open) (struct gdb_symbol_callbacks *cb); - -/* The callback used to create new symbol table. CB is the - gdb_symbol_callbacks which the structure is part of. FILE_NAME is - an (optionally NULL) file name to associate with this new symbol - table. - - Returns a new instance to gdb_symtab that can later be passed to - gdb_block_new, gdb_symtab_add_line_mapping and gdb_symtab_close. */ - -typedef struct gdb_symtab *(gdb_symtab_open) (struct gdb_symbol_callbacks *cb, - struct gdb_object *obj, - const char *file_name); - -/* Creates a new block in a given symbol table. A symbol table is a - forest of blocks, each block representing an code address range and - a corresponding (optionally NULL) NAME. In case the block - corresponds to a function, the NAME passed should be the name of - the function. - - If the new block to be created is a child of (i.e. is nested in) - another block, the parent block can be passed in PARENT. SYMTAB is - the symbol table the new block is to belong in. BEGIN, END is the - code address range the block corresponds to. - - Returns a new instance of gdb_block, which, as of now, has no use. - Note that the gdb_block returned must not be freed by the - caller. */ - -typedef struct gdb_block *(gdb_block_open) (struct gdb_symbol_callbacks *cb, - struct gdb_symtab *symtab, - struct gdb_block *parent, - GDB_CORE_ADDR begin, - GDB_CORE_ADDR end, - const char *name); - -/* Adds a PC to line number mapping for the symbol table SYMTAB. - NLINES is the number of elements in LINES, each element - corresponding to one (PC, line) pair. */ - -typedef void (gdb_symtab_add_line_mapping) (struct gdb_symbol_callbacks *cb, - struct gdb_symtab *symtab, - int nlines, - struct gdb_line_mapping *lines); - -/* Close the symtab SYMTAB. This signals to GDB that no more blocks - will be opened on this symtab. */ - -typedef void (gdb_symtab_close) (struct gdb_symbol_callbacks *cb, - struct gdb_symtab *symtab); - - -/* Closes the gdb_object OBJ and adds the emitted information into - GDB's internal structures. Once this is done, the debug - information will be picked up and used; this will usually be the - last operation in gdb_read_debug_info. */ - -typedef void (gdb_object_close) (struct gdb_symbol_callbacks *cb, - struct gdb_object *obj); - -/* Reads LEN bytes from TARGET_MEM in the target's virtual address - space into GDB_BUF. - - Returns GDB_FAIL on failure, and GDB_SUCCESS on success. */ - -typedef enum gdb_status (gdb_target_read) (GDB_CORE_ADDR target_mem, - void *gdb_buf, int len); - -/* The list of callbacks that are passed to read. These callbacks are - to be used to construct the symbol table. The functions have been - described above. */ - -struct gdb_symbol_callbacks -{ - gdb_object_open *object_open; - gdb_symtab_open *symtab_open; - gdb_block_open *block_open; - gdb_symtab_close *symtab_close; - gdb_object_close *object_close; - - gdb_symtab_add_line_mapping *line_mapping_add; - gdb_target_read *target_read; - - /* For internal use by GDB. */ - void *priv_data; -}; - -/* Forward declaration. */ - -struct gdb_reg_value; - -/* A function of this type is used to free a gdb_reg_value. See the - comment on `free' in struct gdb_reg_value. */ - -typedef void (gdb_reg_value_free) (struct gdb_reg_value *); - -/* Denotes the value of a register. */ - -struct gdb_reg_value -{ - /* The size of the register in bytes. The reader need not set this - field. This will be set for (defined) register values being read - from GDB using reg_get. */ - int size; - - /* Set to non-zero if the value for the register is known. The - registers for which the reader does not call reg_set are also - assumed to be undefined */ - int defined; - - /* Since gdb_reg_value is a variable sized structure, it will - usually be allocated on the heap. This function is expected to - contain the corresponding "free" function. - - When a pointer to gdb_reg_value is being sent from GDB to the - reader (via gdb_unwind_reg_get), the reader is expected to call - this function (with the same gdb_reg_value as argument) once it - is done with the value. - - When the function sends the a gdb_reg_value to GDB (via - gdb_unwind_reg_set), it is expected to set this field to point to - an appropriate cleanup routine (or to NULL if no cleanup is - required). */ - gdb_reg_value_free *free; - - /* The value of the register. */ - unsigned char value[1]; -}; - -/* get_frame_id in gdb_reader_funcs is to return a gdb_frame_id - corresponding to the current frame. The registers corresponding to - the current frame can be read using reg_get. Calling get_frame_id - on a particular frame should return the same gdb_frame_id - throughout its lifetime (i.e. till before it gets unwound). One - way to do this is by having the CODE_ADDRESS point to the - function's first instruction and STACK_ADDRESS point to the value - of the stack pointer when entering the function. */ - -struct gdb_frame_id -{ - GDB_CORE_ADDR code_address; - GDB_CORE_ADDR stack_address; -}; - -/* Forward declaration. */ - -struct gdb_unwind_callbacks; - -/* Returns the value of a particular register in the current frame. - The current frame is the frame that needs to be unwound into the - outer (earlier) frame. - - CB is the struct gdb_unwind_callbacks * the callback belongs to. - REGNUM is the DWARF register number of the register that needs to - be unwound. - - Returns the gdb_reg_value corresponding to the register requested. - In case the value of the register has been optimized away or - otherwise unavailable, the defined flag in the returned - gdb_reg_value will be zero. */ - -typedef struct gdb_reg_value *(gdb_unwind_reg_get) - (struct gdb_unwind_callbacks *cb, int regnum); - -/* Sets the previous value of a particular register. REGNUM is the - (DWARF) register number whose value is to be set. VAL is the value - the register is to be set to. - - VAL is *not* copied, so the memory allocated to it cannot be - reused. Once GDB no longer needs the value, it is deallocated - using the FREE function (see gdb_reg_value). - - A register can also be "set" to an undefined value by setting the - defined in VAL to zero. */ - -typedef void (gdb_unwind_reg_set) (struct gdb_unwind_callbacks *cb, int regnum, - struct gdb_reg_value *val); - -/* This struct is passed to unwind in gdb_reader_funcs, and is to be - used to unwind the current frame (current being the frame whose - registers can be read using reg_get) into the earlier frame. The - functions have been described above. */ - -struct gdb_unwind_callbacks -{ - gdb_unwind_reg_get *reg_get; - gdb_unwind_reg_set *reg_set; - gdb_target_read *target_read; - - /* For internal use by GDB. */ - void *priv_data; -}; - -/* Forward declaration. */ - -struct gdb_reader_funcs; - -/* Parse the debug info off a block of memory, pointed to by MEMORY - (already copied to GDB's address space) and MEMORY_SZ bytes long. - The implementation has to use the functions in CB to actually emit - the parsed data into GDB. SELF is the same structure returned by - gdb_init_reader. - - Return GDB_FAIL on failure and GDB_SUCCESS on success. */ - -typedef enum gdb_status (gdb_read_debug_info) (struct gdb_reader_funcs *self, - struct gdb_symbol_callbacks *cb, - void *memory, long memory_sz); - -/* Unwind the current frame, CB is the set of unwind callbacks that - are to be used to do this. - - Return GDB_FAIL on failure and GDB_SUCCESS on success. */ - -typedef enum gdb_status (gdb_unwind_frame) (struct gdb_reader_funcs *self, - struct gdb_unwind_callbacks *cb); - -/* Return the frame ID corresponding to the current frame, using C to - read the current register values. See the comment on struct - gdb_frame_id. */ - -typedef struct gdb_frame_id (gdb_get_frame_id) (struct gdb_reader_funcs *self, - struct gdb_unwind_callbacks *c); - -/* Called when a reader is being unloaded. This function should also - free SELF, if required. */ - -typedef void (gdb_destroy_reader) (struct gdb_reader_funcs *self); - -/* Called when the reader is loaded. Must either return a properly - populated gdb_reader_funcs or NULL. The memory allocated for the - gdb_reader_funcs is to be managed by the reader itself (i.e. if it - is allocated from the heap, it must also be freed in - gdb_destroy_reader). */ - -extern struct gdb_reader_funcs *gdb_init_reader (void); - -/* Pointer to the functions which implement the reader's - functionality. The individual functions have been documented - above. - - None of the fields are optional. */ - -struct gdb_reader_funcs -{ - /* Must be set to GDB_READER_INTERFACE_VERSION. */ - int reader_version; - - /* For use by the reader. */ - void *priv_data; - - gdb_read_debug_info *read; - gdb_unwind_frame *unwind; - gdb_get_frame_id *get_frame_id; - gdb_destroy_reader *destroy; -}; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/make/gdb_tools_link b/make/gdb_tools_link new file mode 100644 index 000000000000..83c610f1e904 --- /dev/null +++ b/make/gdb_tools_link @@ -0,0 +1 @@ +https://github.com/erlang/otp-gdb-tools diff --git a/make/gdb_tools_vsn b/make/gdb_tools_vsn new file mode 100644 index 000000000000..7d5467acce17 --- /dev/null +++ b/make/gdb_tools_vsn @@ -0,0 +1 @@ +7b864f58c534699e4124e31ecfda86041b941037 diff --git a/otp_build b/otp_build index fbb8f42f2a94..622ef30bf0b0 100755 --- a/otp_build +++ b/otp_build @@ -73,6 +73,10 @@ usage () echo " download_ex_doc - download the correct ExDoc version from github" echo " update_ex_doc [--no-commit] - update and maybe commit new ex_doc version" echo "" + echo "Special targets for setting up gdb tooling:" + echo " download_gdb_tools - download the correct gdb tooling version from github" + echo " update_gdb_tools [--no-commit] - update and maybe commit new gdb tooling version" + echo "" echo "Special targets for Windows(tm) build:" echo " debuginfo_win32 - adds debug emulator and pdb files to " echo " installer_win32 - creates a windows installer from " @@ -1012,30 +1016,184 @@ do_check () do_download_ex_doc () { + SHASUM_FORMAT= + ## Download ex_doc and place in $ERL_TOP/bin folder curl -s -L "$(cat "$ERL_TOP/make/ex_doc_link")" > "$ERL_TOP/bin/ex_doc" chmod +x "$ERL_TOP/bin/ex_doc" - if command -v sha256sum > /dev/null; then - if ! (cd "$ERL_TOP/make" && sha256sum --status -c "ex_doc.sha256sum"); then - echo "The sha256sum check of $ERL_TOP/bin/ex_doc failed!" >&2 + + choose_available_shasum # sets the SHASUM_FORMAT + check_shasum "ex_doc" "$ERL_TOP/bin" "$ERL_TOP/make" + + echo "Downloaded ex_doc to $ERL_TOP/bin/ex_doc" +} + +do_download_gdb_tools () +{ + set_common_vars + + if [ ! -d "$GDB_TOOLS_INSTALL_PATH" ] + then + clone_gdb_tools + fi + + cwd=$(pwd); + + cd "$GDB_TOOLS_INSTALL_PATH" || exit 1 + + CURRENT_GDB_VERSION=$(git log HEAD --oneline --no-abbrev-commit -n1 | cut -d" " -f1) + + if [ "$CURRENT_GDB_VERSION" != "$GDB_TOOLS_VSN" ]; then + echo "Setting up gdb_tools" + git fetch gdb_tools > /dev/null || exit 1 + git checkout "$GDB_TOOLS_VSN" > /dev/null || exit 1 + else + exit 0 + fi + + cd "$cwd" || exit 1 + + echo "Downloaded gdb-tools for Erlang/OTP $OTP_VERSION" + + exit 0 +} + +set_common_vars() { + GDB_TOOLS_INSTALL_PATH="$ERL_TOP/erts/etc/unix/gdb-tools" + GDB_TOOLS_VSN_PATH="$ERL_TOP/make" + GDB_REPO=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_link") + + # Version of gdb-tools to download + GDB_TOOLS_VSN=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_vsn") + + # SHASUM_FORMAT has values: sha256sum, sha1sum, shasum + SHASUM_FORMAT= + + OTP_VERSION= + set_otp_version +} + +clone_gdb_tools () +{ + echo "Downloading gdb-tools for Erlang/OTP $OTP_VERSION" + echo "git clone --origin gdb_tools $GDB_REPO $GDB_TOOLS_INSTALL_PATH" + (git clone --origin gdb_tools "$GDB_REPO" "$GDB_TOOLS_INSTALL_PATH" > /dev/null 2>&1) || { + echo "Downloading gdb_tools failed. Please check your source tree, and report this error." + exit 1 + } +} + +clean_file () +{ + rm -rf "$1" +} + +set_otp_version () +{ + OTP_VERSION=$(cat $ERL_TOP/OTP_VERSION | cut -d. -f1) + if [ $OTP_VERSION -le 24 ] + then + echo "OTP version $OTP_VERSION is too old. Please update to a newer OTP version" + exit 1 + fi +} + +do_update_gdb_tools () +{ + get_do_commit $1 + set_common_vars + + if [ $do_commit = true ] && test -n "$(git status --porcelain --untracked-files=no)" + then + echo "'otp_build update_gdb_tools' will create a commit." + echo "Git's working directory is not clean." + echo "Please stash or commit the working directory before proceeding." + exit 1 + fi + + + if grep "rc" "$ERL_TOP/OTP_VERSION" > /dev/null + then + if [ -d "$GDB_TOOLS_INSTALL_PATH" ] + then + cd "$GDB_TOOLS_INSTALL_PATH" && \ + git fetch $GDB_REPO && \ + GDB_TOOLS_VSN=$(git log gdb_tools/master --oneline --no-abbrev-commit -n1 | cut -d" " -f1) && \ + echo "$GDB_TOOLS_VSN" > "$ERL_TOP/make/gdb_tools_vsn" + else + echo "Please, download gdb_tools invoking the command: \`otp_build download_gdb_tools\`" exit 1 fi + else + echo "Please look in repo: $GDB_REPO the commit sha you are interested." + echo "Copy that commit into $ERL_TOP/make/gdb_tools_vsn and run \`otp_build download_gdb_tools\`" + exit 1 + fi + + out_files= # why is this needed. it was needed for elixir + + echo "Successfully updated gdb_tools" + if [ $do_commit != true ]; then + echo "Updated: make/gdb_tools_vsn make/jit-reader.c.sha256sum" + else + set_common_vars + git add "$ERL_TOP/make/gdb_tools_vsn" \ + "$GDB_TOOLS_VSN_PATH/jit-reader.c.sha256sum" \ + "$GDB_TOOLS_VSN_PATH/jit-reader.h.sha256sum" > /dev/null + git commit -m "Updated gdb_tools version to $GDB_TOOLS_VSN" > /dev/null + fi + echo "Run \`otp_build download_gdb_tools\` to complete the installation of the update" +} + +# $1: jit-reader.c, jit-reader.h, etc +# $2: DGB_TOOLS_VSN, e.g., maint-28, foo, etc it is guaranteed to be an existing branch +# that lives in "$ERL_TOP/make/$1.$SHASUM_FORMAT" +create_shasum_file() { + cat "$GDB_TOOLS_INSTALL_PATH/$1.$SHASUM_FORMAT" > "$GDB_TOOLS_VSN_PATH/$1.$SHASUM_FORMAT" + echo "$GDB_TOOLS_VSN" > "$ERL_TOP/make/gdb_tools_vsn" +} + +choose_available_shasum () +{ + if command -v sha256sum > /dev/null; then + SHASUM_FORMAT="sha256sum" elif command -v sha1sum > /dev/null; then - if ! (cd "$ERL_TOP/make" && sha1sum --status -c "ex_doc.sha1sum"); then - echo "The sha1sum check of $ERL_TOP/bin/ex_doc failed!" >&2 - exit 1 - fi + SHASUM_FORMAT="sha1sum" elif command -v shasum > /dev/null; then - if ! (cd "$ERL_TOP/make" && shasum -a 1 --status -c "ex_doc.sha1sum"); then - echo "The shasum check of $ERL_TOP/bin/ex_doc failed!" >&2 - exit 1 - fi + # shasum produces the same sha as sha1sum. + SHASUM_FORMAT="sha1sum" else - echo "Neither sha1sum nor sha256sum nor shasum found to verify $ERL_TOP/bin/ex_doc" >&2 - echo "Please check manually that the correct ex_doc was downloaded." >&2 + echo "Neither sha1sum nor sha256sum nor shasum found" >&2 exit 1 fi - echo "Downloaded ex_doc to $ERL_TOP/bin/ex_doc" +} + +# $1: expected file, +# e.g., `jit-reader.c`, `ex_doc` +# $2: path to expeted file, +# e.g., `$ERL_TOP/bin`, which is where `ex_doc` is found. +# makes easy to find errors in the path. +# $3: path where shasum lives +# e.g., `$ERL_TOP/make` in case of sha256sum and sha1sum files. +check_shasum() +{ + case $SHASUM_FORMAT in + "sha256sum" ) + if ! (cd "$3" && sha256sum --status -c "$1.$SHASUM_FORMAT"); then + echo "The sha256sum check of $2/$1 failed!" >&2 + exit 1 + fi;; + "sha1sum" ) + if ! (cd "$3" && sha1sum --status -c "$1.$SHASUM_FORMAT"); then + echo "The sha1sum check of $2/$1 failed!" >&2 + exit 1 + fi;; + "shasum" ) + if ! (cd "$3" && shasum -a 1 --status -c "$1.$SHASUM_FORMAT"); then + echo "The shasum check of $2/$1 failed!" >&2 + exit 1 + fi + esac } ## Update make/ex_doc_link, make/ex_doc.sha256sum and make/ex_doc.sha1sum @@ -1334,10 +1492,14 @@ case "$1" in do_save_bootstrap;; copy_primary_bootstrap) do_copy_primary_bootstrap $2 $3;; + download_gdb_tools) + do_download_gdb_tools;; + update_gdb_tools) + do_update_gdb_tools $2;; download_ex_doc) do_download_ex_doc;; update_ex_doc) - do_update_ex_doc;; + do_update_ex_doc $2;; installer_win32) if [ $minus_x_flag = true ]; then shift From 5da77bec0f15840d7ac19f7be2d9dfc77ee386c2 Mon Sep 17 00:00:00 2001 From: Kiko Fernandez-Reyes Date: Fri, 13 Dec 2024 10:30:43 +0100 Subject: [PATCH 2/3] otp: add license and remove unused function --- make/gdb_tools_link | 2 ++ make/gdb_tools_vsn | 2 ++ otp_build | 18 +++++++----------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/make/gdb_tools_link b/make/gdb_tools_link index 83c610f1e904..e0afd40ab599 100644 --- a/make/gdb_tools_link +++ b/make/gdb_tools_link @@ -1 +1,3 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2024 Ericsson and the Erlang/OTP contributors https://github.com/erlang/otp-gdb-tools diff --git a/make/gdb_tools_vsn b/make/gdb_tools_vsn index 7d5467acce17..078a0667bcc5 100644 --- a/make/gdb_tools_vsn +++ b/make/gdb_tools_vsn @@ -1 +1,3 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2024 Ericsson and the Erlang/OTP contributors 7b864f58c534699e4124e31ecfda86041b941037 diff --git a/otp_build b/otp_build index 622ef30bf0b0..47803a09ed86 100755 --- a/otp_build +++ b/otp_build @@ -1061,10 +1061,10 @@ do_download_gdb_tools () set_common_vars() { GDB_TOOLS_INSTALL_PATH="$ERL_TOP/erts/etc/unix/gdb-tools" GDB_TOOLS_VSN_PATH="$ERL_TOP/make" - GDB_REPO=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_link") + GDB_REPO=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_link" | tail -n1) # Version of gdb-tools to download - GDB_TOOLS_VSN=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_vsn") + GDB_TOOLS_VSN=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_vsn" | tail -n1) # SHASUM_FORMAT has values: sha256sum, sha1sum, shasum SHASUM_FORMAT= @@ -1119,7 +1119,11 @@ do_update_gdb_tools () cd "$GDB_TOOLS_INSTALL_PATH" && \ git fetch $GDB_REPO && \ GDB_TOOLS_VSN=$(git log gdb_tools/master --oneline --no-abbrev-commit -n1 | cut -d" " -f1) && \ - echo "$GDB_TOOLS_VSN" > "$ERL_TOP/make/gdb_tools_vsn" + cat < "$ERL_TOP/make/gdb_tools_vsn" +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2024 Ericsson and the Erlang/OTP contributors +$GDB_TOOLS_VSN +EOF else echo "Please, download gdb_tools invoking the command: \`otp_build download_gdb_tools\`" exit 1 @@ -1145,14 +1149,6 @@ do_update_gdb_tools () echo "Run \`otp_build download_gdb_tools\` to complete the installation of the update" } -# $1: jit-reader.c, jit-reader.h, etc -# $2: DGB_TOOLS_VSN, e.g., maint-28, foo, etc it is guaranteed to be an existing branch -# that lives in "$ERL_TOP/make/$1.$SHASUM_FORMAT" -create_shasum_file() { - cat "$GDB_TOOLS_INSTALL_PATH/$1.$SHASUM_FORMAT" > "$GDB_TOOLS_VSN_PATH/$1.$SHASUM_FORMAT" - echo "$GDB_TOOLS_VSN" > "$ERL_TOP/make/gdb_tools_vsn" -} - choose_available_shasum () { if command -v sha256sum > /dev/null; then From 861f5e53c87fd99f8628635597a4d440d75b61cb Mon Sep 17 00:00:00 2001 From: Kiko Fernandez-Reyes Date: Fri, 13 Dec 2024 11:01:39 +0100 Subject: [PATCH 3/3] otp: ignore comments in link and vsn files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lukas Backström (FKA Larsson) --- otp_build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/otp_build b/otp_build index 47803a09ed86..429f278e5565 100755 --- a/otp_build +++ b/otp_build @@ -1061,10 +1061,10 @@ do_download_gdb_tools () set_common_vars() { GDB_TOOLS_INSTALL_PATH="$ERL_TOP/erts/etc/unix/gdb-tools" GDB_TOOLS_VSN_PATH="$ERL_TOP/make" - GDB_REPO=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_link" | tail -n1) + GDB_REPO=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_link" | grep -v "^//") # Version of gdb-tools to download - GDB_TOOLS_VSN=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_vsn" | tail -n1) + GDB_TOOLS_VSN=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_vsn" | grep -v "^//") # SHASUM_FORMAT has values: sha256sum, sha1sum, shasum SHASUM_FORMAT=