exceptions-sparc.c 12.2 KB
Newer Older
P
 
Paolo Molaro 已提交
1
/*
2
 * exceptions-sparc.c: exception support for sparc
P
 
Paolo Molaro 已提交
3 4 5 6 7 8 9 10 11 12 13 14
 *
 * Authors:
 *   Mark Crichton (crichton@gimp.org)
 *   Dietmar Maurer (dietmar@ximian.com)
 *
 * (C) 2003 Ximian, Inc.
 */

#include <config.h>
#include <glib.h>
#include <signal.h>
#include <string.h>
15
#include <sys/ucontext.h>
P
 
Paolo Molaro 已提交
16

M
 
Mark Crichton 已提交
17
#include <mono/arch/sparc/sparc-codegen.h>
P
 
Paolo Molaro 已提交
18 19 20 21 22 23
#include <mono/metadata/appdomain.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/mono-debug.h>
24
#include <mono/metadata/gc-internal.h>
25
#include <mono/metadata/tokentype.h>
P
 
Paolo Molaro 已提交
26 27 28 29

#include "mini.h"
#include "mini-sparc.h"

30 31 32 33
#ifndef REG_SP
#define REG_SP REG_O6
#endif

34 35
#define MONO_SPARC_WINDOW_ADDR(sp) ((gpointer*)(((guint8*)(sp)) + MONO_SPARC_STACK_BIAS))

36
/*
37
 * mono_arch_get_restore_context:
38 39 40
 *
 * Returns a pointer to a method which restores a previously saved sigcontext.
 */
41
gpointer
42
mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
43
{
44
	static guint32 *start;
45 46 47
	static int inited = 0;
	guint32 *code;

48 49 50 51
	g_assert (!aot);
	if (info)
		*info = NULL;

52 53
	if (inited)
		return start;
P
 
Paolo Molaro 已提交
54

55
	code = start = mono_global_codeman_reserve (32 * sizeof (guint32));
P
 
Paolo Molaro 已提交
56

57 58
	sparc_ldi_imm (code, sparc_o0, G_STRUCT_OFFSET (MonoContext, ip), sparc_i7);
	sparc_ldi_imm (code, sparc_o0, G_STRUCT_OFFSET (MonoContext, sp), sparc_i6);
P
 
Paolo Molaro 已提交
59

60 61 62 63 64 65
	sparc_jmpl_imm (code, sparc_i7, 0, sparc_g0);
	/* FIXME: This does not return to the correct window */
	sparc_restore_imm (code, sparc_g0, 0, sparc_g0);

	g_assert ((code - start) < 32);

66 67
	mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start);

68 69 70 71
	inited = 1;

	return start;
}
P
 
Paolo Molaro 已提交
72

73
/*
74
 * mono_arch_get_call_filter:
75 76 77 78 79 80 81
 *
 * Returns a pointer to a method which calls an exception filter. We
 * also use this function to call finally handlers (we pass NULL as 
 * @exc object in this case).
 *
 * call_filter (MonoContext *ctx, gpointer ip)
 */
82
gpointer
83
mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
P
 
