diff -cr /tmp/tct-1.13/CHANGES ./CHANGES *** /tmp/tct-1.13/CHANGES Thu Oct 2 18:20:03 2003 --- ./CHANGES Tue Oct 14 18:29:38 2003 *************** *** 1,7 **** Thu Oct 2 09:14:00 EDT 2003 o Completed support for UFS1 and UFS2 in FreeBSD 5.x. However, ! the pcat command still requires that the /proc flie system is mounted. This will be fixed later. Sat Aug 30 19:21:29 EDT 2003 --- 1,15 ---- + Tue Oct 14 18:23:49 EDT 2003 + + o pcat now fully supports FreeBSD systems that do not have + /proc mounted (it's no longer mounted by default with + FreeBSD 5). pcat tries to use /proc if it can, and uses + ptrace() and gropes kernel memory if it has to. Operation + without /proc requires super-user privileges. + Thu Oct 2 09:14:00 EDT 2003 o Completed support for UFS1 and UFS2 in FreeBSD 5.x. However, ! the pcat command still requires that the /proc file system is mounted. This will be fixed later. Sat Aug 30 19:21:29 EDT 2003 diff -cr /tmp/tct-1.13/conf/paths.pl ./conf/paths.pl *** /tmp/tct-1.13/conf/paths.pl Thu Oct 2 10:11:53 2003 --- ./conf/paths.pl Tue Oct 14 18:24:52 2003 *************** *** 23,29 **** $IPCS="/usr/bin/ipcs"; $LAST="/usr/bin/last"; ! $LSOF="/usr/local/sbin/lsof"; $MKDIR="/bin/mkdir"; $NETSTAT="/usr/bin/netstat"; $PS="/bin/ps"; --- 23,29 ---- $IPCS="/usr/bin/ipcs"; $LAST="/usr/bin/last"; ! $LSOF="/usr/local/bin/lsof"; $MKDIR="/bin/mkdir"; $NETSTAT="/usr/bin/netstat"; $PS="/bin/ps"; diff -cr /tmp/tct-1.13/man/man1/pcat.1 ./man/man1/pcat.1 *** /tmp/tct-1.13/man/man1/pcat.1 Sun Jul 30 19:39:20 2000 --- ./man/man1/pcat.1 Tue Oct 14 15:52:44 2003 *************** *** 28,33 **** --- 28,34 ---- This option does not work on some Solaris versions. .IP "\fB-m\fR \fImapfile\fR" Print the process memory map to \fImapfile\fR, one entry per line. + Specify \fB-m-\fR to write to the standard error stream. Each map entry consists of a region start address and the first address beyond that region. Addresses are separated by space, and are printed as hexadecimal numbers (0xhhhh). diff -cr /tmp/tct-1.13/src/pcat/makedefs ./src/pcat/makedefs *** /tmp/tct-1.13/src/pcat/makedefs Sat Aug 30 19:18:48 2003 --- ./src/pcat/makedefs Tue Oct 14 17:07:44 2003 *************** *** 3,14 **** --- 3,18 ---- case "$SYSTEM.$RELEASE" in FreeBSD.2*) DEFS="-DFREEBSD2" + SYSLIBS="-lkvm" ;; FreeBSD.3*) DEFS="-DFREEBSD3" + SYSLIBS="-lkvm" ;; FreeBSD.4*) DEFS="-DFREEBSD4" + SYSLIBS="-lkvm" ;; FreeBSD.5*) DEFS="-DFREEBSD5" + SYSLIBS="-lkvm" ;; OpenBSD.2*) DEFS="-DOPENBSD2" SYSLIBS="-lkvm" diff -cr /tmp/tct-1.13/src/pcat/pcat.c ./src/pcat/pcat.c *** /tmp/tct-1.13/src/pcat/pcat.c Tue Sep 23 13:03:34 2003 --- ./src/pcat/pcat.c Tue Oct 14 16:21:54 2003 *************** *** 104,114 **** --- 104,143 ---- /* * FreeBSD 2.x and later have /proc, which immensely simplifies our task. + * Unfortunately, FreeBSD 5.x no longer mounts /proc by default. We try to + * use /proc first and use ptrace() only if we have to. + * + * FreeBSD PTRACE_DETACH does not resume the target process so we must send + * SIGCONT, but only if the process was stopped by us. + * + * FreeBSD 5 no longer supports ptrace() access to the u area, so we have to + * grope kernel memory instead. */ #if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \ || defined(FREEBSD5) #define SUPPORTED + #include + #include + #include + #include + #include + #include #define HAVE_PROC_MEM + #define HAVE_PTRACE_MEM + #define PTRACE_ATTACH PT_ATTACH + #define PTRACE_DETACH PT_DETACH + #define PTRACE_PEEKDATA PT_READ_D + #define PTRACE_ARG3_T caddr_t + #endif + + #if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) + #define PROCP_STATUS(p) ((p)->kp_proc.p_stat) + #define PROCP_VMSPACE(p) ((p)->kp_proc.p_vmspace) + #endif + + #if defined(FREEBSD5) + #define PROCP_STATUS(p) ((p)->ki_stat) + #define PROCP_VMSPACE(p) ((p)->ki_vmspace) #endif /* *************** *** 225,236 **** /* * Structure to carry around process-related info. */ ! typedef struct { #ifdef HAVE_PROC_MEM int mem_fd; /* process memory */ #endif pid_t pid; /* a process id */ int map_count; /* nr of map entries */ MAP_INFO map_info[1]; /* actually a bunch. */ } PROC_INFO; --- 254,266 ---- /* * Structure to carry around process-related info. */ ! typedef struct PROC_INFO { #ifdef HAVE_PROC_MEM int mem_fd; /* process memory */ #endif pid_t pid; /* a process id */ int map_count; /* nr of map entries */ + void (*read_proc) (struct PROC_INFO *, char *, int, off_t); MAP_INFO map_info[1]; /* actually a bunch. */ } PROC_INFO; *************** *** 432,442 **** #endif ! /* read_proc - read block of memory at specified position */ ! static void read_proc(PROC_INFO *proc, char *data, int len, off_t offset) { - #ifdef HAVE_PROC_MEM if (verbose) fprintf(stderr, "read seek to 0x%lx\n", (long) offset); #ifdef USE_PREAD --- 462,473 ---- #endif ! #ifdef HAVE_PROC_MEM ! ! /* read_proc_mem - read block of memory at specified position */ ! static void read_proc_mem(PROC_INFO *proc, char *data, int len, off_t offset) { if (verbose) fprintf(stderr, "read seek to 0x%lx\n", (long) offset); #ifdef USE_PREAD *************** *** 448,458 **** --- 479,497 ---- if (read(proc->mem_fd, data, len) != len) error("read: %m"); #endif + } #endif #ifdef HAVE_PTRACE_MEM + + /* read_ptrace_mem - read block of memory at specified position */ + + static void read_ptrace_mem(PROC_INFO *proc, char *data, int len, off_t offset) + { #ifdef USE_PTRACE_READDATA + if (verbose) + fprintf(stderr, "read seek to 0x%lx\n", (long) offset); if (ptrace(PTRACE_READDATA, proc->pid, (int) offset, len, data) < 0) error("PTRACE_READDATA: %m%s", errno == EIO ? "; did you use GCC with another machine's header files?" : ""); *************** *** 465,470 **** --- 504,511 ---- * XXX This breaks when memory segments aren't word-aligned or when * memory segments sizes aren't a multiple of the word size. Tough. */ + if (verbose) + fprintf(stderr, "read seek to 0x%lx\n", (long) offset); if (offset % sizeof(int)) panic("read_proc: offset 0x%lx is not word-aligned", (long) offset); if (len % sizeof(int)) *************** *** 475,483 **** words[n] = call_ptrace(PTRACE_PEEKDATA, proc->pid, addr, 0); memcpy(data, (char *) words, len); #endif #endif - } /* write_here - write a block at specified position */ --- 516,524 ---- words[n] = call_ptrace(PTRACE_PEEKDATA, proc->pid, addr, 0); memcpy(data, (char *) words, len); #endif + } #endif /* write_here - write a block at specified position */ *************** *** 511,517 **** where = proc->map_info[n].start; while (size > 0) { len = (size > sizeof(buf) ? sizeof(buf) : size); ! read_proc(proc, buf, len, where); if (keep_holes) { write_here(out_fd, buf, len, where); } else { --- 552,558 ---- where = proc->map_info[n].start; while (size > 0) { len = (size > sizeof(buf) ? sizeof(buf) : size); ! proc->read_proc(proc, buf, len, where); if (keep_holes) { write_here(out_fd, buf, len, where); } else { *************** *** 531,572 **** #if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \ || defined(FREEBSD5) PROC_INFO *proc = (PROC_INFO *) mymalloc(sizeof(*proc)); - char buf[READ_BUFSIZ_CHARS]; MAP_INFO *mp; FILE *map_fp; /* ! * Attach to process memory. XXX Suspend/resume the process if it isn't ! * stopped. */ - sprintf(buf, "/proc/%ld/mem", (long) pid); - if ((proc->mem_fd = open(buf, O_RDONLY)) < 0) - error("open %s: %m", buf); init_cleanup(pid); /* ! * Look up the process memory map. ! */ ! sprintf(buf, "/proc/%ld/map", (long) pid); ! if ((map_fp = fopen(buf, "r")) == 0) ! error("open %s: %m", buf); ! for (proc->map_count = 0; fgets(buf, sizeof(buf), map_fp) != 0; proc->map_count++) { ! if (proc->map_count > 0) ! proc = (PROC_INFO *) myrealloc((char *) proc, ! sizeof(*proc) + proc->map_count * sizeof(proc->map_info[0])); ! mp = proc->map_info + proc->map_count; ! if (sscanf(buf, "%lx %lx", &mp->start, &mp->end) != 2) ! error("unexpected map format: %s", buf); ! if (verbose) ! fprintf(stderr, "map entry: 0x%lx 0x%lx\n", mp->start, mp->end); ! if (map_out) ! fprintf(map_out, "0x%lx 0x%lx\n", mp->start, mp->end); } - if (ferror(map_fp)) - error("map read: %m"); - (void) fclose(map_fp); - proc->pid = pid; return (proc); --- 572,689 ---- #if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \ || defined(FREEBSD5) PROC_INFO *proc = (PROC_INFO *) mymalloc(sizeof(*proc)); MAP_INFO *mp; + struct kinfo_proc *procp; + kvm_t *kd; + struct vmspace vmspace; + struct vm_map_entry entry; + u_long addr; + int cnt; + char buf[READ_BUFSIZ_CHARS]; FILE *map_fp; /* ! * Attach to process memory. Try to use /proc first. XXX Suspend/resume ! * the process if it isn't stopped. */ init_cleanup(pid); + sprintf(buf, "/proc/%ld/mem", (long) pid); + if ((proc->mem_fd = open(buf, O_RDONLY)) >= 0) { + proc->read_proc = read_proc_mem; + + /* + * Look up the process memory map. + * + * XXX The map must fit inside one read operation. If the read fails + * with EFBIG then we should increase the read buffer size and retry. + */ + sprintf(buf, "/proc/%ld/map", (long) pid); + if ((map_fp = fopen(buf, "r")) == 0) + error("open %s: %m", buf); + + for (proc->map_count = 0; fgets(buf, sizeof(buf), map_fp) != 0; proc->map_count++) { + if (proc->map_count > 0) + proc = (PROC_INFO *) myrealloc((char *) proc, + sizeof(*proc) + proc->map_count * sizeof(proc->map_info[0])); + mp = proc->map_info + proc->map_count; + if (sscanf(buf, "%lx %lx", &mp->start, &mp->end) != 2) + error("unexpected map format: %s", buf); + if (verbose) + fprintf(stderr, "map entry: 0x%lx 0x%lx\n", mp->start, mp->end); + if (map_out) + fprintf(map_out, "0x%lx 0x%lx\n", mp->start, mp->end); + } + if (ferror(map_fp)) + error("map read: %m"); + (void) fclose(map_fp); + } /* ! * We can't use /proc so we fall back to ptrace() and to peeking at ! * kernel memory. Look up the process status before attaching to it: 1) ! * the ptrace() detach operation will resume a stopped process, so we ! * must re-suspend it; 2) the ptrace() detach operation will not resume a ! * process that wasn't stopped, so we must resume it. ! */ ! else { ! proc->read_proc = read_ptrace_mem; ! ! /* ! * Look up the process status before attaching to it: PTRACE_DETACH ! * will resume a stopped process, so we must re-suspend it. ! */ ! if ((kd = kvm_open((char *) 0, (char *) 0, (char *) 0, O_RDONLY, "pcat")) == 0) ! error("kvm_open: %m"); ! if ((procp = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt)) == 0 || cnt != 1) ! error("kvm_getprocs: %m"); ! if (PROCP_STATUS(procp) & SSTOP) ! pre_detach_signal = post_detach_signal = SIGSTOP; ! else ! pre_detach_signal = SIGCONT; ! ! /* ! * Attach to process memory and stop the process. ! */ ! init_cleanup(pid); ! if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ! error("ptrace PTRACE_ATTACH: %m"); ! ptrace_attach_wait(pid); ! ! /* ! * Look up the process memory map. With FreeBSD 5 the u area is no ! * longer accessible via ptrace() so we must grope kernel memory. ! * This requires root privileges. ! */ ! if (kvm_read(kd, (u_long) PROCP_VMSPACE(procp), ! (void *) &vmspace, sizeof(vmspace)) != sizeof(vmspace)) ! error("struct vmspace kvm_read: %m"); ! ! /* ! * Copied from the code that implements /proc/pid/map. ! */ ! for (proc->map_count = 0, addr = (u_long) vmspace.vm_map.header.next; ! addr != (u_long) PROCP_VMSPACE(procp) ! + offsetof(struct vmspace, vm_map) ! + offsetof(struct vm_map, header); ! proc->map_count++, addr = (u_long) entry.next) { ! ! if (kvm_read(kd, addr, (void *) &entry, ! sizeof(entry)) != sizeof(entry)) ! error("struct vm_map_entry kvm_read: %m"); ! if (proc->map_count > 0) ! proc = (PROC_INFO *) myrealloc((char *) proc, ! sizeof(*proc) + proc->map_count * sizeof(proc->map_info[0])); ! mp = proc->map_info + proc->map_count; ! mp->start = entry.start; ! mp->end = entry.end; ! if (verbose) ! fprintf(stderr, "map entry: 0x%lx 0x%lx\n", mp->start, mp->end); ! if (map_out) ! fprintf(map_out, "0x%lx 0x%lx\n", mp->start, mp->end); ! } ! kvm_close(kd); } proc->pid = pid; return (proc); *************** *** 579,584 **** --- 696,703 ---- struct prmap *pr; MAP_INFO *mp; + proc->read_proc = read_proc_mem; + /* * Attach to process memory. XXX Suspend/resume the process if it isn't * stopped. *************** *** 593,598 **** --- 712,719 ---- */ if (ioctl(proc->mem_fd, PIOCNMAP, (char *) &proc->map_count) < 0) error("ioctl PIOCNMAP: %m"); + proc = (PROC_INFO *) myrealloc((char *) proc, + sizeof(*proc) + proc->map_count * sizeof(proc->map_info[0])); prmap = (struct prmap *) mymalloc((proc->map_count + 1) * sizeof(*prmap)); if (ioctl(proc->mem_fd, PIOCMAP, (char *) prmap) < 0) error("ioctl PIOCMAP: %m"); *************** *** 618,623 **** --- 739,746 ---- MAP_INFO *mp; FILE *map_fp; + proc->read_proc = read_proc_mem; + /* * Attach to process memory. XXX Suspend/resume the process if it isn't * stopped. *************** *** 666,676 **** --- 789,801 ---- */ init_cleanup(pid); #ifdef HAVE_PROC_MEM + proc->read_proc = read_proc_mem; sprintf(buf, "/proc/%ld/mem", (long) pid); if ((proc->mem_fd = open(buf, O_RDONLY)) < 0) error("open %s: %m", buf); #endif #ifdef HAVE_PTRACE_MEM + proc->read_proc = read_ptrace_mem; if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) error("ptrace PTRACE_ATTACH: %m"); ptrace_attach_wait(pid); *************** *** 734,739 **** --- 859,865 ---- */ proc = (PROC_INFO *) mymalloc(sizeof(*proc) + 2 * sizeof(MAP_INFO)); proc->map_count = 3; + proc->read_proc = read_ptrace_mem; /* * Attach to process memory and stop the process. *************** *** 821,826 **** --- 947,953 ---- */ proc = (PROC_INFO *) mymalloc(sizeof(*proc) + 2 * sizeof(MAP_INFO)); proc->map_count = 3; + proc->read_proc = read_ptrace_mem; /* * Attach to process memory and stop the process. *************** *** 899,904 **** --- 1026,1032 ---- */ proc = (PROC_INFO *) mymalloc(sizeof(*proc) + 2 * sizeof(MAP_INFO)); proc->map_count = 3; + proc->read_proc = read_ptrace_mem; /* * Attach to process memory and stop the process. *************** *** 960,966 **** static void close_process(PROC_INFO *proc) { #ifdef HAVE_PROC_MEM ! if (close(proc->mem_fd) < 0) error("close memory: %m"); #endif free((char *) proc); --- 1088,1094 ---- static void close_process(PROC_INFO *proc) { #ifdef HAVE_PROC_MEM ! if (proc->mem_fd >= 0 && close(proc->mem_fd) < 0) error("close memory: %m"); #endif free((char *) proc);