prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  pwndbg.gdblib.arch.current is wrong if executed in a pwntools gdbscript command
  TL;DR: This should not fail, but does so, because the `patch` command fetches `pwndbg.gdblib.arch.current` which for some reason is wrong/not updated.
  
  
  ```py
  from pwn import *
  
  gdbscript = '''
  tbreak main
  patch $rip 'xor rax, rax'
  continue
  '''
  
  p = gdb.debug('/bin/ls', gdbscript=gdbscript)
  
  p.interactive()
  ```
  
  Stacktrace:
  ```
  Traceback (most recent call last):
    File "/home/dc/tools/pwndbg/pwndbg/commands/__init__.py", line 145, in __call__
      return self.function(*args, **kwargs)
    File "/home/dc/tools/pwndbg/pwndbg/commands/__init__.py", line 216, in _OnlyWhenRunning
      return function(*a, **kw)
    File "/home/dc/tools/pwndbg/pwndbg/commands/patch.py", line 25, in patch
      new_mem = asm(ins, arch=pwndbg.gdblib.arch.current)
    File "/home/dc/.virtualenvs/pwn/lib/python3.8/site-packages/pwnlib/context/__init__.py", line 1444, in setter
      raise AttributeError("Invalid arch/bits combination: %s/%s" % (arch, bits))
  AttributeError: Invalid arch/bits combination: i386/64
  
  If that is an issue, you can report it on https://github.com/pwndbg/pwndbg/issues
  (Please don't forget to search if it hasn't been reported before)
  To generate the report and open a browser, you may run `bugreport --run-browser`
  PS: Pull requests are welcome
  > /home/dc/.virtualenvs/pwn/lib/python3.8/site-packages/pwnlib/context/__init__.py(1444)setter()
  -> raise AttributeError("Invalid arch/bits combination: %s/%s" % (arch, bits))
  (Pdb) p arch, bits
  ('i386', 64)
  (Pdb) 
  ```
  
  --- 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/commands/patch.py`
  Content:
  ```
  1 #!/usr/bin/env python
  2 # -*- coding: utf-8 -*-
  3 import argparse
  4 
  5 from pwnlib.asm import asm
  6 from pwnlib.asm import disasm
  7 
  8 import pwndbg.color.message as message
  9 import pwndbg.commands
  10 import pwndbg.gdblib.memory
  11 import pwndbg.lib.memoize
  12 
  13 # Keep old patches made so we can revert them
  14 patches = {}
  15 
  16 
  17 parser = argparse.ArgumentParser(description="Patches given instruction with given code or bytes")
  18 parser.add_argument("address", type=int, help="The address to patch")
  19 parser.add_argument("ins", type=str, help="instruction[s]")
  20 
  21 
  22 @pwndbg.commands.ArgparsedCommand(parser)
  23 @pwndbg.commands.OnlyWhenRunning
  24 def patch(address, ins):
  25     new_mem = asm(ins, arch=pwndbg.gdblib.arch.current)
  26 
  27     old_mem = pwndbg.gdblib.memory.read(address, len(new_mem))
  28 
  29     patches[address] = (old_mem, new_mem)
  30 
  31     pwndbg.gdblib.memory.write(address, new_mem)
  32 
  33     pwndbg.lib.memoize.reset()
  34 
  35 
  36 parser2 = argparse.ArgumentParser(description="Revert patch at given address")
  37 parser2.add_argument("address", type=int, help="Address to revert patch on")
  38 
  39 
  40 @pwndbg.commands.ArgparsedCommand(parser2)
  41 @pwndbg.commands.OnlyWhenRunning
  42 def patch_revert(address):
  43     if not patches:
  44         print(message.notice("No patches to revert"))
  45         return
  46 
  47     if address == -1:
  48         for addr, (old, _new) in patches.items():
  49             pwndbg.gdblib.memory.write(addr, old)
  50             print(message.notice("Reverted patch at %#x" % addr))
  51         patches.clear()
  52     else:
  53         old, _new = patches[address]
  54         pwndbg.gdblib.memory.write(address, old)
  55 
  56     pwndbg.lib.memoize.reset()
  57 
  58 
  59 parser3 = argparse.ArgumentParser(description="List all patches")
  60 
  61 
  62 @pwndbg.commands.ArgparsedCommand(parser3)
  63 @pwndbg.commands.OnlyWhenRunning
  64 def patch_list():
  65     if not patches:
  66         print(message.hint("No patches to list"))
  67         return
  68 
  69     print(message.hint("Patches:"))
  70     for addr, (old, new) in patches.items():
  71         old_insns = disasm(old, arch=pwndbg.gdblib.arch.current)
  72         new_insns = disasm(new, arch=pwndbg.gdblib.arch.current)
  73 
  74         print(
  75             message.hint("Patch at"),
  76             message.warning("%#x:" % addr),
  77             message.hint("from"),
  78             message.warning(old_insns.replace("\n", "; ")),
  79             message.hint("to"),
  80             message.warning(new_insns.replace("\n", "; ")),
  81         )
  82
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/pwndbg/commands/patch.py b/pwndbg/commands/patch.py
  --- a/pwndbg/commands/patch.py
  +++ b/pwndbg/commands/patch.py
  @@ -22,7 +22,7 @@
   @pwndbg.commands.ArgparsedCommand(parser)
   @pwndbg.commands.OnlyWhenRunning
   def patch(address, ins):
  -    new_mem = asm(ins, arch=pwndbg.gdblib.arch.current)
  +    new_mem = asm(ins)
   
       old_mem = pwndbg.gdblib.memory.read(address, len(new_mem))
   
  @@ -68,8 +68,8 @@
   
       print(message.hint("Patches:"))
       for addr, (old, new) in patches.items():
  -        old_insns = disasm(old, arch=pwndbg.gdblib.arch.current)
  -        new_insns = disasm(new, arch=pwndbg.gdblib.arch.current)
  +        old_insns = disasm(old)
  +        new_insns = disasm(new)
   
           print(
               message.hint("Patch at"),
  
verification_info: {"golden_diff": "diff --git a/pwndbg/commands/patch.py b/pwndbg/commands/patch.py\n--- a/pwndbg/commands/patch.py\n+++ b/pwndbg/commands/patch.py\n@@ -22,7 +22,7 @@\n @pwndbg.commands.ArgparsedCommand(parser)\n @pwndbg.commands.OnlyWhenRunning\n def patch(address, ins):\n-    new_mem = asm(ins, arch=pwndbg.gdblib.arch.current)\n+    new_mem = asm(ins)\n \n     old_mem = pwndbg.gdblib.memory.read(address, len(new_mem))\n \n@@ -68,8 +68,8 @@\n \n     print(message.hint(\"Patches:\"))\n     for addr, (old, new) in patches.items():\n-        old_insns = disasm(old, arch=pwndbg.gdblib.arch.current)\n-        new_insns = disasm(new, arch=pwndbg.gdblib.arch.current)\n+        old_insns = disasm(old)\n+        new_insns = disasm(new)\n \n         print(\n             message.hint(\"Patch at\"),\n", "issue": "pwndbg.gdblib.arch.current is wrong if executed in a pwntools gdbscript command\nTL;DR: This should not fail, but does so, because the `patch` command fetches `pwndbg.gdblib.arch.current` which for some reason is wrong/not updated.\r\n\r\n\r\n```py\r\nfrom pwn import *\r\n\r\ngdbscript = '''\r\ntbreak main\r\npatch $rip 'xor rax, rax'\r\ncontinue\r\n'''\r\n\r\np = gdb.debug('/bin/ls', gdbscript=gdbscript)\r\n\r\np.interactive()\r\n```\r\n\r\nStacktrace:\r\n```\r\nTraceback (most recent call last):\r\n  File \"/home/dc/tools/pwndbg/pwndbg/commands/__init__.py\", line 145, in __call__\r\n    return self.function(*args, **kwargs)\r\n  File \"/home/dc/tools/pwndbg/pwndbg/commands/__init__.py\", line 216, in _OnlyWhenRunning\r\n    return function(*a, **kw)\r\n  File \"/home/dc/tools/pwndbg/pwndbg/commands/patch.py\", line 25, in patch\r\n    new_mem = asm(ins, arch=pwndbg.gdblib.arch.current)\r\n  File \"/home/dc/.virtualenvs/pwn/lib/python3.8/site-packages/pwnlib/context/__init__.py\", line 1444, in setter\r\n    raise AttributeError(\"Invalid arch/bits combination: %s/%s\" % (arch, bits))\r\nAttributeError: Invalid arch/bits combination: i386/64\r\n\r\nIf that is an issue, you can report it on https://github.com/pwndbg/pwndbg/issues\r\n(Please don't forget to search if it hasn't been reported before)\r\nTo generate the report and open a browser, you may run `bugreport --run-browser`\r\nPS: Pull requests are welcome\r\n> /home/dc/.virtualenvs/pwn/lib/python3.8/site-packages/pwnlib/context/__init__.py(1444)setter()\r\n-> raise AttributeError(\"Invalid arch/bits combination: %s/%s\" % (arch, bits))\r\n(Pdb) p arch, bits\r\n('i386', 64)\r\n(Pdb) \r\n```\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport argparse\n\nfrom pwnlib.asm import asm\nfrom pwnlib.asm import disasm\n\nimport pwndbg.color.message as message\nimport pwndbg.commands\nimport pwndbg.gdblib.memory\nimport pwndbg.lib.memoize\n\n# Keep old patches made so we can revert them\npatches = {}\n\n\nparser = argparse.ArgumentParser(description=\"Patches given instruction with given code or bytes\")\nparser.add_argument(\"address\", type=int, help=\"The address to patch\")\nparser.add_argument(\"ins\", type=str, help=\"instruction[s]\")\n\n\n@pwndbg.commands.ArgparsedCommand(parser)\n@pwndbg.commands.OnlyWhenRunning\ndef patch(address, ins):\n    new_mem = asm(ins, arch=pwndbg.gdblib.arch.current)\n\n    old_mem = pwndbg.gdblib.memory.read(address, len(new_mem))\n\n    patches[address] = (old_mem, new_mem)\n\n    pwndbg.gdblib.memory.write(address, new_mem)\n\n    pwndbg.lib.memoize.reset()\n\n\nparser2 = argparse.ArgumentParser(description=\"Revert patch at given address\")\nparser2.add_argument(\"address\", type=int, help=\"Address to revert patch on\")\n\n\n@pwndbg.commands.ArgparsedCommand(parser2)\n@pwndbg.commands.OnlyWhenRunning\ndef patch_revert(address):\n    if not patches:\n        print(message.notice(\"No patches to revert\"))\n        return\n\n    if address == -1:\n        for addr, (old, _new) in patches.items():\n            pwndbg.gdblib.memory.write(addr, old)\n            print(message.notice(\"Reverted patch at %#x\" % addr))\n        patches.clear()\n    else:\n        old, _new = patches[address]\n        pwndbg.gdblib.memory.write(address, old)\n\n    pwndbg.lib.memoize.reset()\n\n\nparser3 = argparse.ArgumentParser(description=\"List all patches\")\n\n\n@pwndbg.commands.ArgparsedCommand(parser3)\n@pwndbg.commands.OnlyWhenRunning\ndef patch_list():\n    if not patches:\n        print(message.hint(\"No patches to list\"))\n        return\n\n    print(message.hint(\"Patches:\"))\n    for addr, (old, new) in patches.items():\n        old_insns = disasm(old, arch=pwndbg.gdblib.arch.current)\n        new_insns = disasm(new, arch=pwndbg.gdblib.arch.current)\n\n        print(\n            message.hint(\"Patch at\"),\n            message.warning(\"%#x:\" % addr),\n            message.hint(\"from\"),\n            message.warning(old_insns.replace(\"\\n\", \"; \")),\n            message.hint(\"to\"),\n            message.warning(new_insns.replace(\"\\n\", \"; \")),\n        )\n", "path": "pwndbg/commands/patch.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport argparse\n\nfrom pwnlib.asm import asm\nfrom pwnlib.asm import disasm\n\nimport pwndbg.color.message as message\nimport pwndbg.commands\nimport pwndbg.gdblib.memory\nimport pwndbg.lib.memoize\n\n# Keep old patches made so we can revert them\npatches = {}\n\n\nparser = argparse.ArgumentParser(description=\"Patches given instruction with given code or bytes\")\nparser.add_argument(\"address\", type=int, help=\"The address to patch\")\nparser.add_argument(\"ins\", type=str, help=\"instruction[s]\")\n\n\n@pwndbg.commands.ArgparsedCommand(parser)\n@pwndbg.commands.OnlyWhenRunning\ndef patch(address, ins):\n    new_mem = asm(ins)\n\n    old_mem = pwndbg.gdblib.memory.read(address, len(new_mem))\n\n    patches[address] = (old_mem, new_mem)\n\n    pwndbg.gdblib.memory.write(address, new_mem)\n\n    pwndbg.lib.memoize.reset()\n\n\nparser2 = argparse.ArgumentParser(description=\"Revert patch at given address\")\nparser2.add_argument(\"address\", type=int, help=\"Address to revert patch on\")\n\n\n@pwndbg.commands.ArgparsedCommand(parser2)\n@pwndbg.commands.OnlyWhenRunning\ndef patch_revert(address):\n    if not patches:\n        print(message.notice(\"No patches to revert\"))\n        return\n\n    if address == -1:\n        for addr, (old, _new) in patches.items():\n            pwndbg.gdblib.memory.write(addr, old)\n            print(message.notice(\"Reverted patch at %#x\" % addr))\n        patches.clear()\n    else:\n        old, _new = patches[address]\n        pwndbg.gdblib.memory.write(address, old)\n\n    pwndbg.lib.memoize.reset()\n\n\nparser3 = argparse.ArgumentParser(description=\"List all patches\")\n\n\n@pwndbg.commands.ArgparsedCommand(parser3)\n@pwndbg.commands.OnlyWhenRunning\ndef patch_list():\n    if not patches:\n        print(message.hint(\"No patches to list\"))\n        return\n\n    print(message.hint(\"Patches:\"))\n    for addr, (old, new) in patches.items():\n        old_insns = disasm(old)\n        new_insns = disasm(new)\n\n        print(\n            message.hint(\"Patch at\"),\n            message.warning(\"%#x:\" % addr),\n            message.hint(\"from\"),\n            message.warning(old_insns.replace(\"\\n\", \"; \")),\n            message.hint(\"to\"),\n            message.warning(new_insns.replace(\"\\n\", \"; \")),\n        )\n", "path": "pwndbg/commands/patch.py"}]}