We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`pwndbg.gdblib.symbol.address` might return invalid address if vmmap is not working
https://github.com/pwndbg/pwndbg/blob/be306da2553596443d2bdaa378bf11cf59e3eab5/pwndbg/gdblib/symbol.py#L146-L147

Some weird results for thread-local variables might pass this check if our vmmap is not working.
For example, with qemu-user, the result of vmmap is a 0~0xfffff…ffff region, so `not pwndbg.gdblib.vmmap.find(address)` will always be `False`.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pwndbg/gdblib/symbol.py`
Content:
```
1 """
2 Looking up addresses for function names / symbols, and
3 vice-versa.
4 
5 Uses IDA when available if there isn't sufficient symbol
6 information available.
7 """
8 import re
9 from typing import Optional
10 
11 import gdb
12 
13 import pwndbg.gdblib.android
14 import pwndbg.gdblib.arch
15 import pwndbg.gdblib.elf
16 import pwndbg.gdblib.events
17 import pwndbg.gdblib.file
18 import pwndbg.gdblib.info
19 import pwndbg.gdblib.memory
20 import pwndbg.gdblib.qemu
21 import pwndbg.gdblib.remote
22 import pwndbg.gdblib.stack
23 import pwndbg.gdblib.vmmap
24 import pwndbg.ida
25 import pwndbg.lib.cache
26 
27 
28 def _get_debug_file_directory():
29     """
30     Retrieve the debug file directory path.
31 
32     The debug file directory path ('show debug-file-directory') is a comma-
33     separated list of directories which GDB will look in to find the binaries
34     currently loaded.
35     """
36     result = gdb.execute("show debug-file-directory", to_string=True, from_tty=False)
37     expr = r'The directory where separate debug symbols are searched for is "(.*)".\n'
38 
39     match = re.search(expr, result)
40 
41     if match:
42         return match.group(1)
43     return ""
44 
45 
46 def _set_debug_file_directory(d) -> None:
47     gdb.execute(f"set debug-file-directory {d}", to_string=True, from_tty=False)
48 
49 
50 def _add_debug_file_directory(d) -> None:
51     current = _get_debug_file_directory()
52     if current:
53         _set_debug_file_directory(f"{current}:{d}")
54     else:
55         _set_debug_file_directory(d)
56 
57 
58 if "/usr/lib/debug" not in _get_debug_file_directory():
59     _add_debug_file_directory("/usr/lib/debug")
60 
61 
62 @pwndbg.lib.cache.cache_until("objfile")
63 def get(address: int, gdb_only=False) -> str:
64     """
65     Retrieve the name for the symbol located at `address` - either from GDB or from IDA sync
66     Passing `gdb_only=True`
67     """
68     # Note: we do not return "" on `address < pwndbg.gdblib.memory.MMAP_MIN_ADDR`
69     # because this may be used to find out the symbol name on PIE binaries that weren't started yet
70     # and then their symbol addresses can be found by GDB on their (non-rebased) offsets
71 
72     # Fast path: GDB's `info symbol` returns 'Numeric constant too large' here
73     if address >= ((1 << 64) - 1):
74         return ""
75 
76     # This sucks, but there's not a GDB API for this.
77     result = gdb.execute("info symbol %#x" % int(address), to_string=True, from_tty=False)
78 
79     if not gdb_only and result.startswith("No symbol"):
80         address = int(address)
81         exe = pwndbg.gdblib.elf.exe()
82         if exe:
83             exe_map = pwndbg.gdblib.vmmap.find(exe.address)
84             if exe_map and address in exe_map:
85                 res = pwndbg.ida.Name(address) or pwndbg.ida.GetFuncOffset(address)
86                 return res or ""
87 
88     # If there are newlines, which means that there are multiple symbols for the address
89     # then use the first one (see also #1610)
90     result = result[: result.index("\n")]
91 
92     # See https://github.com/bminor/binutils-gdb/blob/d1702fea87aa62dff7de465464097dba63cc8c0f/gdb/printcmd.c#L1594-L1624
93     # The most often encountered formats looks like this:
94     #   "main in section .text of /bin/bash"
95     #   "main + 3 in section .text of /bin/bash"
96     #   "system + 1 in section .text of /lib/x86_64-linux-gnu/libc.so.6"
97     #   "No symbol matches system-1"
98     # But there are some others that we have to account for as well
99     if " in section " in result:
100         loc_string, _ = result.split(" in section ")
101     elif " in load address range of " in result:
102         loc_string, _ = result.split(" in load address range of ")
103     elif " overlay section " in result:
104         result, _ = result.split(" overlay section ")
105         loc_string, _ = result.split(" in ")
106     else:
107         loc_string = ""
108 
109     # If there is 'main + 87' we want to replace it with 'main+87' etc.
110     return loc_string.replace(" + ", "+")
111 
112 
113 @pwndbg.lib.cache.cache_until("objfile")
114 def address(symbol: str) -> int:
115     """
116     Get the address for `symbol`
117     """
118     try:
119         symbol_obj = gdb.lookup_symbol(symbol)[0]
120         if symbol_obj:
121             return int(symbol_obj.value().address)
122     except gdb.error as e:
123         # Symbol lookup only throws exceptions on errors, not if it failed to
124         # lookup a symbol. We want to raise these errors so we can handle them
125         # properly, but there are some we haven't figured out how to fix yet, so
126         # we ignore those here
127         skipped_exceptions = []
128 
129         # This is exception is being thrown by the Go typeinfo tests, we should
130         # investigate why this is happening and see if we can explicitly check
131         # for it with `gdb.selected_frame()`
132         skipped_exceptions.append("No frame selected")
133 
134         # If we try to look up a TLS variable when there is no TLS, this
135         # exception occurs. Ideally we should come up with a way to check for
136         # this case before calling `gdb.lookup_symbol`
137         skipped_exceptions.append("Cannot find thread-local")
138 
139         if all(x not in str(e) for x in skipped_exceptions):
140             raise e
141 
142     try:
143         # Unfortunately, `gdb.lookup_symbol` does not seem to handle all
144         # symbols, so we need to fallback to using `info address`. See
145         # https://sourceware.org/pipermail/gdb/2022-October/050362.html
146         address = pwndbg.gdblib.info.address(symbol)
147         if address is None or not pwndbg.gdblib.vmmap.find(address):
148             return None
149 
150         return address
151 
152     except gdb.error:
153         return None
154 
155     try:
156         # TODO: We should properly check if we have a connection to the IDA server first
157         address = pwndbg.ida.LocByName(symbol)
158         if address:
159             return address
160     except Exception:
161         pass
162 
163     return None
164 
165 
166 @pwndbg.lib.cache.cache_until("objfile", "thread")
167 def static_linkage_symbol_address(symbol: str) -> int:
168     """
169     Get the address for static linkage `symbol`
170     """
171 
172     try:
173         if hasattr(gdb, "lookup_static_symbol"):
174             symbol_obj = gdb.lookup_static_symbol(symbol)
175         else:
176             # GDB < 9.x does not have `gdb.lookup_static_symbol`
177             # We will fallback to `gdb.lookup_symbol` here, but the drawback is that we might find incorrect symbol if there is a symbol with the same name which is not static linkage
178             # But this is better than just returning None
179             # TODO/FIXME: Find a way to get the static linkage symbol's address in GDB < 9.x
180             symbol_obj = gdb.lookup_symbol(symbol)[0]
181         return int(symbol_obj.value().address) if symbol_obj else None
182     except gdb.error:
183         return None
184 
185 
186 @pwndbg.lib.cache.cache_until("stop", "start")
187 def selected_frame_source_absolute_filename():
188     """
189     Retrieve the symbol table’s source absolute file name from the selected frame.
190 
191     In case of missing symbol table or frame information, None is returned.
192     """
193     try:
194         frame = gdb.selected_frame()
195     except gdb.error:
196         return None
197 
198     if not frame:
199         return None
200 
201     sal = frame.find_sal()
202     if not sal:
203         return None
204 
205     symtab = sal.symtab
206     if not symtab:
207         return None
208 
209     return symtab.fullname()
210 
211 
212 def parse_and_eval(expression: str) -> Optional[gdb.Value]:
213     """Error handling wrapper for GDBs parse_and_eval function"""
214     try:
215         return gdb.parse_and_eval(expression)
216     except gdb.error:
217         return None
218
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pwndbg/gdblib/symbol.py b/pwndbg/gdblib/symbol.py
--- a/pwndbg/gdblib/symbol.py
+++ b/pwndbg/gdblib/symbol.py
@@ -15,7 +15,6 @@
 import pwndbg.gdblib.elf
 import pwndbg.gdblib.events
 import pwndbg.gdblib.file
-import pwndbg.gdblib.info
 import pwndbg.gdblib.memory
 import pwndbg.gdblib.qemu
 import pwndbg.gdblib.remote
@@ -141,27 +140,18 @@
 
     try:
         # Unfortunately, `gdb.lookup_symbol` does not seem to handle all
-        # symbols, so we need to fallback to using `info address`. See
+        # symbols, so we need to fallback to using `gdb.parse_and_eval`. See
         # https://sourceware.org/pipermail/gdb/2022-October/050362.html
-        address = pwndbg.gdblib.info.address(symbol)
-        if address is None or not pwndbg.gdblib.vmmap.find(address):
-            return None
-
-        return address
+        # (We tried parsing the output of the `info address` before, but there were some issues. See #1628 and #1666)
+        if "\\" in symbol:
+            # Is it possible that happens? Probably not, but just in case
+            raise ValueError(f"Symbol {symbol!r} contains a backslash")
+        sanitized_symbol_name = symbol.replace("'", "\\'")
+        return int(gdb.parse_and_eval(f"&'{sanitized_symbol_name}'"))
 
     except gdb.error:
         return None
 
-    try:
-        # TODO: We should properly check if we have a connection to the IDA server first
-        address = pwndbg.ida.LocByName(symbol)
-        if address:
-            return address
-    except Exception:
-        pass
-
-    return None
-
 
 @pwndbg.lib.cache.cache_until("objfile", "thread")
 def static_linkage_symbol_address(symbol: str) -> int:

{"golden_diff": "diff --git a/pwndbg/gdblib/symbol.py b/pwndbg/gdblib/symbol.py\n--- a/pwndbg/gdblib/symbol.py\n+++ b/pwndbg/gdblib/symbol.py\n@@ -15,7 +15,6 @@\n import pwndbg.gdblib.elf\n import pwndbg.gdblib.events\n import pwndbg.gdblib.file\n-import pwndbg.gdblib.info\n import pwndbg.gdblib.memory\n import pwndbg.gdblib.qemu\n import pwndbg.gdblib.remote\n@@ -141,27 +140,18 @@\n \n     try:\n         # Unfortunately, `gdb.lookup_symbol` does not seem to handle all\n-        # symbols, so we need to fallback to using `info address`. See\n+        # symbols, so we need to fallback to using `gdb.parse_and_eval`. See\n         # https://sourceware.org/pipermail/gdb/2022-October/050362.html\n-        address = pwndbg.gdblib.info.address(symbol)\n-        if address is None or not pwndbg.gdblib.vmmap.find(address):\n-            return None\n-\n-        return address\n+        # (We tried parsing the output of the `info address` before, but there were some issues. See #1628 and #1666)\n+        if \"\\\\\" in symbol:\n+            # Is it possible that happens? Probably not, but just in case\n+            raise ValueError(f\"Symbol {symbol!r} contains a backslash\")\n+        sanitized_symbol_name = symbol.replace(\"'\", \"\\\\'\")\n+        return int(gdb.parse_and_eval(f\"&'{sanitized_symbol_name}'\"))\n \n     except gdb.error:\n         return None\n \n-    try:\n-        # TODO: We should properly check if we have a connection to the IDA server first\n-        address = pwndbg.ida.LocByName(symbol)\n-        if address:\n-            return address\n-    except Exception:\n-        pass\n-\n-    return None\n-\n \n @pwndbg.lib.cache.cache_until(\"objfile\", \"thread\")\n def static_linkage_symbol_address(symbol: str) -> int:\n", "issue": "`pwndbg.gdblib.symbol.address` might return invalid address if vmmap is not working\nhttps://github.com/pwndbg/pwndbg/blob/be306da2553596443d2bdaa378bf11cf59e3eab5/pwndbg/gdblib/symbol.py#L146-L147\r\n\r\nSome weird results for thread-local variables might pass this check if our vmmap is not working.\r\nFor example, with qemu-user, the result of vmmap is a 0~0xfffff\u2026ffff region, so `not pwndbg.gdblib.vmmap.find(address)` will always be `False`.\n", "before_files": [{"content": "\"\"\"\nLooking up addresses for function names / symbols, and\nvice-versa.\n\nUses IDA when available if there isn't sufficient symbol\ninformation available.\n\"\"\"\nimport re\nfrom typing import Optional\n\nimport gdb\n\nimport pwndbg.gdblib.android\nimport pwndbg.gdblib.arch\nimport pwndbg.gdblib.elf\nimport pwndbg.gdblib.events\nimport pwndbg.gdblib.file\nimport pwndbg.gdblib.info\nimport pwndbg.gdblib.memory\nimport pwndbg.gdblib.qemu\nimport pwndbg.gdblib.remote\nimport pwndbg.gdblib.stack\nimport pwndbg.gdblib.vmmap\nimport pwndbg.ida\nimport pwndbg.lib.cache\n\n\ndef _get_debug_file_directory():\n    \"\"\"\n    Retrieve the debug file directory path.\n\n    The debug file directory path ('show debug-file-directory') is a comma-\n    separated list of directories which GDB will look in to find the binaries\n    currently loaded.\n    \"\"\"\n    result = gdb.execute(\"show debug-file-directory\", to_string=True, from_tty=False)\n    expr = r'The directory where separate debug symbols are searched for is \"(.*)\".\\n'\n\n    match = re.search(expr, result)\n\n    if match:\n        return match.group(1)\n    return \"\"\n\n\ndef _set_debug_file_directory(d) -> None:\n    gdb.execute(f\"set debug-file-directory {d}\", to_string=True, from_tty=False)\n\n\ndef _add_debug_file_directory(d) -> None:\n    current = _get_debug_file_directory()\n    if current:\n        _set_debug_file_directory(f\"{current}:{d}\")\n    else:\n        _set_debug_file_directory(d)\n\n\nif \"/usr/lib/debug\" not in _get_debug_file_directory():\n    _add_debug_file_directory(\"/usr/lib/debug\")\n\n\n@pwndbg.lib.cache.cache_until(\"objfile\")\ndef get(address: int, gdb_only=False) -> str:\n    \"\"\"\n    Retrieve the name for the symbol located at `address` - either from GDB or from IDA sync\n    Passing `gdb_only=True`\n    \"\"\"\n    # Note: we do not return \"\" on `address < pwndbg.gdblib.memory.MMAP_MIN_ADDR`\n    # because this may be used to find out the symbol name on PIE binaries that weren't started yet\n    # and then their symbol addresses can be found by GDB on their (non-rebased) offsets\n\n    # Fast path: GDB's `info symbol` returns 'Numeric constant too large' here\n    if address >= ((1 << 64) - 1):\n        return \"\"\n\n    # This sucks, but there's not a GDB API for this.\n    result = gdb.execute(\"info symbol %#x\" % int(address), to_string=True, from_tty=False)\n\n    if not gdb_only and result.startswith(\"No symbol\"):\n        address = int(address)\n        exe = pwndbg.gdblib.elf.exe()\n        if exe:\n            exe_map = pwndbg.gdblib.vmmap.find(exe.address)\n            if exe_map and address in exe_map:\n                res = pwndbg.ida.Name(address) or pwndbg.ida.GetFuncOffset(address)\n                return res or \"\"\n\n    # If there are newlines, which means that there are multiple symbols for the address\n    # then use the first one (see also #1610)\n    result = result[: result.index(\"\\n\")]\n\n    # See https://github.com/bminor/binutils-gdb/blob/d1702fea87aa62dff7de465464097dba63cc8c0f/gdb/printcmd.c#L1594-L1624\n    # The most often encountered formats looks like this:\n    #   \"main in section .text of /bin/bash\"\n    #   \"main + 3 in section .text of /bin/bash\"\n    #   \"system + 1 in section .text of /lib/x86_64-linux-gnu/libc.so.6\"\n    #   \"No symbol matches system-1\"\n    # But there are some others that we have to account for as well\n    if \" in section \" in result:\n        loc_string, _ = result.split(\" in section \")\n    elif \" in load address range of \" in result:\n        loc_string, _ = result.split(\" in load address range of \")\n    elif \" overlay section \" in result:\n        result, _ = result.split(\" overlay section \")\n        loc_string, _ = result.split(\" in \")\n    else:\n        loc_string = \"\"\n\n    # If there is 'main + 87' we want to replace it with 'main+87' etc.\n    return loc_string.replace(\" + \", \"+\")\n\n\n@pwndbg.lib.cache.cache_until(\"objfile\")\ndef address(symbol: str) -> int:\n    \"\"\"\n    Get the address for `symbol`\n    \"\"\"\n    try:\n        symbol_obj = gdb.lookup_symbol(symbol)[0]\n        if symbol_obj:\n            return int(symbol_obj.value().address)\n    except gdb.error as e:\n        # Symbol lookup only throws exceptions on errors, not if it failed to\n        # lookup a symbol. We want to raise these errors so we can handle them\n        # properly, but there are some we haven't figured out how to fix yet, so\n        # we ignore those here\n        skipped_exceptions = []\n\n        # This is exception is being thrown by the Go typeinfo tests, we should\n        # investigate why this is happening and see if we can explicitly check\n        # for it with `gdb.selected_frame()`\n        skipped_exceptions.append(\"No frame selected\")\n\n        # If we try to look up a TLS variable when there is no TLS, this\n        # exception occurs. Ideally we should come up with a way to check for\n        # this case before calling `gdb.lookup_symbol`\n        skipped_exceptions.append(\"Cannot find thread-local\")\n\n        if all(x not in str(e) for x in skipped_exceptions):\n            raise e\n\n    try:\n        # Unfortunately, `gdb.lookup_symbol` does not seem to handle all\n        # symbols, so we need to fallback to using `info address`. See\n        # https://sourceware.org/pipermail/gdb/2022-October/050362.html\n        address = pwndbg.gdblib.info.address(symbol)\n        if address is None or not pwndbg.gdblib.vmmap.find(address):\n            return None\n\n        return address\n\n    except gdb.error:\n        return None\n\n    try:\n        # TODO: We should properly check if we have a connection to the IDA server first\n        address = pwndbg.ida.LocByName(symbol)\n        if address:\n            return address\n    except Exception:\n        pass\n\n    return None\n\n\n@pwndbg.lib.cache.cache_until(\"objfile\", \"thread\")\ndef static_linkage_symbol_address(symbol: str) -> int:\n    \"\"\"\n    Get the address for static linkage `symbol`\n    \"\"\"\n\n    try:\n        if hasattr(gdb, \"lookup_static_symbol\"):\n            symbol_obj = gdb.lookup_static_symbol(symbol)\n        else:\n            # GDB < 9.x does not have `gdb.lookup_static_symbol`\n            # We will fallback to `gdb.lookup_symbol` here, but the drawback is that we might find incorrect symbol if there is a symbol with the same name which is not static linkage\n            # But this is better than just returning None\n            # TODO/FIXME: Find a way to get the static linkage symbol's address in GDB < 9.x\n            symbol_obj = gdb.lookup_symbol(symbol)[0]\n        return int(symbol_obj.value().address) if symbol_obj else None\n    except gdb.error:\n        return None\n\n\n@pwndbg.lib.cache.cache_until(\"stop\", \"start\")\ndef selected_frame_source_absolute_filename():\n    \"\"\"\n    Retrieve the symbol table\u2019s source absolute file name from the selected frame.\n\n    In case of missing symbol table or frame information, None is returned.\n    \"\"\"\n    try:\n        frame = gdb.selected_frame()\n    except gdb.error:\n        return None\n\n    if not frame:\n        return None\n\n    sal = frame.find_sal()\n    if not sal:\n        return None\n\n    symtab = sal.symtab\n    if not symtab:\n        return None\n\n    return symtab.fullname()\n\n\ndef parse_and_eval(expression: str) -> Optional[gdb.Value]:\n    \"\"\"Error handling wrapper for GDBs parse_and_eval function\"\"\"\n    try:\n        return gdb.parse_and_eval(expression)\n    except gdb.error:\n        return None\n", "path": "pwndbg/gdblib/symbol.py"}], "after_files": [{"content": "\"\"\"\nLooking up addresses for function names / symbols, and\nvice-versa.\n\nUses IDA when available if there isn't sufficient symbol\ninformation available.\n\"\"\"\nimport re\nfrom typing import Optional\n\nimport gdb\n\nimport pwndbg.gdblib.android\nimport pwndbg.gdblib.arch\nimport pwndbg.gdblib.elf\nimport pwndbg.gdblib.events\nimport pwndbg.gdblib.file\nimport pwndbg.gdblib.memory\nimport pwndbg.gdblib.qemu\nimport pwndbg.gdblib.remote\nimport pwndbg.gdblib.stack\nimport pwndbg.gdblib.vmmap\nimport pwndbg.ida\nimport pwndbg.lib.cache\n\n\ndef _get_debug_file_directory():\n    \"\"\"\n    Retrieve the debug file directory path.\n\n    The debug file directory path ('show debug-file-directory') is a comma-\n    separated list of directories which GDB will look in to find the binaries\n    currently loaded.\n    \"\"\"\n    result = gdb.execute(\"show debug-file-directory\", to_string=True, from_tty=False)\n    expr = r'The directory where separate debug symbols are searched for is \"(.*)\".\\n'\n\n    match = re.search(expr, result)\n\n    if match:\n        return match.group(1)\n    return \"\"\n\n\ndef _set_debug_file_directory(d) -> None:\n    gdb.execute(f\"set debug-file-directory {d}\", to_string=True, from_tty=False)\n\n\ndef _add_debug_file_directory(d) -> None:\n    current = _get_debug_file_directory()\n    if current:\n        _set_debug_file_directory(f\"{current}:{d}\")\n    else:\n        _set_debug_file_directory(d)\n\n\nif \"/usr/lib/debug\" not in _get_debug_file_directory():\n    _add_debug_file_directory(\"/usr/lib/debug\")\n\n\n@pwndbg.lib.cache.cache_until(\"objfile\")\ndef get(address: int, gdb_only=False) -> str:\n    \"\"\"\n    Retrieve the name for the symbol located at `address` - either from GDB or from IDA sync\n    Passing `gdb_only=True`\n    \"\"\"\n    # Note: we do not return \"\" on `address < pwndbg.gdblib.memory.MMAP_MIN_ADDR`\n    # because this may be used to find out the symbol name on PIE binaries that weren't started yet\n    # and then their symbol addresses can be found by GDB on their (non-rebased) offsets\n\n    # Fast path: GDB's `info symbol` returns 'Numeric constant too large' here\n    if address >= ((1 << 64) - 1):\n        return \"\"\n\n    # This sucks, but there's not a GDB API for this.\n    result = gdb.execute(\"info symbol %#x\" % int(address), to_string=True, from_tty=False)\n\n    if not gdb_only and result.startswith(\"No symbol\"):\n        address = int(address)\n        exe = pwndbg.gdblib.elf.exe()\n        if exe:\n            exe_map = pwndbg.gdblib.vmmap.find(exe.address)\n            if exe_map and address in exe_map:\n                res = pwndbg.ida.Name(address) or pwndbg.ida.GetFuncOffset(address)\n                return res or \"\"\n\n    # If there are newlines, which means that there are multiple symbols for the address\n    # then use the first one (see also #1610)\n    result = result[: result.index(\"\\n\")]\n\n    # See https://github.com/bminor/binutils-gdb/blob/d1702fea87aa62dff7de465464097dba63cc8c0f/gdb/printcmd.c#L1594-L1624\n    # The most often encountered formats looks like this:\n    #   \"main in section .text of /bin/bash\"\n    #   \"main + 3 in section .text of /bin/bash\"\n    #   \"system + 1 in section .text of /lib/x86_64-linux-gnu/libc.so.6\"\n    #   \"No symbol matches system-1\"\n    # But there are some others that we have to account for as well\n    if \" in section \" in result:\n        loc_string, _ = result.split(\" in section \")\n    elif \" in load address range of \" in result:\n        loc_string, _ = result.split(\" in load address range of \")\n    elif \" overlay section \" in result:\n        result, _ = result.split(\" overlay section \")\n        loc_string, _ = result.split(\" in \")\n    else:\n        loc_string = \"\"\n\n    # If there is 'main + 87' we want to replace it with 'main+87' etc.\n    return loc_string.replace(\" + \", \"+\")\n\n\n@pwndbg.lib.cache.cache_until(\"objfile\")\ndef address(symbol: str) -> int:\n    \"\"\"\n    Get the address for `symbol`\n    \"\"\"\n    try:\n        symbol_obj = gdb.lookup_symbol(symbol)[0]\n        if symbol_obj:\n            return int(symbol_obj.value().address)\n    except gdb.error as e:\n        # Symbol lookup only throws exceptions on errors, not if it failed to\n        # lookup a symbol. We want to raise these errors so we can handle them\n        # properly, but there are some we haven't figured out how to fix yet, so\n        # we ignore those here\n        skipped_exceptions = []\n\n        # This is exception is being thrown by the Go typeinfo tests, we should\n        # investigate why this is happening and see if we can explicitly check\n        # for it with `gdb.selected_frame()`\n        skipped_exceptions.append(\"No frame selected\")\n\n        # If we try to look up a TLS variable when there is no TLS, this\n        # exception occurs. Ideally we should come up with a way to check for\n        # this case before calling `gdb.lookup_symbol`\n        skipped_exceptions.append(\"Cannot find thread-local\")\n\n        if all(x not in str(e) for x in skipped_exceptions):\n            raise e\n\n    try:\n        # Unfortunately, `gdb.lookup_symbol` does not seem to handle all\n        # symbols, so we need to fallback to using `gdb.parse_and_eval`. See\n        # https://sourceware.org/pipermail/gdb/2022-October/050362.html\n        # (We tried parsing the output of the `info address` before, but there were some issues. See #1628 and #1666)\n        if \"\\\\\" in symbol:\n            # Is it possible that happens? Probably not, but just in case\n            raise ValueError(f\"Symbol {symbol!r} contains a backslash\")\n        sanitized_symbol_name = symbol.replace(\"'\", \"\\\\'\")\n        return int(gdb.parse_and_eval(f\"&'{sanitized_symbol_name}'\"))\n\n    except gdb.error:\n        return None\n\n\n@pwndbg.lib.cache.cache_until(\"objfile\", \"thread\")\ndef static_linkage_symbol_address(symbol: str) -> int:\n    \"\"\"\n    Get the address for static linkage `symbol`\n    \"\"\"\n\n    try:\n        if hasattr(gdb, \"lookup_static_symbol\"):\n            symbol_obj = gdb.lookup_static_symbol(symbol)\n        else:\n            # GDB < 9.x does not have `gdb.lookup_static_symbol`\n            # We will fallback to `gdb.lookup_symbol` here, but the drawback is that we might find incorrect symbol if there is a symbol with the same name which is not static linkage\n            # But this is better than just returning None\n            # TODO/FIXME: Find a way to get the static linkage symbol's address in GDB < 9.x\n            symbol_obj = gdb.lookup_symbol(symbol)[0]\n        return int(symbol_obj.value().address) if symbol_obj else None\n    except gdb.error:\n        return None\n\n\n@pwndbg.lib.cache.cache_until(\"stop\", \"start\")\ndef selected_frame_source_absolute_filename():\n    \"\"\"\n    Retrieve the symbol table\u2019s source absolute file name from the selected frame.\n\n    In case of missing symbol table or frame information, None is returned.\n    \"\"\"\n    try:\n        frame = gdb.selected_frame()\n    except gdb.error:\n        return None\n\n    if not frame:\n        return None\n\n    sal = frame.find_sal()\n    if not sal:\n        return None\n\n    symtab = sal.symtab\n    if not symtab:\n        return None\n\n    return symtab.fullname()\n\n\ndef parse_and_eval(expression: str) -> Optional[gdb.Value]:\n    \"\"\"Error handling wrapper for GDBs parse_and_eval function\"\"\"\n    try:\n        return gdb.parse_and_eval(expression)\n    except gdb.error:\n        return None\n", "path": "pwndbg/gdblib/symbol.py"}]}