File 0196-jit-Unregister-unloaded-code-with-GDB-integration.patch of Package erlang

From 17f34a063d0011e4f5de9f9f354fef2030983ab5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Fri, 5 Jan 2024 11:16:10 +0100
Subject: [PATCH] jit: Unregister unloaded code with GDB integration

This resolves some random crashes when stepping backwards under rr,
but sadly not all.
---
 erts/emulator/beam/beam_bif_load.c            |   1 +
 erts/emulator/beam/jit/arm/beam_asm.hpp       |  10 +-
 .../emulator/beam/jit/arm/beam_asm_global.cpp |   8 +-
 erts/emulator/beam/jit/asm_load.c             |   2 +-
 erts/emulator/beam/jit/beam_asm.h             |   3 +-
 erts/emulator/beam/jit/beam_jit_common.cpp    |  12 ++-
 erts/emulator/beam/jit/beam_jit_main.cpp      |   5 +-
 erts/emulator/beam/jit/beam_jit_metadata.cpp  | 101 +++++++++++++-----
 erts/emulator/beam/jit/x86/beam_asm.hpp       |  10 +-
 .../emulator/beam/jit/x86/beam_asm_global.cpp |   8 +-
 erts/emulator/beam/module.h                   |   1 +
 11 files changed, 106 insertions(+), 55 deletions(-)

diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 7fe9e9960c..03d4f48961 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -2066,6 +2066,7 @@ BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2)
                 __lsan_unregister_root_region(modp->old.code_hdr,
                                               modp->old.code_length);
 #   endif
+                beamasm_unregister_metadata(modp->old.metadata);
                 beamasm_purge_module(modp->old.executable_region,
                                      modp->old.writable_region,
                                      modp->old.code_length);
diff --git a/erts/emulator/beam/jit/arm/beam_asm.hpp b/erts/emulator/beam/jit/arm/beam_asm.hpp
index 415f114e9e..1e78abfc2c 100644
--- a/erts/emulator/beam/jit/arm/beam_asm.hpp
+++ b/erts/emulator/beam/jit/arm/beam_asm.hpp
@@ -1105,7 +1105,7 @@ public:
 
     void codegen(char *buff, size_t len);
 
-    void register_metadata(const BeamCodeHeader *header);
+    void *register_metadata(const BeamCodeHeader *header);
 
     ErtsCodePtr getCode(unsigned label);
     ErtsCodePtr getLambda(unsigned index);
@@ -1829,9 +1829,9 @@ protected:
     }
 };
 
-void beamasm_metadata_update(std::string module_name,
-                             ErtsCodePtr base_address,
-                             size_t code_size,
-                             const std::vector<AsmRange> &ranges);
+void *beamasm_metadata_insert(std::string module_name,
+                              ErtsCodePtr base_address,
+                              size_t code_size,
+                              const std::vector<AsmRange> &ranges);
 void beamasm_metadata_early_init();
 void beamasm_metadata_late_init();
diff --git a/erts/emulator/beam/jit/arm/beam_asm_global.cpp b/erts/emulator/beam/jit/arm/beam_asm_global.cpp
index 84cbf0a515..ff1c0e924c 100644
--- a/erts/emulator/beam/jit/arm/beam_asm_global.cpp
+++ b/erts/emulator/beam/jit/arm/beam_asm_global.cpp
@@ -79,10 +79,10 @@ BeamGlobalAssembler::BeamGlobalAssembler(JitAllocator *allocator)
                           .name = code.labelEntry(labels[val.first])->name()});
     }
 
-    beamasm_metadata_update("global",
-                            (ErtsCodePtr)getBaseAddress(),
-                            code.codeSize(),
-                            ranges);
+    (void)beamasm_metadata_insert("global",
+                                  (ErtsCodePtr)getBaseAddress(),
+                                  code.codeSize(),
+                                  ranges);
 
     /* `this->get_xxx` are populated last to ensure that we crash if we use
      * them instead of labels in global code. */
