prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  qemu local_path bug
  ### Description
  
  It seems like some commands e.g. plt, got tries to use ELF file's content as path.
  
  ### Steps to reproduce
  
  ```
  $ qemu-arm -g 23946 ./target
  $ gdb-multiarch ./target
  (gdb) target remote :23946
  (gdb) plt # or
  (gdb) got
  ```
  
  ### My setup
  
  Ubuntu 18.04, branch c6473ba (master)
  
  ### Analysis (and temporary patch)
  
  plt/got command uses `get_elf_info` at [elf.py](https://github.com/pwndbg/pwndbg/blob/dev/pwndbg/elf.py#L95), which uses get_file at file.py.
  
  It seems like the path itself should be used in [file.py L36](https://github.com/pwndbg/pwndbg/blob/c6473ba7aea797f7b4d2251febf419382564d3f8/pwndbg/file.py#L36):
  
  https://github.com/pwndbg/pwndbg/blob/203f10710e8a9a195a7bade59661ed7f3e3e641c/pwndbg/file.py#L35-L36
  
  to
  ```py
      if pwndbg.qemu.root() and recurse:
          return os.path.join(pwndbg.qemu.binfmt_root, path)
  ```
  
  I'm not sure if it's ok in all cases, since I think relative path should be also searched, but it works on plt/got case since absolute path is used (e.g. if path is 'a/b', I'm not sure if binfmt_root + '/a/b' and 'a/b' shoud be searched.)
  
  --- 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/file.py`
  Content:
  ```
  1 #!/usr/bin/env python
  2 # -*- coding: utf-8 -*-
  3 """
  4 Retrieve files from the debuggee's filesystem.  Useful when
  5 debugging a remote process over SSH or similar, where e.g.
  6 /proc/FOO/maps is needed from the remote system.
  7 """
  8 from __future__ import absolute_import
  9 from __future__ import division
  10 from __future__ import print_function
  11 from __future__ import unicode_literals
  12 
  13 import binascii
  14 import errno as _errno
  15 import os
  16 import subprocess
  17 import tempfile
  18 
  19 import gdb
  20 
  21 import pwndbg.qemu
  22 import pwndbg.remote
  23 
  24 
  25 def get_file(path, recurse=1):
  26     """
  27     Downloads the specified file from the system where the current process is
  28     being debugged.
  29 
  30     Returns:
  31         The local path to the file
  32     """
  33     local_path = path
  34 
  35     if pwndbg.qemu.root() and recurse:
  36         return get(os.path.join(pwndbg.qemu.binfmt_root, path), 0)
  37     elif pwndbg.remote.is_remote() and not pwndbg.qemu.is_qemu():
  38         local_path = tempfile.mktemp()
  39         error      = None
  40         try:
  41             error = gdb.execute('remote get "%s" "%s"' % (path, local_path),
  42                                  to_string=True)
  43         except gdb.error as e:
  44             error = e
  45 
  46         if error:
  47             raise OSError("Could not download remote file %r:\n" \
  48                             "Error: %s" % (path, error))
  49 
  50     return local_path
  51 
  52 def get(path, recurse=1):
  53     """
  54     Retrieves the contents of the specified file on the system
  55     where the current process is being debugged.
  56 
  57     Returns:
  58         A byte array, or None.
  59     """
  60     local_path = get_file(path, recurse)
  61 
  62     try:
  63         with open(local_path,'rb') as f:
  64             return f.read()
  65     except:
  66         return b''
  67 
  68 def readlink(path):
  69     """readlink(path) -> str
  70 
  71     Read the link specified by 'path' on the system being debugged.
  72 
  73     Handles local, qemu-usermode, and remote debugging cases.
  74     """
  75     is_qemu = pwndbg.qemu.is_qemu_usermode()
  76 
  77     if is_qemu:
  78         if not os.path.exists(path):
  79             path = os.path.join(pwndbg.qemu.root(), path)
  80 
  81     if is_qemu or not pwndbg.remote.is_remote():
  82         try:
  83             return os.readlink(path)
  84         except Exception:
  85             return ''
  86 
  87     #
  88     # Hurray unexposed packets!
  89     #
  90     # The 'vFile:readlink:' packet does exactly what it sounds like,
  91     # but there is no API exposed to do this and there is also no
  92     # command exposed... so we have to send the packet manually.
  93     #
  94     cmd = 'maintenance packet vFile:readlink:%s'
  95 
  96     # The path must be uppercase hex-encoded and NULL-terminated.
  97     path += '\x00'
  98     path = binascii.hexlify(path.encode())
  99     path = path.upper()
  100     path = path.decode()
  101 
  102     result = gdb.execute(cmd % path, from_tty=False, to_string=True)
  103 
  104     """
  105     sending: "vFile:readlink:2F70726F632F3130303839302F66642F3000"
  106     received: "Fc;pipe:[98420]"
  107 
  108     sending: "vFile:readlink:2F70726F632F3130303839302F66642F333300"
  109     received: "F-1,2"
  110     """
  111 
  112     _, data = result.split('\n', 1)
  113 
  114     # Sanity check
  115     expected = 'received: "F'
  116     if not data.startswith(expected):
  117         return ''
  118 
  119     # Negative values are errors
  120     data = data[len(expected):]
  121     if data[0] == '-':
  122         return ''
  123 
  124     # If non-negative, there will be a hex-encoded length followed
  125     # by a semicolon.
  126     n, data = data.split(';', 1)
  127 
  128     n = int(n, 16)
  129     if n < 0:
  130         return ''
  131 
  132     # The result is quoted by GDB, strip the quote and newline.
  133     # I have no idea how well it handles other crazy stuff.
  134     ending = '"\n'
  135     data = data[:-len(ending)]
  136 
  137     return data
  138
  ```
  --- 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/file.py b/pwndbg/file.py
  --- a/pwndbg/file.py
  +++ b/pwndbg/file.py
  @@ -33,7 +33,7 @@
       local_path = path
   
       if pwndbg.qemu.root() and recurse:
  -        return get(os.path.join(pwndbg.qemu.binfmt_root, path), 0)
  +        return os.path.join(pwndbg.qemu.binfmt_root, path)
       elif pwndbg.remote.is_remote() and not pwndbg.qemu.is_qemu():
           local_path = tempfile.mktemp()
           error      = None
  
verification_info: {"golden_diff": "diff --git a/pwndbg/file.py b/pwndbg/file.py\n--- a/pwndbg/file.py\n+++ b/pwndbg/file.py\n@@ -33,7 +33,7 @@\n     local_path = path\n \n     if pwndbg.qemu.root() and recurse:\n-        return get(os.path.join(pwndbg.qemu.binfmt_root, path), 0)\n+        return os.path.join(pwndbg.qemu.binfmt_root, path)\n     elif pwndbg.remote.is_remote() and not pwndbg.qemu.is_qemu():\n         local_path = tempfile.mktemp()\n         error      = None\n", "issue": "qemu local_path bug\n### Description\r\n\r\nIt seems like some commands e.g. plt, got tries to use ELF file's content as path.\r\n\r\n### Steps to reproduce\r\n\r\n```\r\n$ qemu-arm -g 23946 ./target\r\n$ gdb-multiarch ./target\r\n(gdb) target remote :23946\r\n(gdb) plt # or\r\n(gdb) got\r\n```\r\n\r\n### My setup\r\n\r\nUbuntu 18.04, branch c6473ba (master)\r\n\r\n### Analysis (and temporary patch)\r\n\r\nplt/got command uses `get_elf_info` at [elf.py](https://github.com/pwndbg/pwndbg/blob/dev/pwndbg/elf.py#L95), which uses get_file at file.py.\r\n\r\nIt seems like the path itself should be used in [file.py L36](https://github.com/pwndbg/pwndbg/blob/c6473ba7aea797f7b4d2251febf419382564d3f8/pwndbg/file.py#L36):\r\n\r\nhttps://github.com/pwndbg/pwndbg/blob/203f10710e8a9a195a7bade59661ed7f3e3e641c/pwndbg/file.py#L35-L36\r\n\r\nto\r\n```py\r\n    if pwndbg.qemu.root() and recurse:\r\n        return os.path.join(pwndbg.qemu.binfmt_root, path)\r\n```\r\n\r\nI'm not sure if it's ok in all cases, since I think relative path should be also searched, but it works on plt/got case since absolute path is used (e.g. if path is 'a/b', I'm not sure if binfmt_root + '/a/b' and 'a/b' shoud be searched.)\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\nRetrieve files from the debuggee's filesystem.  Useful when\ndebugging a remote process over SSH or similar, where e.g.\n/proc/FOO/maps is needed from the remote system.\n\"\"\"\nfrom __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport binascii\nimport errno as _errno\nimport os\nimport subprocess\nimport tempfile\n\nimport gdb\n\nimport pwndbg.qemu\nimport pwndbg.remote\n\n\ndef get_file(path, recurse=1):\n    \"\"\"\n    Downloads the specified file from the system where the current process is\n    being debugged.\n\n    Returns:\n        The local path to the file\n    \"\"\"\n    local_path = path\n\n    if pwndbg.qemu.root() and recurse:\n        return get(os.path.join(pwndbg.qemu.binfmt_root, path), 0)\n    elif pwndbg.remote.is_remote() and not pwndbg.qemu.is_qemu():\n        local_path = tempfile.mktemp()\n        error      = None\n        try:\n            error = gdb.execute('remote get \"%s\" \"%s\"' % (path, local_path),\n                                 to_string=True)\n        except gdb.error as e:\n            error = e\n\n        if error:\n            raise OSError(\"Could not download remote file %r:\\n\" \\\n                            \"Error: %s\" % (path, error))\n\n    return local_path\n\ndef get(path, recurse=1):\n    \"\"\"\n    Retrieves the contents of the specified file on the system\n    where the current process is being debugged.\n\n    Returns:\n        A byte array, or None.\n    \"\"\"\n    local_path = get_file(path, recurse)\n\n    try:\n        with open(local_path,'rb') as f:\n            return f.read()\n    except:\n        return b''\n\ndef readlink(path):\n    \"\"\"readlink(path) -> str\n\n    Read the link specified by 'path' on the system being debugged.\n\n    Handles local, qemu-usermode, and remote debugging cases.\n    \"\"\"\n    is_qemu = pwndbg.qemu.is_qemu_usermode()\n\n    if is_qemu:\n        if not os.path.exists(path):\n            path = os.path.join(pwndbg.qemu.root(), path)\n\n    if is_qemu or not pwndbg.remote.is_remote():\n        try:\n            return os.readlink(path)\n        except Exception:\n            return ''\n\n    #\n    # Hurray unexposed packets!\n    #\n    # The 'vFile:readlink:' packet does exactly what it sounds like,\n    # but there is no API exposed to do this and there is also no\n    # command exposed... so we have to send the packet manually.\n    #\n    cmd = 'maintenance packet vFile:readlink:%s'\n\n    # The path must be uppercase hex-encoded and NULL-terminated.\n    path += '\\x00'\n    path = binascii.hexlify(path.encode())\n    path = path.upper()\n    path = path.decode()\n\n    result = gdb.execute(cmd % path, from_tty=False, to_string=True)\n\n    \"\"\"\n    sending: \"vFile:readlink:2F70726F632F3130303839302F66642F3000\"\n    received: \"Fc;pipe:[98420]\"\n\n    sending: \"vFile:readlink:2F70726F632F3130303839302F66642F333300\"\n    received: \"F-1,2\"\n    \"\"\"\n\n    _, data = result.split('\\n', 1)\n\n    # Sanity check\n    expected = 'received: \"F'\n    if not data.startswith(expected):\n        return ''\n\n    # Negative values are errors\n    data = data[len(expected):]\n    if data[0] == '-':\n        return ''\n\n    # If non-negative, there will be a hex-encoded length followed\n    # by a semicolon.\n    n, data = data.split(';', 1)\n\n    n = int(n, 16)\n    if n < 0:\n        return ''\n\n    # The result is quoted by GDB, strip the quote and newline.\n    # I have no idea how well it handles other crazy stuff.\n    ending = '\"\\n'\n    data = data[:-len(ending)]\n\n    return data\n", "path": "pwndbg/file.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\nRetrieve files from the debuggee's filesystem.  Useful when\ndebugging a remote process over SSH or similar, where e.g.\n/proc/FOO/maps is needed from the remote system.\n\"\"\"\nfrom __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport binascii\nimport errno as _errno\nimport os\nimport subprocess\nimport tempfile\n\nimport gdb\n\nimport pwndbg.qemu\nimport pwndbg.remote\n\n\ndef get_file(path, recurse=1):\n    \"\"\"\n    Downloads the specified file from the system where the current process is\n    being debugged.\n\n    Returns:\n        The local path to the file\n    \"\"\"\n    local_path = path\n\n    if pwndbg.qemu.root() and recurse:\n        return os.path.join(pwndbg.qemu.binfmt_root, path)\n    elif pwndbg.remote.is_remote() and not pwndbg.qemu.is_qemu():\n        local_path = tempfile.mktemp()\n        error      = None\n        try:\n            error = gdb.execute('remote get \"%s\" \"%s\"' % (path, local_path),\n                                 to_string=True)\n        except gdb.error as e:\n            error = e\n\n        if error:\n            raise OSError(\"Could not download remote file %r:\\n\" \\\n                            \"Error: %s\" % (path, error))\n\n    return local_path\n\ndef get(path, recurse=1):\n    \"\"\"\n    Retrieves the contents of the specified file on the system\n    where the current process is being debugged.\n\n    Returns:\n        A byte array, or None.\n    \"\"\"\n    local_path = get_file(path, recurse)\n\n    try:\n        with open(local_path,'rb') as f:\n            return f.read()\n    except:\n        return b''\n\ndef readlink(path):\n    \"\"\"readlink(path) -> str\n\n    Read the link specified by 'path' on the system being debugged.\n\n    Handles local, qemu-usermode, and remote debugging cases.\n    \"\"\"\n    is_qemu = pwndbg.qemu.is_qemu_usermode()\n\n    if is_qemu:\n        if not os.path.exists(path):\n            path = os.path.join(pwndbg.qemu.root(), path)\n\n    if is_qemu or not pwndbg.remote.is_remote():\n        try:\n            return os.readlink(path)\n        except Exception:\n            return ''\n\n    #\n    # Hurray unexposed packets!\n    #\n    # The 'vFile:readlink:' packet does exactly what it sounds like,\n    # but there is no API exposed to do this and there is also no\n    # command exposed... so we have to send the packet manually.\n    #\n    cmd = 'maintenance packet vFile:readlink:%s'\n\n    # The path must be uppercase hex-encoded and NULL-terminated.\n    path += '\\x00'\n    path = binascii.hexlify(path.encode())\n    path = path.upper()\n    path = path.decode()\n\n    result = gdb.execute(cmd % path, from_tty=False, to_string=True)\n\n    \"\"\"\n    sending: \"vFile:readlink:2F70726F632F3130303839302F66642F3000\"\n    received: \"Fc;pipe:[98420]\"\n\n    sending: \"vFile:readlink:2F70726F632F3130303839302F66642F333300\"\n    received: \"F-1,2\"\n    \"\"\"\n\n    _, data = result.split('\\n', 1)\n\n    # Sanity check\n    expected = 'received: \"F'\n    if not data.startswith(expected):\n        return ''\n\n    # Negative values are errors\n    data = data[len(expected):]\n    if data[0] == '-':\n        return ''\n\n    # If non-negative, there will be a hex-encoded length followed\n    # by a semicolon.\n    n, data = data.split(';', 1)\n\n    n = int(n, 16)\n    if n < 0:\n        return ''\n\n    # The result is quoted by GDB, strip the quote and newline.\n    # I have no idea how well it handles other crazy stuff.\n    ending = '\"\\n'\n    data = data[:-len(ending)]\n\n    return data\n", "path": "pwndbg/file.py"}]}