aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/include
diff options
context:
space:
mode:
authorMatt Fleming <matt@console-pimps.org>2009-08-13 12:58:43 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-08-13 12:58:43 -0400
commitbd353861c735b2265c9d8b2559960c693e7c68ab (patch)
tree2cd13808cb4d50b6b4d63eff0d7ad5fa6d19f04d /arch/sh/include
parent0eff9f66de79a0707a9c3a2f8528ccfd62100f0b (diff)
sh: dwarf unwinder support.
This is a first cut at a generic DWARF unwinder for the kernel. It's still lacking DWARF64 support and the DWARF expression support hasn't been tested very well but it is generating proper stacktraces on SH for WARN_ON() and NULL dereferences. Signed-off-by: Matt Fleming <matt@console-pimps.org> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/include')
-rw-r--r--arch/sh/include/asm/dwarf.h407
-rw-r--r--arch/sh/include/asm/sections.h1
-rw-r--r--arch/sh/include/asm/vmlinux.lds.h17
3 files changed, 425 insertions, 0 deletions
diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h
new file mode 100644
index 00000000000..23eba12880b
--- /dev/null
+++ b/arch/sh/include/asm/dwarf.h
@@ -0,0 +1,407 @@
1/*
2 * Copyright (C) 2009 Matt Fleming <matt@console-pimps.org>
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 */
9#ifndef __ASM_SH_DWARF_H
10#define __ASM_SH_DWARF_H
11
12#ifdef CONFIG_DWARF_UNWINDER
13
14/*
15 * DWARF expression operations
16 */
17#define DW_OP_addr 0x03
18#define DW_OP_deref 0x06
19#define DW_OP_const1u 0x08
20#define DW_OP_const1s 0x09
21#define DW_OP_const2u 0x0a
22#define DW_OP_const2s 0x0b
23#define DW_OP_const4u 0x0c
24#define DW_OP_const4s 0x0d
25#define DW_OP_const8u 0x0e
26#define DW_OP_const8s 0x0f
27#define DW_OP_constu 0x10
28#define DW_OP_consts 0x11
29#define DW_OP_dup 0x12
30#define DW_OP_drop 0x13
31#define DW_OP_over 0x14
32#define DW_OP_pick 0x15
33#define DW_OP_swap 0x16
34#define DW_OP_rot 0x17
35#define DW_OP_xderef 0x18
36#define DW_OP_abs 0x19
37#define DW_OP_and 0x1a
38#define DW_OP_div 0x1b
39#define DW_OP_minus 0x1c
40#define DW_OP_mod 0x1d
41#define DW_OP_mul 0x1e
42#define DW_OP_neg 0x1f
43#define DW_OP_not 0x20
44#define DW_OP_or 0x21
45#define DW_OP_plus 0x22
46#define DW_OP_plus_uconst 0x23
47#define DW_OP_shl 0x24
48#define DW_OP_shr 0x25
49#define DW_OP_shra 0x26
50#define DW_OP_xor 0x27
51#define DW_OP_skip 0x2f
52#define DW_OP_bra 0x28
53#define DW_OP_eq 0x29
54#define DW_OP_ge 0x2a
55#define DW_OP_gt 0x2b
56#define DW_OP_le 0x2c
57#define DW_OP_lt 0x2d
58#define DW_OP_ne 0x2e
59#define DW_OP_lit0 0x30
60#define DW_OP_lit1 0x31
61#define DW_OP_lit2 0x32
62#define DW_OP_lit3 0x33
63#define DW_OP_lit4 0x34
64#define DW_OP_lit5 0x35
65#define DW_OP_lit6 0x36
66#define DW_OP_lit7 0x37
67#define DW_OP_lit8 0x38
68#define DW_OP_lit9 0x39
69#define DW_OP_lit10 0x3a
70#define DW_OP_lit11 0x3b
71#define DW_OP_lit12 0x3c
72#define DW_OP_lit13 0x3d
73#define DW_OP_lit14 0x3e
74#define DW_OP_lit15 0x3f
75#define DW_OP_lit16 0x40
76#define DW_OP_lit17 0x41
77#define DW_OP_lit18 0x42
78#define DW_OP_lit19 0x43
79#define DW_OP_lit20 0x44
80#define DW_OP_lit21 0x45
81#define DW_OP_lit22 0x46
82#define DW_OP_lit23 0x47
83#define DW_OP_lit24 0x48
84#define DW_OP_lit25 0x49
85#define DW_OP_lit26 0x4a
86#define DW_OP_lit27 0x4b
87#define DW_OP_lit28 0x4c
88#define DW_OP_lit29 0x4d
89#define DW_OP_lit30 0x4e
90#define DW_OP_lit31 0x4f
91#define DW_OP_reg0 0x50
92#define DW_OP_reg1 0x51
93#define DW_OP_reg2 0x52
94#define DW_OP_reg3 0x53
95#define DW_OP_reg4 0x54
96#define DW_OP_reg5 0x55
97#define DW_OP_reg6 0x56
98#define DW_OP_reg7 0x57
99#define DW_OP_reg8 0x58
100#define DW_OP_reg9 0x59
101#define DW_OP_reg10 0x5a
102#define DW_OP_reg11 0x5b
103#define DW_OP_reg12 0x5c
104#define DW_OP_reg13 0x5d
105#define DW_OP_reg14 0x5e
106#define DW_OP_reg15 0x5f
107#define DW_OP_reg16 0x60
108#define DW_OP_reg17 0x61
109#define DW_OP_reg18 0x62
110#define DW_OP_reg19 0x63
111#define DW_OP_reg20 0x64
112#define DW_OP_reg21 0x65
113#define DW_OP_reg22 0x66
114#define DW_OP_reg23 0x67
115#define DW_OP_reg24 0x68
116#define DW_OP_reg25 0x69
117#define DW_OP_reg26 0x6a
118#define DW_OP_reg27 0x6b
119#define DW_OP_reg28 0x6c
120#define DW_OP_reg29 0x6d
121#define DW_OP_reg30 0x6e
122#define DW_OP_reg31 0x6f
123#define DW_OP_breg0 0x70
124#define DW_OP_breg1 0x71
125#define DW_OP_breg2 0x72
126#define DW_OP_breg3 0x73
127#define DW_OP_breg4 0x74
128#define DW_OP_breg5 0x75
129#define DW_OP_breg6 0x76
130#define DW_OP_breg7 0x77
131#define DW_OP_breg8 0x78
132#define DW_OP_breg9 0x79
133#define DW_OP_breg10 0x7a
134#define DW_OP_breg11 0x7b
135#define DW_OP_breg12 0x7c
136#define DW_OP_breg13 0x7d
137#define DW_OP_breg14 0x7e
138#define DW_OP_breg15 0x7f
139#define DW_OP_breg16 0x80
140#define DW_OP_breg17 0x81
141#define DW_OP_breg18 0x82
142#define DW_OP_breg19 0x83
143#define DW_OP_breg20 0x84
144#define DW_OP_breg21 0x85
145#define DW_OP_breg22 0x86
146#define DW_OP_breg23 0x87
147#define DW_OP_breg24 0x88
148#define DW_OP_breg25 0x89
149#define DW_OP_breg26 0x8a
150#define DW_OP_breg27 0x8b
151#define DW_OP_breg28 0x8c
152#define DW_OP_breg29 0x8d
153#define DW_OP_breg30 0x8e
154#define DW_OP_breg31 0x8f
155#define DW_OP_regx 0x90
156#define DW_OP_fbreg 0x91
157#define DW_OP_bregx 0x92
158#define DW_OP_piece 0x93
159#define DW_OP_deref_size 0x94
160#define DW_OP_xderef_size 0x95
161#define DW_OP_nop 0x96
162#define DW_OP_push_object_address 0x97
163#define DW_OP_call2 0x98
164#define DW_OP_call4 0x99
165#define DW_OP_call_ref 0x9a
166#define DW_OP_form_tls_address 0x9b
167#define DW_OP_call_frame_cfa 0x9c
168#define DW_OP_bit_piece 0x9d
169#define DW_OP_lo_user 0xe0
170#define DW_OP_hi_user 0xff
171
172/*
173 * Addresses used in FDE entries in the .eh_frame section may be encoded
174 * using one of the following encodings.
175 */
176#define DW_EH_PE_absptr 0x00
177#define DW_EH_PE_omit 0xff
178#define DW_EH_PE_uleb128 0x01
179#define DW_EH_PE_udata2 0x02
180#define DW_EH_PE_udata4 0x03
181#define DW_EH_PE_udata8 0x04
182#define DW_EH_PE_sleb128 0x09
183#define DW_EH_PE_sdata2 0x0a
184#define DW_EH_PE_sdata4 0x0b
185#define DW_EH_PE_sdata8 0x0c
186#define DW_EH_PE_signed 0x09
187
188#define DW_EH_PE_pcrel 0x10
189
190/*
191 * The architecture-specific register number that contains the return
192 * address in the .debug_frame table.
193 */
194#define DWARF_ARCH_RA_REG 17
195
196/*
197 * At what offset into dwarf_unwind_stack() is DWARF_ARCH_RA_REG setup?
198 */
199#define DWARF_ARCH_UNWIND_OFFSET 0x20
200
201#ifndef __ASSEMBLY__
202/*
203 * Read either the frame pointer (r14) or the stack pointer (r15).
204 * NOTE: this MUST be inlined.
205 */
206static __always_inline unsigned long dwarf_read_arch_reg(unsigned int reg)
207{
208 unsigned long value;
209
210 switch (reg) {
211 case 14:
212 __asm__ __volatile__("mov r14, %0\n" : "=r" (value));
213 break;
214 case 15:
215 __asm__ __volatile__("mov r15, %0\n" : "=r" (value));
216 break;
217 default:
218 BUG();
219 }
220
221 return value;
222}
223
224/**
225 * dwarf_cie - Common Information Entry
226 */
227struct dwarf_cie {
228 unsigned long length;
229 unsigned long cie_id;
230 unsigned char version;
231 const char *augmentation;
232 unsigned int code_alignment_factor;
233 int data_alignment_factor;
234
235 /* Which column in the rule table represents return addr of func. */
236 unsigned int return_address_reg;
237
238 unsigned char *initial_instructions;
239 unsigned char *instructions_end;
240
241 unsigned char encoding;
242
243 unsigned long cie_pointer;
244
245 struct list_head link;
246
247 unsigned long flags;
248#define DWARF_CIE_Z_AUGMENTATION (1 << 0)
249};
250
251/**
252 * dwarf_fde - Frame Description Entry
253 */
254struct dwarf_fde {
255 unsigned long length;
256 unsigned long cie_pointer;
257 struct dwarf_cie *cie;
258 unsigned long initial_location;
259 unsigned long address_range;
260 unsigned char *instructions;
261 unsigned char *end;
262 struct list_head link;
263};
264
265/**
266 * dwarf_frame - DWARF information for a frame in the call stack
267 */
268struct dwarf_frame {
269 struct dwarf_frame *prev, *next;
270
271 unsigned long pc;
272
273 struct dwarf_reg *regs;
274 unsigned int num_regs; /* how many regs are allocated? */
275
276 unsigned int depth; /* what level are we in the callstack? */
277
278 unsigned long cfa;
279
280 /* Valid when DW_FRAME_CFA_REG_OFFSET is set in flags */
281 unsigned int cfa_register;
282 unsigned int cfa_offset;
283
284 /* Valid when DW_FRAME_CFA_REG_EXP is set in flags */
285 unsigned char *cfa_expr;
286 unsigned int cfa_expr_len;
287
288 unsigned long flags;
289#define DWARF_FRAME_CFA_REG_OFFSET (1 << 0)
290#define DWARF_FRAME_CFA_REG_EXP (1 << 1)
291
292 unsigned long return_addr;
293};
294
295/**
296 * dwarf_reg - DWARF register
297 * @flags: Describes how to calculate the value of this register
298 */
299struct dwarf_reg {
300 unsigned long addr;
301 unsigned long flags;
302#define DWARF_REG_OFFSET (1 << 0)
303};
304
305/**
306 * dwarf_stack - a DWARF stack contains a collection of DWARF frames
307 * @depth: the number of frames in the stack
308 * @level: an array of DWARF frames, indexed by stack level
309 *
310 */
311struct dwarf_stack {
312 unsigned int depth;
313 struct dwarf_frame **level;
314};
315
316/*
317 * Call Frame instruction opcodes.
318 */
319#define DW_CFA_advance_loc 0x40
320#define DW_CFA_offset 0x80
321#define DW_CFA_restore 0xc0
322#define DW_CFA_nop 0x00
323#define DW_CFA_set_loc 0x01
324#define DW_CFA_advance_loc1 0x02
325#define DW_CFA_advance_loc2 0x03
326#define DW_CFA_advance_loc4 0x04
327#define DW_CFA_offset_extended 0x05
328#define DW_CFA_restore_extended 0x06
329#define DW_CFA_undefined 0x07
330#define DW_CFA_same_value 0x08
331#define DW_CFA_register 0x09
332#define DW_CFA_remember_state 0x0a
333#define DW_CFA_restore_state 0x0b
334#define DW_CFA_def_cfa 0x0c
335#define DW_CFA_def_cfa_register 0x0d
336#define DW_CFA_def_cfa_offset 0x0e
337#define DW_CFA_def_cfa_expression 0x0f
338#define DW_CFA_expression 0x10
339#define DW_CFA_offset_extended_sf 0x11
340#define DW_CFA_def_cfa_sf 0x12
341#define DW_CFA_def_cfa_offset_sf 0x13
342#define DW_CFA_val_offset 0x14
343#define DW_CFA_val_offset_sf 0x15
344#define DW_CFA_val_expression 0x16
345#define DW_CFA_lo_user 0x1c
346#define DW_CFA_hi_user 0x3f
347
348/*
349 * Some call frame instructions encode their operands in the opcode. We
350 * need some helper functions to extract both the opcode and operands
351 * from an instruction.
352 */
353static inline unsigned int DW_CFA_opcode(unsigned long insn)
354{
355 return (insn & 0xc0);
356}
357
358static inline unsigned int DW_CFA_operand(unsigned long insn)
359{
360 return (insn & 0x3f);
361}
362
363#define DW_EH_FRAME_CIE 0 /* .eh_frame CIE IDs are 0 */
364#define DW_CIE_ID 0xffffffff
365#define DW64_CIE_ID 0xffffffffffffffffULL
366
367/*
368 * DWARF FDE/CIE length field values.
369 */
370#define DW_EXT_LO 0xfffffff0
371#define DW_EXT_HI 0xffffffff
372#define DW_EXT_DWARF64 DW_EXT_HI
373
374extern void dwarf_unwinder_init(void);
375
376extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
377 struct dwarf_frame *);
378#endif /* __ASSEMBLY__ */
379
380#define CFI_STARTPROC .cfi_startproc
381#define CFI_ENDPROC .cfi_endproc
382#define CFI_DEF_CFA .cfi_def_cfa
383#define CFI_REGISTER .cfi_register
384#define CFI_REL_OFFSET .cfi_rel_offset
385
386#else
387
388/*
389 * Use the asm comment character to ignore the rest of the line.
390 */
391#define CFI_IGNORE !
392
393#define CFI_STARTPROC CFI_IGNORE
394#define CFI_ENDPROC CFI_IGNORE
395#define CFI_DEF_CFA CFI_IGNORE
396#define CFI_REGISTER CFI_IGNORE
397#define CFI_REL_OFFSET CFI_IGNORE
398
399#ifndef __ASSEMBLY__
400static inline void dwarf_unwinder_init(void)
401{
402}
403#endif
404
405#endif /* CONFIG_DWARF_UNWINDER */
406
407#endif /* __ASM_SH_DWARF_H */
diff --git a/arch/sh/include/asm/sections.h b/arch/sh/include/asm/sections.h
index 01a4076a371..a78701da775 100644
--- a/arch/sh/include/asm/sections.h
+++ b/arch/sh/include/asm/sections.h
@@ -7,6 +7,7 @@ extern void __nosave_begin, __nosave_end;
7extern long __machvec_start, __machvec_end; 7extern long __machvec_start, __machvec_end;
8extern char __uncached_start, __uncached_end; 8extern char __uncached_start, __uncached_end;
9extern char _ebss[]; 9extern char _ebss[];
10extern char __start_eh_frame[], __stop_eh_frame[];
10 11
11#endif /* __ASM_SH_SECTIONS_H */ 12#endif /* __ASM_SH_SECTIONS_H */
12 13
diff --git a/arch/sh/include/asm/vmlinux.lds.h b/arch/sh/include/asm/vmlinux.lds.h
new file mode 100644
index 00000000000..244ec4ad9a7
--- /dev/null
+++ b/arch/sh/include/asm/vmlinux.lds.h
@@ -0,0 +1,17 @@
1#ifndef __ASM_SH_VMLINUX_LDS_H
2#define __ASM_SH_VMLINUX_LDS_H
3
4#include <asm-generic/vmlinux.lds.h>
5
6#ifdef CONFIG_DWARF_UNWINDER
7#define DWARF_EH_FRAME \
8 .eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) { \
9 VMLINUX_SYMBOL(__start_eh_frame) = .; \
10 *(.eh_frame) \
11 VMLINUX_SYMBOL(__stop_eh_frame) = .; \
12 }
13#else
14#define DWARF_EH_FRAME
15#endif
16
17#endif /* __ASM_SH_VMLINUX_LDS_H */