Repository: compiler-explorer/compiler-explorer (ts)

Issue:
[BUG]: Not all identifiers are demangled
### Describe the bug

Some identifiers are not demangled, for example
```asm
        jmp     qword ptr [rip + _ZN4core3fmt3num3imp54_$LT$impl$u20$core..fmt..Display$u20$for$u20$usize$GT$3fmt17h7bbbd896a38dcccaE@GOTPCREL]
        mov     edx, OFFSET FLAT:_ZN1a1gEi
```

### Steps to reproduce

Write some code that (for example) is compiled to a `rip`-relative jump: https://godbolt.org/z/5zWGxhxKq

### Expected behavior

The identifiers should be demangled.

I believe these regexes are too restrictive?
https://github.com/compiler-explorer/compiler-explorer/blob/a47d3c68fc98b5c3a17298aa121e13665bb7245a/lib/demangler/base.ts#L47
https://github.com/compiler-explorer/compiler-explorer/blob/a47d3c68fc98b5c3a17298aa121e13665bb7245a/lib/demangler/base.ts#L55

### Reproduction link

https://godbolt.org/z/5zWGxhxKq

### Screenshots

Not applicable

### Operating System

_No response_

### Browser version

_No response_

Pull request:
Fix missed demangles
This PR fixes missed demangle cases pointed out in #6348, namely of the form `mov eax, OFFSET FLAT:_Z...` and `jmp qword ptr [rip + _Z...]`.

Closes #6348.