Paolo Molaro 已提交
84
{
85
	static guint32 *start;
86 87 88
	static int inited = 0;
	guint32 *code;
	int i;
P
 
Paolo Molaro 已提交
89

90 91 92 93
	g_assert (!aot);
	if (info)
		*info = NULL;

94 95
	if (inited)
		return start;
P
 
Paolo Molaro 已提交
96

97
	code = start = mono_global_codeman_reserve (64 * sizeof (guint32));
P
 
Paolo Molaro 已提交
98

99 100 101 102 103
	/*
	 * There are two frames here:
	 * - the first frame is used by call_filter
	 * - the second frame is used to run the filter code
	 */
P
 
Paolo Molaro 已提交
104

105
	/* Create first frame */
106
	sparc_save_imm (code, sparc_sp, -256, sparc_sp);
P
 
Paolo Molaro 已提交
107

108
	sparc_mov_reg_reg (code, sparc_i1, sparc_o0);
109
	sparc_ldi_imm (code, sparc_i0, G_STRUCT_OFFSET (MonoContext, sp), sparc_o1);
P
 
Paolo Molaro 已提交
110

111
	/* Create second frame */
112
	sparc_save_imm (code, sparc_sp, -256, sparc_sp);
P
 
Paolo Molaro 已提交
113

114 115
	sparc_mov_reg_reg (code, sparc_i0, sparc_o0);
	sparc_mov_reg_reg (code, sparc_i1, sparc_o1);
P
 
Paolo Molaro 已提交
116 117

	/*
118 119 120 121 122
	 * We need to change %fp to point to the stack frame of the method
	 * containing the filter. But changing %fp also changes the %sp of
	 * the parent frame (the first frame), so if the OS saves the first frame,
	 * it saves it to the stack frame of the method, which is not good.
	 * So flush all register windows to memory before changing %fp.
P
 
Paolo Molaro 已提交
123
	 */
124
	sparc_flushw (code);
P
 
Paolo Molaro 已提交
125

126
	sparc_mov_reg_reg (code, sparc_fp, sparc_o7);
P
 
Paolo Molaro 已提交
127

128 129 130 131 132
	/* 
	 * Modify the second frame so it is identical to the one used in the
	 * method containing the filter.
	 */
	for (i = 0; i < 16; ++i)
133
		sparc_ldi_imm (code, sparc_o1, MONO_SPARC_STACK_BIAS + i * sizeof (gpointer), sparc_l0 + i);
P
 
Paolo Molaro 已提交
134

135
	/* Save %fp to a location reserved in mono_arch_allocate_vars */
136
	sparc_sti_imm (code, sparc_o7, sparc_fp, MONO_SPARC_STACK_BIAS - sizeof (gpointer));
P
 
Paolo Molaro 已提交
137

138
	/* Call the filter code, after this returns, %o0 will hold the result */
139 140 141 142
	sparc_call_imm (code, sparc_o0, 0);
	sparc_nop (code);

	/* Restore original %fp */
143
	sparc_ldi_imm (code, sparc_fp, MONO_SPARC_STACK_BIAS - sizeof (gpointer), sparc_fp);
144

145 146
	sparc_mov_reg_reg (code, sparc_o0, sparc_i0);

147 148 149 150 151 152 153 154 155 156 157 158
	/* Return to first frame */
	sparc_restore (code, sparc_g0, sparc_g0, sparc_g0);

	/* FIXME: Save locals to the stack */

	/* Return to caller */
	sparc_ret (code);
	/* Return result in delay slot */
	sparc_restore (code, sparc_o0, sparc_g0, sparc_o0);

	g_assert ((code - start) < 64);

159 160
	mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start);

161 162 163
	inited = 1;

	return start;
P
 
Paolo Molaro 已提交
164 165
}

166
static void
167
throw_exception (MonoObject *exc, gpointer sp, gpointer ip, gboolean rethrow)
P
 
Paolo Molaro 已提交
168
{
169 170
	MonoContext ctx;
	static void (*restore_context) (MonoContext *);
171 172
	gpointer *window;
	
173
	if (!restore_context)
174
		restore_context = mono_get_restore_context ();
175

176 177
	window = MONO_SPARC_WINDOW_ADDR (sp);
	ctx.sp = (gpointer*)sp;
178
	ctx.ip = ip;
179
	ctx.fp = (gpointer*)(MONO_SPARC_WINDOW_ADDR (sp) [sparc_i6 - 16]);
180

P
 
Paolo Molaro 已提交
181 182
	if (mono_object_isinst (exc, mono_defaults.exception_class)) {
		MonoException *mono_ex = (MonoException*)exc;
183 184
		if (!rethrow)
			mono_ex->stack_trace = NULL;
P
 
Paolo Molaro 已提交
185
	}
186
	mono_handle_exception (&ctx, exc, ip, FALSE);
187
	restore_context (&ctx);
P
 
Paolo Molaro 已提交
188

189 190 191
	g_assert_not_reached ();
}

192
static gpointer 
193
get_throw_exception (gboolean rethrow)
P
 
Paolo Molaro 已提交
194
{
195
	guint32 *start, *code;
196

197
	code = start = mono_global_codeman_reserve (16 * sizeof (guint32));
198

199
	sparc_save_imm (code, sparc_sp, -512, sparc_sp);
200 201 202 203 204

	sparc_flushw (code);
	sparc_mov_reg_reg (code, sparc_i0, sparc_o0);
	sparc_mov_reg_reg (code, sparc_fp, sparc_o1);
	sparc_mov_reg_reg (code, sparc_i7, sparc_o2);
205
	sparc_set (code, rethrow, sparc_o3);
206 207 208 209
	sparc_set (code, throw_exception, sparc_o7);
	sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
	sparc_nop (code);

210
	g_assert ((code - start) <= 16);
211

212 213
	mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start);

214 215 216 217 218 219 220 221 222 223
	return start;
}

/**
 * mono_arch_get_throw_exception:
 *
 * Returns a function pointer which can be used to raise exceptions.
 * The returned function has the following 
 * signature: void (*func) (MonoException *exc); 
 */
