blob: 538e87d5a3df6d647e525d5df872d5ef1ca28a69 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _STACK_WALKER_H
#define _STACK_WALKER_H
/**
@file
\ref stack_walking
This module contains the interfaces to provide stack walking functionality.
Note, that this interfaces are common to all types of stack frames.
See specific modules for more on information on particular types
of stack frames, e.g. native_frame.h
*/
/**
@page stack_walking Stack Walking subsystem
@section sw_introduction Introduction
The interface for stack walking is given in stack_walker.h.
Various types of the frames are discussed in \ref native_frame
@section rationale Rationale
<UL>
<LI>each method invocation has an activation record
(see programming tutorials on detailed explanation).
We will refer activation records as "stack frames".
<LI>some of the stack frames are of interest to us,
particularly those related to Java and having following
properties:
<UL>
<LI> enumerable
<LI> unwindable
<LI> security reportable (associated with java method)
</UL>
<LI> there is a number of different types of stack frames,
e.g. java method stack frames, JNI stack frames, VM
internal stack frames. We want to treat them uniformly.
We particularly want to consider stack frames as
entities, in order to avoid square growth of number
of possible transition types.
<LI> different stack frames have different physical
representation. For example, native frame is likely to
be a C struct in memory, and jitted method frame may
be represented as a just pair of values: stack pointer
and instruction pointer. This non-uniformity of
possible stack frames calls for a different ways of
working with stack frames. The most natural way of
representing the stack walking is the iterator.
<LI> as we want different stack frames to be represented
uniformly, we opt for a iterator as a designated
structure in memory. Thus we need to manage memory,
which is used to store stack iterators. The currently
used model is explicit memory management by
si_create()/si_free() functions. This may be
improved by using managed heap and handles.
<LI> a pointer to NativeFrame or InterpreterFrame
is not a complete information about corresponding
stack frame, as we need to know the owning execution
engine as well. Thus, a designated stack iterator
is useful for native and interpreted methods too.
<LI> Most of the information required to clients of stack walking
is directly computable from IP, for example, method,
owning execution engine, file name, line number.
Other information, e.g. needed during unwinding
</UL>
@section scenarios Usage scenarios.
<OL>
<LI> update_code_addresses_for_thread. (on-stack replacement?)
In case a code block was moved, iterate over the thread stack frames
and change the ip in each stack frame.
\code
StackIterator* iterator = si_create();
while (!si_over(iterator)) {
NativeCodePtr old_ip = si_get_ip(iterator);
NativeCodePtr new_ip = update_address(old_ip);
si_set_ip(iterator,new_ip);
si_next(iterator);
}
si_free(iterator);
\endcode
<LI> compile_rewrite_dcl{1,2} rewrite direct call
\code
StackIterator* si = si_create();
si_next(si);
assert(!si_over(si));
Execution_Engine_Handle jit = si_get_owner(si);
Method_Handle method = si_get_method(si);
NativeCodePtr ret_ip = si_get_ip(si);
si_free(si);
jit->rewrite_direct_call(REWRITE_PATCH_CALLER, (Method_Handle)method, ret_ip, method->get_code_addr());
\endcode
<LI> throw exception
\code
StackIterator* frame = si_create();
while (!si_over(frame) && si_is_unwindable(frame)) {
Execution_Engine_Handle ee = si_get_owner(frame);
Pointer ip = si_get_ip(frame);
for (handlers in ee_get_handlers(ee,frame)) { // XXX
if (hanlder catches exception at ip) {
Execution_Context* context = si_get_context(frame);
ee_fix_context(ee,context,handler);
si_free(frame);
vm_transfer_control(context);
}
}
si_unwind(frame);
}
if (si_over(frame)) {
// uncaught exception
} else if (!si_is_unwindable(frame)) {
set_current_thread_exception(exception);
}
si_free(frame);
\endcode
<LI> Stack trace construction (security or printStackTrace())
\code
StackIterator* frame = si_create();
while (!si_over(frame)) {
Method_Handle method = si_get_trace_method(frame);
char filename[256];
si_get_trace_file(frame,filename,sizeof(filename));
int linenumber = si_get_trace_line(frame);
// fill in some other structure
si_next_trace(frame);
}
si_free(frame);
\endcode
<LI> Root set enumeration
\code
StackIterator *frame = si_create();
while (!si_over(frame)) {
Execution_Engine_Handle ee = si_get_owner(frame);
ee_enumerate(ee,frame);
si_next(frame);
}
si_free(frame);
\endcode
</OL>
@section external_reqs External requirements
Only very rough list of required from EE functionality,
needs thorough work.
GC needs to
\li iterate over enumerable frames
\li enumerate each of them
Security manager nees to
\li iterate over formal method activation records
\li get method info for each activation record
Stack trace constructor needs to
\li iterate over real or formal stack frames (depending on the context)
\li get method, file, line information for each frame
Unwinding needs to
\li unwind unwindable frame (with appropriate context propagation)
\li release locks associated with unwinded frame
\li modify and resume context of handler stack frame
The rough list of methods required from external components to accomplish
stack walking tasks follows.
\code
Method_Handle ee_get_method(Execution_Engine_Handle ee, NativeCodePtr ip);
Execution_Engine_Handle vm_get_owner(NativeCodePtr ip);
void ee_get_line_info(Execution_Engine_Handle ee, Method_Handle method, int *pline, char **pfile);
?? ee_get_arg_description(Execution_Engine_Handle ee, Method_Handle method, ??);
void ee_enumerate(Execution_Engine_Handle ee, Method_Handle method, void* info);
void ee_unwind(Execution_Engine_Handle ee, Method_Handle method, Execution_Context* context, void* info); //??
void ee_fix_context(Execution_Engine_Handle ee, Method_Handle method, Execution_Context* context, Exception e); //??
\endcode
@section issues Issues
\li use managed heap to avoid explicit si_free()
\li should we expose the internal structure of StackIterator?
\li what do we need si_transfer_all_preserved_registers() for?
\li what do we need si_reload_registers() for?
\li is_ip_past?
\li CodeChunkInfo?
\li jit->unwind and native frame interaction?
\li formal and actual parameters access from stack frame?
\li M2NFrame: ip, registers, method, object handles, link to next M2nFrame.
\li what do we need si_dup() for: the only use in exn_propagate_exception()
@section existing Existing interfaces
\code
struct StackIterator {
CodeChunkInfo* cci;
JitFrameContext c;
M2nFrame* m2nfl;
U_32 ip;
};
StackIterator* si_create_from_native();
StackIterator* si_create_from_native(VM_thread* thread);
StackIterator* si_create_from_registers(Registers* regs, bool is_ip_past, M2nFrame* lm2nf);
void si_transfer_all_preserved_registers(StackIterator*);
bool si_is_past_end(StackIterator* si);
void si_goto_previous(StackIterator* si);
StackIterator* si_dup(StackIterator* si);
void si_free(StackIterator* si);
NativeCodePtr si_get_ip(StackIterator* si);
void si_set_ip(StackIterator* si, NativeCodePtr ip, bool also_update_stack_itself);
void si_set_code_chunk_info(StackIterator* si, CodeChunkInfo* cci);
CodeChunkInfo* si_get_code_chunk_info(StackIterator* si);
JitFrameContext* si_get_jit_context(StackIterator* si);
bool si_is_native(StackIterator* si);
M2nFrame* si_get_m2n(StackIterator* si);
void si_set_return_pointer(StackIterator* si, void** return_value);
void si_transfer_control(StackIterator* si);
void si_copy_to_registers(StackIterator* si, Registers* regs);
void si_reload_registers();
static void si_unwind_from_m2n(StackIterator* si);
// Stack trace
unsigned st_get_depth()
bool st_get_frame(unsigned target_depth, StackTraceFrame* stf)
void st_get_trace(unsigned* res_depth, StackTraceFrame** stfs)
void st_print_frame(ExpandableMemBlock* buf, StackTraceFrame* stf)
void st_print(FILE* f)
struct StackTraceFrame {
Method_Handle method;
NativeCodePtr ip;
const char* file;
int line; // -2 for native methods, -1 for unknown line number
};
\endcode
*/
/**
* Pointer to code.
*/
typedef unsigned* NativeCodePtr;
/**
* Opaque pointer to execution engine.
*/
typedef struct ExecutionEngine* Execution_Engine_Handle;
/**
* Machine-dependent thread context (fully or partly filled): register values.
*/
typedef struct Execution_Context Execution_Context;
/**
* Return execution context of current thread.
*/
Execution_Context ec_get_current();
/**
* Return execution context of suspended thread.
*/
Execution_Context ec_get_suspended(Thread_Handle thread);
/**
* On architectures with register stacks, ensure that the register stack of the
* current thread is consistent with its backing store, as the backing store
* might have been modified by stack walking code.
*
* @note rename of the function si_reload_registers
*/
void ec_update_current();
/**
* Kinds of values stored in executed context.
* This clasification is machine dependent, but there are common part like IP and return IP.
*/
typedef enum {
EC_CT_IP, EC_CT_RETIP
} ContextType;
/**
* Returns value contained in specified executing context for specified register
*/
ContextValue ec_get(Execution_Context context, ContextType type);
/**
* Sets value contained in specified executing context for specified register
*/
void ec_set(Execution_Context context, ContextType type, ContextValue value);
/**
* Stack iterator structure. At any moment of time stack
* iterator may point to a particular stack frame or be
* past the end of iteration.
*
* @note This is an possible implementation note,
* and this will not be exposed in final interface.
*
*/
typedef struct StackIterator {
/**
* Handle of owner of current stack frame.
* @note computable from ip.
*/
Execution_Engine_Handle ee;
/**
* Depth of inlined method.
*/
int depth;
/**
* Execution engine-specific field.
* May be used to store NativeFrame* or ebp value.
*/
void *info;
/**
* Execution context (register values).
* Fully or partly filled machine-dependent structure
* @note rename of JitFrameContext
*/
Execution_Context context;
} StackIterator;
///**
// * Create stack iterator from current thread context.
// * @note rename of si_create_from_native()
// */
//StackIterator* si_create_for_current();
//
///**
// * Create stack iterator for the specified suspended thread.
// * @note rename of si_create_from_native()
// */
//StackIterator* si_create_for_suspended(Thread_Handle thread);
//
///**
// * Create stack iterator for the specified execution context.
// * @note consolidation of si_create_from_registers()
// * and si_create_from_native(thread)
// */
//StackIterator* si_create_from_context(Execution_Context* context);
/**
* Create stack iterator for the specified execution context.
* @note consolidation of si_create_from_registers()
* and si_create_from_native(thread)
*/
StackIterator* si_create(Execution_Context* context);
/**
* Duplicate stack iterator.
*
* @note used only once in current VM. Probably may be eliminated.
*/
StackIterator* si_dup(StackIterator* iterator);
/**
* Free memory used by stack iterator.
*/
void si_free(StackIterator* iterator);
/**
* Kinds of stack frame.
* This classification is intended for security manager to be able
* to distinguish stack frames it does not need to take into account,
* for example, VM stack frames.
*
* @note XXX <UL>In fact, two different orthogonal classifications exist:
* <LI>by the owner: interpreter, JIT, VM, JNI
* <LI>by the java spec: java, JNI, other
* </UL>
* Current vision is that owner classification is available
* through si_get_owner().
*/
typedef enum {
SF_JAVA_REAL = 0x1,
SF_JAVA_INLINED = 0x2,
SF_JNI = 0x4,
SF_VM = 0x8,
SF_JAVA = SF_JAVA_REAL | SF_JAVA_INLINED,
SF_OTHER
} SF_Kind;
/**
* Returns the kind of the current stack frame.
*
* @see SF_Kind
* @note How to compute the kind of the stack frame?
*/
SF_Kind si_get_kind(StackIterator* iterator);
/**
* Iterate to next stack frame.
*
* @param iterator - the pointer to the stack frame
*
* @return true if iterator still points to a stack frame,
* false if iteration is complete.
* @note rename of si_goto_previous()
*/
bool si_next(StackIterator* iterator, SF_Kind kind);
/**
* Returns true if iteration is over.
* @note rename of si_is_past_end()
*
* @param iterator - the pointer to the stack frame
*
*/
bool si_done(StackIterator* iterator);
/**
* Returns true if current stack frame is unwindable.
*
* @param iterator - the pointer to the stack frame
*
*/
bool si_is_unwindable(StackIterator* iterator);
/**
* Unwind current stack frame with restoring the values
* of saved registers. The synchronization objects
* must be carefully released by this method.
*
* @param iterator - the pointer to the stack frame
*
*/
void si_unwind(StackIterator* iterator);
/**
* Resume current stack frame on current thread.
* This function frees the iterator and does not return.
*
* @note Equivalent to transfer_control(si_get_context(iterator))
* and may be eliminated as such.
*
* @param iterator - the pointer to the stack frame
*
*/
void si_transfer_control(StackIterator* iterator);
/**
* Return pointer to context structure of the current stack
* frame context.
*
* @param iterator - the pointer to the stack frame
*
*/
Execution_Context* si_get_context(StackIterator* iterator);
/**
* Get the pointer to the owner of the stack frame
* (i.e. JIT or interpreter).
*
* @note We may want to have a dummy execution engine
* corresponding to the native C++ compiler in order to
* provide more functionality for VM code.
*
* @param iterator - the pointer to the stack frame
*
*/
Execution_Engine_Handle si_get_owner(StackIterator* iterator);
/**
* Enumerate live pointers in current stack frame.
*
* @note Real enumeration is delegated to the exucution
* engine owning the current stack frame.
* This method may be completely eliminated
* in favour of using EE interfaces directly.
*
* @param iterator - the pointer to the stack frame
*
*/
void si_enumerate(StackIterator* iterator);
/**
* Retrieves information associated with current stack frame.
* For native or interpreter frames it is likely to return
* pointer to the actual frame structure, for jitted frames
* may return the value of base stack register.
*
* The returned value may be used as a parameter to functions
* provided by the execution engine owning the stack frame.
*
* @param iterator - the pointer to the stack frame
*
*/
void* si_get_info(StackIterator* iterator);
/**
* Get the method handle of the current stack frame.
*
* @param iterator - the pointer to the stack frame
*
*/
Method_Handle si_get_method(StackIterator* iterator);
/**
* Retrieves the file name corresponding to the current stack frame.
* If no information is available, an empty string is written to the
* buffer.
*
* @param iterator - the pointer to the stack frame
* @param buf - the buffer to be filled
* @param length - the size of the buffer. If the size is not sufficient
* to hold the file name, then file name is truncated.
*
* @note the request is delegated to execution engine.
*/
void si_get_trace_file(StackIterator* iterator, char* buf, int length);
/**
* Retrieves the line number corresponding to the current stack frame.
* If the number is not available, returns 0.
*
* @param iterator - the pointer to the stack frame
* @return the line number corresponding to the current stack frame, where routine is working now.
* @note The request is delegated to execution engine.
*/
int si_get_trace_line(StackIterator* iterator);
/**
* Retrieves debug information associated
* with the current stack frame.
* The format of this information is implementation-dependent.
*
* @param iterator - the pointer to the stack frame
*
* @note the request is delegated to execution engine.
*/
void si_get_debug_info(StackIterator* iterator, char* buf, int length);
#endif // _STACK_WALKER_H