about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorChristian Krinitsin <mail@krinitsin.com>2025-11-26 15:37:23 +0100
committerChristian Krinitsin <mail@krinitsin.com>2025-11-26 15:37:23 +0100
commitb5179f8f12a8cb76d564a9fc8a76aac7733568a3 (patch)
treea83a4101490287217f8ac3cfe0dc2037de6f91ec
parent45ce3f21537cb6d614dd20c27f9e9640adc7edb0 (diff)
downloadfocaccia-b5179f8f12a8cb76d564a9fc8a76aac7733568a3.tar.gz
focaccia-b5179f8f12a8cb76d564a9fc8a76aac7733568a3.zip
QEMU tool: generate minimal reproducer
-rw-r--r--reproducers/1370-minimal.S44
-rw-r--r--src/focaccia/qemu/_qemu_tool.py20
-rw-r--r--src/focaccia/reproducer.py7
-rwxr-xr-xsrc/focaccia/tools/validate_qemu.py4
4 files changed, 71 insertions, 4 deletions
diff --git a/reproducers/1370-minimal.S b/reproducers/1370-minimal.S
new file mode 100644
index 0000000..4f213d9
--- /dev/null
+++ b/reproducers/1370-minimal.S
@@ -0,0 +1,44 @@
+.section .text
+.global _start
+
+_bb_0x401040:
+blsiq %rax, %rbx
+ret
+
+_start:
+call _setup_dyn
+call _setup_regs
+call _bb_0x401040
+call _exit
+
+_exit:
+movq $0, %rdi
+movq $60, %rax
+syscall
+
+_alloc:
+movq $4096, %rsi
+movq $(PROT_READ | PROT_WRITE), %rdx
+movq $(MAP_PRIVATE | MAP_ANONYMOUS), %r10
+movq $-1, %r8
+movq $0, %r9
+movq $syscall_mmap, %rax
+syscall
+ret
+
+_setup_regs:
+mov $0x0, %rax
+ret
+
+_setup_dyn:
+ret
+
+.section .data
+PROT_READ  = 0x1
+PROT_WRITE = 0x2
+MAP_PRIVATE = 0x2
+MAP_ANONYMOUS = 0x20
+syscall_mmap = 9
+
+_setup_mem:
+
diff --git a/src/focaccia/qemu/_qemu_tool.py b/src/focaccia/qemu/_qemu_tool.py
index 7ca556b..d667cdd 100644
--- a/src/focaccia/qemu/_qemu_tool.py
+++ b/src/focaccia/qemu/_qemu_tool.py
@@ -45,6 +45,12 @@ qemu_crash = {
         'snap': None,
 }
 
+verbosity = {
+    'info':    ErrorTypes.INFO,
+    'warning': ErrorTypes.POSSIBLE,
+    'error':   ErrorTypes.CONFIRMED,
+}
+
 def match_event(event: Event, target: ReadableProgramState) -> bool:
     # Match just on PC
     debug(f'Matching for PC {hex(target.read_pc())} with event {hex(event.pc)}')
@@ -597,6 +603,20 @@ def main():
         except Exception as e:
             raise Exception(f'Unable to serialize snapshots to file {args.output}: {e}')
 
+    if args.reproducer:
+        from focaccia.reproducer import Reproducer
+        try:
+            for r in res:
+                errs = [e for e in r['errors'] if e.severity >= verbosity[args.error_level]]
+                if not errs:
+                    continue
+
+                rep = Reproducer(symb_transforms.env.binary_name, symb_transforms.env.argv, symb_transforms.env.envp, r['snap'], r['ref'])
+                with open(args.reproducer, 'w') as file:
+                    file.write(rep.asm())
+        except Exception as e:
+            raise Exception(f'Unable to generate reproducer: {e}')
+
 if __name__ == "__main__":
     main()
 
diff --git a/src/focaccia/reproducer.py b/src/focaccia/reproducer.py
index 90e1378..6af259d 100644
--- a/src/focaccia/reproducer.py
+++ b/src/focaccia/reproducer.py
@@ -1,5 +1,5 @@
 
-from .lldb_target import LLDBConcreteTarget
+from .native.lldb_target import LLDBLocalTarget
 from .snapshot import ProgramState
 from .symbolic import SymbolicTransform, eval_symbol
 from .arch import x86
@@ -12,9 +12,9 @@ class ReproducerRegisterError(Exception):
     pass
 
 class Reproducer():
-    def __init__(self, oracle: str, argv: str, snap: ProgramState, sym: SymbolicTransform) -> None:
+    def __init__(self, oracle: str, argv: str, envp: str, snap: ProgramState, sym: SymbolicTransform) -> None:
 
-        target = LLDBConcreteTarget(oracle)
+        target = LLDBLocalTarget(oracle, argv, envp)
 
         self.pc = snap.read_register("pc")
         self.bb = target.get_basic_block_inst(self.pc)
@@ -140,7 +140,6 @@ class Reproducer():
         asm += f'.section .text\n'
         asm += f'.global _start\n'
         asm += f'\n'
-        asm += f'.org {hex(self.pc)}\n'
         asm += self.get_bb()
         asm += self.get_start()
         asm += self.get_exit()
diff --git a/src/focaccia/tools/validate_qemu.py b/src/focaccia/tools/validate_qemu.py
index 4b5160f..0b01f87 100755
--- a/src/focaccia/tools/validate_qemu.py
+++ b/src/focaccia/tools/validate_qemu.py
@@ -86,6 +86,10 @@ memory, and stepping forward by single instructions.
                       help='GDB binary to invoke.')
     prog.add_argument('--deterministic-log', default=None,
                       help='The directory containing rr traces')
+    prog.add_argument('--reproducer',
+                        type=str,
+                        help='Generate repoducer executables for detected'
+                             ' errors.')
     return prog
 
 def quoted(s: str) -> str: