Tease out symbol name and library in undefined_symbol() handler, for friendlier errors when calling an unresolved C function name. Fixes #93
parent
c489f7a9f5
commit
7c3827190b
|
@ -1,12 +1,18 @@
|
|||
USING: tools.test namespaces assocs alien.syntax kernel
|
||||
compiler.errors accessors alien alien.c-types ;
|
||||
FROM: alien.libraries => add-library ;
|
||||
compiler.errors accessors alien alien.c-types alien.strings
|
||||
debugger literals ;
|
||||
FROM: alien.libraries => add-library load-library ;
|
||||
IN: compiler.tests.linkage-errors
|
||||
|
||||
! Regression: calling an undefined function would raise a protection fault
|
||||
FUNCTION: void this_does_not_exist ( ) ;
|
||||
|
||||
[ this_does_not_exist ] [ { "kernel-error" 9 f f } = ] must-fail-with
|
||||
[ this_does_not_exist ] try
|
||||
|
||||
[ this_does_not_exist ] [
|
||||
{ "kernel-error" 9 $[ "this_does_not_exist" string>symbol ] f }
|
||||
=
|
||||
] must-fail-with
|
||||
|
||||
[ T{ no-such-symbol { name "this_does_not_exist" } } ]
|
||||
[ \ this_does_not_exist linkage-errors get at error>> ] unit-test
|
||||
|
@ -17,5 +23,16 @@ LIBRARY: no_such_library
|
|||
|
||||
FUNCTION: void no_such_function ( ) ;
|
||||
|
||||
[ no_such_function ] try
|
||||
|
||||
[ no_such_function ] [
|
||||
{
|
||||
"kernel-error" 9
|
||||
$[ "no_such_function" string>symbol ]
|
||||
$[ "no_such_library" load-library ]
|
||||
}
|
||||
=
|
||||
] must-fail-with
|
||||
|
||||
[ T{ no-such-library { name "no_such_library" } } ]
|
||||
[ \ no_such_function linkage-errors get at error>> ] unit-test
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
! Copyright (C) 2004, 2010 Slava Pestov.
|
||||
! Copyright (C) 2004, 2011 Slava Pestov.
|
||||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: slots arrays definitions generic hashtables summary io
|
||||
kernel math namespaces make prettyprint prettyprint.config
|
||||
sequences assocs sequences.private strings io.styles
|
||||
io.pathnames vectors words system splitting math.parser
|
||||
classes.mixin classes.tuple continuations continuations.private
|
||||
combinators generic.math classes.builtin classes compiler.units
|
||||
generic.standard generic.single vocabs init kernel.private
|
||||
io.encodings accessors math.order destructors source-files
|
||||
parser classes.tuple.parser effects.parser lexer generic.parser
|
||||
strings.parser vocabs.loader vocabs.parser source-files.errors ;
|
||||
USING: alien.strings slots arrays definitions generic hashtables
|
||||
summary io kernel math namespaces make prettyprint
|
||||
prettyprint.config sequences assocs sequences.private strings
|
||||
io.styles io.pathnames vectors words system splitting
|
||||
math.parser classes.mixin classes.tuple continuations
|
||||
continuations.private combinators generic.math classes.builtin
|
||||
classes compiler.units generic.standard generic.single vocabs
|
||||
init kernel.private io.encodings accessors math.order
|
||||
destructors source-files parser classes.tuple.parser
|
||||
effects.parser lexer generic.parser strings.parser vocabs.loader
|
||||
vocabs.parser source-files.errors ;
|
||||
IN: debugger
|
||||
|
||||
GENERIC: error-help ( error -- topic )
|
||||
|
@ -107,8 +108,9 @@ HOOK: signal-error. os ( obj -- )
|
|||
"FFI error" print drop ;
|
||||
|
||||
: undefined-symbol-error. ( obj -- )
|
||||
"The image refers to a library or symbol that was not found at load time"
|
||||
print drop ;
|
||||
"Cannot resolve C library function" print
|
||||
"Symbol: " write dup third symbol>string print
|
||||
"Library: " write fourth . ;
|
||||
|
||||
: stack-underflow. ( obj name -- )
|
||||
write " stack underflow" print drop ;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
! Copyright (C) 2008, 2010 Slava Pestov.
|
||||
! Copyright (C) 2008, 2011 Slava Pestov.
|
||||
! See http://factorcode.org/license.txt for BSD license.
|
||||
USING: arrays sequences kernel kernel.private accessors math
|
||||
alien.accessors byte-arrays io io.encodings io.encodings.utf8
|
||||
|
@ -51,19 +51,14 @@ M: windows native-string-encoding utf16n ;
|
|||
: dll-path ( dll -- string )
|
||||
path>> alien>native-string ;
|
||||
|
||||
HOOK: string>symbol* os ( str/seq -- alien )
|
||||
GENERIC: string>symbol ( str/seq -- alien )
|
||||
|
||||
M: winnt string>symbol* utf8 string>alien ;
|
||||
M: string string>symbol utf8 string>alien ;
|
||||
|
||||
M: wince string>symbol* utf16n string>alien ;
|
||||
M: sequence string>symbol [ utf8 string>alien ] map ;
|
||||
|
||||
M: unix string>symbol* utf8 string>alien ;
|
||||
|
||||
GENERIC: string>symbol ( str -- alien )
|
||||
|
||||
M: string string>symbol string>symbol* ;
|
||||
|
||||
M: sequence string>symbol [ string>symbol* ] map ;
|
||||
: symbol>string ( alien -- str )
|
||||
utf8 alien>string ;
|
||||
|
||||
[
|
||||
8 special-object utf8 alien>string string>cpu \ cpu set-global
|
||||
|
|
|
@ -160,7 +160,6 @@ void factor_vm::primitive_dlsym_raw()
|
|||
ctx->push(allot_alien(ffi_dlsym_raw(NULL,sym)));
|
||||
}
|
||||
|
||||
|
||||
/* close a native library handle */
|
||||
void factor_vm::primitive_dlclose()
|
||||
{
|
||||
|
|
|
@ -129,13 +129,8 @@ void factor_vm::set_frame_offset(stack_frame *frame, cell offset)
|
|||
|
||||
void factor_vm::scrub_return_address()
|
||||
{
|
||||
stack_frame *top = ctx->callstack_top;
|
||||
stack_frame *bottom = ctx->callstack_bottom;
|
||||
stack_frame *frame = bottom - 1;
|
||||
|
||||
while(frame >= top && frame_successor(frame) >= top)
|
||||
frame = frame_successor(frame);
|
||||
|
||||
stack_frame *frame = innermost_stack_frame(ctx->callstack_top,
|
||||
ctx->callstack_bottom);
|
||||
set_frame_offset(frame,0);
|
||||
}
|
||||
|
||||
|
@ -191,10 +186,8 @@ void factor_vm::primitive_callstack_to_array()
|
|||
ctx->push(accum.frames.elements.value());
|
||||
}
|
||||
|
||||
stack_frame *factor_vm::innermost_stack_frame(callstack *stack)
|
||||
stack_frame *factor_vm::innermost_stack_frame(stack_frame *bottom, stack_frame *top)
|
||||
{
|
||||
stack_frame *top = stack->top();
|
||||
stack_frame *bottom = stack->bottom();
|
||||
stack_frame *frame = bottom - 1;
|
||||
|
||||
while(frame >= top && frame_successor(frame) >= top)
|
||||
|
@ -207,13 +200,15 @@ stack_frame *factor_vm::innermost_stack_frame(callstack *stack)
|
|||
Used by the single stepper. */
|
||||
void factor_vm::primitive_innermost_stack_frame_executing()
|
||||
{
|
||||
stack_frame *frame = innermost_stack_frame(untag_check<callstack>(ctx->pop()));
|
||||
callstack *stack = untag_check<callstack>(ctx->pop());
|
||||
stack_frame *frame = innermost_stack_frame(stack->bottom(), stack->top());
|
||||
ctx->push(frame_executing_quot(frame));
|
||||
}
|
||||
|
||||
void factor_vm::primitive_innermost_stack_frame_scan()
|
||||
{
|
||||
stack_frame *frame = innermost_stack_frame(untag_check<callstack>(ctx->pop()));
|
||||
callstack *stack = untag_check<callstack>(ctx->pop());
|
||||
stack_frame *frame = innermost_stack_frame(stack->bottom(), stack->top());
|
||||
ctx->push(frame_scan(frame));
|
||||
}
|
||||
|
||||
|
@ -227,7 +222,7 @@ void factor_vm::primitive_set_innermost_stack_frame_quot()
|
|||
|
||||
jit_compile_quot(quot.value(),true);
|
||||
|
||||
stack_frame *inner = innermost_stack_frame(callstack.untagged());
|
||||
stack_frame *inner = innermost_stack_frame(callstack->bottom(), callstack->top());
|
||||
cell offset = frame_offset(inner);
|
||||
inner->entry_point = quot->entry_point;
|
||||
set_frame_offset(inner,offset);
|
||||
|
|
|
@ -140,23 +140,11 @@ void factor_vm::update_word_references(code_block *compiled, bool reset_inline_c
|
|||
}
|
||||
}
|
||||
|
||||
/* References to undefined symbols are patched up to call this function on
|
||||
image load */
|
||||
void factor_vm::undefined_symbol()
|
||||
{
|
||||
general_error(ERROR_UNDEFINED_SYMBOL,false_object,false_object);
|
||||
}
|
||||
|
||||
void undefined_symbol()
|
||||
{
|
||||
return current_vm()->undefined_symbol();
|
||||
}
|
||||
|
||||
/* Look up an external library symbol referenced by a compiled code block */
|
||||
cell factor_vm::compute_dlsym_address(array *literals, cell index)
|
||||
cell factor_vm::compute_dlsym_address(array *parameters, cell index)
|
||||
{
|
||||
cell symbol = array_nth(literals,index);
|
||||
cell library = array_nth(literals,index + 1);
|
||||
cell symbol = array_nth(parameters,index);
|
||||
cell library = array_nth(parameters,index + 1);
|
||||
|
||||
dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
|
||||
|
||||
|
@ -197,10 +185,10 @@ cell factor_vm::compute_dlsym_address(array *literals, cell index)
|
|||
}
|
||||
|
||||
#ifdef FACTOR_PPC
|
||||
cell factor_vm::compute_dlsym_toc_address(array *literals, cell index)
|
||||
cell factor_vm::compute_dlsym_toc_address(array *parameters, cell index)
|
||||
{
|
||||
cell symbol = array_nth(literals,index);
|
||||
cell library = array_nth(literals,index + 1);
|
||||
cell symbol = array_nth(parameters,index);
|
||||
cell library = array_nth(parameters,index + 1);
|
||||
|
||||
dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
|
||||
|
||||
|
@ -240,7 +228,6 @@ cell factor_vm::compute_dlsym_toc_address(array *literals, cell index)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
cell factor_vm::compute_vm_address(cell arg)
|
||||
{
|
||||
return (cell)this + untag_fixnum(arg);
|
||||
|
@ -248,9 +235,9 @@ cell factor_vm::compute_vm_address(cell arg)
|
|||
|
||||
void factor_vm::store_external_address(instruction_operand op)
|
||||
{
|
||||
code_block *compiled = op.parent_code_block();
|
||||
code_block *compiled = op.compiled;
|
||||
array *parameters = (to_boolean(compiled->parameters) ? untag<array>(compiled->parameters) : NULL);
|
||||
cell index = op.parameter_index();
|
||||
cell index = op.index;
|
||||
|
||||
switch(op.rel_type())
|
||||
{
|
||||
|
@ -327,7 +314,7 @@ struct initial_code_block_visitor {
|
|||
op.store_value(parent->compute_entry_point_pic_tail_address(next_literal()));
|
||||
break;
|
||||
case RT_HERE:
|
||||
op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.parent_code_block()));
|
||||
op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.compiled));
|
||||
break;
|
||||
case RT_UNTAGGED:
|
||||
op.store_value(untag_fixnum(next_literal()));
|
||||
|
@ -451,4 +438,49 @@ code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell lab
|
|||
return compiled;
|
||||
}
|
||||
|
||||
/* Find the RT_DLSYM relocation nearest to the given return address. */
|
||||
struct find_symbol_at_address_visitor {
|
||||
factor_vm *parent;
|
||||
cell return_address;
|
||||
cell symbol;
|
||||
cell library;
|
||||
|
||||
find_symbol_at_address_visitor(factor_vm *parent_, cell return_address_) :
|
||||
parent(parent_), return_address(return_address_),
|
||||
symbol(false_object), library(false_object) { }
|
||||
|
||||
void operator()(instruction_operand op)
|
||||
{
|
||||
if(op.rel_type() == RT_DLSYM && op.pointer < return_address)
|
||||
{
|
||||
code_block *compiled = op.compiled;
|
||||
array *parameters = untag<array>(compiled->parameters);
|
||||
cell index = op.index;
|
||||
symbol = array_nth(parameters,index);
|
||||
library = array_nth(parameters,index + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* References to undefined symbols are patched up to call this function on
|
||||
image load. It finds the symbol and library, and throws an error. */
|
||||
void factor_vm::undefined_symbol()
|
||||
{
|
||||
stack_frame *frame = innermost_stack_frame(ctx->callstack_bottom,
|
||||
ctx->callstack_top);
|
||||
code_block *compiled = frame_code(frame);
|
||||
cell return_address = (cell)FRAME_RETURN_ADDRESS(frame, this);
|
||||
find_symbol_at_address_visitor visitor(this, return_address);
|
||||
compiled->each_instruction_operand(visitor);
|
||||
if (!to_boolean(visitor.symbol))
|
||||
critical_error("Can't find RT_DLSYM at return address", return_address);
|
||||
else
|
||||
general_error(ERROR_UNDEFINED_SYMBOL,visitor.symbol,visitor.library);
|
||||
}
|
||||
|
||||
void undefined_symbol()
|
||||
{
|
||||
return current_vm()->undefined_symbol();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -83,4 +83,5 @@ struct code_block
|
|||
}
|
||||
};
|
||||
|
||||
VM_C_API void undefined_symbol(void);
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ struct startup_code_block_relocation_visitor {
|
|||
|
||||
void operator()(instruction_operand op)
|
||||
{
|
||||
code_block *compiled = op.parent_code_block();
|
||||
code_block *compiled = op.compiled;
|
||||
cell old_offset = op.rel_offset() + (cell)compiled->entry_point() - fixup.code_offset;
|
||||
|
||||
switch(op.rel_type())
|
||||
|
|
|
@ -143,16 +143,6 @@ struct instruction_operand {
|
|||
return rel.rel_offset();
|
||||
}
|
||||
|
||||
cell parameter_index()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
code_block *parent_code_block()
|
||||
{
|
||||
return compiled;
|
||||
}
|
||||
|
||||
fixnum load_value_2_2();
|
||||
fixnum load_value_2_2_2_2();
|
||||
fixnum load_value_masked(cell mask, cell bits, cell shift);
|
||||
|
|
|
@ -593,7 +593,7 @@ struct factor_vm
|
|||
void set_frame_offset(stack_frame *frame, cell offset);
|
||||
void scrub_return_address();
|
||||
void primitive_callstack_to_array();
|
||||
stack_frame *innermost_stack_frame(callstack *stack);
|
||||
stack_frame *innermost_stack_frame(stack_frame *bottom, stack_frame *top);
|
||||
void primitive_innermost_stack_frame_executing();
|
||||
void primitive_innermost_stack_frame_scan();
|
||||
void primitive_set_innermost_stack_frame_quot();
|
||||
|
|
Loading…
Reference in New Issue