We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
search --asm: look for assembly instruction[s] bytes
The `search` command should have a way to search for a given assembly instruction[s] bytes.

We can assemble the given instructions through pwntools (its `pwnlib` import) similarly as we do in the `asm` command implementation: https://github.com/pwndbg/pwndbg/blob/c0d785565b499ba32d674c9e84a27e4967aee315/pwndbg/commands/asm.py#L69

This can probably be implemented as a `-a --asm` or `-t|--type=asm` option, where if provided, we would search for assebmled bytes.

E.g. in x86-64 programs `search --asm "xor rax, rax"` should assemble it through pwnlib to the following bytes:
  ```py
  In [4]: asm('xor rax, rax', arch='amd64')
  Out[4]: b'H1\xc0'
  ```
And then search the memory for those bytes (`b'H1\xc0'`). Ofc it should work with all the other options in `search` command like `--writable` or the ability to pass in a mapping name as the last argument of the search.


--- 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/search.py`
Content:
```
1 from __future__ import annotations
2 
3 import argparse
4 import binascii
5 import codecs
6 import os
7 import struct
8 
9 import pwndbg.color.memory as M
10 import pwndbg.commands
11 import pwndbg.enhance
12 import pwndbg.gdblib.arch
13 import pwndbg.gdblib.config
14 import pwndbg.gdblib.vmmap
15 import pwndbg.search
16 from pwndbg.color import message
17 from pwndbg.commands import CommandCategory
18 
19 saved: set[int] = set()
20 
21 
22 def print_search_hit(address) -> None:
23     """Prints out a single search hit.
24 
25     Arguments:
26         address(int): Address to print
27     """
28     if not address:
29         return
30 
31     vmmap = pwndbg.gdblib.vmmap.find(address)
32     if vmmap:
33         region = os.path.basename(vmmap.objfile)
34     else:
35         region = "[mapped]"
36 
37     region = region.ljust(15)
38 
39     region = M.get(address, region)
40     addr = M.get(address)
41     display = pwndbg.enhance.enhance(address)
42     print(region, addr, display)
43 
44 
45 auto_save = pwndbg.gdblib.config.add_param(
46     "auto-save-search", False, 'automatically pass --save to "search" command'
47 )
48 parser = argparse.ArgumentParser(
49     formatter_class=argparse.RawTextHelpFormatter,
50     description="""Search memory for byte sequences, strings, pointers, and integer values.
51 
52 By default search results are cached. If you want to cache all results, but only print a subset, use --trunc-out. If you want to cache only a subset of results, and print the results immediately, use --limit. The latter is specially useful if you're searching a huge section of memory.
53 
54 """,
55 )
56 parser.add_argument(
57     "-t",
58     "--type",
59     choices=["byte", "short", "word", "dword", "qword", "pointer", "string", "bytes"],
60     help="Size of search target",
61     default="bytes",
62     type=str,
63 )
64 parser.add_argument(
65     "-1",
66     "--byte",
67     dest="type",
68     action="store_const",
69     const="byte",
70     help="Search for a 1-byte integer",
71 )
72 parser.add_argument(
73     "-2",
74     "--word",
75     "--short",
76     dest="type",
77     action="store_const",
78     const="word",
79     help="Search for a 2-byte integer",
80 )
81 parser.add_argument(
82     "-4",
83     "--dword",
84     dest="type",
85     action="store_const",
86     const="dword",
87     help="Search for a 4-byte integer",
88 )
89 parser.add_argument(
90     "-8",
91     "--qword",
92     dest="type",
93     action="store_const",
94     const="qword",
95     help="Search for an 8-byte integer",
96 )
97 parser.add_argument(
98     "-p",
99     "--pointer",
100     dest="type",
101     action="store_const",
102     const="pointer",
103     help="Search for a pointer-width integer",
104 )
105 parser.add_argument(
106     "-x", "--hex", action="store_true", help="Target is a hex-encoded (for bytes/strings)"
107 )
108 parser.add_argument(
109     "-e", "--executable", action="store_true", help="Search executable segments only"
110 )
111 parser.add_argument("-w", "--writable", action="store_true", help="Search writable segments only")
112 parser.add_argument(
113     "-s",
114     "--step",
115     default=None,
116     type=str,
117     help="Step search address forward to next alignment after each hit (ex: 0x1000)",
118 )
119 parser.add_argument(
120     "-l",
121     "--limit",
122     default=None,
123     type=str,
124     help="Max results before quitting the search. Differs from --trunc-out in that it will not save all search results before quitting",
125 )
126 parser.add_argument(
127     "-a", "--aligned", default=None, type=str, help="Result must be aligned to this byte boundary"
128 )
129 parser.add_argument("value", type=str, help="Value to search for")
130 parser.add_argument(
131     "mapping_name", type=str, nargs="?", default=None, help="Mapping to search [e.g. libc]"
132 )
133 parser.add_argument(
134     "--save",
135     action="store_true",
136     default=None,
137     help="Save results for further searches with --next. Default comes from config %r"
138     % auto_save.name,
139 )
140 parser.add_argument(
141     "--no-save", action="store_false", default=None, dest="save", help="Invert --save"
142 )
143 parser.add_argument(
144     "-n",
145     "--next",
146     action="store_true",
147     help="Search only locations returned by previous search with --save",
148 )
149 parser.add_argument(
150     "--trunc-out",
151     action="store_true",
152     default=False,
153     help="Truncate the output to 20 results. Differs from --limit in that it will first save all search results",
154 )
155 
156 
157 @pwndbg.commands.ArgparsedCommand(parser, category=CommandCategory.MEMORY)
158 @pwndbg.commands.OnlyWhenRunning
159 def search(
160     type,
161     hex,
162     executable,
163     writable,
164     step,
165     limit,
166     aligned,
167     value,
168     mapping_name,
169     save,
170     next,
171     trunc_out,
172 ) -> None:
173     global saved
174     if next and not saved:
175         print(
176             "WARNING: cannot filter previous search results as they were empty. Performing new search saving results."
177         )
178         next = False
179         save = True
180 
181     # Adjust pointer sizes to the local architecture
182     if type == "pointer":
183         type = {4: "dword", 8: "qword"}[pwndbg.gdblib.arch.ptrsize]
184 
185     if save is None:
186         save = bool(pwndbg.gdblib.config.auto_save_search)
187 
188     if hex:
189         try:
190             value = codecs.decode(value, "hex")
191         except binascii.Error as e:
192             print(f"invalid input for type hex: {e}")
193             return
194 
195     if step:
196         step = pwndbg.commands.fix_int(step)
197 
198     if aligned:
199         aligned = pwndbg.commands.fix_int(aligned)
200 
201     if limit:
202         limit = pwndbg.commands.fix_int(limit)
203     # Convert to an integer if needed, and pack to bytes
204     if type not in ("string", "bytes"):
205         value = pwndbg.commands.fix_int(value)
206         value &= pwndbg.gdblib.arch.ptrmask
207         fmt = {"little": "<", "big": ">"}[pwndbg.gdblib.arch.endian] + {
208             "byte": "B",
209             "short": "H",
210             "word": "H",
211             "dword": "L",
212             "qword": "Q",
213         }[type]
214 
215         try:
216             value = struct.pack(fmt, value)
217         except struct.error as e:
218             print(f"invalid input for type {type}: {e}")
219             return
220 
221     # Null-terminate strings
222     elif type == "string":
223         value = value.encode()
224         value += b"\x00"
225 
226     # Find the mappings that we're looking for
227     mappings = pwndbg.gdblib.vmmap.get()
228 
229     if mapping_name:
230         mappings = [m for m in mappings if mapping_name in m.objfile]
231 
232     if not mappings:
233         print(message.error("Could not find mapping %r" % mapping_name))
234         return
235 
236     # If next is passed, only perform a manual search over previously saved addresses
237     print("Searching for value: " + repr(value))
238     if next:
239         val_len = len(value)
240         new_saved = set()
241 
242         i = 0
243         for addr in saved:
244             try:
245                 val = pwndbg.gdblib.memory.read(addr, val_len)
246             except Exception:
247                 continue
248             if val == value:
249                 new_saved.add(addr)
250                 if not trunc_out or i < 20:
251                     print_search_hit(addr)
252                 i += 1
253 
254         print("Search found %d items" % i)
255         saved = new_saved
256         return
257 
258     # Prep the saved set if necessary
259     if save:
260         saved = set()
261 
262     # Perform the search
263     i = 0
264     for address in pwndbg.search.search(
265         value,
266         mappings=mappings,
267         executable=executable,
268         writable=writable,
269         step=step,
270         aligned=aligned,
271         limit=limit,
272     ):
273         if save:
274             saved.add(address)
275 
276         if not trunc_out or i < 20:
277             print_search_hit(address)
278         i += 1
279
```
--- 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/commands/search.py b/pwndbg/commands/search.py
--- a/pwndbg/commands/search.py
+++ b/pwndbg/commands/search.py
@@ -6,6 +6,8 @@
 import os
 import struct
 
+import pwnlib
+
 import pwndbg.color.memory as M
 import pwndbg.commands
 import pwndbg.enhance
@@ -56,7 +58,7 @@
 parser.add_argument(
     "-t",
     "--type",
-    choices=["byte", "short", "word", "dword", "qword", "pointer", "string", "bytes"],
+    choices=["byte", "short", "word", "dword", "qword", "pointer", "string", "bytes", "asm"],
     help="Size of search target",
     default="bytes",
     type=str,
@@ -102,6 +104,19 @@
     const="pointer",
     help="Search for a pointer-width integer",
 )
+parser.add_argument(
+    "--asm",
+    dest="type",
+    action="store_const",
+    const="asm",
+    help="Search for an assembly instruction",
+)
+parser.add_argument(
+    "--arch",
+    choices=pwnlib.context.context.architectures.keys(),
+    type=str,
+    help="Target architecture",
+)
 parser.add_argument(
     "-x", "--hex", action="store_true", help="Target is a hex-encoded (for bytes/strings)"
 )
@@ -158,6 +173,7 @@
 @pwndbg.commands.OnlyWhenRunning
 def search(
     type,
+    arch,
     hex,
     executable,
     writable,
@@ -178,6 +194,9 @@
         next = False
         save = True
 
+    if not arch:
+        arch = pwnlib.context.context.arch
+
     # Adjust pointer sizes to the local architecture
     if type == "pointer":
         type = {4: "dword", 8: "qword"}[pwndbg.gdblib.arch.ptrsize]
@@ -201,7 +220,7 @@
     if limit:
         limit = pwndbg.commands.fix_int(limit)
     # Convert to an integer if needed, and pack to bytes
-    if type not in ("string", "bytes"):
+    if type not in ("string", "bytes", "asm"):
         value = pwndbg.commands.fix_int(value)
         value &= pwndbg.gdblib.arch.ptrmask
         fmt = {"little": "<", "big": ">"}[pwndbg.gdblib.arch.endian] + {
@@ -223,6 +242,10 @@
         value = value.encode()
         value += b"\x00"
 
+    elif type == "asm":
+        bits_for_arch = pwnlib.context.context.architectures.get(arch, {}).get("bits")
+        value = pwnlib.asm.asm(value, arch=arch, bits=bits_for_arch)
+
     # Find the mappings that we're looking for
     mappings = pwndbg.gdblib.vmmap.get()
 
@@ -234,7 +257,11 @@
         return
 
     # If next is passed, only perform a manual search over previously saved addresses
-    print("Searching for value: " + repr(value))
+    if type == "asm":
+        print("Searching for instruction (assembled value): " + repr(value))
+    else:
+        print("Searching for value: " + repr(value))
+
     if next:
         val_len = len(value)
         new_saved = set()

{"golden_diff": "diff --git a/pwndbg/commands/search.py b/pwndbg/commands/search.py\n--- a/pwndbg/commands/search.py\n+++ b/pwndbg/commands/search.py\n@@ -6,6 +6,8 @@\n import os\n import struct\n \n+import pwnlib\n+\n import pwndbg.color.memory as M\n import pwndbg.commands\n import pwndbg.enhance\n@@ -56,7 +58,7 @@\n parser.add_argument(\n     \"-t\",\n     \"--type\",\n-    choices=[\"byte\", \"short\", \"word\", \"dword\", \"qword\", \"pointer\", \"string\", \"bytes\"],\n+    choices=[\"byte\", \"short\", \"word\", \"dword\", \"qword\", \"pointer\", \"string\", \"bytes\", \"asm\"],\n     help=\"Size of search target\",\n     default=\"bytes\",\n     type=str,\n@@ -102,6 +104,19 @@\n     const=\"pointer\",\n     help=\"Search for a pointer-width integer\",\n )\n+parser.add_argument(\n+    \"--asm\",\n+    dest=\"type\",\n+    action=\"store_const\",\n+    const=\"asm\",\n+    help=\"Search for an assembly instruction\",\n+)\n+parser.add_argument(\n+    \"--arch\",\n+    choices=pwnlib.context.context.architectures.keys(),\n+    type=str,\n+    help=\"Target architecture\",\n+)\n parser.add_argument(\n     \"-x\", \"--hex\", action=\"store_true\", help=\"Target is a hex-encoded (for bytes/strings)\"\n )\n@@ -158,6 +173,7 @@\n @pwndbg.commands.OnlyWhenRunning\n def search(\n     type,\n+    arch,\n     hex,\n     executable,\n     writable,\n@@ -178,6 +194,9 @@\n         next = False\n         save = True\n \n+    if not arch:\n+        arch = pwnlib.context.context.arch\n+\n     # Adjust pointer sizes to the local architecture\n     if type == \"pointer\":\n         type = {4: \"dword\", 8: \"qword\"}[pwndbg.gdblib.arch.ptrsize]\n@@ -201,7 +220,7 @@\n     if limit:\n         limit = pwndbg.commands.fix_int(limit)\n     # Convert to an integer if needed, and pack to bytes\n-    if type not in (\"string\", \"bytes\"):\n+    if type not in (\"string\", \"bytes\", \"asm\"):\n         value = pwndbg.commands.fix_int(value)\n         value &= pwndbg.gdblib.arch.ptrmask\n         fmt = {\"little\": \"<\", \"big\": \">\"}[pwndbg.gdblib.arch.endian] + {\n@@ -223,6 +242,10 @@\n         value = value.encode()\n         value += b\"\\x00\"\n \n+    elif type == \"asm\":\n+        bits_for_arch = pwnlib.context.context.architectures.get(arch, {}).get(\"bits\")\n+        value = pwnlib.asm.asm(value, arch=arch, bits=bits_for_arch)\n+\n     # Find the mappings that we're looking for\n     mappings = pwndbg.gdblib.vmmap.get()\n \n@@ -234,7 +257,11 @@\n         return\n \n     # If next is passed, only perform a manual search over previously saved addresses\n-    print(\"Searching for value: \" + repr(value))\n+    if type == \"asm\":\n+        print(\"Searching for instruction (assembled value): \" + repr(value))\n+    else:\n+        print(\"Searching for value: \" + repr(value))\n+\n     if next:\n         val_len = len(value)\n         new_saved = set()\n", "issue": "search --asm: look for assembly instruction[s] bytes\nThe `search` command should have a way to search for a given assembly instruction[s] bytes.\r\n\r\nWe can assemble the given instructions through pwntools (its `pwnlib` import) similarly as we do in the `asm` command implementation: https://github.com/pwndbg/pwndbg/blob/c0d785565b499ba32d674c9e84a27e4967aee315/pwndbg/commands/asm.py#L69\r\n\r\nThis can probably be implemented as a `-a --asm` or `-t|--type=asm` option, where if provided, we would search for assebmled bytes.\r\n\r\nE.g. in x86-64 programs `search --asm \"xor rax, rax\"` should assemble it through pwnlib to the following bytes:\r\n  ```py\r\n  In [4]: asm('xor rax, rax', arch='amd64')\r\n  Out[4]: b'H1\\xc0'\r\n  ```\r\nAnd then search the memory for those bytes (`b'H1\\xc0'`). Ofc it should work with all the other options in `search` command like `--writable` or the ability to pass in a mapping name as the last argument of the search.\r\n\n", "before_files": [{"content": "from __future__ import annotations\n\nimport argparse\nimport binascii\nimport codecs\nimport os\nimport struct\n\nimport pwndbg.color.memory as M\nimport pwndbg.commands\nimport pwndbg.enhance\nimport pwndbg.gdblib.arch\nimport pwndbg.gdblib.config\nimport pwndbg.gdblib.vmmap\nimport pwndbg.search\nfrom pwndbg.color import message\nfrom pwndbg.commands import CommandCategory\n\nsaved: set[int] = set()\n\n\ndef print_search_hit(address) -> None:\n    \"\"\"Prints out a single search hit.\n\n    Arguments:\n        address(int): Address to print\n    \"\"\"\n    if not address:\n        return\n\n    vmmap = pwndbg.gdblib.vmmap.find(address)\n    if vmmap:\n        region = os.path.basename(vmmap.objfile)\n    else:\n        region = \"[mapped]\"\n\n    region = region.ljust(15)\n\n    region = M.get(address, region)\n    addr = M.get(address)\n    display = pwndbg.enhance.enhance(address)\n    print(region, addr, display)\n\n\nauto_save = pwndbg.gdblib.config.add_param(\n    \"auto-save-search\", False, 'automatically pass --save to \"search\" command'\n)\nparser = argparse.ArgumentParser(\n    formatter_class=argparse.RawTextHelpFormatter,\n    description=\"\"\"Search memory for byte sequences, strings, pointers, and integer values.\n\nBy default search results are cached. If you want to cache all results, but only print a subset, use --trunc-out. If you want to cache only a subset of results, and print the results immediately, use --limit. The latter is specially useful if you're searching a huge section of memory.\n\n\"\"\",\n)\nparser.add_argument(\n    \"-t\",\n    \"--type\",\n    choices=[\"byte\", \"short\", \"word\", \"dword\", \"qword\", \"pointer\", \"string\", \"bytes\"],\n    help=\"Size of search target\",\n    default=\"bytes\",\n    type=str,\n)\nparser.add_argument(\n    \"-1\",\n    \"--byte\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"byte\",\n    help=\"Search for a 1-byte integer\",\n)\nparser.add_argument(\n    \"-2\",\n    \"--word\",\n    \"--short\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"word\",\n    help=\"Search for a 2-byte integer\",\n)\nparser.add_argument(\n    \"-4\",\n    \"--dword\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"dword\",\n    help=\"Search for a 4-byte integer\",\n)\nparser.add_argument(\n    \"-8\",\n    \"--qword\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"qword\",\n    help=\"Search for an 8-byte integer\",\n)\nparser.add_argument(\n    \"-p\",\n    \"--pointer\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"pointer\",\n    help=\"Search for a pointer-width integer\",\n)\nparser.add_argument(\n    \"-x\", \"--hex\", action=\"store_true\", help=\"Target is a hex-encoded (for bytes/strings)\"\n)\nparser.add_argument(\n    \"-e\", \"--executable\", action=\"store_true\", help=\"Search executable segments only\"\n)\nparser.add_argument(\"-w\", \"--writable\", action=\"store_true\", help=\"Search writable segments only\")\nparser.add_argument(\n    \"-s\",\n    \"--step\",\n    default=None,\n    type=str,\n    help=\"Step search address forward to next alignment after each hit (ex: 0x1000)\",\n)\nparser.add_argument(\n    \"-l\",\n    \"--limit\",\n    default=None,\n    type=str,\n    help=\"Max results before quitting the search. Differs from --trunc-out in that it will not save all search results before quitting\",\n)\nparser.add_argument(\n    \"-a\", \"--aligned\", default=None, type=str, help=\"Result must be aligned to this byte boundary\"\n)\nparser.add_argument(\"value\", type=str, help=\"Value to search for\")\nparser.add_argument(\n    \"mapping_name\", type=str, nargs=\"?\", default=None, help=\"Mapping to search [e.g. libc]\"\n)\nparser.add_argument(\n    \"--save\",\n    action=\"store_true\",\n    default=None,\n    help=\"Save results for further searches with --next. Default comes from config %r\"\n    % auto_save.name,\n)\nparser.add_argument(\n    \"--no-save\", action=\"store_false\", default=None, dest=\"save\", help=\"Invert --save\"\n)\nparser.add_argument(\n    \"-n\",\n    \"--next\",\n    action=\"store_true\",\n    help=\"Search only locations returned by previous search with --save\",\n)\nparser.add_argument(\n    \"--trunc-out\",\n    action=\"store_true\",\n    default=False,\n    help=\"Truncate the output to 20 results. Differs from --limit in that it will first save all search results\",\n)\n\n\n@pwndbg.commands.ArgparsedCommand(parser, category=CommandCategory.MEMORY)\n@pwndbg.commands.OnlyWhenRunning\ndef search(\n    type,\n    hex,\n    executable,\n    writable,\n    step,\n    limit,\n    aligned,\n    value,\n    mapping_name,\n    save,\n    next,\n    trunc_out,\n) -> None:\n    global saved\n    if next and not saved:\n        print(\n            \"WARNING: cannot filter previous search results as they were empty. Performing new search saving results.\"\n        )\n        next = False\n        save = True\n\n    # Adjust pointer sizes to the local architecture\n    if type == \"pointer\":\n        type = {4: \"dword\", 8: \"qword\"}[pwndbg.gdblib.arch.ptrsize]\n\n    if save is None:\n        save = bool(pwndbg.gdblib.config.auto_save_search)\n\n    if hex:\n        try:\n            value = codecs.decode(value, \"hex\")\n        except binascii.Error as e:\n            print(f\"invalid input for type hex: {e}\")\n            return\n\n    if step:\n        step = pwndbg.commands.fix_int(step)\n\n    if aligned:\n        aligned = pwndbg.commands.fix_int(aligned)\n\n    if limit:\n        limit = pwndbg.commands.fix_int(limit)\n    # Convert to an integer if needed, and pack to bytes\n    if type not in (\"string\", \"bytes\"):\n        value = pwndbg.commands.fix_int(value)\n        value &= pwndbg.gdblib.arch.ptrmask\n        fmt = {\"little\": \"<\", \"big\": \">\"}[pwndbg.gdblib.arch.endian] + {\n            \"byte\": \"B\",\n            \"short\": \"H\",\n            \"word\": \"H\",\n            \"dword\": \"L\",\n            \"qword\": \"Q\",\n        }[type]\n\n        try:\n            value = struct.pack(fmt, value)\n        except struct.error as e:\n            print(f\"invalid input for type {type}: {e}\")\n            return\n\n    # Null-terminate strings\n    elif type == \"string\":\n        value = value.encode()\n        value += b\"\\x00\"\n\n    # Find the mappings that we're looking for\n    mappings = pwndbg.gdblib.vmmap.get()\n\n    if mapping_name:\n        mappings = [m for m in mappings if mapping_name in m.objfile]\n\n    if not mappings:\n        print(message.error(\"Could not find mapping %r\" % mapping_name))\n        return\n\n    # If next is passed, only perform a manual search over previously saved addresses\n    print(\"Searching for value: \" + repr(value))\n    if next:\n        val_len = len(value)\n        new_saved = set()\n\n        i = 0\n        for addr in saved:\n            try:\n                val = pwndbg.gdblib.memory.read(addr, val_len)\n            except Exception:\n                continue\n            if val == value:\n                new_saved.add(addr)\n                if not trunc_out or i < 20:\n                    print_search_hit(addr)\n                i += 1\n\n        print(\"Search found %d items\" % i)\n        saved = new_saved\n        return\n\n    # Prep the saved set if necessary\n    if save:\n        saved = set()\n\n    # Perform the search\n    i = 0\n    for address in pwndbg.search.search(\n        value,\n        mappings=mappings,\n        executable=executable,\n        writable=writable,\n        step=step,\n        aligned=aligned,\n        limit=limit,\n    ):\n        if save:\n            saved.add(address)\n\n        if not trunc_out or i < 20:\n            print_search_hit(address)\n        i += 1\n", "path": "pwndbg/commands/search.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport argparse\nimport binascii\nimport codecs\nimport os\nimport struct\n\nimport pwnlib\n\nimport pwndbg.color.memory as M\nimport pwndbg.commands\nimport pwndbg.enhance\nimport pwndbg.gdblib.arch\nimport pwndbg.gdblib.config\nimport pwndbg.gdblib.vmmap\nimport pwndbg.search\nfrom pwndbg.color import message\nfrom pwndbg.commands import CommandCategory\n\nsaved: set[int] = set()\n\n\ndef print_search_hit(address) -> None:\n    \"\"\"Prints out a single search hit.\n\n    Arguments:\n        address(int): Address to print\n    \"\"\"\n    if not address:\n        return\n\n    vmmap = pwndbg.gdblib.vmmap.find(address)\n    if vmmap:\n        region = os.path.basename(vmmap.objfile)\n    else:\n        region = \"[mapped]\"\n\n    region = region.ljust(15)\n\n    region = M.get(address, region)\n    addr = M.get(address)\n    display = pwndbg.enhance.enhance(address)\n    print(region, addr, display)\n\n\nauto_save = pwndbg.gdblib.config.add_param(\n    \"auto-save-search\", False, 'automatically pass --save to \"search\" command'\n)\nparser = argparse.ArgumentParser(\n    formatter_class=argparse.RawTextHelpFormatter,\n    description=\"\"\"Search memory for byte sequences, strings, pointers, and integer values.\n\nBy default search results are cached. If you want to cache all results, but only print a subset, use --trunc-out. If you want to cache only a subset of results, and print the results immediately, use --limit. The latter is specially useful if you're searching a huge section of memory.\n\n\"\"\",\n)\nparser.add_argument(\n    \"-t\",\n    \"--type\",\n    choices=[\"byte\", \"short\", \"word\", \"dword\", \"qword\", \"pointer\", \"string\", \"bytes\", \"asm\"],\n    help=\"Size of search target\",\n    default=\"bytes\",\n    type=str,\n)\nparser.add_argument(\n    \"-1\",\n    \"--byte\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"byte\",\n    help=\"Search for a 1-byte integer\",\n)\nparser.add_argument(\n    \"-2\",\n    \"--word\",\n    \"--short\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"word\",\n    help=\"Search for a 2-byte integer\",\n)\nparser.add_argument(\n    \"-4\",\n    \"--dword\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"dword\",\n    help=\"Search for a 4-byte integer\",\n)\nparser.add_argument(\n    \"-8\",\n    \"--qword\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"qword\",\n    help=\"Search for an 8-byte integer\",\n)\nparser.add_argument(\n    \"-p\",\n    \"--pointer\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"pointer\",\n    help=\"Search for a pointer-width integer\",\n)\nparser.add_argument(\n    \"--asm\",\n    dest=\"type\",\n    action=\"store_const\",\n    const=\"asm\",\n    help=\"Search for an assembly instruction\",\n)\nparser.add_argument(\n    \"--arch\",\n    choices=pwnlib.context.context.architectures.keys(),\n    type=str,\n    help=\"Target architecture\",\n)\nparser.add_argument(\n    \"-x\", \"--hex\", action=\"store_true\", help=\"Target is a hex-encoded (for bytes/strings)\"\n)\nparser.add_argument(\n    \"-e\", \"--executable\", action=\"store_true\", help=\"Search executable segments only\"\n)\nparser.add_argument(\"-w\", \"--writable\", action=\"store_true\", help=\"Search writable segments only\")\nparser.add_argument(\n    \"-s\",\n    \"--step\",\n    default=None,\n    type=str,\n    help=\"Step search address forward to next alignment after each hit (ex: 0x1000)\",\n)\nparser.add_argument(\n    \"-l\",\n    \"--limit\",\n    default=None,\n    type=str,\n    help=\"Max results before quitting the search. Differs from --trunc-out in that it will not save all search results before quitting\",\n)\nparser.add_argument(\n    \"-a\", \"--aligned\", default=None, type=str, help=\"Result must be aligned to this byte boundary\"\n)\nparser.add_argument(\"value\", type=str, help=\"Value to search for\")\nparser.add_argument(\n    \"mapping_name\", type=str, nargs=\"?\", default=None, help=\"Mapping to search [e.g. libc]\"\n)\nparser.add_argument(\n    \"--save\",\n    action=\"store_true\",\n    default=None,\n    help=\"Save results for further searches with --next. Default comes from config %r\"\n    % auto_save.name,\n)\nparser.add_argument(\n    \"--no-save\", action=\"store_false\", default=None, dest=\"save\", help=\"Invert --save\"\n)\nparser.add_argument(\n    \"-n\",\n    \"--next\",\n    action=\"store_true\",\n    help=\"Search only locations returned by previous search with --save\",\n)\nparser.add_argument(\n    \"--trunc-out\",\n    action=\"store_true\",\n    default=False,\n    help=\"Truncate the output to 20 results. Differs from --limit in that it will first save all search results\",\n)\n\n\n@pwndbg.commands.ArgparsedCommand(parser, category=CommandCategory.MEMORY)\n@pwndbg.commands.OnlyWhenRunning\ndef search(\n    type,\n    arch,\n    hex,\n    executable,\n    writable,\n    step,\n    limit,\n    aligned,\n    value,\n    mapping_name,\n    save,\n    next,\n    trunc_out,\n) -> None:\n    global saved\n    if next and not saved:\n        print(\n            \"WARNING: cannot filter previous search results as they were empty. Performing new search saving results.\"\n        )\n        next = False\n        save = True\n\n    if not arch:\n        arch = pwnlib.context.context.arch\n\n    # Adjust pointer sizes to the local architecture\n    if type == \"pointer\":\n        type = {4: \"dword\", 8: \"qword\"}[pwndbg.gdblib.arch.ptrsize]\n\n    if save is None:\n        save = bool(pwndbg.gdblib.config.auto_save_search)\n\n    if hex:\n        try:\n            value = codecs.decode(value, \"hex\")\n        except binascii.Error as e:\n            print(f\"invalid input for type hex: {e}\")\n            return\n\n    if step:\n        step = pwndbg.commands.fix_int(step)\n\n    if aligned:\n        aligned = pwndbg.commands.fix_int(aligned)\n\n    if limit:\n        limit = pwndbg.commands.fix_int(limit)\n    # Convert to an integer if needed, and pack to bytes\n    if type not in (\"string\", \"bytes\", \"asm\"):\n        value = pwndbg.commands.fix_int(value)\n        value &= pwndbg.gdblib.arch.ptrmask\n        fmt = {\"little\": \"<\", \"big\": \">\"}[pwndbg.gdblib.arch.endian] + {\n            \"byte\": \"B\",\n            \"short\": \"H\",\n            \"word\": \"H\",\n            \"dword\": \"L\",\n            \"qword\": \"Q\",\n        }[type]\n\n        try:\n            value = struct.pack(fmt, value)\n        except struct.error as e:\n            print(f\"invalid input for type {type}: {e}\")\n            return\n\n    # Null-terminate strings\n    elif type == \"string\":\n        value = value.encode()\n        value += b\"\\x00\"\n\n    elif type == \"asm\":\n        bits_for_arch = pwnlib.context.context.architectures.get(arch, {}).get(\"bits\")\n        value = pwnlib.asm.asm(value, arch=arch, bits=bits_for_arch)\n\n    # Find the mappings that we're looking for\n    mappings = pwndbg.gdblib.vmmap.get()\n\n    if mapping_name:\n        mappings = [m for m in mappings if mapping_name in m.objfile]\n\n    if not mappings:\n        print(message.error(\"Could not find mapping %r\" % mapping_name))\n        return\n\n    # If next is passed, only perform a manual search over previously saved addresses\n    if type == \"asm\":\n        print(\"Searching for instruction (assembled value): \" + repr(value))\n    else:\n        print(\"Searching for value: \" + repr(value))\n\n    if next:\n        val_len = len(value)\n        new_saved = set()\n\n        i = 0\n        for addr in saved:\n            try:\n                val = pwndbg.gdblib.memory.read(addr, val_len)\n            except Exception:\n                continue\n            if val == value:\n                new_saved.add(addr)\n                if not trunc_out or i < 20:\n                    print_search_hit(addr)\n                i += 1\n\n        print(\"Search found %d items\" % i)\n        saved = new_saved\n        return\n\n    # Prep the saved set if necessary\n    if save:\n        saved = set()\n\n    # Perform the search\n    i = 0\n    for address in pwndbg.search.search(\n        value,\n        mappings=mappings,\n        executable=executable,\n        writable=writable,\n        step=step,\n        aligned=aligned,\n        limit=limit,\n    ):\n        if save:\n            saved.add(address)\n\n        if not trunc_out or i < 20:\n            print_search_hit(address)\n        i += 1\n", "path": "pwndbg/commands/search.py"}]}