diff --git a/erts/emulator/beam/jit/asm_load.c b/erts/emulator/beam/jit/asm_load.c
index bf97d32987..adfcf61631 100644
--- a/erts/emulator/beam/jit/asm_load.c
+++ b/erts/emulator/beam/jit/asm_load.c
@@ -1133,7 +1133,7 @@ void beam_load_finalize_code(LoaderState *stp,
     }
 
     /* Register debug / profiling info with external tools. */
-    beamasm_register_metadata(stp->ba, stp->code_hdr);
+    inst_p->metadata = beamasm_register_metadata(stp->ba, stp->code_hdr);
 
     erts_seal_module(inst_p);
 
diff --git a/erts/emulator/beam/jit/beam_asm.h b/erts/emulator/beam/jit/beam_asm.h
index 595d579aa8..70f0121846 100644
--- a/erts/emulator/beam/jit/beam_asm.h
+++ b/erts/emulator/beam/jit/beam_asm.h
@@ -59,7 +59,8 @@ void beamasm_codegen(void *ba,
                      const BeamCodeHeader *in_hdr,
                      const BeamCodeHeader **out_exec_hdr,
                      BeamCodeHeader **out_rw_hdr);
-void beamasm_register_metadata(void *ba, const BeamCodeHeader *hdr);
+void *beamasm_register_metadata(void *ba, const BeamCodeHeader *header);
+void beamasm_unregister_metadata(void *handle);
 void beamasm_purge_module(const void *executable_region,
                           void *writable_region,
                           size_t size);
diff --git a/erts/emulator/beam/jit/beam_jit_common.cpp b/erts/emulator/beam/jit/beam_jit_common.cpp
index 7013f25c8d..4fbadb68b5 100644
--- a/erts/emulator/beam/jit/beam_jit_common.cpp
+++ b/erts/emulator/beam/jit/beam_jit_common.cpp
@@ -357,7 +357,7 @@ BeamModuleAssembler::BeamModuleAssembler(BeamGlobalAssembler *_ga,
     }
 }
 
-void BeamModuleAssembler::register_metadata(const BeamCodeHeader *header) {
+void *BeamModuleAssembler::register_metadata(const BeamCodeHeader *header) {
 #ifndef WIN32
     const BeamCodeLineTab *line_table = header->line_table;
 
@@ -472,10 +472,12 @@ void BeamModuleAssembler::register_metadata(const BeamCodeHeader *header) {
              .stop = (ErtsCodePtr)(code.baseAddress() + code.codeSize()),
              .name = module_name + "::codeFooter"});
 
-    beamasm_metadata_update(module_name,
-                            (ErtsCodePtr)code.baseAddress(),
-                            code.codeSize(),
-                            ranges);
+    return beamasm_metadata_insert(module_name,
+                                   (ErtsCodePtr)code.baseAddress(),
+                                   code.codeSize(),
+                                   ranges);
+#else
+    return NULL;
 #endif
 }
 
diff --git a/erts/emulator/beam/jit/beam_jit_main.cpp b/erts/emulator/beam/jit/beam_jit_main.cpp
index 000b3c6c70..f976d6031e 100644
--- a/erts/emulator/beam/jit/beam_jit_main.cpp
+++ b/erts/emulator/beam/jit/beam_jit_main.cpp
@@ -623,9 +623,10 @@ extern "C"
                     out_rw_hdr);
     }
 