224 225
gpointer
mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
226 227 228 229
{
	static guint32* start;
	static int inited = 0;

230 231 232 233
	g_assert (!aot);
	if (info)
		*info = NULL;

234 235 236 237 238 239 240 241 242 243
	if (inited)
		return start;

	inited = 1;

	start = get_throw_exception (FALSE);

	return start;
}

244 245
gpointer
mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
246 247 248 249
{
	static guint32* start;
	static int inited = 0;

250 251 252 253
	g_assert (!aot);
	if (info)
		*info = NULL;

254 255 256 257 258 259
	if (inited)
		return start;

	inited = 1;

	start = get_throw_exception (TRUE);
260 261

	return start;
P
 
Paolo Molaro 已提交
262 263
}

264 265 266 267 268 269 270 271 272 273
/**
 * mono_arch_get_throw_corlib_exception:
 *
 * Returns a function pointer which can be used to raise 
 * corlib exceptions. The returned function has the following 
 * signature: void (*func) (guint32 ex_token, guint32 offset); 
 * Here, offset is the offset which needs to be substracted from the caller IP 
 * to get the IP of the throw. Passing the offset has the advantage that it 
 * needs no relocations in the caller.
 */
274 275
gpointer
mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
276
{
277
	static guint32 *start;
278 279 280 281
	static int inited = 0;
	guint32 *code;
	int reg;

282 283 284 285
	g_assert (!aot);
	if (info)
		*info = NULL;

286 287 288 289
	if (inited)
		return start;

	inited = 1;
290
	code = start = mono_global_codeman_reserve (64 * sizeof (guint32));
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314

#ifdef SPARCV9
	reg = sparc_g4;
#else
	reg = sparc_g1;
#endif

	sparc_mov_reg_reg (code, sparc_o7, sparc_o2);
	sparc_save_imm (code, sparc_sp, -160, sparc_sp);

	sparc_set (code, MONO_TOKEN_TYPE_DEF, sparc_o7);
	sparc_add (code, FALSE, sparc_i0, sparc_o7, sparc_o1);
	sparc_set (code, mono_defaults.exception_class->image, sparc_o0);
	sparc_set (code, mono_exception_from_token, sparc_o7);
	sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
	sparc_nop (code);

	/* Return to the caller, so exception handling does not see this frame */
	sparc_restore (code, sparc_o0, sparc_g0, sparc_o0);

	/* Compute throw ip */
	sparc_sll_imm (code, sparc_o1, 2, sparc_o1);
	sparc_sub (code, 0, sparc_o2, sparc_o1, sparc_o7);

315
	sparc_set (code, mono_arch_get_throw_exception (NULL, FALSE), reg);
316 317 318 319 320 321
	/* Use a jmp instead of a call so o7 is preserved */
	sparc_jmpl_imm (code, reg, 0, sparc_g0);
	sparc_nop (code);

	g_assert ((code - start) < 32);

322 323
	mono_arch_flush_icache ((guint8*)start, (guint8*)code - (guint8*)start);

324 325
	return start;
}
P
 
Paolo Molaro 已提交
326

327 328 329 330 331 332 333 334 335
/* mono_arch_find_jit_info:
 *
 * This function is used to gather information from @ctx. It return the 
 * MonoJitInfo of the corresponding function, unwinds one stack frame and
 * stores the resulting context into @new_ctx. It also stores a string 
 * describing the stack location into @trace (if not NULL), and modifies
 * the @lmf if necessary. @native_offset return the IP offset from the 
 * start of the function or -1 if that info is not available.
 */
336
gboolean
337
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
338
							 MonoJitInfo *ji, MonoContext *ctx, 
339 340
							 MonoContext *new_ctx, MonoLMF **lmf,
							 mgreg_t **save_locations,
341
							 StackFrameInfo *frame)
342
{
343
	gpointer *window;
344

345 346 347
	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;
	frame->managed = FALSE;
348

349
	*new_ctx = *ctx;
350 351

	if (ji != NULL) {
352
		frame->type = FRAME_TYPE_MANAGED;
353

Z
Zoltan Varga 已提交
354 355 356
		if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
			frame->managed = TRUE;

357 358 359 360
		if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
			/* remove any unused lmf */
			*lmf = (*lmf)->previous_lmf;
		}
361 362

		/* Restore ip and sp from the saved register window */
363
		window = MONO_SPARC_WINDOW_ADDR (ctx->sp);
364
		new_ctx->ip = window [sparc_i7 - 16];
365 366
		new_ctx->sp = (gpointer*)(window [sparc_i6 - 16]);
		new_ctx->fp = (gpointer*)(MONO_SPARC_WINDOW_ADDR (new_ctx->sp) [sparc_i6 - 16]);
367

368
		return TRUE;
369 370 371
	}
	else {
		if (!(*lmf))
372
			return FALSE;
373 374

		if (!(*lmf)->method)
375
			return FALSE;
376

377 378 379 380 381 382
		ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->ip, NULL);
		if (!ji)
			return FALSE;

		frame->ji = ji;
		frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
