|
4 | 4 | [asm-interp (-> (listof instruction?) any/c)] |
5 | 5 | [asm-interp/io (-> (listof instruction?) string? any/c)]) |
6 | 6 |
|
| 7 | +(define-logger a86) |
| 8 | + |
7 | 9 | (require "printer.rkt" "ast.rkt" "callback.rkt" "check-nasm.rkt" |
8 | 10 | (rename-in ffi/unsafe [-> _->])) |
9 | 11 | (require (submod "printer.rkt" private)) |
10 | 12 |
|
11 | 13 | ;; Check NASM availability when required to fail fast. |
12 | 14 | (check-nasm-available) |
13 | 15 |
|
| 16 | +(define *debug*? |
| 17 | + (let ((r (getenv "PLTSTDERR"))) |
| 18 | + (and r |
| 19 | + (string=? r "info@a86")))) |
| 20 | + |
14 | 21 | ;; Assembly code is linked with object files in this parameter |
15 | 22 | (define current-objs |
16 | 23 | (make-parameter '())) |
|
39 | 46 | (malloc _int64 20000 'raw)) |
40 | 47 |
|
41 | 48 |
|
42 | | -;; Integer -> String |
43 | | -(define (number->binary n) |
| 49 | +;; Integer64 -> String |
| 50 | +(define (int64->binary-string n) |
44 | 51 | (format "#b~a" |
45 | 52 | (~r n #:base 2 #:min-width 64 #:pad-string "0"))) |
46 | 53 |
|
47 | | -;; Integer -> String |
48 | | -(define (number->octal n) |
| 54 | +;; Integer64 -> String |
| 55 | +(define (int64->octal-string n) |
49 | 56 | (format "#o~a" |
50 | 57 | (~r n #:base 8 #:min-width 22 #:pad-string "0"))) |
51 | 58 |
|
52 | | -(define (number->hex n) |
| 59 | +;; Integer64 |
| 60 | +(define (int64->hex-string n) |
53 | 61 | (format "#x~a" |
54 | 62 | (~r n #:base 16 #:min-width 16 #:pad-string "0"))) |
55 | 63 |
|
56 | 64 | (define (show-state . regs) |
57 | | - (for-each (lambda (v) |
58 | | - (printf "reg: ~a\n" (number->hex v))) |
59 | | - regs)) |
| 65 | + (format "\n~a" |
| 66 | + (map (lambda (r v) |
| 67 | + (format "(~a ~a)" r (int64->hex-string v))) |
| 68 | + '(rax rbx rcx rdx rbp rsp rsi rdi |
| 69 | + r8 r9 r10 r11 r12 r13 r14 r15 instr flags) |
| 70 | + regs))) |
60 | 71 |
|
61 | 72 | ;; Asm String -> (cons Value String) |
62 | 73 | ;; Like asm-interp, but uses given string for input and returns |
63 | 74 | ;; result with string output |
64 | 75 | (define (asm-interp/io a input) |
| 76 | + |
| 77 | + (log-a86-info (~v a)) |
| 78 | + |
65 | 79 | (define t.s (make-temporary-file "nasm~a.s")) |
66 | 80 | (define t.o (path-replace-extension t.s #".o")) |
67 | 81 | (define t.so (path-replace-extension t.s #".so")) |
|
72 | 86 | #:exists 'truncate |
73 | 87 | (λ () |
74 | 88 | (parameterize ((current-shared? #t)) |
75 | | - (asm-display a)))) |
| 89 | + (asm-display (if *debug*? |
| 90 | + (debug-transform a) |
| 91 | + a))))) |
76 | 92 |
|
77 | 93 | (nasm t.s t.o) |
78 | 94 | (ld t.o t.so) |
|
95 | 111 | (set-ffi-obj! "error_handler" libt.so _pointer |
96 | 112 | (function-ptr (λ () (raise 'err)) (_fun _-> _void)))) |
97 | 113 |
|
98 | | - (when (ffi-obj-ref "place" libt.so (thunk #f)) |
99 | | - (set-ffi-obj! "place" libt.so _pointer |
100 | | - (function-ptr (λ (n) |
101 | | - (apply show-state |
102 | | - (build-list 16 (lambda (i) (ptr-ref n _int64 (add1 i)))))) |
103 | | - (_fun _pointer _-> _void)))) |
| 114 | + (when *debug*? |
| 115 | + (define log (ffi-obj-ref log-label libt.so (thunk #f))) |
| 116 | + (when log |
| 117 | + (set-ffi-obj! log-label libt.so _pointer |
| 118 | + (function-ptr |
| 119 | + (λ () (log-a86-info |
| 120 | + (apply show-state |
| 121 | + (build-list 18 (lambda (i) (ptr-ref log _int64 (add1 i))))))) |
| 122 | + (_fun _-> _void))))) |
104 | 123 |
|
105 | 124 | (define has-heap? #f) |
106 | 125 |
|
|
206 | 225 | (regexp-match #rx"undefined reference to `(.*)'" err-msg)) ; linux |
207 | 226 | [(list _ symbol) (ld:undef-symbol symbol)] |
208 | 227 | [_ (ld:error (format "unknown link error.\n\n~a" err-msg))]))) |
| 228 | + |
| 229 | + |
| 230 | + |
| 231 | +;; Debugging facilities |
| 232 | + |
| 233 | +(define log-label (symbol->label (gensym 'log))) |
| 234 | + |
| 235 | +(define (Log i) |
| 236 | + (seq (save-registers) |
| 237 | + (Pushf) |
| 238 | + (Mov 'rax i) |
| 239 | + (Mov (Offset log-label (* 8 17)) 'rax) |
| 240 | + (Mov 'rax (Offset 'rsp 0)) |
| 241 | + (Mov (Offset log-label (* 8 18)) 'rax) |
| 242 | + (Call (Offset log-label 0)) |
| 243 | + (Popf) |
| 244 | + (restore-registers))) |
| 245 | + |
| 246 | +(define (instrument is) |
| 247 | + (for/fold ([ls '()] |
| 248 | + #:result (reverse ls)) |
| 249 | + ([idx (in-naturals)] |
| 250 | + [ins (in-list is)]) |
| 251 | + (if (serious-instruction? ins) |
| 252 | + (seq ins (reverse (Log idx)) ls) |
| 253 | + (seq ins ls)))) |
| 254 | + |
| 255 | +(define (serious-instruction? ins) |
| 256 | + (match ins |
| 257 | + [(Label _) #f] |
| 258 | + [(Global _) #f] |
| 259 | + [(? Comment?) #f] |
| 260 | + [_ #t])) |
| 261 | + |
| 262 | +(define (debug-transform is) |
| 263 | + (seq (instrument is) |
| 264 | + ;; End of user program |
| 265 | + (Data) |
| 266 | + (Global log-label) |
| 267 | + (Label log-label) |
| 268 | + (Dq 0) ; callback placeholder |
| 269 | + (static-alloc-registers) |
| 270 | + (Dq 0) ; index of instruction |
| 271 | + (Dq 0) ; flags |
| 272 | + )) |
| 273 | + |
| 274 | +(define registers |
| 275 | + '(rax rbx rcx rdx rbp rsp rsi rdi |
| 276 | + r8 r9 r10 r11 r12 r13 r14 r15)) |
| 277 | + |
| 278 | +(define (static-alloc-registers) |
| 279 | + (apply seq |
| 280 | + (map (λ (r) (seq (Dq 0) (% (~a r)))) |
| 281 | + registers))) |
| 282 | + |
| 283 | +(define (save-registers) |
| 284 | + (apply seq |
| 285 | + (map (λ (r i) (seq (Mov (Offset log-label (* 8 i)) r))) |
| 286 | + registers |
| 287 | + (build-list (length registers) add1)))) |
| 288 | + |
| 289 | +(define (restore-registers) |
| 290 | + (apply seq |
| 291 | + (map (λ (r i) (seq (Mov r (Offset log-label (* 8 i))))) |
| 292 | + registers |
| 293 | + (build-list (length registers) add1)))) |
0 commit comments