summaryrefslogtreecommitdiff
path: root/sys/arch/ia64/unwind/stackframe.h
blob: b6d884770b34ea126ed723bdf470220a9f442915 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*	$NetBSD: stackframe.h,v 1.4 2016/07/31 19:33:18 dholland Exp $	*/

/* 
 * Contributed to the NetBSD foundation by Cherry G. Mathew
 */

#define UNW_VER(x)           ((x) >> 48)
#define UNW_FLAG_MASK        0x0000ffff00000000L
#define UNW_FLAG_OSMASK      0x0000f00000000000L
#define UNW_FLAG_EHANDLER(x) ((x) & 0x0000000100000000L)
#define UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000L)
#define UNW_LENGTH(x)        ((x) & 0x00000000ffffffffL)

/* Unwind table entry. */
struct uwtable_ent {
	uint64_t start;
	uint64_t end;
	char *infoptr;
};


enum regrecord_type{
	/* Register contents live ( and therefore untouched ). */
	UNSAVED,
	/* .offset field is the saved content. */
	IMMED,
	/* Register saved in one of the Branch Registers. */
	BRREL,
	/*
	 * Register saved in one of the Stacked GRs 
	 * regstate.offset contains GR number (usually >= 32)
	 */
	GRREL,
	/*
	 * Register saved on the memory stack frame.
	 * regstate.offset is in words; ie; location == (sp + 4 * spoff).
	 */
	SPREL,
	/*
	 * Register saved on the memory stack frame but offseted via psp 
	 * regstate.offset is in words; ie, 
	 * location == (psp + 16 – 4 * pspoff) 
	 */
	PSPREL
}; 


struct regstate {
	enum regrecord_type where;
	uint64_t when;	

#define INVALID -1UL	/* Indicates uninitialised offset value. */
	uint64_t offset;
};


/* A staterecord contains the net state of 
 * sequentially parsing unwind descriptors.
 * The entry state of the current prologue region
 * is the exit state of the previous region.
 * We record info about registers we care about
 * ie; just enough to re-construct an unwind frame,
 * and ignore the rest.
 * Initial state is where = UNSAVED for all .where fields.
 */

struct staterecord {
	struct regstate bsp;
   	struct regstate psp;
 	struct regstate rp;
 	struct regstate pfs;
};

/* The unwind frame is a simpler version of the trap frame
 * and contains a subset of preserved registers, which are 
 * useful in unwinding an ia64 stack frame.
 * Keep this in sync with the staterecord. See: stackframe.c:updateregs()
 */
   
struct unwind_frame {
	uint64_t		bsp;	/* Base of the RSE. */
				    /* !!! XXX: Stack Frame discontinuities */
	uint64_t		psp;	/* Mem stack (variable size) base. */
	uint64_t		rp;	/* Return Pointer */
	uint64_t		pfs;	/* Previous Frame size info */

	/* Don't mirror anything below this line with struct staterecord */
	uint64_t		sp;
};


void buildrecordchain(uint64_t, struct recordchain *);
void initrecord(struct staterecord *);
void modifyrecord(struct staterecord *, struct recordchain *, uint64_t);
void pushrecord(struct staterecord *);
void poprecord(struct staterecord *, int);
void dump_staterecord(struct staterecord *);
void clonerecordstack(u_int);
void switchrecordstack(u_int);

struct uwtable_ent *get_unwind_table_entry(uint64_t);
void patchunwindframe(struct unwind_frame *, uint64_t, uint64_t);
void updateregs(struct unwind_frame *uwf, struct staterecord *, uint64_t);
struct uwtable_ent * get_unwind_table_entry(uint64_t ip);

struct staterecord *buildrecordstack(struct recordchain *, uint64_t);
void dump_recordchain(struct recordchain *);

/* Convenience macros to decompose CFM & ar.pfs. */
#define	IA64_CFM_SOF(x)		((x) & 0x7f)
#define	IA64_CFM_SOL(x)		(((x) >> 7) & 0x7f)
#define	IA64_CFM_SOR(x)		(((x) >> 14) & 0x0f)
#define	IA64_CFM_RRB_GR(x)	(((x) >> 18) & 0x7f)
#define	IA64_CFM_RRB_FR(x)	(((x) >> 25) & 0x7f)
#define	IA64_CFM_RRB_PR(x)	(((x) >> 32) & 0x3f)

#define IA64_RNATINDEX(x)	(((x) & 0x1f8) >> 3)

/* Obeys Table 6:2 RSE Operation Instructions and State Modification */

/* These functions adjust for RSE rnat saves to bsp in the forward and 
 * reverse directions respectively.
 */
#define ia64_rnat_adjust ia64_bsp_adjust_call

static __inline uint64_t
ia64_bsp_adjust_call(uint64_t bsp, int sol)
{
	bsp += ((sol + (IA64_RNATINDEX(bsp) + sol) / 63) << 3);
	return bsp;
}

static __inline uint64_t
ia64_bsp_adjust_ret(uint64_t bsp, int sol)
{
	bsp -= ((sol + (62 - IA64_RNATINDEX(bsp) + sol) / 63) << 3);
	return bsp;
}

static __inline uint64_t
ia64_getrse_gr(uint64_t bsp, uint64_t gr)
{
	bsp = ia64_bsp_adjust_call(bsp, gr);
	return *(uint64_t *) bsp;
}