Return to BSD News archive
Newsgroups: comp.unix.bsd
Path: sserve!manuel!munnari.oz.au!uunet!mcsun!sun4nl!eur.nl!pk
From: pk@cs.few.eur.nl (Paul Kranenburg)
Subject: Re: GDB under 386bsd 0.1
Message-ID: <1992Sep4.153554.4387@cs.few.eur.nl>
Keywords: gdb, ptrace
Sender: news@cs.few.eur.nl
Reply-To: pk@cs.eur.nl
Organization: Erasmus University Rotterdam
References: <1992Sep4.005417.3876@gumby.dsd.trw.com>
Date: Fri, 4 Sep 1992 15:35:54 GMT
Lines: 89
In <1992Sep4.005417.3876@gumby.dsd.trw.com> gottloeb@eel.dsd.trw.com writes:
>I have noticed a problem using gdb under 386bsd 0.1.
>When at least one breakpoint has been set and the program terminates,
>e.g. executes exit(), the breakpoint is not removed from the process's
>text image. When the program is subsequently re-executed under gdb,
>gdb remembers that a breakpoint is supposed to at the memory location
>and puts one there again. However this time it shadows the breakpoint
>instruction from the previous run rather than the original instruction.
>When execution begins after reaching the breakpoint, various traps occur.
>If the program is run after quitting gdb, a Trace/BPT trap occurs.
>I think the problem is that gdb assumes that when ptrace modifies the
>process's image the kernel either makes a private copy of the text image
>or it will throw away the text image after the process terminates.
>However, this is not the case - the kernel keeps the modified text image
>around and executes it rather than a fresh copy from the original file.
The 386 does not generate a page protection fault while it is executing
in supervisor mode :-(, so copy on write handling never takes place when
the kernel stuffs data into a process's text- or any other non-anonymous
segment. So these cases must be explicitly checked for. Here's a patch
for kern/sys_process.c:
------- sys_process.c -------
*** /tmp/da05975 Fri Sep 4 16:51:50 1992
--- sys_process.c Fri Sep 4 16:51:18 1992
***************
*** 278,286 ****
break;
case PT_WRITE_I:
! case PT_WRITE_D:
! ipc.error = copyout((char *)&ipc.data, (char *)ipc.addr, sizeof(ipc.data));
break;
case PT_WRITE_U:
if ((u_int)ipc.addr > UPAGES * NBPG - sizeof(int)) {
--- 278,318 ----
break;
case PT_WRITE_I:
! case PT_WRITE_D: {
! vm_prot_t prot; /* current protection of region */
! int cow; /* ensure copy-on-write happens */
!
! if (cow = (useracc(ipc.addr, sizeof(ipc.data), B_WRITE) == 0)) {
! vm_offset_t addr = (vm_offset_t)ipc.addr;
! vm_size_t size;
! vm_prot_t max_prot;
! vm_inherit_t inh;
! boolean_t shared;
! vm_object_t object;
! vm_offset_t objoff;
!
! if (vm_region(&p->p_vmspace->vm_map, &addr, &size,
! &prot, &max_prot, &inh, &shared,
! &object, &objoff) != KERN_SUCCESS ||
! vm_protect(&p->p_vmspace->vm_map, ipc.addr,
! sizeof(ipc.data), FALSE,
! prot|VM_PROT_WRITE) != KERN_SUCCESS ||
! vm_fault(&p->p_vmspace->vm_map,trunc_page(ipc.addr),
! VM_PROT_WRITE, FALSE) != KERN_SUCCESS) {
!
! ipc.error = EFAULT;
! break;
! }
! }
! ipc.error = copyout((char *)&ipc.data,
! (char *)ipc.addr, sizeof(ipc.data));
! if (cow)
! if (vm_protect(&p->p_vmspace->vm_map, ipc.addr,
! sizeof(ipc.data), FALSE,
! prot) != KERN_SUCCESS)
! printf("ptrace: oops\n");
break;
+ }
case PT_WRITE_U:
if ((u_int)ipc.addr > UPAGES * NBPG - sizeof(int)) {
------------ EOP --------------------
I am not entirely happy about the call to `vm_fault', but at this moment
I don't see another way to enforce a copy on write.
-pk