Patch:
diff --git a/lib/demangler/base.ts b/lib/demangler/base.ts
index 54237d1f4..bd64bf4be 100644
--- a/lib/demangler/base.ts
+++ b/lib/demangler/base.ts
@@ -52,9 +52,10 @@ export class BaseDemangler extends AsmRegex {
     readonly callPtrDef4 = /callq?.*qword\sptr\s\[[a-z]*\s\+\s([$._a-z][\w$.@]*)\+?\d?]/i;
 
     // symbols in a mov or lea command starting with an underscore
-    readonly movUnderscoreDef = /mov.*\s(_[\w$.@]*)/i;
-    readonly leaUnderscoreDef = /lea.*\s(_[\w$.@]*)/i;
+    readonly movUnderscoreDef = /mov.*[\s:](_[\w$.@]*)/i;
+    readonly leaUnderscoreDef = /lea.*[\s:](_[\w$.@]*)/i;
     readonly quadUnderscoreDef = /\.quad\s*(_[\w$.@]*)/i;
+    readonly ptrOffset = /\bptr\s*\[.+\b(_[\w$.@]*)\s*\]/i;
 
     // E.g., ".entry _Z6squarePii("
     // E.g., ".func  (.param .b32 func_retval0) bar("
@@ -117,6 +118,9 @@ export class BaseDemangler extends AsmRegex {
 
     protected collectLabels() {
         const symbolMatchers = [
+            // this.ptrOffset needs to be checked before the jmp test since the jumpDef regex doesn't match the mangled
+            // symbol in `qword ptr [rip + _Z...]` and instead matches the `qword`
+            this.ptrOffset,
             this.jumpDef,
             this.callPtrDef4,
             this.callPtrDef3,
@@ -129,8 +133,7 @@ export class BaseDemangler extends AsmRegex {
             this.ptxFuncDef,
             this.ptxVarDef,
         ];
-        for (let j = 0; j < this.result.asm.length; ++j) {
-            const line = this.result.asm[j].text;
+        for (const {text: line} of this.result.asm) {
             if (!line) continue;
 
             const labelMatch = line.match(this.labelDef);


Test patch:
diff --git a/test/demangle-cases/bug-1336-first-20000-lines.asm.demangle b/test/demangle-cases/bug-1336-first-20000-lines.asm.demangle
index b83eadf73..74fb45c0d 100644
--- a/test/demangle-cases/bug-1336-first-20000-lines.asm.demangle
+++ b/test/demangle-cases/bug-1336-first-20000-lines.asm.demangle
@@ -736,7 +736,7 @@ std::regex_error::regex_error(std::regex_constants::error_type, char const*) [ba
   mov rsi, rdx
   mov rdi, rax
   call std::runtime_error::runtime_error(char const*) [base object constructor]
-  mov edx, OFFSET FLAT:_ZTVSt11regex_error+16
+  mov edx, OFFSET FLAT:vtable for std::regex_error+16
   mov rax, QWORD PTR [rbp-8]
   mov QWORD PTR [rax], rdx
   mov rax, QWORD PTR [rbp-8]
@@ -761,8 +761,8 @@ std::__throw_regex_error(std::regex_constants::error_type, char const*):
   mov esi, eax
   mov rdi, rbx
   call std::regex_error::regex_error(std::regex_constants::error_type, char const*) [complete object constructor]
-  mov edx, OFFSET FLAT:_ZNSt11regex_errorD1Ev
-  mov esi, OFFSET FLAT:_ZTISt11regex_error
+  mov edx, OFFSET FLAT:std::regex_error::~regex_error() [complete object destructor]
+  mov esi, OFFSET FLAT:typeinfo for std::regex_error
   mov rdi, rbx
   call __cxa_throw
   mov r12, rax
@@ -1235,9 +1235,9 @@ main:
   call bool std::regex_match<char, std::__cxx11::regex_traits<char> >(char const*, std::__cxx11::basic_regex<char, std::__cxx11::regex_traits<char> > const&, std::regex_constants::match_flag_type)
   movzx eax, al
   mov esi, eax
-  mov edi, OFFSET FLAT:_ZSt4cout
+  mov edi, OFFSET FLAT:std::cout
   call std::basic_ostream<char, std::char_traits<char> >::operator<<(bool)
-  mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
+  mov esi, OFFSET FLAT:std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
   mov rdi, rax
   call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
   mov BYTE PTR [rbp-51], 1
@@ -1251,7 +1251,7 @@ main:
   mov rdi, rcx
   call int std::accumulate<bool*, int, std::bit_and<bool> >(bool*, bool*, int, std::bit_and<bool>)
   mov esi, eax
-  mov edi, OFFSET FLAT:_ZSt4cout
+  mov edi, OFFSET FLAT:std::cout
   call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
   lea rax, [rbp-48]
   mov rdi, rax
@@ -3728,7 +3728,7 @@ std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::~_Sp_counted_base() [base obj
   push rbp
   mov rbp, rsp
   mov QWORD PTR [rbp-8], rdi
-  mov edx, OFFSET FLAT:_ZTVSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE+16
+  mov edx, OFFSET FLAT:vtable for std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>+16
   mov rax, QWORD PTR [rbp-8]
   mov QWORD PTR [rax], rdx
   nop
@@ -6586,7 +6586,7 @@ std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_Sp_counted_base() [base obje
   push rbp
   mov rbp, rsp
   mov QWORD PTR [rbp-8], rdi
-  mov edx, OFFSET FLAT:_ZTVSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE+16
+  mov edx, OFFSET FLAT:vtable for std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>+16
   mov rax, QWORD PTR [rbp-8]
   mov QWORD PTR [rax], rdx
   mov rax, QWORD PTR [rbp-8]
@@ -6674,7 +6674,7 @@ std::ctype<char> const& std::use_facet<std::ctype<char> const>(std::locale const
   mov rbp, rsp
   sub rsp, 32
   mov QWORD PTR [rbp-24], rdi
-  mov edi, OFFSET FLAT:_ZNSt5ctypeIcE2idE
+  mov edi, OFFSET FLAT:std::ctype<char>::id
   call std::locale::id::_M_id() const
   mov QWORD PTR [rbp-8], rax
   mov rax, QWORD PTR [rbp-24]
@@ -6702,8 +6702,8 @@ std::ctype<char> const& std::use_facet<std::ctype<char> const>(std::locale const
   add rax, rdx
   mov rax, QWORD PTR [rax]
   mov ecx, 0
-  mov edx, OFFSET FLAT:_ZTISt5ctypeIcE
-  mov esi, OFFSET FLAT:_ZTINSt6locale5facetE
+  mov edx, OFFSET FLAT:typeinfo for std::ctype<char>
+  mov esi, OFFSET FLAT:typeinfo for std::locale::facet
   mov rdi, rax
   call __dynamic_cast
   test rax, rax
diff --git a/test/demangler-tests.ts b/test/demangler-tests.ts
index c0faaecb4..420d66dc8 100644
--- a/test/demangler-tests.ts
+++ b/test/demangler-tests.ts
@@ -116,6 +116,46 @@ describe('Basic demangling', () => {
         ]);
     });
 
+    it('Mov with OFFSET FLAT', () => {
+        // regression test for https://github.com/compiler-explorer/compiler-explorer/issues/6348
+        const result = {asm: [{text: 'mov     eax, OFFSET FLAT:_ZN1a1gEi'}]};
+
+        const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']);
+
+        return Promise.all([
+            demangler
+                .process(result)
+                .then(output => {
+                    expect(output.asm[0].text).toEqual('mov     eax, OFFSET FLAT:a::g(int)');
+                })
+                .catch(catchCppfiltNonexistence),
+        ]);
+    });
+
+    it('rip-relative jump', () => {
+        // regression test for https://github.com/compiler-explorer/compiler-explorer/issues/6348
+        const result = {
+            asm: [
+                {
+                    text: 'jmp     qword ptr [rip + _ZN4core3fmt3num3imp54_$LT$impl$u20$core..fmt..Display$u20$for$u20$usize$GT$3fmt17h7bbbd896a38dcccaE@GOTPCREL]',
+                },
+            ],
+        };
+
+        const demangler = new DummyCppDemangler(cppfiltpath, new DummyCompiler(), ['-n']);
+
+        return Promise.all([
+            demangler
+                .process(result)
+                .then(output => {
+                    expect(output.asm[0].text).toEqual(
+                        'jmp     qword ptr [rip + core::fmt::num::imp::<impl core::fmt::Display for usize>::fmt::h7bbbd896a38dccca@GOTPCREL]',
+                    );
+                })
+                .catch(catchCppfiltNonexistence),
+        ]);
+    });
+
     it('Two destructors', () => {
         const result = {
             asm: [