[ Home ]
SBCL Internals

The pages on this CLiki-driven site can be edited by anybody at any time. No warranty of any kind can therefore be made; any implied warranties of merchantability or fitness for a particular purpose are expressly disclaimed
[ Home ] [ Recent Changes ] [ About CLiki ] [ Text Formatting ]

On the PPC port, we got undefined function errors wrong for a while. Solving the problem involved learning about SC-OFFSETs, as detailed below:

* (foo)
[...]
debugger invoked on condition of type SB-KERNEL:CASE-FAILURE:
  #C(2.1219957648426468d-314 5.968123474651662d-315) fell through ETYPECASE expression.
  Wanted one of (SB-KERNEL:FDEFN? SYMBOL).

--- src/runtime/ppc-assem.S     18 Mar 2002 17:59:37 -0000      1.1
+++ src/runtime/ppc-assem.S     17 Jul 2002 17:08:59 -0000
@@ -360,7 +359,7 @@
        twllei reg_ZERO,trap_Cerror
        .byte 4
        .byte UNDEFINED_FUN_ERROR?
-       .byte 254, 140, 2       /* 140?  sparc says sc_descriptorReg */
+       .byte 254, sc_DescriptorReg+0x40, 1
        .align 2
 1:     lwz reg_CODE,FDEFN_RAW_ADDR_OFFSET(reg_FDEFN)
        la reg_LIP,SIMPLE_FUN_CODE_OFFSET(reg_CODE)

We get booted into assembly (into this trampoline function, undefined_tramp) when we attempt to call an undefined function. We start executing at the "twllei" line above, which causes the program to receive a SIGTRAP?, and thus go to the sigtrap_handler defined in ppc-arch.c, and eventually back into lisp into internal error handlers defined in src/code/interr.lisp. The handler for undefined-fun-error takes one argument, which is either a symbol or an fdefn (incidentally explaining the error message above, about ETYPECASE failure) and passes that as the :NAME initarg to the undefined-function lisp-level error.

How does the lisp system find the argument? After all, all attempts to execute undefined functions, no matter what their names, end here. Well, after the trap instruction comes one byte, which code in src/code/ppc-vm.lisp interprets as the number of following bytes to read. In this case, there are four; the first is the type of the error that we are hitting (UNDEFINED_FUN_ERROR?), so that lisp can dispatch to the appropriate handler. The remaining three bytes must therefore carry the information required to find the function name.

At this point, I had no choice but to grovel some code. The system reads off the arguments as integers. However, 254 is a magical flag, saying "read the next two bytes, shifting the /second/ by 8". (255 is similar, but for four bytes). Thus, the remaining three bytes actually make up only one integer. With sc_DescriptorReg being 14, the number in question is 0x40 + 14 + 0x100 = 334 (or 101001110 in binary). This is then interpreted as an SC-OFFSET; we want it to be treated as a DescriptorReg, as we are going to be getting a descriptor object; what next? Well, the remaining 22 bits of an SC-OFFSET (the SC-OFFSET-OFFSET; see src/code/sc-offset.lisp) are treated as a register number, and the os_context_t object is grovelled for the register content! So, then, it was simple to examine what the sparc port did (it grabbed reg_CNAME?, for "current function name") and copy that logic. Of course, logic being what it is, that didn't work, because the ppc backend actually uses reg_FDEFN for that (see src/compiler/ppc/call.lisp, the DEFINE-FULL-CALL? macro), but once I'd spotted that and made the necessary adjustment (reg_FDEFN is 10 on the PPC port), it worked fine.

sc_DescriptorReg+0x40__
                       | 
           <- 1  -><---+-->
000000000000000000101001110 (the SC-OFFSET)
<-    reg_FDEFN     -><-+->
                        | 
                        |___ sc_DescriptorReg

This page is linked from: SC  

CLiki pages can be edited by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively