338 lines
8.2 KiB
NASM
338 lines
8.2 KiB
NASM
|
;******************************************************
|
|||
|
;
|
|||
|
; Copyrigth (C) 1984 Logitech. All Rights Reserved.
|
|||
|
;
|
|||
|
; Permission is hereby granted to registered users to use or
|
|||
|
; abstract the following program in the implementation of
|
|||
|
; customized versions. This permission does not include the
|
|||
|
; right to redistribute the source code of this program.
|
|||
|
;
|
|||
|
;
|
|||
|
; Modula-2/86 Run Time Support package
|
|||
|
;
|
|||
|
; PMD.ASM - Post Mortem Dump module
|
|||
|
;
|
|||
|
;
|
|||
|
|
|||
|
include RTS.INC
|
|||
|
|
|||
|
code segment public
|
|||
|
extrn RTS_DS:word ; really belongs here!
|
|||
|
extrn GET_CURR_DISK:near
|
|||
|
extrn SELECT_DISK:near
|
|||
|
extrn DELETE_FILE:near
|
|||
|
extrn MAKE_FILE:near
|
|||
|
extrn SET_DEFAULT_DMA:near
|
|||
|
extrn NORM_ADDR:near
|
|||
|
extrn SEQ_WRITE:near
|
|||
|
extrn CLOSE_FILE:near
|
|||
|
extrn DELETE_FILE:near
|
|||
|
extrn WRITE_LN:near
|
|||
|
extrn WRITE_MSG:near
|
|||
|
|
|||
|
data segment public
|
|||
|
|
|||
|
; Variables for Post Mortem Dump:
|
|||
|
DUMP_NAME DB 'MEMORY.PMD',0
|
|||
|
NO_DUMP DB 'Post Mortem Dump failed', 0DH,0AH, '$'
|
|||
|
PARAG_IN_REC DB 0 ; paragraph counter for PMD
|
|||
|
even
|
|||
|
DUMP_LOW_START dw ? ; first paragraph of 'low' dump area
|
|||
|
DUMP_LOW_END dw ? ; last paragraph of same
|
|||
|
DUMP_HIGH_START dw ?
|
|||
|
DUMP_HIGH_END dw ?
|
|||
|
TEMP_W dd ?
|
|||
|
|
|||
|
extrn START_MEM:word, MEM_SIZE:word
|
|||
|
extrn SAVED_DISK:byte
|
|||
|
extrn RTS_DISK:byte
|
|||
|
extrn CUR_PROCESS:byte ;:ProcessDescriptor
|
|||
|
extrn RTS_PROCESS:byte ;:ProcessDescriptor
|
|||
|
extrn CUR_P_PTR:dword
|
|||
|
extrn FILE_HANDLE:word
|
|||
|
extrn FILE_SPEC:byte
|
|||
|
data ends
|
|||
|
|
|||
|
public P_M_DUMP
|
|||
|
assume CS:code, DS:data
|
|||
|
|
|||
|
P_M_DUMP proc NEAR
|
|||
|
;========
|
|||
|
; Entry point for Post Mortem Dump
|
|||
|
; When arriving here, we assume the relevant
|
|||
|
; registers to be saved in the process descriptor.
|
|||
|
; Before dumping memory, we are going to
|
|||
|
; write the copy of the P.D. back into the
|
|||
|
; workspace of the process:
|
|||
|
Les di, CUR_P_PTR
|
|||
|
Mov si, offset CUR_PROCESS
|
|||
|
Mov cx, (size ProcessDescriptor)/2
|
|||
|
Rep Movsw
|
|||
|
|
|||
|
; Now, we create the file on the same disk
|
|||
|
; where the resident part was found. Therefore,
|
|||
|
; we have first to save the currrent disk:
|
|||
|
call GET_CURR_DISK
|
|||
|
|
|||
|
; set up the filespec:
|
|||
|
MOV AL, RTS_DISK
|
|||
|
add al,'A'
|
|||
|
PUSH DS
|
|||
|
POP ES
|
|||
|
MOV SI, OFFSET DUMP_NAME
|
|||
|
MOV DI, offset FILE_SPEC
|
|||
|
mov byte ptr[di],al
|
|||
|
inc di
|
|||
|
mov byte ptr[di],':'
|
|||
|
inc di
|
|||
|
MOV CX, 11 ; Drive, Name, Typ and Extent
|
|||
|
REP MOVSB
|
|||
|
|
|||
|
CALL DELETE_FILE ; Delete the old DUMP-file
|
|||
|
CALL MAKE_FILE ; and create the new-one
|
|||
|
JNB D_FILE_MADE ; yes
|
|||
|
JMP AFTER_DUMP ; no, dump fails
|
|||
|
D_FILE_MADE:
|
|||
|
mov FILE_HANDLE,ax
|
|||
|
CALL SET_DEFAULT_DMA
|
|||
|
; Fill the header record:
|
|||
|
MOV AX, 0 ; First fill with zeroes
|
|||
|
MOV DI, DEFAULT_DMA
|
|||
|
PUSH DS
|
|||
|
POP ES
|
|||
|
MOV CX, 64
|
|||
|
REP STOSW
|
|||
|
; Now put the info required by the debugger:
|
|||
|
MOV DI, DEFAULT_DMA
|
|||
|
; addr of MAIN process descr:
|
|||
|
MOV word ptr [DI], OFFSET RTS_PROCESS
|
|||
|
MOV word ptr 2[DI], DS
|
|||
|
; addr of descriptor of terminating process:
|
|||
|
LES SI, CUR_P_PTR
|
|||
|
MOV [DI]+4, SI
|
|||
|
MOV [DI]+6, ES
|
|||
|
; start and end of interrupt vector table:
|
|||
|
MOV WORD PTR [DI]+16, 0
|
|||
|
MOV WORD PTR [DI]+18, 3FH
|
|||
|
; paragraph address of RESIDENT:
|
|||
|
mov ax, RTS_DS
|
|||
|
mov DUMP_LOW_START, ax
|
|||
|
mov [di]+20, ax
|
|||
|
; end of lower memory area:
|
|||
|
MOV BX, RTS_PROCESS.PD_HEAP_TOP + 2
|
|||
|
MOV AX, RTS_PROCESS.PD_HEAP_TOP
|
|||
|
CALL NORM_ADDR
|
|||
|
INC BX ; next paragraph
|
|||
|
MOV DUMP_LOW_END, BX ; just save it
|
|||
|
MOV [DI]+22, BX ; top of main heap (parag)
|
|||
|
; start of higher memory area:
|
|||
|
MOV BX, RTS_PROCESS.PD_SS
|
|||
|
MOV AX, RTS_PROCESS.PD_SP
|
|||
|
CALL NORM_ADDR
|
|||
|
MOV DUMP_HIGH_START, BX ; just save it
|
|||
|
MOV [DI]+24, BX ; top of main stack (parag)
|
|||
|
; last paragraph of memory:
|
|||
|
mov bx, START_MEM
|
|||
|
dec bx
|
|||
|
add bx, MEM_SIZE
|
|||
|
MOV DUMP_HIGH_END, BX ; just save it
|
|||
|
MOV [DI]+26, BX
|
|||
|
|
|||
|
; Send the first record to the file:
|
|||
|
CALL SEQ_WRITE
|
|||
|
CMP AL, 80H
|
|||
|
JNE DUMP_BAD
|
|||
|
|
|||
|
; Now dump the memory:
|
|||
|
; We dump 3 memory areas: the interrupt vectors (0..3FFH), the 'low'
|
|||
|
; memory from start of RESIDENT to heaptop of main and the 'high'
|
|||
|
; memory starting at stacktop of main to end of memory.
|
|||
|
; These 3 areas are dumped paragraph-wise.
|
|||
|
MOV PARAG_IN_REC, 0 ; counter = 0
|
|||
|
MOV CX, 0 ; start of first area
|
|||
|
MOV BX, 03FH ; end of first area
|
|||
|
CALL DUMP_PART
|
|||
|
CMP AL, 0
|
|||
|
JNE DUMP_BAD ; there was an error
|
|||
|
MOV CX, DUMP_LOW_START ; start of second area
|
|||
|
MOV BX, DUMP_LOW_END ; end of second area
|
|||
|
CALL DUMP_PART
|
|||
|
CMP AL, 0
|
|||
|
JNE DUMP_BAD ; there was an error
|
|||
|
MOV CX, DUMP_HIGH_START ; start of third area
|
|||
|
MOV BX, DUMP_HIGH_END ; end of third area
|
|||
|
CALL DUMP_PART
|
|||
|
CMP AL, 0
|
|||
|
JNE DUMP_BAD ; there was an error
|
|||
|
CMP PARAG_IN_REC, 0
|
|||
|
JE CLOSE_DUMP
|
|||
|
CALL SET_DEFAULT_DMA ; We have to write the buffer
|
|||
|
CALL SEQ_WRITE
|
|||
|
CMP AL, 80H
|
|||
|
JNE DUMP_BAD
|
|||
|
|
|||
|
CLOSE_DUMP:
|
|||
|
MOV AX, 0 ; to indicate 'no error'
|
|||
|
DUMP_BAD:
|
|||
|
PUSH AX
|
|||
|
; Close the file:
|
|||
|
CALL CLOSE_FILE
|
|||
|
POP AX
|
|||
|
|
|||
|
AFTER_DUMP:
|
|||
|
; Dump is made. AX contains 0 for successfull
|
|||
|
; dump and > 0 if an error occured:
|
|||
|
CMP AX, 0
|
|||
|
JE DUMP_OK
|
|||
|
CALL WRITE_LN
|
|||
|
MOV DX, OFFSET NO_DUMP
|
|||
|
CALL WRITE_MSG
|
|||
|
CALL DELETE_FILE
|
|||
|
DUMP_OK:
|
|||
|
; Restore the disk of before the dump:
|
|||
|
MOV DL, SAVED_DISK
|
|||
|
CALL SELECT_DISK
|
|||
|
RET
|
|||
|
P_M_DUMP endp
|
|||
|
|
|||
|
DUMP_PARTIAL_REC proc NEAR
|
|||
|
; The variable 'PARAG_IN_REC' gives the number of paragraphs that
|
|||
|
; are already in the record at CPM_DMA. It is updated here.
|
|||
|
; AX holds the number of paragraphs to dump at entry and the
|
|||
|
; remaining-ones at exit.
|
|||
|
; CX is paragraph address of memory to dump and is updated here.
|
|||
|
; When the record can be filled completely, it is written to the
|
|||
|
; file (DEFAULT_FCB). BL returns 0 if no error, 0FFH otherwise.
|
|||
|
CMP AX, 8
|
|||
|
JB DO_PARTIAL_DUMP
|
|||
|
JZ GOOD_PARTIAL_DUMP
|
|||
|
; nothing to dump
|
|||
|
CMP PARAG_IN_REC, 0
|
|||
|
JZ GOOD_PARTIAL_DUMP
|
|||
|
; This means: nothing in the
|
|||
|
; buffer and more than 8
|
|||
|
; paragraphs to dump.
|
|||
|
DO_PARTIAL_DUMP:
|
|||
|
; There are some paragraphs to copy:
|
|||
|
MOV BX, 8
|
|||
|
SUB BL, PARAG_IN_REC
|
|||
|
; BX= number of par. to copy
|
|||
|
CMP AX, BX
|
|||
|
JAE ENOUGH_TO_FILL
|
|||
|
MOV BX, AX
|
|||
|
MOV AX, 0
|
|||
|
JMP SHORT PARTIAL_DUMP
|
|||
|
ENOUGH_TO_FILL:
|
|||
|
SUB AX, BX
|
|||
|
PARTIAL_DUMP:
|
|||
|
; AX = remaining paragraphs to dump later.
|
|||
|
; BX = number of paragraphs to copy in buffer.
|
|||
|
; CX = paragraph addr of area to copy (offset=0).
|
|||
|
MOV TEMP_W, AX
|
|||
|
MOV TEMP_W+2, BX
|
|||
|
MOV ES, RTS_DS
|
|||
|
MOV DI, DEFAULT_DMA ; offset of buffer
|
|||
|
MOV AL, PARAG_IN_REC
|
|||
|
MOV AH, 0
|
|||
|
MOV DS, CX
|
|||
|
MOV CL, 4
|
|||
|
SHL AX, CL ; offset inside buffer
|
|||
|
ADD DI, AX ; (ES,DI) = dest addr
|
|||
|
MOV SI, 0 ; source offset
|
|||
|
MOV CX, 4
|
|||
|
SHL BL, CL
|
|||
|
MOV CL, BL
|
|||
|
; number of bytes to copy
|
|||
|
REP MOVSB
|
|||
|
; Now, the paragraphs to copy are in the
|
|||
|
; buffer, update counters and pointers:
|
|||
|
MOV CX, DS
|
|||
|
MOV DS, RTS_DS
|
|||
|
MOV AX, TEMP_W+2 ; number of copied paragraphs
|
|||
|
ADD PARAG_IN_REC, AL
|
|||
|
ADD AX, CX
|
|||
|
MOV TEMP_W+2, AX
|
|||
|
MOV CX, AX
|
|||
|
MOV AX, TEMP_W
|
|||
|
CMP PARAG_IN_REC, 8
|
|||
|
JB GOOD_PARTIAL_DUMP
|
|||
|
; The buffer is full, we write it on the file:
|
|||
|
CALL SET_DEFAULT_DMA
|
|||
|
CALL SEQ_WRITE
|
|||
|
CMP AL, 80H
|
|||
|
JNE BAD_PARTIAL_DUMP
|
|||
|
MOV AX, TEMP_W
|
|||
|
MOV CX, TEMP_W+2
|
|||
|
MOV PARAG_IN_REC, 0
|
|||
|
GOOD_PARTIAL_DUMP:
|
|||
|
MOV BL, 0
|
|||
|
RET
|
|||
|
BAD_PARTIAL_DUMP:
|
|||
|
MOV BL, 0FFH
|
|||
|
RET
|
|||
|
DUMP_PARTIAL_REC endp
|
|||
|
|
|||
|
|
|||
|
DUMP_PART proc NEAR
|
|||
|
; Dumps a part of the memory to an open
|
|||
|
; disk file, using the DEFAULT_FCB.
|
|||
|
; Upon entry:
|
|||
|
; CX holds addr of first paragraph to
|
|||
|
; dump, BX is addr of last paragraph
|
|||
|
; to dump (BX=CX means 1 par. to dump).
|
|||
|
; Upon exit:
|
|||
|
; AL=0 if no error occured while writing,
|
|||
|
; AL=1 otherwise.
|
|||
|
MOV AX, BX
|
|||
|
INC AX
|
|||
|
SUB AX, CX
|
|||
|
JA DUMP_SIZE_OK
|
|||
|
RET
|
|||
|
; endaddr < startaddr
|
|||
|
DUMP_SIZE_OK:
|
|||
|
CALL DUMP_PARTIAL_REC
|
|||
|
; needed to fill partially filled
|
|||
|
; buffer, as remainder from dumping
|
|||
|
; the previous area.
|
|||
|
CMP BL, 0
|
|||
|
JZ DUMP_NEXT_REC
|
|||
|
MOV AL, 0FFH
|
|||
|
RET
|
|||
|
DUMP_NEXT_REC:
|
|||
|
;;;;;; start of LOOP ;;;;;;;
|
|||
|
; AX holds number of paragraphs to dump
|
|||
|
; CX holds first paragr-addr
|
|||
|
CMP AX, 8
|
|||
|
JB DUMP_LAST_REC
|
|||
|
MOV TEMP_W, AX
|
|||
|
MOV TEMP_W+2, CX
|
|||
|
push DS
|
|||
|
mov DS,cx
|
|||
|
mov dx,0
|
|||
|
mov ah, 01Ah
|
|||
|
int OS ; Set disk transfer address (DS:DX)
|
|||
|
pop DS
|
|||
|
CALL SEQ_WRITE ; Write next record
|
|||
|
CMP AL, 80H
|
|||
|
JE DUMP_REC_OK
|
|||
|
RET
|
|||
|
;
|
|||
|
DUMP_REC_OK:
|
|||
|
|
|||
|
MOV AX, TEMP_W ; The next record is written,
|
|||
|
SUB AX, 8 ; update counter and address.
|
|||
|
MOV CX, TEMP_W+2
|
|||
|
ADD CX, 8
|
|||
|
JMP SHORT DUMP_NEXT_REC
|
|||
|
;;;;; End of LOOP ;;;;;;;
|
|||
|
|
|||
|
DUMP_LAST_REC:
|
|||
|
CALL DUMP_PARTIAL_REC ; copy the remaining paragraphs
|
|||
|
; in the buffer.
|
|||
|
MOV AL, BL ; error flag
|
|||
|
RET
|
|||
|
DUMP_PART endp
|
|||
|
|
|||
|
code ends
|
|||
|
end
|
|||
|
|