From: CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 26-AUG-1990 04:08:42.94 To: MRGATE::"ARISIA::EVERHART" CC: Subj: Re(2): debugger: DBG$INPUT, DBG$OUTPUT logical Received: by crdgw1.ge.com (5.57/GE 1.70) id AA06563; Sun, 26 Aug 90 03:53:51 EDT Message-Id: <9008260753.AA06563@crdgw1.ge.com> Received: From SOL1.GPS.CALTECH.EDU by CRVAX.SRI.COM with TCP; Sun, 26 AUG 90 00:44:56 PDT Date: 25 Aug 1990 23:39:53 EST From: Carl.J.Lydick@SOL1.GPS.CALTECH.EDU To: uswat!jbw@boulder.colorado.edu, info-vax@sri.com Subject: Re(2): debugger: DBG$INPUT, DBG$OUTPUT logical X-Vms-Original-To: INET%"uswat!jbw@boulder.colorado.edu" > 1. Does anyone have an example of using RMS to change the protection of a > *device*? I don't think RMS will do this for you. The only sort of device I know of that can have its protection changed other than by using the SET PROTECTION command is a mailbox. > 2. Alternatively, if an image is installed with priveleges, do processes > it spawn have the same priveleges? (This way, I could spawn a DCL SET > PROTECTION command. Does anyone have an example of spawning a DCL > command?) Yes. The subprocess inherits the privs that belonged to the parent process (as opposed to the image it was running) as its default privs; it inherits any privs that the parent had as a result of the image used to spawn being installed with privs as authorized privs (i.e., if you issue a SHOW PROC/PRIV command from the spawned process, you'll see the same privs the parent process had before the privileged image was activated; however, if you then issue a SET PROC/PRIV=ALL command, you'll end up with all the privs the parent had when the subprocess was spawned. You really don't want to try to go this way though. You obviously don't know enough about VMS to write a really bullet-proof program to do this, and since the image would have to be installed with SYSPRV and OPER in order to change the terminal protection, I doubt you'd convince a system manager to install it. > 1. The SHARE privelege is sufficient to allow the debugger to allocate > the target terminal device. It is not necessary for the process already > using the terminal to deallocate the terminal or disconnect. This is true, given that the protections on the device and the privileges of the user are such that he would have been able to access the device were there nobody else with channels assigned to it. > 2. BYPASS or SYSPRV privelege is sufficient to allow the debugger to > access the terminal device. (I'm not using this method myself.) BYPASS will let you access it as long as there are no channels assigned to it. SYSPRV will let you access it if it's protected system-readable and has no channels assigned. In order to guarantee that you can do I/O to the device, you need BYPASS and SHARE. If you want to be able to change its protections, you need BYPASS and OPER. > 3. Arne Vajhxj has used the debugger with > DBG$OUTPUT and DBG$INPUT connected to files. (Didn't he post this?) So, > presumably, mailboxes would also work. The only problem with using mailboxes is that you have no obvious and easy way to force the debugger to respond to your commands (if you cancel your last breakpoint and issue a GO command, there's no way you can get back to the debugger unless you've prepared the image you're debugging for such an eventuality. I'm enclosing two routines at the end of this message that will do just that. > 4. The method of using FORCEX, DCLEXH, and UNWIND does indeed work > reliably for sending signals from one process to another. Here is a > description of the procedure: This may be true, but you're going through a lot of unnecessary work for what it seems you want to accomplish. > A process that wants to receive signals sets up an exit handler, after > all other exit handlers. Alternatively, it could simply issue a call to $CREMBX, which is a lot easier. In either case, you've got the problem of whatever other process wanting to communicate needing to figure out where to direct their signals. If you don't want to have to keep checking the mailbox, you can enable a write-attention AST on the mailbox. > To send a signal, another process calls FORCEX and passes the value of > the signal as the "completion code". Now, of course, if the other process happens to accidentally use the wrong PID in the call to FORCEX, some innocent bystander could stand to lose. > The target process receives a user mode AST. This AST calls EXIT in the > context of the target process, passing EXIT the completion code. EXIT > then runs any exit handlers. Using a mailbox, the target process gets an AST (normally delivered at user-level, but the target process controls the access mode at which the write-attention AST is delivered. > The exit handler looks at the completion code. The processes that are > using this technique to communicate must have previously agreed on a set > of values that will represent signals. This set should not include any > normally used VMS condition values. If the completion code is not one > expected by the exit handler, it should simply return. Using a mailbox, the target process simply reads the mailbox (which not only gets it whatever data the other process wanted to send [we're not talking about limiting ourselves to as single longword here, either], but also the identity of the sender. This can all be done in the context of the AST routine, or you can have the AST routine set a flag somewhere in your data space, and your process can handle the message at its leisure. > Now the exit handler should do whatever it is supposed to when this > signal is received. > After it is done processing the signal, the exit handler must abort the > EXIT and FORCEX as if they never occurred. To do this it calls UNWIND. > Since UNWIND can not be called except from a condition handler, the exit > handler must establish a condition handler (with LIB$ESTABLISH) and > signal a condition (with LIB$SIGNAL). With a mailbox and a write-attention AST, once processing of the message is complete, the AST procedure needs only to issue a QIO request to reenable the write-attention AST, then execute a return instruction, in order to return the process to the state it was in before the AST was delivered. > The condition handler then calls UNWIND, which modifies the return PC > values in the stack frames below the condition handler's frame. > The condition handler then returns, starting the unwinding of the stack. > The condition handler is called again (with argument SS$_UNWIND) during > the unwinding of the stack frame of the exit handler, and it must simply > return. > If the proper number of stack frames were unwound (!), then execution of > the program resumes where it was interrupted by the FORCEX AST. With a mailbox and a write-attention AST enabled, you don't have to guess how far to unwind the stack. The operating system takes care of keeping track of that for you, automatically. Now, the routines you need to make debugging through a mailbox relatively reliable (I'm not about to spend any time on a user interface for it; the two routines (well, three if you count a routine that does nothing but execute a return instruction) that follow are designed to make sure that you can always get the debugger's attention. /* ASTROUTINE - Clear out the mailbox and enable another write-attention AST */ /* Takes one argument: the number of a channel assigned to the mailbox */ #include iodef #include ssdef astroutine(short chan) { short iosb[4]; long stat; while((((stat = SYS$QIOW(0, chan, IO$_READVBLK | IO$M_NOW, iosb, 0, 0, 0, 0, 0, 0, 0, 0)) & 7) == 1) && (((stat = iosb[0]) & 7) == 1) || (stat == SS$_BUFFEROVF)); if(stat != SS$_ENDOFFILE) SYS$EXIT(stat); if((((stat = SYS$QIOW(0, chan, IO$_SETMODE|IO$M_WRTATTN, iosb, 0, 0, astroutine, chan, 0, 0, 0, 0)) & 7) != 1) || (((stat = iosb[0]) & 7) != 1)) SYS$EXIT(stat); } /***************************** End of ASTROUTINE ******************************/ /********************** Routine to create three mailboxes *********************/ /* In this version, logical names for the mailboxes are built in */ #include descrip crembx() { short chan; long stat, i; $DESCRIPTOR(input_mailbox, "INPUT_MAILBOX"); $DESCRIPTOR(output_mailbox, "OUTPUT_MAILBOX"); $DESCRIPTOR(attention _mailbox, "ATTENTION_MAILBOX"); dsc$descriptor *lognams[3] = { &input_mailbox, &output_mailbox, &attention_mailbox }; /* Create three temporary mailboxes */ for(i = 0; i < 3; ++i) { if(((stat =SYS$CREMBX(0,&chan,0,0,0,0,lognams[i])) & 7) != 1) SYS$EXIT(stat); } astroutine(chan); } /* And give the astroutine the channel number of the last one */ /*********************** End of mailbox creation routine **********************/ To start up a debugging session through mailboxes using these routines, 1) Compile and link your program with these two routines, linking with the /DEBUG qualifier; 2) Define DBG$INIT to point to a file containing at least the following instructions: CALL crembx ! set up mailboxes and enable attention AST SET BREAK astroutine ! BREAK when the mailbox is active GO; @INPUT_MAILBOX ! Start the image (the GO is optional) 3) To cause the program to enter the debugger, just write to the ATTENTION_MAILBOX. 4) To issue commands to the debugger, write to the INPUT_MAILBOX. 5) To see the results of your commands to the debugger, write: SET LOG OUTPUT_MAILBOX:; SET OUTPUT LOG to the INPUT_MAILBOX, and startup a process to copy from OUTPUT_MAILBOX to wherever you want to see the output. The command SPAWN/NOWAIT COPY OUTPUT_MAILBOX: SYS$OUTPUT: will suffice. Hope this is of some use to you.