-    void beamasm_register_metadata(void *instance, const BeamCodeHeader *hdr) {
+    void *beamasm_register_metadata(void *instance,
+                                    const BeamCodeHeader *header) {
         BeamModuleAssembler *ba = static_cast<BeamModuleAssembler *>(instance);
-        ba->register_metadata(hdr);
+        return ba->register_metadata(header);
     }
 
     Uint beamasm_get_header(void *instance, const BeamCodeHeader **hdr) {
diff --git a/erts/emulator/beam/jit/beam_jit_metadata.cpp b/erts/emulator/beam/jit/beam_jit_metadata.cpp
index 10e82fdf37..54e7cba5c3 100644
--- a/erts/emulator/beam/jit/beam_jit_metadata.cpp
+++ b/erts/emulator/beam/jit/beam_jit_metadata.cpp
@@ -131,34 +131,31 @@ static void beamasm_init_late_gdb() {
     entry->symfile_size = sizeof(struct debug_info);
 
     /* Insert into linked list */
-    entry->next_entry = __jit_debug_descriptor.first_entry;
-    if (entry->next_entry) {
-        entry->next_entry->prev_entry = entry;
-    } else {
-        entry->prev_entry = nullptr;
+    erts_mtx_lock(&__jit_debug_descriptor.mutex);
+
+    if (__jit_debug_descriptor.first_entry) {
+        ASSERT(__jit_debug_descriptor.first_entry->prev_entry == nullptr);
+        __jit_debug_descriptor.first_entry->prev_entry = entry;
     }
 
-    /* Insert into linked list */
-    erts_mtx_lock(&__jit_debug_descriptor.mutex);
+    entry->prev_entry = nullptr;
     entry->next_entry = __jit_debug_descriptor.first_entry;
-    if (entry->next_entry) {
-        entry->next_entry->prev_entry = entry;
-    } else {
-        entry->prev_entry = nullptr;
-    }
+    __jit_debug_descriptor.first_entry = entry;
 
     /* Register with gdb */
+    ASSERT(__jit_debug_descriptor.relevant_entry == nullptr);
     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
-    __jit_debug_descriptor.first_entry = entry;
     __jit_debug_descriptor.relevant_entry = entry;
     __jit_debug_register_code();
+    __jit_debug_descriptor.relevant_entry = nullptr;
+
     erts_mtx_unlock(&__jit_debug_descriptor.mutex);
 }
 
-static void beamasm_update_gdb_info(std::string module_name,
-                                    ErtsCodePtr base_address,
-                                    size_t code_size,
-                                    const std::vector<AsmRange> &ranges) {
+static void *beamasm_insert_gdb_info(std::string module_name,
+                                     ErtsCodePtr base_address,
+                                     size_t code_size,
+                                     const std::vector<AsmRange> &ranges) {
     Sint symfile_size = sizeof(struct debug_info) + module_name.size() + 1;
 
     for (const auto &range : ranges) {
@@ -221,21 +218,58 @@ static void beamasm_update_gdb_info(std::string module_name,
 
     /* Insert into linked list */
     erts_mtx_lock(&__jit_debug_descriptor.mutex);
-    entry->next_entry = __jit_debug_descriptor.first_entry;
-    if (entry->next_entry) {
-        entry->next_entry->prev_entry = entry;
-    } else {
-        entry->prev_entry = nullptr;
+
+    if (__jit_debug_descriptor.first_entry) {
+        ASSERT(__jit_debug_descriptor.first_entry->prev_entry == nullptr);
+        __jit_debug_descriptor.first_entry->prev_entry = entry;
     }
 
+    entry->prev_entry = nullptr;
+    entry->next_entry = __jit_debug_descriptor.first_entry;
+    __jit_debug_descriptor.first_entry = entry;
+
     /* register with gdb */
+    ASSERT(__jit_debug_descriptor.relevant_entry == nullptr);
     __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
-    __jit_debug_descriptor.first_entry = entry;
     __jit_debug_descriptor.relevant_entry = entry;
     __jit_debug_register_code();
+    __jit_debug_descriptor.relevant_entry = nullptr;
+
     erts_mtx_unlock(&__jit_debug_descriptor.mutex);
+
+    /* Return a reference to our debugger entry so we can remove it when
+     * unloading. */
+    return entry;
 }
 
+static void beamasm_delete_gdb_info(void *metadata) {
+    jit_code_entry *entry = (jit_code_entry *)metadata;
+
+    erts_mtx_lock(&__jit_debug_descriptor.mutex);
+
+    /* Unlink current module from the entry list. */
+    if (entry->prev_entry) {
+        entry->prev_entry->next_entry = entry->next_entry;
+    } else {
+        __jit_debug_descriptor.first_entry = entry->next_entry;
+    }
+
+    if (entry->next_entry) {
+        entry->next_entry->prev_entry = entry->prev_entry;
+    }
+
+    /* unregister with gdb  */
+    ASSERT(__jit_debug_descriptor.relevant_entry == nullptr);
+    __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
+    __jit_debug_descriptor.relevant_entry = entry;
+    __jit_debug_register_code();
+    __jit_debug_descriptor.relevant_entry = nullptr;
+
+    erts_mtx_unlock(&__jit_debug_descriptor.mutex);
+
+    free((void *)entry->symfile_addr);
+    free(entry);
+}
 #endif /* HAVE_GDB_SUPPORT */
 
 #ifdef HAVE_LINUX_PERF_SUPPORT
@@ -525,15 +559,26 @@ void beamasm_metadata_late_init() {
 #endif
 }
 
-void beamasm_metadata_update(std::string module_name,
-                             ErtsCodePtr base_address,
-                             size_t code_size,
-                             const std::vector<AsmRange> &ranges) {
+void *beamasm_metadata_insert(std::string module_name,
+                              ErtsCodePtr base_address,
+                              size_t code_size,
+                              const std::vector<AsmRange> &ranges) {
 #ifdef HAVE_LINUX_PERF_SUPPORT
     perf.update(ranges);
 #endif
 
 #ifdef HAVE_GDB_SUPPORT
-    beamasm_update_gdb_info(module_name, base_address, code_size, ranges);
+    return beamasm_insert_gdb_info(module_name,
+                                   base_address,
+                                   code_size,
+                                   ranges);
+#else
+    return NULL;
+#endif
+}
+
+void beamasm_unregister_metadata(void *metadata) {
+#ifdef HAVE_GDB_SUPPORT
+    beamasm_delete_gdb_info(metadata);
 #endif
 }
diff --git a/erts/emulator/beam/jit/x86/beam_asm.hpp b/erts/emulator/beam/jit/x86/beam_asm.hpp
index eed39447a1..1b74628529 100644
--- a/erts/emulator/beam/jit/x86/beam_asm.hpp
+++ b/erts/emulator/beam/jit/x86/beam_asm.hpp
@@ -1186,7 +1186,7 @@ public:
 
     void codegen(char *buff, size_t len);
 
-    void register_metadata(const BeamCodeHeader *header);
+    void *register_metadata(const BeamCodeHeader *header);
 
     ErtsCodePtr getCode(unsigned label);
     ErtsCodePtr getLambda(unsigned index);
@@ -1663,9 +1663,9 @@ protected:
     }
 };
 
-void beamasm_metadata_update(std::string module_name,
-                             ErtsCodePtr base_address,
-                             size_t code_size,
-                             const std::vector<AsmRange> &ranges);
+void *beamasm_metadata_insert(std::string module_name,
+                              ErtsCodePtr base_address,
+                              size_t code_size,
+                              const std::vector<AsmRange> &ranges);
 void beamasm_metadata_early_init();
 void beamasm_metadata_late_init();
diff --git a/erts/emulator/beam/jit/x86/beam_asm_global.cpp b/erts/emulator/beam/jit/x86/beam_asm_global.cpp
index bb62938b99..ccd89c8749 100644
--- a/erts/emulator/beam/jit/x86/beam_asm_global.cpp
+++ b/erts/emulator/beam/jit/x86/beam_asm_global.cpp
@@ -80,10 +80,10 @@ BeamGlobalAssembler::BeamGlobalAssembler(JitAllocator *allocator)
                           .name = code.labelEntry(labels[val.first])->name()});
     }
 
-    beamasm_metadata_update("global",
-                            (ErtsCodePtr)getBaseAddress(),
-                            code.codeSize(),
-                            ranges);
+    (void)beamasm_metadata_insert("global",
+                                  (ErtsCodePtr)getBaseAddress(),
+                                  code.codeSize(),
+                                  ranges);
 #endif
 
     /* `this->get_xxx` are populated last to ensure that we crash if we use them
diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h
index 6bbadbd505..63e8e111a1 100644
--- a/erts/emulator/beam/module.h
+++ b/erts/emulator/beam/module.h
@@ -34,6 +34,7 @@ struct erl_module_instance {
 
     const void *executable_region;
     void *writable_region;
+    void *metadata;
 
     /* Protected by code modification permission. */
     int unsealed;
-- 
2.35.3

openSUSE Build Service is sponsored by