Files
Perfectium/logger.asm
T

297 lines
8.5 KiB
NASM

INCLUDE include\master.inc
IFDEF DEBUG
EXTRN printf :PROC
EXTRN GetLocalTime :PROC
EXTRN GetModuleFileNameA :PROC
EXTRN CreateFileA :PROC
EXTRN WriteFile :PROC
EXTRN CloseHandle :PROC
EXTRN FlushFileBuffers :PROC
EXTRN wsprintfA :PROC
; Win32 constants
GENERIC_WRITE EQU 40000000h
FILE_SHARE_READ EQU 00000001h
CREATE_ALWAYS EQU 00000002h
FILE_ATTRIBUTE_NORMAL EQU 00000080h
; SYSTEMTIME field byte offsets
ST_wHour EQU 8
ST_wMinute EQU 0Ah
ST_wSecond EQU 0Ch
ST_wMilliseconds EQU 0Eh
.const
szFmtInfo DB "[INFO] [%02d:%02d:%02d.%03d] %s", 0Ah, 0
szFmtWarn DB "[WARN] [%02d:%02d:%02d.%03d] %s", 0Ah, 0
szFmtError DB "[ERROR] [%02d:%02d:%02d.%03d] %s", 0Ah, 0
szFmtFatal DB "[FATAL] [%02d:%02d:%02d.%03d] %s", 0Ah, 0
.data?
Logger_hFile QWORD ?
.code
; Logger_Initialize
; Builds a log path by taking the host EXE directory (via
; GetModuleFileNameA(NULL,...)) and appending "raider_debug.txt",
; then opens that file with CREATE_ALWAYS. Using the EXE directory
;
; Frame: 0 pushes + sub 148h = 328; 328 mod 16 = 8; RSP = 0
; [rsp+000..+01F] shadow (32)
; [rsp+020..+027] CreateFileA 5th arg: dwCreationDisposition
; [rsp+028..+02F] CreateFileA 6th arg: dwFlagsAndAttributes
; [rsp+030..+037] CreateFileA 7th arg: hTemplateFile
; [rsp+038..+13B] path buffer (260 bytes, MAX_PATH)
; [rsp+13C..+147] padding (12 bytes)
Logger_Initialize PROC
sub rsp, 148h
; GetModuleFileNameA(NULL, &path, MAX_PATH) -> EAX = length
xor ecx, ecx ; hModule = NULL -> host EXE
lea rdx, [rsp+38h] ; path buffer
mov r8d, 104h ; MAX_PATH = 260
call GetModuleFileNameA
test eax, eax
jz @@done ; failed, skip file logging
; Scan backward from end of path to find last '\'
lea rcx, [rsp+38h] ; rcx = buf start
add rax, rcx ; rax = &buf[len] (null terminator)
@@find_slash:
dec rax
cmp rax, rcx
jb @@done ; no backslash found, give up
cmp BYTE PTR [rax], '\'
jne @@find_slash
; rax = pointer to last '\'; write filename starting at rax+1
inc rax
mov BYTE PTR [rax+ 0], 'r'
mov BYTE PTR [rax+ 1], 'a'
mov BYTE PTR [rax+ 2], 'i'
mov BYTE PTR [rax+ 3], 'd'
mov BYTE PTR [rax+ 4], 'e'
mov BYTE PTR [rax+ 5], 'r'
mov BYTE PTR [rax+ 6], '_'
mov BYTE PTR [rax+ 7], 'd'
mov BYTE PTR [rax+ 8], 'e'
mov BYTE PTR [rax+ 9], 'b'
mov BYTE PTR [rax+10], 'u'
mov BYTE PTR [rax+11], 'g'
mov BYTE PTR [rax+12], '.'
mov BYTE PTR [rax+13], 't'
mov BYTE PTR [rax+14], 'x'
mov BYTE PTR [rax+15], 't'
mov BYTE PTR [rax+16], 0
; CreateFileA(&path, GENERIC_WRITE, FILE_SHARE_READ, NULL,
; CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)
lea rcx, [rsp+38h]
mov edx, GENERIC_WRITE
mov r8d, FILE_SHARE_READ
xor r9d, r9d ; lpSecurityAttributes = NULL
mov DWORD PTR [rsp+20h], CREATE_ALWAYS
mov DWORD PTR [rsp+28h], FILE_ATTRIBUTE_NORMAL
mov QWORD PTR [rsp+30h], 0 ; hTemplateFile = NULL
call CreateFileA
mov QWORD PTR [Logger_hFile], rax ; INVALID_HANDLE_VALUE if open failed
@@done:
add rsp, 148h
ret
Logger_Initialize ENDP
; Logger_Shutdown
; Closes the log file handle.
;
; Frame: 0 pushes + sub 28h = 40; 40 mod 16 = 8; RSP = 0
Logger_Shutdown PROC
sub rsp, 28h
mov rcx, QWORD PTR [Logger_hFile]
test rcx, rcx
jz @@done
cmp rcx, -1 ; INVALID_HANDLE_VALUE
je @@done
call CloseHandle
mov QWORD PTR [Logger_hFile], 0
@@done:
add rsp, 28h
ret
Logger_Shutdown ENDP
; Logger__Print (internal)
; Writes a timestamped log line to the console (printf) and,
; if the file handle is valid, also to raider_debug.txt with
; an immediate FlushFileBuffers so no data is lost on crash.
;
; In: RCX = format string* (one of szFmtInfo/Warn/Error/Fatal)
; RDX = message string*
;
; Frame: 0 pushes + sub 268h = 616; 616 mod 16 = 8; RSP = 0
;
; [rsp+000..+01F] shadow space (32)
; [rsp+020..+027] printf/wsprintfA 5th arg slot (ms / S)
; [rsp+028..+02F] printf/wsprintfA 6th arg slot (msg* / ms)
; [rsp+030..+03F] SYSTEMTIME struct (16); later reused as wsprintfA 7th arg
; [rsp+040..+047] saved msg*
; [rsp+048..+04F] saved fmt*
; [rsp+050..+05F] spare (16)
; [rsp+060..+25F] szLine[512] - wsprintfA output buffer
; [rsp+260..+263] dwWritten (DWORD for WriteFile)
; [rsp+264..+267] pad
Logger__Print PROC
sub rsp, 268h
mov QWORD PTR [rsp+40h], rdx ; save msg*
mov QWORD PTR [rsp+48h], rcx ; save fmt*
; GetLocalTime
lea rcx, [rsp+30h]
call GetLocalTime
; Console: printf(fmt, H, M, S, ms, msg)
mov rcx, QWORD PTR [rsp+48h]
movzx edx, WORD PTR [rsp+30h + ST_wHour]
movzx r8d, WORD PTR [rsp+30h + ST_wMinute]
movzx r9d, WORD PTR [rsp+30h + ST_wSecond]
movzx eax, WORD PTR [rsp+30h + ST_wMilliseconds]
mov DWORD PTR [rsp+20h], eax ; 5th arg: ms
mov rax, QWORD PTR [rsp+40h]
mov QWORD PTR [rsp+28h], rax ; 6th arg: msg*
call printf
; File: skip if handle invalid
mov rcx, QWORD PTR [Logger_hFile]
test rcx, rcx
jz @@skip_file
cmp rcx, -1 ; INVALID_HANDLE_VALUE
je @@skip_file
; wsprintfA(szLine, fmt, H, M, S, ms, msg)
; SYSTEMTIME is still valid at [rsp+30h]; fmt* and msg* saved above.
lea rcx, [rsp+60h] ; arg1: dest buffer
mov rdx, QWORD PTR [rsp+48h] ; arg2: fmt*
movzx r8d, WORD PTR [rsp+30h + ST_wHour] ; arg3: H
movzx r9d, WORD PTR [rsp+30h + ST_wMinute] ; arg4: M
movzx eax, WORD PTR [rsp+30h + ST_wSecond]
mov QWORD PTR [rsp+20h], rax ; arg5: S
movzx eax, WORD PTR [rsp+30h + ST_wMilliseconds]
mov QWORD PTR [rsp+28h], rax ; arg6: ms
mov rax, QWORD PTR [rsp+40h]
mov QWORD PTR [rsp+30h], rax ; arg7: msg* (overwrites SYSTEMTIME - done with it)
call wsprintfA ; EAX = chars written
test eax, eax
jle @@skip_file
; WriteFile(hFile, szLine, chars, &dwWritten, NULL)
mov r10d, eax ; save char count
mov rcx, QWORD PTR [Logger_hFile]
lea rdx, [rsp+60h] ; szLine buffer
mov r8d, r10d ; byte count
lea r9, [rsp+260h] ; &dwWritten
mov QWORD PTR [rsp+20h], 0 ; lpOverlapped = NULL
call WriteFile
; FlushFileBuffers - ensures data reaches disk before any crash
mov rcx, QWORD PTR [Logger_hFile]
call FlushFileBuffers
@@skip_file:
add rsp, 268h
ret
Logger__Print ENDP
; Logger_LogInfo / LogWarn / LogError / LogFatal
; Frame: 0 pushes + sub 28h = 40; RSP = 0
Logger_LogInfo PROC
sub rsp, 28h
mov rdx, rcx
lea rcx, [szFmtInfo]
call Logger__Print
add rsp, 28h
ret
Logger_LogInfo ENDP
Logger_LogWarn PROC
sub rsp, 28h
mov rdx, rcx
lea rcx, [szFmtWarn]
call Logger__Print
add rsp, 28h
ret
Logger_LogWarn ENDP
Logger_LogError PROC
sub rsp, 28h
mov rdx, rcx
lea rcx, [szFmtError]
call Logger__Print
add rsp, 28h
ret
Logger_LogError ENDP
Logger_LogFatal PROC
sub rsp, 28h
mov rdx, rcx
lea rcx, [szFmtFatal]
call Logger__Print
add rsp, 28h
ret
Logger_LogFatal ENDP
; Logger_LogInfoFmt(RCX=fmt*, RDX/R8/R9/stack=args)
; Console-only printf passthrough (variadic - can't redirect to file).
; Frame: 0 pushes + sub 28h; RSP = 0
Logger_LogInfoFmt PROC
sub rsp, 28h
call printf
add rsp, 28h
ret
Logger_LogInfoFmt ENDP
ELSE ; Release build - all logger functions are single-instruction stubs
.code
Logger_Initialize PROC
ret
Logger_Initialize ENDP
Logger_Shutdown PROC
ret
Logger_Shutdown ENDP
Logger_LogInfo PROC
ret
Logger_LogInfo ENDP
Logger_LogWarn PROC
ret
Logger_LogWarn ENDP
Logger_LogError PROC
ret
Logger_LogError ENDP
Logger_LogFatal PROC
ret
Logger_LogFatal ENDP
Logger_LogInfoFmt PROC
ret
Logger_LogInfoFmt ENDP
ENDIF
END