source: trunk/source/level-1/ppc-trap-support.lisp

Last change on this file was 16782, checked in by rme, 4 years ago

Undo r16779.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.4 KB
Line 
1;;;
2;;; Copyright 1994-2009 Clozure Associates
3;;;
4;;; Licensed under the Apache License, Version 2.0 (the "License");
5;;; you may not use this file except in compliance with the License.
6;;; You may obtain a copy of the License at
7;;;
8;;;     http://www.apache.org/licenses/LICENSE-2.0
9;;;
10;;; Unless required by applicable law or agreed to in writing, software
11;;; distributed under the License is distributed on an "AS IS" BASIS,
12;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13;;; See the License for the specific language governing permissions and
14;;; limitations under the License.
15
16;;; Support for PPC traps, this includes the event-poll trap
17;;; and all the trxxx traps for type checks & arg count checks.
18
19(in-package "CCL")
20
21(eval-when (:compile-toplevel :execute)
22  (require "NUMBER-MACROS")
23
24 
25  (defparameter *ppc-instruction-fields*
26    `((:opcode . ,(byte 6 26))
27      (:rt . ,(byte 5 21))
28      (:to . ,(byte 5 21))
29      (:ra . ,(byte 5 16))
30      (:rb . ,(byte 5 11))
31      (:d . ,(byte 16 0))
32      (:ds . ,(byte 14 2))
33      (:ds-xo . ,(byte 2 0))
34      (:sh . ,(byte 5 11))
35      (:mb . ,(byte 5 6))
36      (:me . ,(byte 5 1))
37      (:mb6 . ,(byte 6 5))
38      (:me6 . ,(byte 6 5))
39      (:sh6 . ,(byte 1 1))
40      (:x-minor . ,(byte 10 1))
41      (:fulltag32 . ,(byte ppc32::ntagbits 0))
42      (:lisptag32 . ,(byte ppc32::nlisptagbits 0))
43      (:fulltag64 . ,(byte ppc64::ntagbits 0))
44      (:lisptag64 . ,(byte ppc64::nlisptagbits 0))
45      (:lowtag64 . ,(byte ppc64::nlowtagbits 0))))
46 
47  (defun ppc-instruction-field (field-name)
48    (or (cdr (assoc field-name *ppc-instruction-fields*))
49        (error "Unknown PPC instruction field: ~s" field-name)))
50 
51  (defun ppc-instruction-field-mask (field-spec)
52    (let* ((name (if (atom field-spec) field-spec (car field-spec)))
53           (value (if (atom field-spec) -1 (cadr field-spec))))
54      (dpb value (ppc-instruction-field name) 0)))
55
56  #+darwinppc-target
57  (progn
58    (def-foreign-type nil
59        (:struct :darwin-ppc-float-state
60                 (:fpregs (:array :double 32))
61                 (:fpscr-pad (:unsigned 32))
62                 (:fpscr (:unsigned 32))))
63    (def-foreign-type nil
64        (:struct :darwin-ppc-vector-state
65                 (:save-vr (:array (:array (:unsigned 32) 4) 32))
66                 (:save-vscr (:array (:unsigned 32) 4))
67                 (:save-pad5 (:array (:unsigned 32) 4))
68                 (:save-vrvalid (:unsigned 32))
69                 (:save-pad6 (:array (:unsigned 32) 7))))
70    #+ppc64-target
71    (progn
72      (def-foreign-type nil
73          (:struct :darwin-ppc-exception-state64
74                   (:dar (:unsigned 64))
75                   (:dsisr (:unsigned 32))
76                   (:exception (:unsigned 32))
77                   (:pad1 (:array (:unsigned 32) 4))))
78      (def-foreign-type nil
79          ;; The real record type is defined with
80          ;; #pragma pack(4) in effect.
81          ;; The :struct parser should really accept
82          ;; some option to deal with that, but Apple
83          ;; should also stop mis-aligning things.
84          (:struct :darwin-ppc-thread-state64
85                   (:srr0 (:unsigned 64))
86                   (:srr1 (:unsigned 64))
87                   (:r0  (:unsigned 64))
88                   (:r1  (:unsigned 64))
89                   (:r2  (:unsigned 64))
90                   (:r3  (:unsigned 64))
91                   (:r4  (:unsigned 64))
92                   (:r5  (:unsigned 64))
93                   (:r6  (:unsigned 64))
94                   (:r7  (:unsigned 64))
95                   (:r8  (:unsigned 64))
96                   (:r9  (:unsigned 64))
97                   (:r10  (:unsigned 64))
98                   (:r11  (:unsigned 64))
99                   (:r12 (:unsigned 64))
100                   (:r13  (:unsigned 64))
101                   (:r14  (:unsigned 64))
102                   (:r15  (:unsigned 64))
103                   (:r16  (:unsigned 64))
104                   (:r17  (:unsigned 64))
105                   (:r18  (:unsigned 64))
106                   (:r19  (:unsigned 64))
107                   (:r20  (:unsigned 64))
108                   (:r21  (:unsigned 64))
109                   (:r22  (:unsigned 64))
110                   (:r23  (:unsigned 64))
111                   (:r24  (:unsigned 64))
112                   (:r25  (:unsigned 64))
113                   (:r26  (:unsigned 64))
114                   (:r27  (:unsigned 64))
115                   (:r28  (:unsigned 64))
116                   (:r29  (:unsigned 64))
117                   (:r30  (:unsigned 64))
118                   (:r31  (:unsigned 64))
119                   (:cr   (:unsigned 32))
120                   (:xer  (:unsigned 32))
121                   (:xer-low (:unsigned 32))
122                   (:lr   (:unsigned 32))
123                   (:lr-low (:unsigned 32))
124                   (:ctr  (:unsigned 32))
125                   (:ctr-low (:unsigned 32))
126                   (:vrsave (:unsigned 32))))
127      (def-foreign-type nil
128          (:struct :darwin-sigaltstack64
129                   (:ss-sp (:* :void))
130                   (:ss-size (:unsigned 64))
131                   (:ss-flags (:unsigned 32))))
132      (def-foreign-type nil
133          (:struct :darwin-mcontext64
134                   (:es (:struct :darwin-ppc-exception-state64))
135                   (:ss (:struct :darwin-ppc-thread-state64))
136                   (:fs (:struct :darwin-ppc-float-state))
137                   (:vs (:struct :darwin-ppc-vector-state))))
138      (def-foreign-type nil
139          (:struct :darwin-ucontext64
140                   (:uc-onstack (:signed 32))
141                   (:uc-sigmask (:signed 32))
142                   (:uc-stack (:struct :darwin-sigaltstack64))
143                   (:uc-link (:* (:struct :darwin-ucontext64)))
144                   (:uc-mcsize (:signed 64))
145                   (:uc-mcontext64 (:* (:struct :darwin-mcontext64)))))
146      )
147    #+ppc32-target
148    (progn
149      (def-foreign-type nil
150          (:struct :darwin-ppc-exception-state32
151                   (:dar (:unsigned 32))
152                   (:dsisr (:unsigned 32))
153                   (:exception (:unsigned 32))
154                   (:pad0 (:unsigned 32))
155                   (:pad1 (:array (:unsigned 32) 4))))
156      (def-foreign-type nil
157          (:struct :darwin-ppc-thread-state32
158                   (:srr0 (:unsigned 32))
159                   (:srr1 (:unsigned 32))
160                   (:r0  (:unsigned 32))
161                   (:r1  (:unsigned 32))
162                   (:r2  (:unsigned 32))
163                   (:r3  (:unsigned 32))
164                   (:r4  (:unsigned 32))
165                   (:r5  (:unsigned 32))
166                   (:r6  (:unsigned 32))
167                   (:r7  (:unsigned 32))
168                   (:r8  (:unsigned 32))
169                   (:r9  (:unsigned 32))
170                   (:r10  (:unsigned 32))
171                   (:r11  (:unsigned 32))
172                   (:r12 (:unsigned 32))
173                   (:r13  (:unsigned 32))
174                   (:r14  (:unsigned 32))
175                   (:r15  (:unsigned 32))
176                   (:r16  (:unsigned 32))
177                   (:r17  (:unsigned 32))
178                   (:r18  (:unsigned 32))
179                   (:r19  (:unsigned 32))
180                   (:r20  (:unsigned 32))
181                   (:r21  (:unsigned 32))
182                   (:r22  (:unsigned 32))
183                   (:r23  (:unsigned 32))
184                   (:r24  (:unsigned 32))
185                   (:r25  (:unsigned 32))
186                   (:r26  (:unsigned 32))
187                   (:r27  (:unsigned 32))
188                   (:r28  (:unsigned 32))
189                   (:r29  (:unsigned 32))
190                   (:r30  (:unsigned 32))
191                   (:r31  (:unsigned 32))
192                   (:cr   (:unsigned 32))
193                   (:xer  (:unsigned 32))
194                   (:lr   (:unsigned 32))
195                   (:ctr  (:unsigned 32))
196                   (:mq (:unsigned 32)) ; ppc 601!
197                   (:vrsave (:unsigned 32))))
198      (def-foreign-type nil
199          (:struct :darwin-sigaltstack32
200                   (:ss-sp (:* :void))
201                   (:ss-size (:unsigned 32))
202                   (:ss-flags (:unsigned 32))))
203      (def-foreign-type nil
204          (:struct :darwin-mcontext32
205                   (:es (:struct :darwin-ppc-exception-state32))
206                   (:ss (:struct :darwin-ppc-thread-state32))
207                   (:fs (:struct :darwin-ppc-float-state))
208                   (:vs (:struct :darwin-ppc-vector-state))))
209      (def-foreign-type nil
210          (:struct :darwin-ucontext32
211                   (:uc-onstack (:signed 32))
212                   (:uc-sigmask (:signed 32))
213                   (:uc-stack (:struct :darwin-sigaltstack32))
214                   (:uc-link (:* (:struct :darwin-ucontext32)))
215                   (:uc-mcsize (:signed 32))
216                   (:uc-mcontext32 (:* (:struct :darwin-mcontext32)))))
217      )
218    )
219     
220                   
221           
222
223  (defmacro with-xp-registers-and-gpr-offset ((xp register-number) (registers offset) &body body)
224    (let* ((regform  #+linuxppc-target
225                     `(pref ,xp :ucontext.uc_mcontext.regs)
226                     #+darwinppc-target
227                     (target-arch-case
228                      ;; Gak.  Apple gratuitously renamed things
229                      ;; for Leopard.  Hey, it's not as if anyone
230                      ;; has better things to do than to deal with
231                      ;; this crap ...
232                      (:ppc32 `(pref ,xp :darwin-ucontext32.uc-mcontext32.ss))
233                      (:ppc64 `(pref ,xp :darwin-ucontext64.uc-mcontext64.ss)))))
234    `(with-macptrs ((,registers ,regform))
235      (let ((,offset (xp-gpr-offset ,register-number)))
236        ,@body))))
237
238  (defmacro RA-field (instr)
239    `(ldb (byte 5 16) ,instr))
240
241  (defmacro RB-field (instr)
242    `(ldb (byte 5 11) ,instr))
243
244  (defmacro D-field (instr)
245    `(ldb (byte 16 0) ,instr))
246
247  (defmacro RS-field (instr)
248    `(ldb (byte 5 21) ,instr))
249 
250  (defmacro lisp-reg-p (reg)
251    `(>= ,reg ppc::fn))
252 
253  (defmacro ppc-lap-word (instruction-form)
254    (uvref (uvref (compile nil
255                           `(lambda (&lap 0)
256                             (ppc-lap-function () ((?? 0))
257                              ,instruction-form)))
258                 
259                  0) #+ppc32-host 0 #+ppc64-host 1))
260 
261  (defmacro ppc-instruction-mask (&rest fields)
262    `(logior ,@(mapcar #'ppc-instruction-field-mask (cons :opcode fields))))
263 
264  ) 
265
266
267
268(defun xp-gpr-offset (register-number)
269  (unless (and (fixnump register-number)
270               (<= -2 (the fixnum register-number))
271               (< (the fixnum register-number) 48))
272    (setq register-number (require-type register-number '(integer -2 48))))
273  (the fixnum 
274    (* (the fixnum #+linuxppc-target register-number
275                   #+darwinppc-target (+ register-number 2))
276       target::node-size)))
277
278
279
280(defun xp-gpr-lisp (xp register-number)
281  (with-xp-registers-and-gpr-offset (xp register-number) (registers offset)
282    (values (%get-object registers offset))))
283
284(defun (setf xp-gpr-lisp) (value xp register-number)
285  (with-xp-registers-and-gpr-offset (xp register-number) (registers offset)
286    (%set-object registers offset value)))
287
288(defun xp-gpr-signed-long (xp register-number)
289  (with-xp-registers-and-gpr-offset (xp register-number) (registers offset)
290    (values (%get-signed-long registers offset))))
291
292(defun xp-gpr-signed-doubleword (xp register-number)
293  (with-xp-registers-and-gpr-offset (xp register-number) (registers offset)
294    (values (%%get-signed-longlong registers offset))))
295 
296
297(defun xp-gpr-macptr (xp register-number)
298  (with-xp-registers-and-gpr-offset (xp register-number) (registers offset)
299    (values (%get-ptr registers offset))))
300
301(defun xp-argument-list (xp)
302  (let ((nargs (xp-gpr-lisp xp ppc::nargs))     ; tagged as a fixnum (how convenient)
303        (arg-x (xp-gpr-lisp xp ppc::arg_x))
304        (arg-y (xp-gpr-lisp xp ppc::arg_y))
305        (arg-z (xp-gpr-lisp xp ppc::arg_z)))
306    (cond ((eql nargs 0) nil)
307          ((eql nargs 1) (list arg-z))
308          ((eql nargs 2) (list arg-y arg-z))
309          (t (let ((args (list arg-x arg-y arg-z)))
310               (if (eql nargs 3)
311                 args
312                 (let ((vsp (xp-gpr-macptr xp ppc::vsp)))
313                   (dotimes (i (- nargs 3))
314                     (push (%get-object vsp (* i target::node-size)) args))
315                   args)))))))
316   
317(defun xp-fpscr-info (xp)
318  (let* ((fpscr #+(and linuxppc-target 32-bit-target) (%get-unsigned-long (pref xp :ucontext.uc_mcontext.regs) (ash #$PT_FPSCR 2))
319                #+(and linuxppc-target 64-bit-target)
320                (%get-unsigned-long (pref xp :ucontext.uc_mcontext.fp_regs) (ash 65 2))
321                #+(and darwinppc-target ppc32-target)
322                (pref xp :darwin-ucontext32.uc-mcontext32.fs.fpscr)
323                #+(and darwinppc-target ppc64-target)
324                (pref xp :darwin-ucontext64.uc-mcontext64.fs.fpscr)))
325    (values (ldb (byte 24 8) fpscr) (ldb (byte 8 0) fpscr))))
326
327#+linuxppc-target
328(defun xp-double-float (xp fpr)
329  #+32-bit-target
330  (%get-double-float (pref xp :ucontext.uc_mcontext.regs) (+ (ash #$PT_FPR0 2)  (ash fpr 3)))
331  #+64-bit-target
332  (%get-double-float (pref xp :ucontext.uc_mcontext.fp_regs) (ash fpr 3))
333  )
334
335#+darwinppc-target
336(defun xp-double-float (xp fpr)
337  (%get-double-float
338     #+ppc32-target (pref xp :darwin-ucontext32.uc-mcontext32.fs)
339     #+ppc64-target (pref xp :darwin-ucontext64.uc-mcontext64.fs)
340     (ash fpr 3)))
341
342
343(defparameter *trap-lookup-tries* 5)
344
345
346
347(defun %scan-for-instr (mask opcode fn pc-index tries)
348  (let ((code-vector (and fn (uvref fn 0)))
349        (offset 0))
350    (declare (fixnum offset))
351    (flet ((get-instr ()
352             (if code-vector
353               (let ((index (+ pc-index offset)))
354                 (when (< index 0) (return-from %scan-for-instr nil))
355                 (uvref code-vector index))
356               (%get-long pc-index (the fixnum (* 4 offset))))))
357      (declare (dynamic-extent #'get-instr))
358      (dotimes (i tries)
359        (decf offset)
360        (let ((instr (get-instr)))
361          (when (match-instr instr mask opcode)
362            (return instr))
363          (when (codevec-header-p instr)
364            (return nil)))))))
365
366
367
368
369
370
371(defun return-address-offset (xp fn machine-state-offset)
372  (with-macptrs ((regs (pref xp #+linuxppc-target :ucontext.uc_mcontext.regs
373                                #+(and darwinppc-target ppc32-target)
374                                :darwin-ucontext32.uc-mcontext32
375                                #+(and darwinppc-target ppc64-target)
376                                :darwin-ucontext64.uc-mcontext64)))
377    (if (functionp fn)
378      (or (%code-vector-pc (uvref fn 0) (%inc-ptr regs machine-state-offset))
379           (%get-ptr regs machine-state-offset))
380      (%get-ptr regs machine-state-offset))))
381
382(defconstant lr-offset-in-register-context
383  #+linuxppc-target (ash #$PT_LNK target::word-shift)
384  #+(and darwinppc-target ppc32-target)
385  (+ (get-field-offset :darwin-mcontext32.ss)
386     (get-field-offset :darwin-ppc-thread-state32.lr))
387  #+(and darwinppc-target ppc64-target)
388  (+ (get-field-offset :darwin-mcontext64.ss)
389     (get-field-offset :darwin-ppc-thread-state64.lr)))
390
391(defconstant pc-offset-in-register-context
392  #+linuxppc-target (ash #$PT_NIP target::word-shift)
393  #+(and darwinppc-target ppc32-target)
394  (+ (get-field-offset :darwin-mcontext32.ss)
395     (get-field-offset :darwin-ppc-thread-state32.srr0))
396  #+(and darwinppc-target ppc64-target)
397  (+ (get-field-offset :darwin-mcontext64.ss)
398     (get-field-offset :darwin-ppc-thread-state64.srr0)))
399
400;;; When a trap happens, we may have not yet created control
401;;; stack frames for the functions containing PC & LR.
402;;; If that is the case, we add fake-stack-frame's to *fake-stack-frames*
403;;; There are 4 cases:
404;;;
405;;; PC in FN
406;;;   Push 1 stack frame: PC/FN
407;;;   This might miss one recursive call, but it won't miss any variables
408;;; PC in NFN
409;;;   Push 2 stack frames:
410;;;   1) PC/NFN/VSP
411;;;   2) LR/FN/VSP
412;;;   This might think some of NFN's variables are part of FN's stack frame,
413;;;   but that's the best we can do.
414;;; LR in FN
415;;;   Push 1 stack frame: LR/FN
416;;; None of the above
417;;;   Push no new stack frames
418;;;
419;;; The backtrace support functions in "ccl:l1;l1-lisp-threads.lisp" know how
420;;; to find the fake stack frames and handle them as arguments.
421(defun funcall-with-xp-stack-frames (xp trap-function thunk)
422  (cond ((null trap-function)
423         ; Maybe inside a subprim from a lisp function
424         (let* ((fn (xp-gpr-lisp xp ppc::fn))
425                (lr (return-address-offset
426                     xp fn lr-offset-in-register-context)))
427           (if (fixnump lr)
428             (let* ((sp (xp-gpr-lisp xp ppc::sp))
429                    (vsp (xp-gpr-lisp xp ppc::vsp))
430                    (frame (%cons-fake-stack-frame sp sp fn lr vsp xp *fake-stack-frames*))
431                    (*fake-stack-frames* frame))
432               (declare (dynamic-extent frame))
433               (funcall thunk frame))
434             (funcall thunk (xp-gpr-lisp xp ppc::sp)))))
435        ((eq trap-function (xp-gpr-lisp xp ppc::fn))
436         (let* ((sp (xp-gpr-lisp xp ppc::sp))
437                (fn trap-function)
438                (lr (return-address-offset
439                     xp fn pc-offset-in-register-context))
440                (vsp (xp-gpr-lisp xp ppc::vsp))
441                (frame (%cons-fake-stack-frame sp sp fn lr vsp xp *fake-stack-frames*))
442                (*fake-stack-frames* frame))
443           (declare (dynamic-extent frame))
444           (funcall thunk frame)))
445        ((eq trap-function (xp-gpr-lisp xp ppc::nfn))
446         (let* ((sp (xp-gpr-lisp xp ppc::sp))
447                (fn (xp-gpr-lisp xp ppc::fn))
448                (lr (return-address-offset
449                     xp fn lr-offset-in-register-context))
450                (vsp (xp-gpr-lisp xp ppc::vsp))
451                (lr-frame (%cons-fake-stack-frame sp sp fn lr vsp xp))
452                (pc-fn trap-function)
453                (pc-lr (return-address-offset
454                        xp pc-fn pc-offset-in-register-context))
455                (pc-frame (%cons-fake-stack-frame sp lr-frame pc-fn pc-lr vsp xp *fake-stack-frames*))
456                (*fake-stack-frames* pc-frame))
457           (declare (dynamic-extent lr-frame pc-frame))
458           (funcall thunk pc-frame)))
459        (t (funcall thunk (xp-gpr-lisp xp ppc::sp)))))
460
461
462
463;;; Enter here from handle-trap in "lisp-exceptions.c".
464;;; xp is a pointer to an ExceptionInformationPowerPC record.
465;;; the-trap is the trap instruction that got us here.
466;;; fn-reg is either fn, nfn or 0. If it is fn or nfn, then
467;;; the trap occcurred in that register's code vector.
468;;; If it is 0, then the trap occurred somewhere else.
469;;; pc-index is either the index in fn-reg's code vector
470;;; or, if fn-reg is 0, the address of the PC at the trap instruction.
471;;; This code parallels the trap decoding code in
472;;; "lisp-exceptions.c" that runs if (symbol-value 'cmain)
473;;; is not a macptr.
474;;; Some of these could probably call %err-disp instead of error,
475;;; but I was too lazy to look them up.
476
477#+ppc32-target
478(defcallback xcmain (:without-interrupts t
479                                        :address xp 
480                                        :unsigned-fullword fn-reg 
481                                        :address pc-or-index 
482                                        :unsigned-fullword the-trap
483                                        :signed-fullword  arg-0
484                                        :signed-fullword arg-1)
485  ;; twgti nargs,0
486  ;; time for event polling.
487  ;; This used to happen a lot so we test for it first.
488  (let ((fn (unless (eql fn-reg 0) (xp-gpr-lisp xp fn-reg))))
489    (with-xp-stack-frames (xp fn frame-ptr)
490      (if (eql the-trap (ppc-lap-word (twgti nargs 0)))
491        (cmain)
492        (with-error-reentry-detection
493          (let ((pc-index (if (eql fn-reg 0) pc-or-index (%ptr-to-int pc-or-index)))
494                instr ra temp rs condition)
495            (cond
496              ((= the-trap #$SIGBUS)
497               (%error (make-condition 'invalid-memory-access
498                                       :address arg-0
499                                       :write-p (not (zerop arg-1)))
500                       ()
501                       frame-ptr))             
502             ;; tweqi RA nil-value - resolve-eep, or resolve-foreign-variable
503              ((and (match-instr the-trap
504                                 (ppc-instruction-mask  :opcode :to :d)
505                                 (ppc-lap-word (tweqi ?? (target-nil-value))))
506                    (setq instr (scan-for-instr
507                                 (ppc-instruction-mask :opcode :d)
508                                 (ppc-lap-word (lwz ??
509                                                    (+ 4 ppc32::misc-data-offset)
510                                                    ??))
511                                               fn pc-index)))
512               (let* ((eep-or-fv (xp-gpr-lisp xp (RA-field instr))))
513                 (etypecase eep-or-fv
514                   (external-entry-point
515                    (resolve-eep eep-or-fv)
516                    (setf (xp-gpr-lisp xp (RA-field the-trap))
517                          (eep.address eep-or-fv)))
518                   (foreign-variable
519                    (resolve-foreign-variable eep-or-fv)
520                    (setf (xp-gpr-lisp xp (RA-field the-trap))
521                          (fv.addr eep-or-fv))))))
522             ;; twnei RA,N; RA = nargs
523             ;; nargs check, no optional or rest involved
524              ((match-instr the-trap
525                           (ppc-instruction-mask :opcode :to :ra)
526                           (ppc-lap-word (twnei nargs ??)))
527              (%error (if (< (xp-GPR-signed-long xp ppc::nargs) (D-field the-trap))
528                        'too-few-arguments
529                        'too-many-arguments )
530                      (list :nargs (ash (xp-GPR-signed-long xp ppc::nargs)
531                                        (- ppc32::fixnumshift))
532                            :fn  fn)
533                      frame-ptr))
534             
535             ;; twnei RA,N; RA != nargs, N = fulltag_node/immheader
536             ;; type check; look for "lbz rt-imm,-3(ra-node)"
537             ((and (or (match-instr the-trap
538                                    (ppc-instruction-mask :opcode :to :fulltag32)
539                                    (ppc-lap-word (twnei ?? ppc32::fulltag-nodeheader)))
540                       (match-instr the-trap
541                                    (ppc-instruction-mask :opcode :to :fulltag32)
542                                    (ppc-lap-word (twnei ?? ppc32::fulltag-immheader))))
543                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :d)
544                                               (ppc-lap-word (lbz ?? ppc32::misc-subtag-offset ??))
545                                               fn pc-index))
546                   (lisp-reg-p (setq ra (RA-field instr))))
547              (let* ((typecode (D-field the-trap))
548                     (type-tag (logand typecode ppc32::fulltagmask))
549                     (type-name (svref (if (eql type-tag ppc32::fulltag-nodeheader)
550                                         *nodeheader-types*
551                                         *immheader-types*)
552                                       (ldb (byte (- ppc32::num-subtag-bits ppc32::ntagbits) ppc32::ntagbits) typecode))))
553                (%error (make-condition 'type-error
554                                        :format-control (%rsc-string $XWRONGTYPE)
555                                        :datum (xp-GPR-lisp xp ra)
556                                        :expected-type type-name)
557                        nil
558                        frame-ptr)))
559
560             ;; twnei RA,N; RA != nargs, N = subtag_character
561             ;; type check; look for "clrlwi rs-node,ra-imm,24" = "rlwinm rs,ra,0,24,31"
562             ((and (match-instr the-trap
563                                (ppc-instruction-mask :opcode :to :d)
564                                (ppc-lap-word (twnei ?? ppc32::subtag-character)))
565                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :rb :mb :me)
566                                               (ppc-lap-word (rlwinm ?? ?? 0 24 31))
567                                               fn pc-index))
568                   (lisp-reg-p (setq rs (RS-field instr))))
569              (%error (make-condition 'type-error
570                                        :datum (xp-GPR-lisp xp rs)
571                                        :expected-type 'character)
572                        nil
573                        frame-ptr))
574
575             ;; twnei RA,N; RA != nargs, N != fulltag_node/immheader
576             ;; (since that case was handled above.)
577             ;; type check; look for "clrlwi rs-node,ra-imm,29/30" = "rlwinm rs,ra,0,29/30,31"
578             ((and (match-instr the-trap
579                                (ppc-instruction-mask :opcode :to) 
580                                (ppc-lap-word (twnei ?? ??)))
581                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :rb (:mb 28) :me)
582                                               (ppc-lap-word (rlwinm ?? ?? 0 28 31))                                               
583                                               fn pc-index))
584                   (or (eql (- 32 ppc32::ntagbits) (setq temp (ldb #.(ppc-instruction-field :mb) instr)))
585                       (eql (- 32 ppc32::nlisptagbits) temp))
586                   (lisp-reg-p (setq rs (RS-field instr))))
587              (let* ((tag (logand the-trap ppc32::tagmask))
588                     (type-name 
589                      (case tag
590                        (#.ppc32::tag-fixnum 'fixnum)
591                        (#.ppc32::tag-list (if (eql temp (- 32 ppc32::ntagbits)) 'cons 'list))
592                        (#.ppc32::tag-misc 'uvector)
593                        (#.ppc32::tag-imm 'immediate))))                                     
594                (%error (make-condition 'type-error
595                                        :datum (xp-GPR-lisp xp rs)
596                                        :expected-type type-name)
597                        nil
598                        frame-ptr)))
599             
600             ;; twlgti RA,N; RA = nargs (xy = 01)
601             ;; twllti RA,N; RA = nargs (xy = 10)
602             ;; nargs check, optional or rest involved
603             ((and (match-instr the-trap
604                                (ppc-instruction-mask :opcode (:to #x1c) :ra)
605                                (ppc-lap-word (twi ?? ppc::nargs ??)))
606                   (or (eql #b01 (setq temp (ldb #.(ppc-instruction-field :to) the-trap)))
607                       (eql #b10 temp)))
608              (%error (if (eql temp #b10)
609                        'too-few-arguments
610                        'too-many-arguments)
611                      (list :nargs (ash (xp-GPR-signed-long xp ppc::nargs)
612                                        (- ppc32::fixnumshift))
613                            :fn  fn)
614                      frame-ptr))
615             
616             ;; tweqi RA,N; N = unbound
617             ;; symeval boundp check; look for "lwz RA,symbol.vcell(nodereg)"
618             ((and (match-instr the-trap
619                                (ppc-instruction-mask :opcode :to :d)                               
620                                (ppc-lap-word (tweqi ?? ppc32::unbound-marker)))
621                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :d)
622                                               (ppc-lap-word (lwz ?? ppc32::symbol.vcell ??))                                               
623                                               fn pc-index))
624                   (lisp-reg-p (setq ra (RA-field instr))))
625              (setf (xp-GPR-lisp xp (RA-field the-trap))
626                    (%kernel-restart-internal $xvunbnd (list (xp-GPR-lisp xp ra)) frame-ptr)))
627             ;; tweqi RA,N: n = (%slot-unbound-marker)
628             ;; slot-unbound trap.  Look for preceding "lwzx RA,rx,ry".
629             ;; rx = slots-vector, ry = scaled index in slots vector.
630             ((and (match-instr the-trap
631                                (ppc-instruction-mask :opcode :to :d)
632                                (ppc-lap-word (tweqi ?? ppc32::slot-unbound-marker)))
633                   (setq instr (scan-for-instr (ppc-instruction-mask
634                                                :opcode :rt  :x-minor)
635                                               (dpb
636                                                (RA-field the-trap)
637                                                (byte 5 21)
638                                                (ppc-lap-word
639                                                 (lwzx ?? ?? ??)))
640                                               fn pc-index)))
641              (setq *error-reentry-count* 0)  ; succesfully reported error
642
643              ;; %SLOT-UNBOUND-TRAP will decode the arguments further,
644              ;; then call the generic function SLOT-UNBOUND.  That
645              ;; might return a value; if so, set the value of the
646              ;; register that caused the trap to that value.
647              (setf (xp-gpr-lisp xp (ra-field the-trap))
648                    (%slot-unbound-trap (xp-gpr-lisp xp (RA-field instr))
649                                        (ash (- (xp-gpr-signed-long xp (RB-field instr))
650                                                ppc32::misc-data-offset)
651                                             (- ppc32::word-shift))
652                                        frame-ptr)))
653             ;; twlge RA,RB
654             ;; vector bounds check; look for "lwz immreg, misc_header_offset(nodereg)"
655             ((and (match-instr the-trap
656                                (ppc-instruction-mask :opcode :to :x-minor)                               
657                                (ppc-lap-word (twlge 0 0)))
658                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode #|:d|#)
659                                               (ppc-lap-word (lwz ?? ?? #|ppc32::misc-header-offset|# ??))
660                                               fn pc-index))
661                   (lisp-reg-p (setq ra (RA-field instr))))
662              (%error (%rsc-string $xarroob)
663                      (list (xp-GPR-lisp xp (RA-field the-trap))
664                            (xp-GPR-lisp xp ra))
665                      frame-ptr))
666             ;; twi 27 ra d - array header rank check
667             ((and (match-instr the-trap
668                                (ppc-instruction-mask :opcode :to)
669                                (ppc-lap-word (twi 27 ?? ??)))
670                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :d)
671                                               (ppc-lap-word (lwz ?? ppc32::arrayH.rank ??))
672                                               fn pc-index))
673                   (lisp-reg-p (setq ra (RA-field instr))))
674              (%error (%rsc-string $xndims)
675                      (list (xp-gpr-lisp xp ra)
676                            (ash (ldb (byte 16 0) the-trap) (- ppc32::fixnumshift)))
677                      frame-ptr))
678             ;; tw 27 ra rb - array flags check
679             ((and (match-instr the-trap
680                                (ppc-instruction-mask :opcode :to :x-minor)
681                                (ppc-lap-word (tw 27 ?? ??)))
682                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :d)
683                                               (ppc-lap-word (lwz ?? ppc32::arrayH.flags ??))
684                                               fn pc-index))
685                   (lisp-reg-p (setq ra (RA-field instr)))
686                   (let* ((expected (xp-gpr-lisp xp (RB-field the-trap)))
687                          (expected-subtype (ldb
688                                             ppc32::arrayH.flags-cell-subtag-byte
689                                             expected))
690                          (expect-simple (=
691                                          (ldb ppc32::arrayH.flags-cell-bits-byte
692                                               expected)
693                                          (ash 1 $arh_simple_bit)))
694                          (type-name
695                           (case expected-subtype
696                             (#.ppc32::subtag-double-float-vector 'double-float))))
697
698                     (and type-name expect-simple
699                          (setq condition
700                                (make-condition 'type-error
701                                                :datum (xp-gpr-lisp xp ra)
702                                                :expected-type
703                                                `(simple-array ,type-name))))))
704              (%error condition nil frame-ptr))
705                               
706             ;; Unknown trap
707             (t (%error "Unknown trap: #x~x~%xp: ~s, fn: ~s, pc: #x~x"
708                        (list the-trap xp fn (ash pc-index ppc32::fixnumshift))
709                        frame-ptr)))))))))
710
711#+ppc64-target
712(defcallback xcmain (:without-interrupts t
713                                        :address xp 
714                                        :unsigned-fullword fn-reg 
715                                        :address pc-or-index 
716                                        :unsigned-fullword the-trap
717                                        :signed-doubleword  arg0
718                                        :signed-doubleword arg1)
719  ;; tdgti nargs,0
720  ;; time for event polling.
721  ;; This used to happen a lot so we test for it first.
722  (let ((fn (unless (eql fn-reg 0) (xp-gpr-lisp xp fn-reg))))
723    (with-xp-stack-frames (xp fn frame-ptr)
724      (if (eql the-trap (ppc-lap-word (tdgti nargs 0)))
725        (cmain)
726        (with-error-reentry-detection
727          (let ((pc-index (if (eql fn-reg 0) pc-or-index (%ptr-to-int pc-or-index)))
728                instr ra temp rs condition)
729            (cond
730              ;; tdeqi RA nil-value - resolve-eep, or resolve-foreign-variable
731              ((and (match-instr the-trap
732                                 (ppc-instruction-mask  :opcode :to :d)
733                                 (ppc-lap-word (tdeqi ?? (target-nil-value))))
734                    (setq instr (scan-for-instr
735                                 (ppc-instruction-mask :opcode :ds :ds-xo)
736                                 (ppc-lap-word (ld ??
737                                                    (+ 8 ppc64::misc-data-offset)
738                                                    ??))
739                                               fn pc-index)))
740               (let* ((eep-or-fv (xp-gpr-lisp xp (RA-field instr))))
741                 (etypecase eep-or-fv
742                   (external-entry-point
743                    (resolve-eep eep-or-fv)
744                    (setf (xp-gpr-lisp xp (RA-field the-trap))
745                          (eep.address eep-or-fv)))
746                   (foreign-variable
747                    (resolve-foreign-variable eep-or-fv)
748                    (setf (xp-gpr-lisp xp (RA-field the-trap))
749                          (fv.addr eep-or-fv))))))
750              ((= the-trap #$SIGBUS)
751               (%error (make-condition 'invalid-memory-access
752                                       :address arg0
753                                       :write-p (not (zerop arg1)))
754                       ()
755                       frame-ptr))
756              ;; tdnei RA,N; RA = nargs
757              ;; nargs check, no optional or rest involved
758              ((match-instr the-trap
759                           (ppc-instruction-mask :opcode :to :ra)
760                           (ppc-lap-word (tdnei nargs ??)))
761              (%error (if (< (xp-GPR-signed-doubleword xp ppc::nargs) (D-field the-trap))
762                        'too-few-arguments
763                        'too-many-arguments )
764                      (list :nargs (ash (xp-GPR-signed-doubleword xp ppc::nargs)
765                                        (- ppc64::fixnumshift))
766                            :fn  fn)
767                      frame-ptr))
768             
769             ;; tdnei RA,N; RA != nargs, N = lowtag_node/immheader
770             ;; type check; look for "lbz rt-imm,-5(ra-node)"
771             ((and (or (match-instr the-trap
772                                    (ppc-instruction-mask :opcode :to :lowtag64)
773                                    (ppc-lap-word (tdnei ?? ppc64::lowtag-nodeheader)))
774                       (match-instr the-trap
775                                    (ppc-instruction-mask :opcode :rt :lowtag64)
776                                    (ppc-lap-word (tdnei ?? ppc64::lowtag-immheader))))
777                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :d)
778                                               (ppc-lap-word (lbz ?? ppc64::misc-subtag-offset ??))
779                                               fn pc-index))
780                   (lisp-reg-p (setq ra (RA-field instr))))
781              (let* ((typecode (D-field the-trap))
782                     (type-tag (logand typecode ppc64::lowtagmask))
783                     (type-name (svref (if (eql type-tag ppc64::lowtag-nodeheader)
784                                         *nodeheader-types*
785                                         *immheader-types*)
786                                       (ash typecode (- ppc64::nlowtagbits)))))
787                (%error (make-condition 'type-error
788                                        :format-control (%rsc-string $XWRONGTYPE)
789                                        :datum (xp-GPR-lisp xp ra)
790                                        :expected-type type-name)
791                        nil
792                        frame-ptr)))
793             ;; tdnei RA,N; RA != nargs, N = subtag_character type
794             ;; check; look for "clrldi rs-node,ra-imm,56" = "rldicl
795             ;; rs,ra,0,55"
796             ((and (match-instr the-trap
797                                (ppc-instruction-mask :opcode :rt :d)
798                                (ppc-lap-word (tdnei ?? ppc64::subtag-character)))
799                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :sh :mb6 :sh6)
800                                               (ppc-lap-word (rldicl ?? ?? 0 56))
801                                               fn pc-index))
802                   (lisp-reg-p (setq rs (RS-field instr))))
803              (%error (make-condition 'type-error
804                                        :datum (xp-GPR-lisp xp rs)
805                                        :expected-type 'character)
806                        nil
807                        frame-ptr))
808
809             ;; tdnei RA,N; RA != nargs, N = ppc64::tag-fixnum.  type
810             ;; check; look for "clrldi rs-node,ra-imm,61" = "rldicl
811             ;; rs,ra,61"
812             ((and (match-instr the-trap
813                                (ppc-instruction-mask :opcode :rt)
814                                (ppc-lap-word (tdnei ?? ppc64::tag-fixnum)))
815                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :sh :mb6 :sh6)
816                                               (ppc-lap-word (rldicl ?? ?? 0 61))                                               
817                                               fn pc-index))
818
819                   (lisp-reg-p (setq rs (RS-field instr))))
820                (%error (make-condition 'type-error
821                                        :datum (xp-GPR-lisp xp rs)
822                                        :expected-type 'fixnum)
823                        nil
824                        frame-ptr))
825             ;; tdi 3,RA,ppc64::fulltag-cons; RA != nargs type check;
826             ;; look for "clrldi rs-node,ra-imm,60" = "rldicl
827             ;; rs,ra,60"
828             ((and (match-instr the-trap
829                                (ppc-instruction-mask :opcode :to :d)
830                                (ppc-lap-word (tdi 3 ?? ppc64::fulltag-cons)))
831                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :sh :mb6 :sh6)
832                                               (ppc-lap-word (rldicl ?? ?? 0 60))                                               
833                                               fn pc-index))
834
835                   (lisp-reg-p (setq rs (RS-field instr))))
836                (%error (make-condition 'type-error
837                                        :datum (xp-GPR-lisp xp rs)
838                                        :expected-type 'list)
839                        nil
840                        frame-ptr))             
841             ;; tdnei RA,ppc64::fulltag-cons; RA != nargs type check;
842             ;; look for "clrldi rs-node,ra-imm,60" = "rldicl
843             ;; rs,ra,60"
844             ((and (match-instr the-trap
845                                (ppc-instruction-mask :opcode :to :d)
846                                (ppc-lap-word (tdnei ?? ppc64::fulltag-cons)))
847                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :sh :mb6 :sh6)
848                                               (ppc-lap-word (rldicl ?? ?? 0 60))                                               
849                                               fn pc-index))
850
851                   (lisp-reg-p (setq rs (RS-field instr))))
852                (%error (make-condition 'type-error
853                                        :datum (xp-GPR-lisp xp rs)
854                                        :expected-type 'cons)
855                        nil
856                        frame-ptr))
857             ;; tdnei RA,ppc64::subtag-single-float; RA != nargs type check;
858             ;; look for "clrldi rs-node,ra-imm,60" = "rldicl
859             ;; rs,ra,60"
860             ((and (match-instr the-trap
861                                (ppc-instruction-mask :opcode :to :d)
862                                (ppc-lap-word (tdnei ?? ppc64::subtag-single-float)))
863                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :sh :mb6 :sh6)
864                                               (ppc-lap-word (rldicl ?? ?? 0 60))                                               
865                                               fn pc-index))
866
867                   (lisp-reg-p (setq rs (RS-field instr))))
868                (%error (make-condition 'type-error
869                                        :datum (xp-GPR-lisp xp rs)
870                                        :expected-type 'short-float)
871                        nil
872                        frame-ptr))
873             ;; tdnei RA,ppc64::fulltag-misc; RA != nargs type check;
874             ;; look for "clrldi rs-node,ra-imm,60" = "rldicl
875             ;; rs,ra,60"
876             ((and (match-instr the-trap
877                                (ppc-instruction-mask :opcode :to :d)
878                                (ppc-lap-word (tdnei ?? ppc64::fulltag-misc)))
879                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :sh :mb6 :sh6)
880                                               (ppc-lap-word (rldicl ?? ?? 0 60))                                               
881                                               fn pc-index))
882
883                   (lisp-reg-p (setq rs (RS-field instr))))
884                (%error (make-condition 'type-error
885                                        :datum (xp-GPR-lisp xp rs)
886                                        :expected-type 'uvector)
887                        nil
888                        frame-ptr))
889             ;; tdlgti RA,N; RA = nargs (xy = 01)
890             ;; tdllti RA,N; RA = nargs (xy = 10)
891             ;; nargs check, optional or rest involved
892             ((and (match-instr the-trap
893                                (ppc-instruction-mask :opcode (:to #x1c) :ra)
894                                (ppc-lap-word (tdi ?? ppc::nargs ??)))
895                   (or (eql #b01 (setq temp (ldb #.(ppc-instruction-field :to) the-trap)))
896                       (eql #b10 temp)))
897              (%error (if (eql temp #b10)
898                        'too-few-arguments
899                        'too-many-arguments)
900                      (list :nargs (ash (xp-GPR-signed-doubleword xp ppc::nargs)
901                                        (- ppc64::fixnumshift))
902                            :fn  fn)
903                      frame-ptr))
904             
905             ;; tdeqi RA,N; N = unbound
906             ;; symeval boundp check; look for "ld RA,symbol.vcell(nodereg)"
907             ((and (match-instr the-trap
908                                (ppc-instruction-mask :opcode :to :d) 
909                                (ppc-lap-word (tdeqi ?? ppc64::unbound-marker)))
910                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :ds :ds-xo)
911                                               (ppc-lap-word (ld ?? ppc64::symbol.vcell ??))                                               
912                                               fn pc-index))
913                   (lisp-reg-p (setq ra (RA-field instr))))
914              (setf (xp-GPR-lisp xp (RA-field the-trap))
915                    (%kernel-restart-internal $xvunbnd (list (xp-GPR-lisp xp ra)) frame-ptr)))
916             ;; tdeqi RA,N: n = (%slot-unbound-marker)
917             ;; slot-unbound trap.  Look for preceding "ldx RA,rx,ry".
918             ;; rx = slots-vector, ry = scaled index in slots vector.
919             ((and (match-instr the-trap
920                                (ppc-instruction-mask :opcode :to :d)
921                                (ppc-lap-word (tdeqi ?? ppc64::slot-unbound-marker)))
922                   (setq instr (scan-for-instr (ppc-instruction-mask
923                                                :opcode :rt  :x-minor)
924                                               (dpb
925                                                (RA-field the-trap)
926                                                (byte 5 21)
927                                                (ppc-lap-word
928                                                 (ldx ?? ?? ??)))
929                                               fn pc-index)))
930              (setq *error-reentry-count* 0)  ; succesfully reported error
931              ;; %SLOT-UNBOUND-TRAP will decode the arguments further,
932              ;; then call the generic function SLOT-UNBOUND.  That
933              ;; might return a value; if so, set the value of the
934              ;; register that caused the trap to that value.
935              (setf (xp-gpr-lisp xp (ra-field the-trap))
936                    (%slot-unbound-trap (xp-gpr-lisp xp (RA-field instr))
937                                        (ash (- (xp-gpr-signed-doubleword xp (RB-field instr))
938                                                ppc64::misc-data-offset)
939                                             (- ppc64::word-shift))
940                                        frame-ptr)))
941             ;; tdlge RA,RB
942             ;; vector bounds check; look for "ld immreg, misc_header_offset(nodereg)"
943             ((and (match-instr the-trap
944                                (ppc-instruction-mask :opcode :to :x-minor)
945                                (ppc-lap-word (tdlge ?? ??)))
946                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode #|:d|# :ds-xo)
947                                               (ppc-lap-word (ld ?? ?? #|ppc32::misc-header-offset|# ??))
948                                               fn pc-index))
949                   (lisp-reg-p (setq ra (RA-field instr))))
950              (%error (%rsc-string $xarroob)
951                      (list (xp-GPR-lisp xp (RA-field the-trap))
952                            (xp-GPR-lisp xp ra))
953                      frame-ptr))
954             ;; tdi 27 ra d - array header rank check
955             ((and (match-instr the-trap
956                                (ppc-instruction-mask :opcode :to)
957                                (ppc-lap-word (tdi 27 ?? ??)))
958                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :ds :ds-xo)
959                                               (ppc-lap-word (ld ?? ppc64::arrayH.rank ??))
960                                               fn pc-index))
961                   (lisp-reg-p (setq ra (RA-field instr))))
962              (%error (%rsc-string $xndims)
963                      (list (xp-gpr-lisp xp ra)
964                            (ash (ldb (byte 16 0) the-trap) (- ppc64::fixnumshift)))
965                      frame-ptr))
966             ;; td 27 ra rb - array flags check
967             ((and (match-instr the-trap
968                                (ppc-instruction-mask :opcode :to :x-minor)
969                                (ppc-lap-word (td 27 ?? ??)))
970                   (setq instr (scan-for-instr (ppc-instruction-mask :opcode :ds :ds-xo)
971                                               (ppc-lap-word (ld ?? ppc64::arrayH.flags ??))
972                                               fn pc-index))
973                   (lisp-reg-p (setq ra (RA-field instr)))
974                   (let* ((expected (xp-gpr-lisp xp (RB-field the-trap)))
975                          (expected-subtype (ldb
976                                             ppc64::arrayH.flags-cell-subtag-byte
977                                             expected))
978                          (expect-simple (=
979                                          (ldb ppc64::arrayH.flags-cell-bits-byte
980                                               expected)
981                                          (ash 1 $arh_simple_bit)))
982                          (type-name
983                           (case expected-subtype
984                             (#.ppc64::subtag-double-float-vector 'double-float))))
985
986                     (and type-name expect-simple
987                          (setq condition
988                                (make-condition 'type-error
989                                                :datum (xp-gpr-lisp xp ra)
990                                                :expected-type
991                                                `(simple-array ,type-name))))))
992              (%error condition nil frame-ptr))
993                               
994             ;; Unknown trap
995             (t (%error "Unknown trap: #x~x~%xp: ~s, fn: ~s, pc: #x~x"
996                        (list the-trap xp fn (ash pc-index ppc64::fixnumshift))
997                        frame-ptr)))))))))
998
999
1000
1001
1002
Note: See TracBrowser for help on using the repository browser.