383 384 385 386 387 388 389

		new_ctx->ip = (*lmf)->ip;
		new_ctx->sp = (*lmf)->sp;
		new_ctx->fp = (*lmf)->ebp;

		*lmf = (*lmf)->previous_lmf;

390
		return TRUE;
391 392 393
	}
}

394 395 396 397 398 399
gboolean
mono_arch_has_unwind_info (gconstpointer addr)
{
	return FALSE;
}

400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
#ifdef __linux__

gboolean
mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
{
       MonoContext mctx;
       struct sigcontext *sc = sigctx;
       gpointer *window;

#ifdef SPARCV9
       mctx.ip = (gpointer) sc->sigc_regs.tpc;
       mctx.sp = (gpointer) sc->sigc_regs.u_regs[14];
#else
       mctx.ip = (gpointer) sc->si_regs.pc;
       mctx.sp = (gpointer) sc->si_regs.u_regs[14];
#endif

       window = (gpointer*)(((guint8*)mctx.sp) + MONO_SPARC_STACK_BIAS);
       mctx.fp = window [sparc_fp - 16];

       mono_handle_exception (&mctx, obj, mctx.ip, test_only);

#ifdef SPARCV9
       sc->sigc_regs.tpc = (unsigned long) mctx.ip;
       sc->sigc_regs.tnpc = (unsigned long) (mctx.ip + 4);
       sc->sigc_regs.u_regs[14] = (unsigned long) mctx.sp;
#else
       sc->si_regs.pc = (unsigned long) mctx.ip;
       sc->si_regs.npc = (unsigned long) (mctx.ip + 4);
       sc->si_regs.u_regs[14] = (unsigned long) mctx.sp;
#endif

       window = (gpointer*)(((guint8*)mctx.sp) + MONO_SPARC_STACK_BIAS);
       window [sparc_fp - 16] = mctx.fp;

       return TRUE;
}

gpointer
mono_arch_ip_from_context (void *sigctx)
{
       struct sigcontext *sc = sigctx;
       gpointer *ret;

#ifdef SPARCV9
       ret = (gpointer) sc->sigc_regs.tpc;
#else
       ret = (gpointer) sc->si_regs.pc;
#endif

       return ret;
}

#else /* !__linux__ */

455
gboolean
456
mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
457 458
{
	MonoContext mctx;
459
	ucontext_t *ctx = (ucontext_t*)sigctx;
460
	gpointer *window;
461 462 463 464 465 466 467 468 469 470

	/*
	 * Access to the machine state using the ucontext_t parameter is somewhat
	 * under documented under solaris. The code below seems to work under
	 * Solaris 9.
	 */
	g_assert (!ctx->uc_mcontext.gwins);

	mctx.ip = ctx->uc_mcontext.gregs [REG_PC];
	mctx.sp = ctx->uc_mcontext.gregs [REG_SP];
471 472
	window = (gpointer*)(((guint8*)mctx.sp) + MONO_SPARC_STACK_BIAS);
	mctx.fp = window [sparc_fp - 16];
473

474
	mono_handle_exception (&mctx, obj, mctx.ip, test_only);
475 476 477 478 479
	
	/* We can't use restore_context to return from a signal handler */
	ctx->uc_mcontext.gregs [REG_PC] = mctx.ip;
	ctx->uc_mcontext.gregs [REG_nPC] = mctx.ip + 4;
	ctx->uc_mcontext.gregs [REG_SP] = mctx.sp;
480 481
	window = (gpointer*)(((guint8*)mctx.sp) + MONO_SPARC_STACK_BIAS);
	window [sparc_fp - 16] = mctx.fp;
482 483 484

	return TRUE;
}
P
 
Paolo Molaro 已提交
485 486 487 488 489 490 491 492

gpointer
mono_arch_ip_from_context (void *sigctx)
{
	ucontext_t *ctx = (ucontext_t*)sigctx;
	return (gpointer)ctx->uc_mcontext.gregs [REG_PC];
}

493
#endif