From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  6-OCT-1989 10:45
To:	MRGATE::"ARISIA::EVERHART"
Subj:	PROCESS_DUMP (DUMP/PROCESS/IDENT=xxx utility) 3/4

Message-Id:  <8910061326.AA02274@crdgw1.ge.com>
Received: From NSFNET-RELAY.AC.UK by CRVAX.SRI.COM with TCP; Fri,  6 OCT 89 05:24:23 PDT
Received: from ncdlab.ulcc.ac.uk by NSFnet-Relay.AC.UK   via Janet with NIFTP
           id aa04117; 6 Oct 89 12:14 BST
Date:           Fri, 6 Oct 89  12:12 BST
From: Nick de Smith <"PSI%JANET.000000000040::NICK%ncdlab.ulcc.ac.uk"@NSFnet-Relay.AC.UK>
To: INFO-VAX <@NSFnet-Relay.AC.UK:INFO-VAX@crvax.sri.com>
Subject:        PROCESS_DUMP (DUMP/PROCESS/IDENT=xxx utility) 3/4

-+-+-+-+-+-+-+-+ START OF PART 3 -+-+-+-+-+-+-+-+
X;`009  converted into binary, treat it as a process name.
X;`009- Calls K_AST to queue the special KERNEL mode AST
X;`009- Ends
X;--
X`009.psect`009$CODE`009Rd, NoWrt, Exe, Pic, Long
X
XK_MAIN:`009.word`009`094m<>
X`009pushab`009EPID_DESC`009`009; Where to return PID text
X`009pushab`009PID_PROMPT`009`009; Prompt to use for input
X`009pushab`009EPID_DESC`009`009; Returned resultant length
X`009calls`009#3, g`094LIB$GET_FOREIGN`009; Get the PID text
X`009blbc`009r0, 100$`009`009; Check for errors
X
X`009pushab`009EPID`009`009`009; Where to return binary PID
X`009pushab`009EPID_DESC`009`009; Ascii PID text
X`009calls`009#2, g`094OTS$CVT_TZ_L`009; Convert the PID to binary
X`009blbs`009r0, 10$`009`009`009; Check for errors
X`009clrl`009K_ARGS+<1*4>`009`009; Use PID as a process name
X
X10$:`009$cmkrnl_s`009`009 -`009; Queue the AST
X`009`009routin = QUEUE_KERNEL_AST,- ; Routine to call
X`009`009arglst = K_ARGS`009`009; Argument list
X
X100$:`009ret`009`009`009`009; Exit this program
X
X`009.end`009K_MAIN`009`009`009; This is the entry point module
$ CALL UNPACK [.PDUMP]K_MAIN.MAR;1 544954691
$ create/nolog 'f'
X.title`009`009PDUMP`009Process Dump another PID
X.subtitle`009PDUMP`009Process Dump another PID
X;++
X; PDUMP - Generate a Process Dump for another PID
X;
X; Author:`009Nick de Smith
X;`009`009Applied Telematics Services, 7 Vale Avenue
X;`009`009Tunbridge Wells, Kent TN1 1DJ, England.
X;`009`009+44 892 511000, PSI%234213300154::NICK
X; Date  :`00905-May-87, 19-Dec-88
X;
X; Copyright (c) 1987,1988 by Applied Telematics Group Limited and Nick de Sm
Vith.
X; This software is supplied for information only. No guarantee is supplied f
Vor
X; this software, and no liability will be accepted for any action resulting
V from
X; the use of this software or the information contained herein. Under no
X; circumstances may this software be used for commercial gain, including its
X; sale, lease or loan. This software may be copied only with the inclusion o
Vf
X; this copyright notice. The author is prepared to enter into correspondance
X; with interested parties, but will not necessarily maintain this software.
X; Having said all that, enjoy it!`032
X;
X; Description:
X;
X; This routine runs in KERNEL mode to deliver a KERNEL mode ast to
X; the target process, which in turn delivers a USER mode AST to the
X; same process.
X; The USER mode AST performs a process dump on the target process,
X; which then continues running (unaffected). This means that you can
X; take a snap dump of any other process on the system without stopping
X; it in any way (apart from the time taken to write the dump file). You
X; can then use ANALYZE/PROCESS_DUMP to inspect the dump file in your
X; own (or the company's) time. In particular, using the /IMAGE=name
X; qualifier to specify a version of the running image LINKed with
X; /DEBUG will make all the image symbols available to your ANALYZE.
X;
X; This program was written to inspect detached servers, but it may be
X; used on any process (see "restrictions" below).
X;
X; Note that while the dump is being taken, all activity in the target
X; process will be blocked (except for ASTs above USER). This can take
X; one or two seconds for a large image with a slow (or full) disk.
X;
X; If the symbol DEBUG is defined (see below) and for some reason the dump
X; cannot be taken, a USER class accounting message is written to the
X; SYS$MANAGER:ACCOUNTNG.DAT file. The first longword of this message is
X; the failure reason as a system error code.
X; If the failure was caused by a file write error, you can assign the
X; logical SYS$PROCDMP (LNM$SYSTEM_TABLE or LNM$GROUP_xxxxxx) to point
X; to a file. If this logical is found by the target process it will be
X; used to place the dump. Do not specifiy any filename extension in the
X; logical as it always has ".DMP" appended to it.
X;
X; Restrictions:
X;
X; Note:`009DUMP may have side effects, eg. it uses EFN 0 (and RMS) for I/O.
V I think
X;`009that this routine is "safe", but, as with all undocumented features, do
Vn't
X;`009walk in with blind faith.
X;
X; I don't think its a good idea to specify ACPs (especially RMS ones) as
X; the target process, as this may crash your system. Also I have seen some
X; strange results occasionally when running PDUMP on a process that spends
X; a lot of time in KERNEL mode.
X; Note that the actual dump AST is delivered in USER mode, so if you try
X; to dump a process that is locked in any AST, the dump won't happen.
X; You could change the delivery mode of the dump AST to SUPERVISOR, but
X; this may have odd side effects (normally the dump file can't be ANALYZEd).
X; The dump AST delivery mode must NOT be higher than SUPERVISOR, as the
X; image dumper uses RMS to write its file, and RMS relies on EXEC mode ASTs
X; to signal completion of asynchronous events. If you are running in an EXEC
X; mode AST already, the RMS I/O routines will never complete and the target
X; process will lock at EXEC mode AST in LEF. The only solution is then to
X; delete the target process.
X;
X;`009$ MACRO PDUMP
X;`009$ LINK PDUMP,K_MAIN,K_AST
X;`009$ RUN PDUMP`009`009! Requires CMKRNL (surprise!)
X;
X; Edit`009Edit date`009By`009Why
X; 2.01`00919-Dec-88`009NMdS`009VMS V5, integrate with common AST code.
X;  04`00928-Apr-88`009NMdS`009Add in call to EXE$SIGTORET as our KERNEL mode
X;`009`009`009`009exception handler.
X;  03`00923-Feb-88`009NMdS`009Add in rigorous checks on target process.
X;`009`009`009`009Also add in target priority boost.
X;  02`00920-Jan-88`009NMdS`009VMS V4.6 version
X;  01`00905-May-87`009NMdS`009First attempt
X;--
X.ident`009/V02.01/
X
X.library`009"Sys$Library:Lib"
X
Xdebug`009= 1`009`009`009`009; Defined to include DEBUG code (log
X`009`009`009`009`009; reason for failure as a USER accounting msg)
X`009$acbdef`009`009`009`009; AST Control Block definitions
X`009$chfdef`009`009`009`009; Define condition handler values
X`009$dscdef`009`009`009`009; VMS descriptors
X`009$iacdef`009`009`009`009; Image activator definitions
X`009$pridef`009`009`009`009; Priority boost classes
X`009$psldef`009`009`009`009; Process status definitions
X`009$sfdef`009`009`009`009; Saved frame offsets
X`009$ssdef`009`009`009`009; Define system statii
X`009$vadef`009`009`009`009; Virtual memory offsets
X.iif`009defined`009debug, $sjcdef`009`009; Job controller interface definiti
Vons
X`012
X.subtitle`009AST_CODE`009Code to execute in target process
X;++
X; AST_CODE`009Code to execute in target process
X;
X;  Input Parameters:
X;
X;`009R0:R3 - Scratch`032
X;`009R4 - PCB address of target process
X;`009R5 - Address of extended ACB
X;
X; Calling sequence:
X;
X;`009JSB`009@ACB$L_KAST(R5)`009`009; From SCH$ASTDEL at IPL$_ASTDEL
X;   which is the same as:
X;       JSB`009g`094AST_CODE`009`009; at IPL$_ASTDEL
X;--
X`009.Psect`009AST_CODE`009Rd, NoWrt, NoExe, Pic, Long
X
XAST_CODE::
X;
X`009pushr`009#`094m<r5>`009`009`009`009; Save ACB address
X`009clrq`009-(sp)`009`009`009`009; Space for return address
X`009movl`009sp, r6`009`009`009`009; R6 => 2 longwords of scratch
X`009$expreg_s`009`009`009,-`009; Expand P0 to hold the AST dump code
X`009`009pagcnt`009= #<<PROCESS_DUMP_LENGTH/512>+1>,-
X`009`009retadr`009= (r6)`009`009,-`009; Returned allocated space
X`009`009acmode`009= #PSL$C_USER`009,-`009; Allocate in USER mode
X`009`009region`009= #0`009`009`009; Allocate in P0
X`009blbc`009r0, 10$`009`009`009`009; Check for any error
X`009movl`009(r6), r6`009`009`009; R6 => Base of allocated region
X`009movc3`009#PROCESS_DUMP_LENGTH, PROCESS_DUMP, (r6) ; Copy USER AST code t
Vo P0
X;
X`009clrq`009(sp)+`009`009`009`009; Restore stack
X`009popr`009#`094m<r5>`009`009`009`009; Restore ACB address
X;
X; Now re-use the ACB to deliver the USER AST.
X; ACB$L_PID is already set to the target process's PID (that's why we're her
Ve).
X;
X`009movb`009#PSL$C_USER, ACB$B_RMOD(r5)`009; Set access mode in ACB
X`009movl`009r6, ACB$L_AST(r5)`009`009; Set the AST address (now in P0)
X`009clrl`009ACB$L_ASTPRM(r5)`009`009; No AST parameter (neatness)
X`009movl`009#PRI$_TICOM, r2`009`009`009; SCH$QAST needs priority boost in R2
X`009jmp`009g`094SCH$QAST`009`009`009; Queue the USER AST
X`009`009`009`009`009`009; ...and dismiss the KERNEL AST
X;
X; Error, so deallocate the ACB and dismiss the AST
X;
X10$:`009clrq`009(sp)+`009`009`009`009; Restore stack
X`009popr`009#`094m<r0>`009`009`009`009; Restore ACB address
X`009jmp`009g`094EXE$DEANONPAGED`009`009; Deallocate ACB
X`009`009`009`009`009`009; And dismiss the AST
X`012
X.subtitle`009Relocatable data area for USER AST
X
X`009$defini`009DMP
X`009$def`009DMP_L_ARGLST`009`009`009; Get some space for an argument list
X`009`009.blkb`009CHF$S_CHFDEF
X`009$def`009DMP_L_SIGARG`009`009`009; Signal array
X`009`009.blkb`009CHF$S_CHFDEF1+<1*4>`009; + 1 extra argument
X`009$def`009DMP_L_MCHARG`009`009`009; Mechanism array
X`009`009.blkb`009CHF$S_CHFDEF2
X`009$def`009DMP_Q_IMGDMP`009`009`009; Descriptor for image dumper
X`009`009.blkq`0091
X`009$def`009DMP_Q_DFLNAM`009`009`009; Defaults for image dumper name
X`009`009.blkq`0091
X`009$def`009DMP_T_HDRBUF`009`009`009; Buffer for the image header
X`009`009.blkb`009512
X`009$def`009DMP_Q_INADR`009`009`009; Input mapping range
X`009`009.blkq`0091
X`009$def`009DMP_Q_RETADR`009`009`009; Returned mapped addresses
X`009`009.blkq`0091
X.if`009defined`009debug
X`009$def`009DMP_T_ACC_ITMLST`009`009; $SNDJBC item list
X`009`009.blkb`0091*<2+2+4+4>+4`009`009; (1 item + longword null)
X`009$def`009DMP_L_ACC_STATUS`009`009; Status to log
X`009`009.blkl`0091
X.endc
X`009$def`009DMP_K_LENGTH
X`009$defend`009DMP
X
X; Offsets from AP for a non-KERNEL AST routine
X
XASTPRM`009`009= 4*1`009`009`009`009; AST parameter
XSAVED_R0`009= 4*2`009`009`009`009; Caller's R0
XSAVED_R1`009= 4*3`009`009`009`009;   ''     R1
XSAVED_PC`009= 4*4`009`009`009`009;   ''     PC when the AST was delivered
XSAVED_PSL`009= 4*5`009`009`009`009;   ''     PSL ''   '' ''   ''   ''
X`012
X.subtitle`009PROCESS_DUMP`009Generate a process dump file
X;++
X; PROCESS_DUMP`009Generate a process dump file
X;
X; Call:`009`009As a USER mode AST
X;
X; Passed:
X;`009ASTPRM(ap)`009Declared AST parameter (not used)
X;`009SAVED_R0(ap)`009Process's R0 at time of AST
X;`009SAVED_R1(ap)`009   ''     R1 at time of AST
X;`009SAVED_PC(ap)`009   ''     PC at time of AST
X;`009SAVED_PSL(ap)`009   ''     PSL at time of AST
X;
X; Returns:
X;
X;`009All registers preserved.
X;`009R0 and R1 are restored by ASTEXIT_CHMK in module ASTDEL (called from EX
VE$ASTDEL).
X;`009Condition codes are not preserved. This is rather dangerous. I am not s
Vure what to
X;`009do about them.
X;--
XPROCESS_DUMP:
X`009.word`009`094m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11> ; Entry mask for AST rou
Vtine
X;
X`009movab`009HANDLER, SF$A_HANDLER(fp)`009; Set up our exception handler
X;
X`009subl`009#DMP_K_LENGTH, sp`009`009; Get some space for required data
X`009movl`009sp, r6`009`009`009`009; We will use R6 as or data pointer
X`009moval`009DMP_L_ARGLST(r6), r7`009`009; R7 => fake argument list
X`009movzwl`009#2, (r7)`009`009`009; 2 arguments (signal and mechanism)
X;
X`009moval`009DMP_L_SIGARG(r6), r0`009`009; R0 => Fake signal array
X`009movl`009r0, CHF$L_SIGARGLST(r7)`009`009; Save pointer in fake argument l
Vist
X`009movl`009#3, CHF$L_SIG_ARGS(r0)`009`009; Three arguments...
X`009movl`009#SS$_DEBUG, CHF$L_SIG_NAME(r0)`009; ...false signal is SS$_DEBUG
X`009movl`009SAVED_PC(ap), CHF$L_SIG_ARG1(r0)`009; Caller's PC
X`009movl`009SAVED_PSL(ap), CHF$L_SIG_ARG1+4(r0)`009; Store caller's PSL
X;
X`009moval`009DMP_L_MCHARG(r6), r0`009`009; R0 => fake mechanism array
X`009movl`009r0, CHF$L_MCHARGLST(r7)`009`009; Save pointer in fake argument l
Vist
X`009movl`009#4, CHF$L_MCH_ARGS(r0)`009`009; Always 4 arguments in mechanism
V array
X`009movl`009fp, CHF$L_MCH_FRAME(r0)`009`009; We are the establisher
X`009movl`009#0, CHF$L_MCH_DEPTH(r0)`009`009; No depth
X`009movl`009SAVED_R0(ap), CHF$L_MCH_SAVR0(r0) ; Caller's R0 value
X`009movl`009SAVED_R1(ap), CHF$L_MCH_SAVR1(r0) ; Caller's R1 value
X;
X`009movaq`009DMP_Q_IMGDMP(r6), r0`009`009; R0 => image dump name descriptor
X`009movw`009#IMGDMP_LEN, DSC$W_LENGTH(r0)`009; Save image dumper name length
X`009movb`009#DSC$K_DTYPE_T, DSC$B_DTYPE(r0)`009; Text string
X`009movb`009#DSC$K_CLASS_S, DSC$B_CLASS(r0)`009; ...and its static
X`009movab`009IMGDMP_NAM, DSC$A_POINTER(r0)`009; Make descriptor PIC
X`009movaq`009DMP_Q_DFLNAM(r6), r0`009`009; R0 => image dump name default des
Vcriptor
X`009movw`009#DFLNAM_LEN, DSC$W_LENGTH(r0)`009; Save image dumper name defaul
Vts
X`009movb`009#DSC$K_DTYPE_T, DSC$B_DTYPE(r0)`009; Text string
X`009movb`009#DSC$K_CLASS_S, DSC$B_CLASS(r0)`009; ...and its static
X`009movab`009DFLNAM_NAM, DSC$A_POINTER(r0)`009; Make descriptor PIC
X;
X`009movl`009r7, ap`009`009`009`009; AP => fake argument list
X`009movq`009INADR, DMP_Q_INADR(r6)`009`009; Say we want to map in P0
X;
X`009$imgact_s`009`009 -`009`009; Activate the image dumper
X`009`009name`009= DMP_Q_IMGDMP(r6),-`009; Name of image dumper to use
X`009`009dflnam`009= DMP_Q_DFLNAM(r6),-`009; Name defaults to use
X`009`009hdrbuf`009= DMP_T_HDRBUF(r6),-`009; Where to place header
X`009`009imgctl`009= #<IAC$M_MERGE!IAC$M_EXPREG>,-`009; Merge into region
X`009`009inadr`009= DMP_Q_INADR(r6) ,-`009; Where to map code (first free VA
V space)
X`009`009retadr`009= DMP_Q_RETADR(r6),-`009; Mapped addresses returned here
X`009`009ident`009= 0`009`009  ,-`009; No ident specified
X`009`009acmode`009= #PSL$C_USER`009`009; Map at lowest access mode
X`009blbc`009r0, 10$`009`009`009`009; Check for any error
X`009$imgfix_s`009`009`009`009; Do any relocation fixups
X`009blbc`009r0, 10$`009`009`009`009; Check for any error
X
X`009movl`009DMP_Q_RETADR(r6), r1`009`009; Get load address
X`009movab`009@8(r1)`091r1`093,r1`009`009`009; Calculate the entry address
X
X`009jsb`009(r1)`009`009`009`009; Call the dump library
X
X10$:
X.if`009defined`009debug
X`009blbs`009r0, 20$`009`009`009`009; Skip the log if no error
X`009movl`009r0, DMP_L_ACC_STATUS(r6)`009; Save status code to write
X`009movw`009#4, DMP_T_ACC_ITMLST(r6)`009; Buffer length (1 longword)
X`009movw`009#SJC$_ACCOUNTING_MESSAGE, DMP_T_ACC_ITMLST+2(r6)
X`009moval`009DMP_L_ACC_STATUS(r6), DMP_T_ACC_ITMLST+4(r6)
X`009clrl`009DMP_T_ACC_ITMLST+8(r6)`009`009; Terminate list with a null
X`009$sndjbc_s`009`009-
X`009`009func`009= #SJC$_WRITE_ACCOUNTING -
X`009`009nullarg`009= #0`009-
X`009`009itmlst`009= DMP_T_ACC_ITMLST(r6)
X20$:
X.endc
X`009ret`009`009`009`009`009; Restore R2-R11 and return
X
+-+-+-+-+-+-+-+-  END  OF PART 3 +-+-+-+-+-+-+-+-

