@@ -8,14 +8,6 @@ import (
88const STACK_SIZE = 2 * 1024
99const STACK_SIZE_PTRS = STACK_SIZE / unsafe .Sizeof (uintptr )
1010
11- // TODO
12- const GOARCH = "arm"
13-
14- // Choose which undwinder implementation to use. "armdecode" is the one that
15- // actually works at the moment.
16- const UNWINDER = "armdecode"
17- //const UNWINDER = "exidx"
18-
1911// Must be the same as defer_t in tinygo.h.
2012type deferred struct {
2113fn unsafe.Pointer
@@ -62,209 +54,6 @@ func tinygo_get_code_bounds() (uintptr, uintptr) __asm__("tinygo_get_code_bounds
6254func tinygo_get_unwind_sections () (uintptr , uintptr ) __asm__ ("tinygo_get_unwind_sections" )
6355func exit (int ) __asm__ ("exit" )
6456
65- func unwind_armdecode (r * goroutine , pc uintptr , sp int ) {
66- stext , etext := tinygo_get_code_bounds ()
67- lr := uintptr (0 )
68- pc_call := pc
69- for sp >= 0 && sp < len (r .stack ) && pc >= stext && pc < etext {
70- pc -= 4
71- instr := * (* uint32 )(unsafe .Pointer (pc ))
72- //printf("unwinding... PC=%p SP=%p LR=%p: ", pc, sp, lr);
73- if ((instr >> 16 ) & 0xffff ) == 0xe92d { // STMFD sp!, {...}: P=1, U=0, S=0, W=1, L=0
74- // STM is: 1110 100P USWL Rn reglist...
75- // cond
76- // Note: condition code 1110 means "always"
77- //printf("STMFD sp!, {...}\n"); // aka push
78- for i := uint (0 ); i < 16 ; i ++ {
79- if (instr >> i ) & 1 == 1 {
80- //printf("\tr%-2d = %x\n", i, *sp);
81- if i == 14 {
82- lr = r .stack [sp ] - 4
83- // We have found the link register.
84- // Note that we will continue walking up, as there
85- // might be more SP-altering instructions (but
86- // we'll break at the first unrecognized/non-SP-
87- // related function as that means we're past the
88- // prologue).
89- }
90- // reading back so reversing direction
91- sp += 1
92- }
93- }
94- } else if (((instr >> 12 ) & 0xffeff ) == 0xe24dd ) { // SUB sp, sp, #imm
95- imm := instr & 0xff
96- shift := (instr >> 8 ) & 0xf
97- //printf("SUB sp, sp, #%d\n", imm << shift);
98- sp += int (imm << shift ) / 4 // reverse operation, so ADD instead of SUB
99- } else {
100- //printf("unknown instruction\n");
101- if lr != 0 {
102- // Done with this function. Let's move up a stack frame!
103- // But first print the stack trace frame.
104- if tinygo_print_stackitem (r , pc + 4 , pc_call + 4 , sp ) {
105- // We're done: this is the last frame.
106- return
107- }
108- pc = lr
109- //printf("next LR: %p\n", lr);
110- lr = 0
111- pc_call = pc
112- }
113- }
114- }
115-
116- // SP or PC was out of range, probably an error while walking the
117- // stack.
118- tinygo_unwind_fail (pc , "pc or sp out of range" )
119- }
120-
121- type exidxEntry struct {
122- address uintptr
123- command uintptr
124- }
125-
126- type decoder struct {
127- lr uintptr
128- pc uintptr
129- sp int
130- }
131-
132- // Decode takes a stream of unwind instructions (possibly unbounded) and decodes
133- // them until the first finish or unrecognized instruction. It returns true on
134- // failure.
135- func (d * decoder ) decode (r * goroutine , instructions []byte ) bool {
136- // See section 9.3, "Frame unwinding instructions":
137- // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
138-
139- for i := 0 ; i < len (instructions ); i ++ {
140- instr := instructions [i ]
141- // Interpret stack unwinding instructions.
142- // This is something quite different from ARM instructions.
143- //println(" ", hex(uintptr(instr)))
144- switch {
145- case instr & 0xc0 == 0x00 : // 00xxxxxx
146- imm := int (instr & 0x3f )
147- d .sp = d .sp + imm + 1
148- //println("\tsp +=", (imm << 2) + 4)
149- case instr & 0xf8 == 0xa8 : // 10101nnn
150- imm := int (instr & 0x07 )
151- // pop r4-r[4+nnn], r14
152- d .sp += imm * 1 + 1
153- d .lr = r .stack [d .sp ]
154- //println("\tpop PC:", hex(d.lr), "registers:", imm + 1)
155- case instr == 0xb0 : // 10110000: finish
156- break
157- case instr & 0xf0 == 0x80 :
158- i ++
159- regs := (uintptr (instr & 0x0f ) << 8 ) | uintptr (instructions [i ])
160- for regnr := uint (15 ); regnr >= 4 ; regnr -- {
161- if (regs >> (regnr - 4 )) & 1 == 1 {
162- //println("\t\tpop reg:", regnr)
163- d .sp ++
164- if regnr == 14 { // lr
165- d .lr = r .stack [d .sp ]
166- }
167- if regnr == 13 { // pc
168- return true // TODO
169- }
170- }
171- }
172- default :
173- //println("\tunknown unwind instruction:", hex(uintptr(instr)))
174- return true
175- }
176- }
177-
178- // implicit finish instruction
179- d .pc = d .lr
180- return false
181- }
182-
183- func unwind_exidx (r * goroutine , pc uintptr , sp int ) {
184- // Scan trough the unwind table until we've found the right PC.
185- // https://wiki.linaro.org/KenWerner/Sandbox/libunwind?action=AttachFile&do=get&target=libunwind-LDS.pdf
186- // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
187-
188- // Load .ARM.exidx from __exidx_start and __exidx_end and create a slice
189- // with exactly the contents of it.
190- // https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
191- stext , etext := tinygo_get_code_bounds ()
192- exidx_start , exidx_end := tinygo_get_unwind_sections ()
193- size := (exidx_end - exidx_start ) / 4
194- exidx := (* [1 << 30 ]exidxEntry )(unsafe .Pointer (exidx_start ))[:size / 2 :size / 2 ]
195- _ = exidx
196-
197- d := decoder {pc : pc , sp : sp }
198-
199- for d .sp >= 0 && d .sp < len (r .stack ) && d .pc >= stext && d .pc < etext {
200- entry := exidxEntry {}
201- functionAddress := uintptr (0 )
202- entryNum := - 1
203-
204- // Do a linear scan for the right function.
205- // We could improve here with a binary search when performance becomes
206- // an issue, but a linear scan is easier to implement right now.
207- //println("\nsearching for address:", hex(d.pc - 4))
208- for i , e := range exidx {
209- addr := e .address + exidx_start + uintptr (i ) * 8 - (1 << 31 )
210- //println(" found address + command:", i, hex(addr), hex(e.command))
211- if addr > d .pc - 4 {
212- //println("\tcheck")
213- break
214- }
215- entry = e
216- functionAddress = addr
217- entryNum = i
218- }
219- //println("using entry for address:", hex(functionAddress), "raw:", hex(entry.address), hex(entry.command))
220-
221- if tinygo_print_stackitem (r , functionAddress , d .pc , d .sp ) {
222- // We're done: this is the last frame.
223- return
224- }
225-
226- if entry .command == 1 {
227- tinygo_unwind_fail (d .pc - 4 , "not in unwind table" )
228- return
229- } else if entry .command >> 31 == 1 {
230- //println("function encoded inline:", hex(entry.command))
231- // Obtain unwind instructions
232- instructions := []byte {
233- byte (entry .command >> 16 ),
234- byte (entry .command >> 8 ),
235- byte (entry .command )}
236- _ = instructions
237- if d .decode (r , instructions ) {
238- tinygo_unwind_fail (d .pc - 4 , "unknown unwind instruction" )
239- return
240- }
241- } else {
242- // Pointer to the exidx table.
243- _ = entryNum
244- //exidxAddress := entry.command + exidx_start + uintptr(entryNum) * 8 - (1 << 31) + 4
245- //println("function encoded externally:", hex(exidxAddress), hex(entry.command), entryNum)
246-
247- // Pointer to the personality function.
248- //personalityAddressRelative := *(*uintptr)(unsafe.Pointer(exidxAddress))
249- //personalityAddress := exidxAddress - ((1 << 31) - personalityAddressRelative)
250- //println(hex(personalityAddressRelative), hex(personalityAddress))
251-
252- // Now we're supposed to call the personality function, I think.
253-
254- // Construct a byteslice from the pointer in `address`.
255- // TODO: length of slice
256- //instructions := (*[1 << 30]byte)(unsafe.Pointer(exidxAddress + 4))[:256:256]
257- //if d.decode(r, instructions) {
258- // break
259- //}
260- tinygo_unwind_fail (d .pc - 4 , "external unwind instructions" )
261- return
262- }
263- }
264-
265- tinygo_unwind_fail (d .pc - 4 , "pc or sp out of range" )
266- }
267-
26857func Panic (msg interface {}, fatal bool ) {
26958if ! fatal {
27059// TODO: actually unwind the stack and call __go_undefer where
@@ -280,17 +69,8 @@ func Panic(msg interface{}, fatal bool) {
28069println ()
28170
28271println ("\n goroutine" , GR .num , "[running]:" )
283- pc , _sp := tinygo_get_lr_sp ()
284- _sp_base := uintptr (unsafe .Pointer (& GR .stack [0 ]))
285- sp := int ((_sp - _sp_base ) / 4 )
28672
287- if UNWINDER == "armdecode" {
288- unwind_armdecode (GR , pc , sp )
289- } else if UNWINDER == "exidx" {
290- unwind_exidx (GR , pc , sp )
291- } else {
292- panic ("unreachable" )
293- }
73+ unwind (GR )
29474
29575if fatal {
29676exit (1 )
0 commit comments