Index: head/devel/gdb/Makefile =================================================================== --- head/devel/gdb/Makefile +++ head/devel/gdb/Makefile @@ -3,7 +3,7 @@ PORTNAME= gdb PORTVERSION= 8.1 -PORTREVISION= 2 +PORTREVISION= 3 CATEGORIES= devel MASTER_SITES= GNU Index: head/devel/gdb/files/extrapatch-kgdb =================================================================== --- head/devel/gdb/files/extrapatch-kgdb +++ head/devel/gdb/files/extrapatch-kgdb @@ -1,5 +1,5 @@ diff --git gdb/Makefile.in gdb/Makefile.in -index 17b71c6e7c..282522187b 100644 +index 17b71c6e7c..95e92d08b4 100644 --- gdb/Makefile.in +++ gdb/Makefile.in @@ -230,7 +230,8 @@ INCGNU = -I$(srcdir)/gnulib/import -I$(GNULIB_BUILDDIR)/import @@ -36,7 +36,15 @@ sparc64-linux-tdep.o \ sparc64-nbsd-tdep.o \ sparc64-obsd-tdep.o \ -@@ -684,6 +688,8 @@ ALL_TARGET_OBS = \ +@@ -670,6 +674,7 @@ ALL_TARGET_OBS = \ + arch/arm-linux.o \ + arch/i386.o \ + arm-bsd-tdep.o \ ++ arm-fbsd-kern.o \ + arm-fbsd-tdep.o \ + arm-linux-tdep.o \ + arm-nbsd-tdep.o \ +@@ -684,6 +689,8 @@ ALL_TARGET_OBS = \ cris-linux-tdep.o \ cris-tdep.o \ dicos-tdep.o \ @@ -45,7 +53,7 @@ fbsd-tdep.o \ frv-linux-tdep.o \ frv-tdep.o \ -@@ -700,6 +706,7 @@ ALL_TARGET_OBS = \ +@@ -700,6 +707,7 @@ ALL_TARGET_OBS = \ i386-darwin-tdep.o \ i386-dicos-tdep.o \ i386-fbsd-tdep.o \ @@ -53,7 +61,7 @@ i386-gnu-tdep.o \ i386-go32-tdep.o \ i386-linux-tdep.o \ -@@ -724,6 +731,7 @@ ALL_TARGET_OBS = \ +@@ -724,6 +732,7 @@ ALL_TARGET_OBS = \ mep-tdep.o \ microblaze-linux-tdep.o \ microblaze-tdep.o \ @@ -61,7 +69,7 @@ mips-fbsd-tdep.o \ mips-linux-tdep.o \ mips-nbsd-tdep.o \ -@@ -741,6 +749,7 @@ ALL_TARGET_OBS = \ +@@ -741,6 +750,7 @@ ALL_TARGET_OBS = \ nto-tdep.o \ obsd-tdep.o \ ppc-fbsd-tdep.o \ @@ -69,7 +77,7 @@ ppc-linux-tdep.o \ ppc-nbsd-tdep.o \ ppc-obsd-tdep.o \ -@@ -1610,7 +1619,7 @@ generated_files = \ +@@ -1610,7 +1620,7 @@ generated_files = \ # Flags needed to compile Python code PYTHON_CFLAGS = @PYTHON_CFLAGS@ @@ -78,7 +86,7 @@ @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do # Rule for compiling .c files in the top-level gdb directory. -@@ -1920,6 +1929,12 @@ gdb$(EXEEXT): gdb.o $(LIBGDB_OBS) $(ADD_DEPS) $(CDEPS) $(TDEPLIBS) +@@ -1920,6 +1930,12 @@ gdb$(EXEEXT): gdb.o $(LIBGDB_OBS) $(ADD_DEPS) $(CDEPS) $(TDEPLIBS) -o gdb$(EXEEXT) gdb.o $(LIBGDB_OBS) \ $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) @@ -91,7 +99,7 @@ # Convenience rule to handle recursion. $(LIBGNU) $(GNULIB_H): all-lib all-lib: $(GNULIB_BUILDDIR)/Makefile -@@ -1964,7 +1979,7 @@ clean mostlyclean: $(CONFIG_CLEAN) +@@ -1964,7 +1980,7 @@ clean mostlyclean: $(CONFIG_CLEAN) @$(MAKE) $(FLAGS_TO_PASS) DO=clean "DODIRS=$(CLEANDIRS)" subdir_do rm -f *.o *.a $(ADD_FILES) *~ init.c-tmp init.l-tmp version.c-tmp rm -f init.c version.c observer.h observer.inc @@ -100,7 +108,7 @@ rm -f gdb[0-9]$(EXEEXT) rm -f test-cp-name-parser$(EXEEXT) rm -f xml-builtin.c stamp-xml -@@ -2178,6 +2193,7 @@ MAKEOVERRIDES = +@@ -2178,6 +2194,7 @@ MAKEOVERRIDES = ALLDEPFILES = \ aarch64-fbsd-nat.c \ @@ -108,7 +116,7 @@ aarch64-fbsd-tdep.c \ aarch64-linux-nat.c \ aarch64-linux-tdep.c \ -@@ -2195,6 +2211,7 @@ ALLDEPFILES = \ +@@ -2195,6 +2212,7 @@ ALLDEPFILES = \ amd64-bsd-nat.c \ amd64-darwin-tdep.c \ amd64-dicos-tdep.c \ @@ -116,7 +124,15 @@ amd64-fbsd-nat.c \ amd64-fbsd-tdep.c \ amd64-linux-nat.c \ -@@ -2228,6 +2245,9 @@ ALLDEPFILES = \ +@@ -2209,6 +2227,7 @@ ALLDEPFILES = \ + arc-tdep.c \ + arm.c \ + arm-bsd-tdep.c \ ++ arm-fbsd-kern.c \ + arm-fbsd-nat.c \ + arm-fbsd-tdep.c \ + arm-get-next-pcs.c \ +@@ -2228,6 +2247,9 @@ ALLDEPFILES = \ darwin-nat.c \ dicos-tdep.c \ exec.c \ @@ -126,7 +142,7 @@ fbsd-nat.c \ fbsd-tdep.c \ fork-child.c \ -@@ -2249,6 +2269,7 @@ ALLDEPFILES = \ +@@ -2249,6 +2271,7 @@ ALLDEPFILES = \ i386-darwin-nat.c \ i386-darwin-tdep.c \ i386-dicos-tdep.c \ @@ -134,7 +150,7 @@ i386-fbsd-nat.c \ i386-fbsd-tdep.c \ i386-gnu-nat.c \ -@@ -2290,6 +2311,7 @@ ALLDEPFILES = \ +@@ -2290,6 +2313,7 @@ ALLDEPFILES = \ mingw-hdep.c \ mips-fbsd-nat.c \ mips-fbsd-tdep.c \ @@ -142,7 +158,7 @@ mips-linux-nat.c \ mips-linux-tdep.c \ mips-nbsd-nat.c \ -@@ -2307,6 +2329,7 @@ ALLDEPFILES = \ +@@ -2307,6 +2331,7 @@ ALLDEPFILES = \ obsd-nat.c \ obsd-tdep.c \ posix-hdep.c \ @@ -150,7 +166,7 @@ ppc-fbsd-nat.c \ ppc-fbsd-tdep.c \ ppc-linux-nat.c \ -@@ -2351,6 +2374,7 @@ ALLDEPFILES = \ +@@ -2351,6 +2376,7 @@ ALLDEPFILES = \ sparc-sol2-nat.c \ sparc-sol2-tdep.c \ sparc-tdep.c \ @@ -158,7 +174,7 @@ sparc64-fbsd-nat.c \ sparc64-fbsd-tdep.c \ sparc64-linux-nat.c \ -@@ -2638,7 +2662,7 @@ endif +@@ -2638,7 +2664,7 @@ endif # A list of all the objects we might care about in this build, for # dependency tracking. @@ -283,7 +299,7 @@ LOADLIBES='-lkvm' ;; diff --git gdb/configure.tgt gdb/configure.tgt -index fb8014a8e8..1a86608840 100644 +index fb8014a8e8..4bb43e366c 100644 --- gdb/configure.tgt +++ gdb/configure.tgt @@ -92,7 +92,7 @@ esac @@ -295,6 +311,24 @@ *-*-netbsd* | *-*-knetbsd*-gnu) os_obs="nbsd-tdep.o solib-svr4.o";; *-*-openbsd*) +@@ -109,7 +109,7 @@ aarch64*-*-elf | aarch64*-*-rtems*) + + aarch64*-*-freebsd*) + # Target: FreeBSD/aarch64 +- gdb_target_obs="aarch64-fbsd-tdep.o" ++ gdb_target_obs="aarch64-fbsd-tdep.o aarch64-fbsd-kern.o" + ;; + + aarch64*-*-linux*) +@@ -162,7 +162,7 @@ arm*-*-linux*) + ;; + arm*-*-freebsd*) + # Target: FreeBSD/arm +- gdb_target_obs="arm-fbsd-tdep.o" ++ gdb_target_obs="arm-fbsd-tdep.o arm-fbsd-kern.o" + ;; + arm*-*-netbsd* | arm*-*-knetbsd*-gnu) + # Target: NetBSD/arm @@ -249,7 +249,11 @@ i[34567]86-*-dicos*) ;; i[34567]86-*-freebsd* | i[34567]86-*-kfreebsd*-gnu) Index: head/devel/gdb/files/kgdb/aarch64-fbsd-kern.c =================================================================== --- head/devel/gdb/files/kgdb/aarch64-fbsd-kern.c +++ head/devel/gdb/files/kgdb/aarch64-fbsd-kern.c @@ -180,6 +180,11 @@ fbsd_vmcore_set_supply_pcb (gdbarch, aarch64_fbsd_supply_pcb); fbsd_vmcore_set_cpu_pcb_addr (gdbarch, kgdb_trgt_stop_pcb); + + /* The kernel is linked at a virtual address with the upper 4 bits + set, so all 64 bits of virtual addresses need to be treated as + significant. */ + set_gdbarch_significant_addr_bit (gdbarch, 64); } /* Provide a prototype to silence -Wmissing-prototypes. */ Index: head/devel/gdb/files/kgdb/amd64fbsd-kern.c =================================================================== --- head/devel/gdb/files/kgdb/amd64fbsd-kern.c +++ head/devel/gdb/files/kgdb/amd64fbsd-kern.c @@ -81,7 +81,14 @@ { gdb_byte buf[8]; int i; - + + memset(buf, 0, sizeof(buf)); + + /* + * XXX The PCB may have been swapped out. Supply a dummy %rip value + * so as to avoid triggering an exception during stack unwinding. + */ + regcache->raw_supply(AMD64_RIP_REGNUM, buf); for (i = 0; i < ARRAY_SIZE (amd64fbsd_pcb_offset); i++) if (amd64fbsd_pcb_offset[i] != -1) { if (target_read_memory(pcb_addr + amd64fbsd_pcb_offset[i], buf, Index: head/devel/gdb/files/kgdb/arm-fbsd-kern.c =================================================================== --- head/devel/gdb/files/kgdb/arm-fbsd-kern.c +++ head/devel/gdb/files/kgdb/arm-fbsd-kern.c @@ -0,0 +1,199 @@ +/*- + * Copyright (c) 2018 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* Target-dependent code for FreeBSD/arm kernels. */ + +#include "defs.h" + +#include "arm-tdep.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "osabi.h" +#include "regcache.h" +#include "regset.h" +#include "solib.h" +#include "target.h" +#include "trad-frame.h" + +#include "kgdb.h" + +static const struct regcache_map_entry arm_fbsd_pcbmap[] = + { + { 9, 4, 4 }, /* r4 ... r12 */ + { 1, ARM_SP_REGNUM, 4 }, + { 1, ARM_LR_REGNUM, 4 }, + { 1, ARM_PC_REGNUM, 4 }, + { 0 } + }; + +static const struct regset arm_fbsd_pcbregset = + { + arm_fbsd_pcbmap, + regcache_supply_regset, regcache_collect_regset + }; + +static void +arm_fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr) +{ + gdb_byte buf[4 * 12]; + + if (target_read_memory (pcb_addr, buf, sizeof buf) == 0) + regcache->supply_regset (&arm_fbsd_pcbregset, -1, buf, sizeof (buf)); + + /* + * XXX: This is a gross hack, but the ARM frame unwinders need the value + * of xPSR to determine if Thumb mode is active. FreeBSD's kernels never + * use Thumb. + */ + regcache->raw_supply_unsigned(ARM_PS_REGNUM, 0); +} + +static struct trad_frame_cache * +arm_fbsd_trapframe_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct trad_frame_cache *cache; + CORE_ADDR addr, func, pc, sp; + const char *name; + int i; + + if (*this_cache != NULL) + return ((struct trad_frame_cache *)*this_cache); + + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + func = get_frame_func (this_frame); + sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); + + find_pc_partial_function (func, &name, NULL, NULL); + + for (i = 0; i <= 12; i++) + trad_frame_set_reg_addr (cache, ARM_A1_REGNUM + i, sp + 4 + i * 4); + trad_frame_set_reg_addr (cache, ARM_SP_REGNUM, sp + 14 * 4); + trad_frame_set_reg_addr (cache, ARM_LR_REGNUM, sp + 15 * 4); + trad_frame_set_reg_addr (cache, ARM_PC_REGNUM, sp + 18 * 4); + trad_frame_set_reg_addr (cache, ARM_PS_REGNUM, sp); + + /* Read $PC from trap frame. */ + pc = read_memory_unsigned_integer (sp + 18 * 4, 4, byte_order); + + if (pc == 0 && strcmp(name, "swi_entry") == 0) + { + /* Initial frame of a kthread; terminate backtrace. */ + trad_frame_set_id (cache, outer_frame_id); + } + else + { + /* Construct the frame ID using the function start. */ + trad_frame_set_id (cache, frame_id_build (sp + 4 * 19, func)); + } + + return cache; +} + +static void +arm_fbsd_trapframe_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct trad_frame_cache *cache = + arm_fbsd_trapframe_cache (this_frame, this_cache); + + trad_frame_get_id (cache, this_id); +} + +static struct value * +arm_fbsd_trapframe_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct trad_frame_cache *cache = + arm_fbsd_trapframe_cache (this_frame, this_cache); + + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +arm_fbsd_trapframe_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + const char *name; + + find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL); + return (name && ((strcmp (name, "data_abort_entry") == 0) + || (strcmp (name, "prefetch_abort_entry") == 0) + || (strcmp (name, "undefined_entry") == 0) + || (strcmp (name, "exception_exit") == 0) + || (strcmp (name, "irq_entry") == 0) + || (strcmp (name, "swi_entry") == 0) + || (strcmp (name, "swi_exit") == 0))); +} + +static const struct frame_unwind arm_fbsd_trapframe_unwind = { + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + arm_fbsd_trapframe_this_id, + arm_fbsd_trapframe_prev_register, + NULL, + arm_fbsd_trapframe_sniffer +}; + +/* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ + +static void +arm_fbsd_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + frame_unwind_prepend_unwinder (gdbarch, &arm_fbsd_trapframe_unwind); + + set_solib_ops (gdbarch, &kld_so_ops); + + tdep->jb_pc = 24; + tdep->jb_elt_size = 4; + + fbsd_vmcore_set_supply_pcb (gdbarch, arm_fbsd_supply_pcb); + fbsd_vmcore_set_cpu_pcb_addr (gdbarch, kgdb_trgt_stop_pcb); + + /* Single stepping. */ + set_gdbarch_software_single_step (gdbarch, arm_software_single_step); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_arm_kgdb_tdep; + +void +_initialize_arm_kgdb_tdep (void) +{ + gdbarch_register_osabi_sniffer(bfd_arch_arm, + bfd_target_elf_flavour, + fbsd_kernel_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_FREEBSD_KERNEL, + arm_fbsd_kernel_init_abi); +} Index: head/devel/gdb/files/kgdb/fbsd-kthr.c =================================================================== --- head/devel/gdb/files/kgdb/fbsd-kthr.c +++ head/devel/gdb/files/kgdb/fbsd-kthr.c @@ -178,23 +178,11 @@ if (dumppcb == 0) return (NULL); -#if 1 TRY { dumptid = parse_and_eval_long("dumptid"); } CATCH(e, RETURN_MASK_ERROR) { dumptid = -1; } END_CATCH -#else - addr = kgdb_lookup("dumptid"); - if (addr != 0) { - TRY { - dumptid = read_memory_integer (addr, 4, byte_order); - } CATCH(e, RETURN_MASK_ERROR) { - dumptid = -1; - } END_CATCH - } else - dumptid = -1; -#endif TRY { mp_maxid = parse_and_eval_long("mp_maxid"); Index: head/devel/gdb/files/kgdb/fbsd-kvm.c =================================================================== --- head/devel/gdb/files/kgdb/fbsd-kvm.c +++ head/devel/gdb/files/kgdb/fbsd-kvm.c @@ -227,7 +227,7 @@ #endif static void -kgdb_trgt_open(const char *arg, int from_tty) +kgdb_trgt_open(const char *args, int from_tty) { struct fbsd_vmcore_ops *ops = (struct fbsd_vmcore_ops *) gdbarch_data (target_gdbarch(), fbsd_vmcore_data); @@ -237,6 +237,7 @@ struct kthr *kt; kvm_t *nkvm; char *temp, *kernel, *filename; + bool writeable; int ontop; if (ops == NULL || ops->supply_pcb == NULL || ops->cpu_pcb_addr == NULL) @@ -247,24 +248,40 @@ if (kernel == NULL) error ("Can't open a vmcore without a kernel"); - if (arg != NULL) { - filename = tilde_expand (arg); - if (!IS_ABSOLUTE_PATH (filename)) { - temp = concat (current_directory, "/", filename, NULL); - xfree(filename); - filename = temp; + writeable = false; + filename = NULL; + if (args != NULL) { + gdb_argv built_argv (args); + + for (char **argv = built_argv.get (); *argv != NULL; argv++) { + if (**argv == '-') { + if (strcmp (*argv, "-w") == 0) + writeable = true; + else + error (_("Invalid argument")); + } else { + if (filename != NULL) + error (_("Invalid argument")); + + filename = tilde_expand (*argv); + if (!IS_ABSOLUTE_PATH (filename)) { + temp = concat (current_directory, "/", + filename, NULL); + xfree(filename); + filename = temp; + } + } } - } else - filename = NULL; + } old_chain = make_cleanup (xfree, filename); #ifdef HAVE_KVM_OPEN2 nkvm = kvm_open2(kernel, filename, - write_files ? O_RDWR : O_RDONLY, kvm_err, kgdb_resolve_symbol); + writeable ? O_RDWR : O_RDONLY, kvm_err, kgdb_resolve_symbol); #else nkvm = kvm_openfiles(kernel, filename, NULL, - write_files ? O_RDWR : O_RDONLY, kvm_err); + writeable ? O_RDWR : O_RDONLY, kvm_err); #endif if (nkvm == NULL) error ("Failed to open vmcore: %s", kvm_err); @@ -294,6 +311,10 @@ TRY { pcb_size = parse_and_eval_long("pcb_size"); } CATCH(e, RETURN_MASK_ERROR) { + pcb_size = 0; + } END_CATCH + + if (pcb_size == 0) { TRY { pcb_size = parse_and_eval_long("sizeof(struct pcb)"); } CATCH(e, RETURN_MASK_ERROR) { @@ -306,7 +327,7 @@ pcb_size = sizeof(struct pcb); #endif } END_CATCH - } END_CATCH + } kvm = nkvm; vmcore = filename; @@ -563,8 +584,9 @@ kgdb_trgt_ops.to_magic = OPS_MAGIC; kgdb_trgt_ops.to_shortname = "vmcore"; kgdb_trgt_ops.to_longname = "kernel core dump file"; - kgdb_trgt_ops.to_doc = - "Use a vmcore file as a target. Specify the filename of the vmcore file."; + kgdb_trgt_ops.to_doc = "Use a vmcore file as a target.\n\ +If no filename is specified, /dev/mem is used to examine the running kernel.\n\ +target vmcore [-w] [filename]"; kgdb_trgt_ops.to_stratum = process_stratum; kgdb_trgt_ops.to_has_memory = kgdb_trgt_return_one; kgdb_trgt_ops.to_has_registers = kgdb_trgt_return_one; Index: head/devel/gdb/files/kgdb/i386fbsd-kern.c =================================================================== --- head/devel/gdb/files/kgdb/i386fbsd-kern.c +++ head/devel/gdb/files/kgdb/i386fbsd-kern.c @@ -128,6 +128,13 @@ gdb_byte buf[4]; int i; + memset(buf, 0, sizeof(buf)); + + /* + * XXX The PCB may have been swapped out. Supply a dummy %eip value + * so as to avoid triggering an exception during stack unwinding. + */ + regcache->raw_supply(I386_EIP_REGNUM, buf); for (i = 0; i < ARRAY_SIZE (i386fbsd_pcb_offset); i++) if (i386fbsd_pcb_offset[i] != -1) { if (target_read_memory(pcb_addr + i386fbsd_pcb_offset[i], buf, sizeof buf) Index: head/devel/gdb/files/kgdb/kgdb-main.c =================================================================== --- head/devel/gdb/files/kgdb/kgdb-main.c +++ head/devel/gdb/files/kgdb/kgdb-main.c @@ -221,9 +221,10 @@ struct stat st; struct captured_main_args args; char *s; - int a, ch; + int a, ch, writeable; dumpnr = NULL; + writeable = 0; strlcpy(crashdir, "/var/crash", sizeof(crashdir)); s = getenv("KGDB_CRASH_DIR"); @@ -303,7 +304,7 @@ verbose++; break; case 'w': /* core file is writeable. */ - add_arg(&args, "--write"); + writeable = 1; break; case '?': default: @@ -386,7 +387,8 @@ /* Open the vmcore if requested. */ if (vmcore != NULL) { add_arg(&args, "-ex"); - if (asprintf(&s, "target vmcore %s", vmcore) < 0) + if (asprintf(&s, "target vmcore %s%s", writeable ? "-w " : "", + vmcore) < 0) err(1, "couldn't build command line"); add_arg(&args, s); }