/*===========================================================*/ /* */ /* Name - LXPROC. */ /* */ /* Function - Map a Process within a Linux Virtual Machine */ /* */ /* Operation - The user specifies the address of a process' */ /* task structure (or '*' for the "current" */ /* active process and the name of the virtual */ /* machine running Linux. */ /* */ /* The task_structure of the desired process is */ /* located and from that the Segment Table Orig- */ /* in (so that XASTOR can map 3rd level virtual */ /* storage), the User Context (where register */ /* information is held, and the current stack */ /* frame is obtained. */ /* */ /* A dump of the registers and the memory map */ /* for the process is performed and placed in */ /* a file called ' A'. */ /* */ /* The user is then able to use the facilities */ /* of XASTOR to inspect the virtual storage of */ /* the process. */ /* */ /* Limits - The method of locating the "current" process */ /* is to get the address at 0xc40 and subtract */ /* 8K. I do not allow for prefix pages such that */ /* this will only work for processes on CPU 0. */ /* */ /* The guest must be running in 31-bit mode as */ /* there is no support in XASTOR (currently) for */ /* translating 64-bit addresses. Similarly, */ /* on a zVM system, all data needs to reside */ /* "under the bar". Work is underway to support */ /* zVM 4.x as the current version 1.7.3 will */ /* only work on a 3.1 system. */ /* */ /* If Linux has swapped a page of the process' */ /* that you are interested in you will not be */ /* able to inspect it. (Given XASTOR has the */ /* ability to read blocks from disk and is able */ /* to locate the necessary control blocks, this */ /* limitation could be removed.) */ /* */ /*===========================================================*/ parse upper arg TSS User . call PROLOG signal on error call GET_TSS call LOCATE_STACK call BUILD_PROC_DATA call DISPLAY_STACK exit /*================== End of Mainline ========================*/ /*===========================================================*/ /* */ /* Name - PROLOG. */ /* */ /* Function - Initial setup and parameter validation. */ /* */ /*===========================================================*/ PROLOG: if TSS=='?' | TSS=='HELP' | TSS = "" then do 'SET MESSAGE Format: LXPROC ' exit end 'EXTRACT USER' parse value User xUser with User . 'SET USER' User /* Establish user */ if rc <> 0 then exit return /*================== End of Routine =========================*/ /*===========================================================*/ /* */ /* Name - GET_TSS. */ /* */ /* Function - Determine if the user wants a specific process */ /* or the currently active process. */ /* */ /*===========================================================*/ GET_TSS: if TSS = '*' then do 'SET ADDRESS C40' 'EXTRACT DATA +0 4' TSS = D2X(C2D(xData) - 8192) end if ^DATATYPE(TSS,'X') then do 'SET MESSAGE Format: LXPROC ' exit end return /*================== End of Routine =========================*/ /*===========================================================*/ /* */ /* Name - LOCATE_STACK. */ /* */ /* Function - Using the TSS as a base, locate the */ /* mm_struct (from which we get the STO), */ /* the user context (from which we get our reg- */ /* isters) and the current stack pointer (we */ /* assume R15 in the user context points to it). */ /* */ /*===========================================================*/ LOCATE_STACK: 'ASCII' 'EXTRACT NEXT' /* Save NEXT */ 'SET ADDRESS' TSS /* Point to task structure */ 'EXTRACT DATA +70 4' /* Get PID */ PID = C2D(xData) 'EXTRACT DATA +30 4' /* Pick up mm_struct address */ MMStruct = C2X(xData) if (MMStruct = 0) then do 'SET MESSAGE TSS not valid' exit end 'SET ADDRESS' MMStruct /* Point to mm_struct */ 'EXTRACT DATA +C 4' /* Pick up A(Page Directory) - STO */ STO = C2X(xData) /* Get segment table origin */ 'SET ADDRESS' TSS /* Point to Task Structure */ 'EXTRACT DATA +358 4' /* Point to register save area */ UCtx = C2X(xData) /* Get A(User Context */ 'SET ADDRESS' UCtx /* Go to the UContext Area */ 'EXTRACT DATA +0 4' /* Extract PSW */ PSWMask = C2X(xData) /* Get the PSW Mask */ 'EXTRACT DATA +4 4' /* Extract PSW */ PSWAddr = C2X(xData) /* Get the PSW Addr */ 'EXTRACT DATA +44 4' /* Get current stack pointer */ StackPtr = C2X(xData) /* This is a 3rd level address */ PidMsg = 'PID:' PID 'TSS:' TSS 'MMS:' MMStruct 'CTX:' UCtx return /*================== End of Routine =========================*/ /*===========================================================*/ /* */ /* Name - BUILD_PROC_DATA. */ /* */ /* Function - Extract interesting data from the process' */ /* kernel control blocks. */ /* */ /*===========================================================*/ BUILD_PROC_DATA: call GET_UCONTEXT call GET_MAP address command , 'PIPE (end ? name WRITE_PID_FILE)', '| var PidMsg', '| append literal ', '| append stem UCtx.', '| append literal ', '| append stem Maps.', '| >' User PID 'A' return /*================== End of Routine =========================*/ /*===========================================================*/ /* */ /* Name - GET_UCONTEXT. */ /* */ /* Function - Dump PSW, general registers and access reg- */ /* isters from the process' user context block. */ /* */ /*===========================================================*/ GET_UCONTEXT: UCtx. = '' UCtx.1 = CENTER('Process Context Data',60) UCtx.2 = ' ' UCtx.3 = 'PSW:' PSWMask PSWAddr I_Out = 4 'SET ADDRESS' UCtx Offset = 8 do I_Reg = 0 to 15 by 4 I_Out = I_Out + 1 do I_R = 0 to 3 'EXTRACT DATA +'D2X(Offset) '4' UCtx.I_Out = UCtx.I_Out || 'R'RIGHT(I_Reg+I_R,2,'0')':' , C2X(xData) ' ' Offset = Offset + 4 end end I_Out = I_Out + 1 UCtx.I_Out = ' ' do I_Reg = 0 to 15 by 4 I_Out = I_Out + 1 do I_R = 0 to 3 'EXTRACT DATA +'D2X(Offset) '4' UCtx.I_Out = UCtx.I_Out || 'AR'RIGHT(I_Reg+I_R,2,'0')':' , C2X(xData) ' ' Offset = Offset + 4 end end UCtx.0 = I_Out return /*================== End of Routine =========================*/ /*===========================================================*/ /* */ /* Name - GET_MAP. */ /* */ /* Function - Go through the vma structure and create a */ /* report on the mapped memory of the process. */ /* */ /*===========================================================*/ GET_MAP: Maps.1 = CENTER('Memory Map',60) Maps.2 = ' ' I_Out = 2 'SET ADDRESS' MMStruct 'EXTRACT DATA +0 4' VM_Next = C2X(xData) /*---------------------------------------------------------*/ /* Traverse through the chain of memory maps. */ /*---------------------------------------------------------*/ do while VM_Next <> 0 'SET ADDRESS' VM_Next 'EXTRACT DATA +4 4' /* Get VM_START */ VM_Start = C2X(xData) 'EXTRACT DATA +8 4' /* Get VM_END */ VM_End = C2X(xData) 'EXTRACT DATA +C 4' /* Get VM_NEXT */ VM_Next = C2X(xData) 'EXTRACT DATA +10 4' /* Get VM_PAGE_PROT */ VM_PGProt = C2X(xData) 'EXTRACT DATA +14 4' /* Get VM_FLAGS */ VM_Flags = xData 'EXTRACT DATA +34 4' VM_File = C2X(xData) /* Get VM_File */ /*------------------------------------------------------*/ /* Print the name of the file associated with range. */ /*------------------------------------------------------*/ if (VM_File <> 0) then do signal off ERROR 'SET ADDRESS' VM_File if (Rc = 0) then do 'EXTRACT DATA +8 4' /* Get *dentry */ 'SET ADDRESS' C2X(xData) if (Rc = 0) then do 'EXTRACT DATA +3C 4' /* Get d_name */ P_FileName = C2X(xData) FileName = GETSTRING(P_FileName) end else FileName = '' end else FileName = '' end else FileName = '' signal on ERROR /*------------------------------------------------------*/ /* Determine privileges of address range. */ /*------------------------------------------------------*/ Flags = '' if BITAND(VM_Flags,'00000001'x) <> '00000000'x then Flags = Flags||'r' else Flags = Flags||'-' if BITAND(VM_Flags,'00000002'x) <> '00000000'x then Flags = Flags||'w' else Flags = Flags||'-' if BITAND(VM_Flags,'00000004'x) <> '00000000'x then Flags = Flags||'x' else Flags = Flags||'-' Flags = Flags||'p' I_Out = I_Out + 1 Maps.I_Out = VM_Start '-' VM_End ':' Flags FileName end Maps.0 = I_Out return /*================== End of Routine =========================*/ /*===========================================================*/ /* */ /* Name - DISPLAY_STACK. */ /* */ /* Function - Simply make the address of the current stack */ /* frame the visible page on the XASTOR display. */ /* */ /*===========================================================*/ DISPLAY_STACK: 'SETSTO' STO 'SET ADDRESS' StackPtr PidMsg = 'PID:' PID 'TSS:' TSS 'MMS:' MMStruct 'CTX:' UCtx 'SET MESSAGE' PidMsg return /*================== End of Routine =========================*/ /*===========================================================*/ /* */ /* Name - GETSTRING. */ /* */ /* Function - Extract a null-terminated ASCII string from */ /* the process' address space and convert it to */ /* EBCDIC. */ /* */ /*===========================================================*/ GETSTRING: parse arg Address String = '' Offset = 0 signal off ERROR 'SET ADDRESS' Address if (Rc <> 0) then return "" 'EXTRACT DATA +'Offset '1' do while xData <> '00'x Offset = Offset + 1 String = String||xData 'EXTRACT DATA +'D2X(Offset) '1' end address command , 'PIPE var String | xlate from 437 to 1047 | var String' return String /*================== End of Routine =========================*/ /*===========================================================*/ /* */ /* Name - ERROR. */ /* */ /* Function - Handle error situations. No real attempt at */ /* recovery is made, just a message indicating */ /* the problem and where it occurred. */ /* */ /*===========================================================*/ ERROR: retC = Rc 'EXTRACT MESSAGE' EMsg = xMessage '(Error occurred at line:' sigl'. Rc:' retC')' 'SET MESSAGE' EMsg 'SET NEXT' xnext /* Restore NEXT */ exit /*================== End of Routine =========================*/