blob: c4650c129099e858ed09d7c41a316b97d160286d [file] [log] [blame]
/**
* @author Ilya Berezhniuk
*/
#define LOG_DOMAIN "ncai.stack"
#include "cxxlog.h"
#include "suspend_checker.h"
#include "interpreter_exports.h"
#include "open/ncai_thread.h"
#include "native_stack.h"
#include "ncai_utils.h"
#include "ncai_direct.h"
#include "ncai_internal.h"
static ncaiError walk_native_stack(hythread_t thread,
int* pcount, int max_depth, native_frame_t* frame_array);
ncaiError JNICALL
ncaiGetFrameCount(ncaiEnv *env, ncaiThread thread, jint *count_ptr)
{
TRACE2("ncai.stack", "GetFrameCount called");
SuspendEnabledChecker sec;
if (env == NULL)
return NCAI_ERROR_INVALID_ENVIRONMENT;
if (thread == NULL)
return NCAI_ERROR_INVALID_THREAD;
if (count_ptr == NULL)
return NCAI_ERROR_NULL_POINTER;
hythread_t hythread = reinterpret_cast<hythread_t>(thread);
int count = 0;
ncaiError err = walk_native_stack(hythread, &count, -1, NULL);
if (err != NCAI_ERROR_NONE)
return err;
*count_ptr = count;
return NCAI_ERROR_NONE;
}
ncaiError JNICALL
ncaiGetStackTrace(ncaiEnv *env, ncaiThread thread, jint depth,
ncaiFrameInfo* frame_buffer, jint *count_ptr)
{
TRACE2("ncai.stack", "GetStackTrace called");
SuspendEnabledChecker sec;
if (env == NULL)
return NCAI_ERROR_INVALID_ENVIRONMENT;
if (thread == NULL)
return NCAI_ERROR_INVALID_THREAD;
if (count_ptr == NULL)
return NCAI_ERROR_NULL_POINTER;
if (depth < 0)
return NCAI_ERROR_ILLEGAL_ARGUMENT;
if (depth == 0)
{
*count_ptr = 0;
return NCAI_ERROR_NONE;
}
if (frame_buffer == NULL)
return NCAI_ERROR_NULL_POINTER;
native_frame_t* frame_array =
(native_frame_t*)ncai_alloc(sizeof(native_frame_t)*depth);
if (!frame_array)
return NCAI_ERROR_OUT_OF_MEMORY;
hythread_t hythread = reinterpret_cast<hythread_t>(thread);
int count = 0;
ncaiError err = walk_native_stack(hythread, &count, depth, frame_array);
assert(count >= 0);
if (err != NCAI_ERROR_NONE)
{
ncai_free(frame_array);
return err;
}
for (jint i = 0; i < count; i++)
{
frame_buffer[i].java_frame_depth = frame_array[i].java_depth;
frame_buffer[i].pc_address = frame_array[i].ip;
frame_buffer[i].frame_address = frame_array[i].frame;
frame_buffer[i].stack_address = frame_array[i].stack;
frame_buffer[i].return_address = NULL;
if (i > 0)
frame_buffer[i - 1].return_address = frame_array[i].ip;
}
ncai_free(frame_array);
*count_ptr = count;
return NCAI_ERROR_NONE;
}
static ncaiError walk_native_stack(hythread_t thread,
int* pcount, int max_depth, native_frame_t* frame_array)
{
if (!hythread_is_alive(thread))
return NCAI_ERROR_THREAD_NOT_ALIVE;
int suspend_count = hythread_get_suspend_count_native(thread);
hythread_t hself = hythread_self();
Registers regs;
int count = 0;
VM_thread* vm_thread;
if (hself == thread) //Current thread is not suspended
{
assert(suspend_count <= 0);
vm_thread = p_TLS_vmthread;
if (vm_thread == NULL)
return NCAI_ERROR_THREAD_NOT_ALIVE;
if (!vm_thread->jvmti_thread.flag_ncai_handler)
return NCAI_ERROR_THREAD_NOT_SUSPENDED;
regs = *((Registers*)vm_thread->jvmti_thread.jvmti_saved_exception_registers);
}
else
{
if (suspend_count <= 0)
return NCAI_ERROR_THREAD_NOT_SUSPENDED;
// We know that the thread is suspended
bool res = ncai_get_generic_registers(thread, &regs);
if (!res)
return NCAI_ERROR_INTERNAL;
vm_thread = jthread_get_vm_thread(thread);
}
UnwindContext context;
if (!port_init_unwind_context(&context, NULL, &regs))
return NCAI_ERROR_INTERNAL;
*pcount = walk_native_stack_registers(&context, &regs,
vm_thread, max_depth, frame_array);
port_clean_unwind_context(&context);
return NCAI_ERROR_NONE;
}