1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/kernel.h>
16#include <linux/string.h>
17#include <asm/byteorder.h>
18#include <asm/backtrace.h>
19#include <asm/tile-desc.h>
20#include <arch/abi.h>
21
22#ifdef __tilegx__
23#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
24#define tile_decoded_instruction tilegx_decoded_instruction
25#define tile_mnemonic tilegx_mnemonic
26#define parse_insn_tile parse_insn_tilegx
27#define TILE_OPC_IRET TILEGX_OPC_IRET
28#define TILE_OPC_ADDI TILEGX_OPC_ADDI
29#define TILE_OPC_ADDLI TILEGX_OPC_ADDLI
30#define TILE_OPC_INFO TILEGX_OPC_INFO
31#define TILE_OPC_INFOL TILEGX_OPC_INFOL
32#define TILE_OPC_JRP TILEGX_OPC_JRP
33#define TILE_OPC_MOVE TILEGX_OPC_MOVE
34#define OPCODE_STORE TILEGX_OPC_ST
35typedef long long bt_int_reg_t;
36#else
37#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE
38#define tile_decoded_instruction tilepro_decoded_instruction
39#define tile_mnemonic tilepro_mnemonic
40#define parse_insn_tile parse_insn_tilepro
41#define TILE_OPC_IRET TILEPRO_OPC_IRET
42#define TILE_OPC_ADDI TILEPRO_OPC_ADDI
43#define TILE_OPC_ADDLI TILEPRO_OPC_ADDLI
44#define TILE_OPC_INFO TILEPRO_OPC_INFO
45#define TILE_OPC_INFOL TILEPRO_OPC_INFOL
46#define TILE_OPC_JRP TILEPRO_OPC_JRP
47#define TILE_OPC_MOVE TILEPRO_OPC_MOVE
48#define OPCODE_STORE TILEPRO_OPC_SW
49typedef int bt_int_reg_t;
50#endif
51
52
53struct BacktraceBundle {
54 tile_bundle_bits bits;
55 int num_insns;
56 struct tile_decoded_instruction
57 insns[TILE_MAX_INSTRUCTIONS_PER_BUNDLE];
58};
59
60
61
62
63
64
65static const struct tile_decoded_instruction *find_matching_insn(
66 const struct BacktraceBundle *bundle,
67 tile_mnemonic mnemonic,
68 const int *operand_values,
69 int num_operands_to_match)
70{
71 int i, j;
72 bool match;
73
74 for (i = 0; i < bundle->num_insns; i++) {
75 const struct tile_decoded_instruction *insn =
76 &bundle->insns[i];
77
78 if (insn->opcode->mnemonic != mnemonic)
79 continue;
80
81 match = true;
82 for (j = 0; j < num_operands_to_match; j++) {
83 if (operand_values[j] != insn->operand_values[j]) {
84 match = false;
85 break;
86 }
87 }
88
89 if (match)
90 return insn;
91 }
92
93 return NULL;
94}
95
96
97static inline bool bt_has_iret(const struct BacktraceBundle *bundle)
98{
99 return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL;
100}
101
102
103
104
105static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
106{
107 static const int vals[2] = { TREG_SP, TREG_SP };
108
109 const struct tile_decoded_instruction *insn =
110 find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2);
111 if (insn == NULL)
112 insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2);
113#ifdef __tilegx__
114 if (insn == NULL)
115 insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2);
116 if (insn == NULL)
117 insn = find_matching_insn(bundle, TILEGX_OPC_ADDXI, vals, 2);
118#endif
119 if (insn == NULL)
120 return false;
121
122 *adjust = insn->operand_values[2];
123 return true;
124}
125
126
127
128
129
130
131static int bt_get_info_ops(const struct BacktraceBundle *bundle,
132 int operands[MAX_INFO_OPS_PER_BUNDLE])
133{
134 int num_ops = 0;
135 int i;
136
137 for (i = 0; i < bundle->num_insns; i++) {
138 const struct tile_decoded_instruction *insn =
139 &bundle->insns[i];
140
141 if (insn->opcode->mnemonic == TILE_OPC_INFO ||
142 insn->opcode->mnemonic == TILE_OPC_INFOL) {
143 operands[num_ops++] = insn->operand_values[0];
144 }
145 }
146
147 return num_ops;
148}
149
150
151
152
153static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
154{
155 const struct tile_decoded_instruction *insn =
156 find_matching_insn(bundle, TILE_OPC_JRP, NULL, 0);
157 if (insn == NULL)
158 return false;
159
160 *target_reg = insn->operand_values[0];
161 return true;
162}
163
164
165static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
166{
167 int i, j;
168 for (i = 0; i < bundle->num_insns; i++) {
169 const struct tile_decoded_instruction *insn =
170 &bundle->insns[i];
171
172 if (insn->opcode->implicitly_written_register == reg)
173 return true;
174
175 for (j = 0; j < insn->opcode->num_operands; j++)
176 if (insn->operands[j]->is_dest_reg &&
177 insn->operand_values[j] == reg)
178 return true;
179 }
180
181 return false;
182}
183
184
185static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle)
186{
187 return bt_modifies_reg(bundle, TREG_SP);
188}
189
190
191static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle)
192{
193 return bt_modifies_reg(bundle, TREG_LR);
194}
195
196
197static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle)
198{
199 static const int vals[2] = { 52, TREG_SP };
200 return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL;
201}
202
203
204static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle)
205{
206 static const int vals[2] = { TREG_SP, TREG_LR };
207 return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL;
208}
209
210#ifdef __tilegx__
211
212static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
213 int moveli_args[])
214{
215 int i;
216 for (i = 0; i < bundle->num_insns; i++) {
217 const struct tile_decoded_instruction *insn =
218 &bundle->insns[i];
219
220 if (insn->opcode->mnemonic == TILEGX_OPC_MOVELI) {
221 int reg = insn->operand_values[0];
222 moveli_args[reg] = insn->operand_values[1];
223 }
224 }
225}
226
227
228
229
230
231static bool bt_has_add_sp(const struct BacktraceBundle *bundle, int *adjust,
232 int moveli_args[])
233{
234 static const int vals[2] = { TREG_SP, TREG_SP };
235
236 const struct tile_decoded_instruction *insn =
237 find_matching_insn(bundle, TILEGX_OPC_ADDX, vals, 2);
238 if (insn) {
239 int reg = insn->operand_values[2];
240 if (moveli_args[reg]) {
241 *adjust = moveli_args[reg];
242 return true;
243 }
244 }
245 return false;
246}
247#endif
248
249
250
251
252static void find_caller_pc_and_caller_sp(CallerLocation *location,
253 const unsigned long start_pc,
254 BacktraceMemoryReader read_memory_func,
255 void *read_memory_func_extra)
256{
257
258
259
260 bool sp_determined = false;
261
262
263 bool lr_modified = false;
264
265
266 bool sp_moved_to_r52 = false;
267
268
269 bool seen_terminating_bundle = false;
270
271
272
273
274 tile_bundle_bits prefetched_bundles[32];
275 int num_bundles_prefetched = 0;
276 int next_bundle = 0;
277 unsigned long pc;
278
279#ifdef __tilegx__
280
281 int moveli_args[TILEGX_NUM_REGISTERS] = { 0 };
282#endif
283
284
285
286
287
288 location->sp_location = SP_LOC_OFFSET;
289 location->sp_offset = 0;
290
291
292 location->pc_location = PC_LOC_UNKNOWN;
293
294
295 if (start_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0)
296 return;
297
298 for (pc = start_pc;; pc += sizeof(tile_bundle_bits)) {
299
300 struct BacktraceBundle bundle;
301 int num_info_ops, info_operands[MAX_INFO_OPS_PER_BUNDLE];
302 int one_ago, jrp_reg;
303 bool has_jrp;
304
305 if (next_bundle >= num_bundles_prefetched) {
306
307
308
309
310
311
312
313 unsigned int bytes_to_prefetch = 4096 - (pc & 4095);
314 if (bytes_to_prefetch > sizeof prefetched_bundles)
315 bytes_to_prefetch = sizeof prefetched_bundles;
316
317 if (!read_memory_func(prefetched_bundles, pc,
318 bytes_to_prefetch,
319 read_memory_func_extra)) {
320 if (pc == start_pc) {
321
322
323
324
325
326
327 location->pc_location = PC_LOC_IN_LR;
328 return;
329 }
330
331
332 break;
333 }
334
335 next_bundle = 0;
336 num_bundles_prefetched =
337 bytes_to_prefetch / sizeof(tile_bundle_bits);
338 }
339
340
341
342
343
344
345 bundle.bits = le64_to_cpu(prefetched_bundles[next_bundle++]);
346 bundle.num_insns =
347 parse_insn_tile(bundle.bits, pc, bundle.insns);
348 num_info_ops = bt_get_info_ops(&bundle, info_operands);
349
350
351
352
353 for (one_ago = (pc != start_pc) ? 1 : 0;
354 one_ago >= 0; one_ago--) {
355 int i;
356 for (i = 0; i < num_info_ops; i++) {
357 int info_operand = info_operands[i];
358 if (info_operand < CALLER_UNKNOWN_BASE) {
359
360 continue;
361 }
362
363
364
365
366 if (((info_operand & ONE_BUNDLE_AGO_FLAG) != 0)
367 != (one_ago != 0))
368 continue;
369
370
371
372 info_operand &= ~ONE_BUNDLE_AGO_FLAG;
373
374
375 if (info_operand & PC_IN_LR_FLAG)
376 location->pc_location =
377 PC_LOC_IN_LR;
378 else
379 location->pc_location =
380 PC_LOC_ON_STACK;
381
382 switch (info_operand) {
383 case CALLER_UNKNOWN_BASE:
384 location->pc_location = PC_LOC_UNKNOWN;
385 location->sp_location = SP_LOC_UNKNOWN;
386 return;
387
388 case CALLER_SP_IN_R52_BASE:
389 case CALLER_SP_IN_R52_BASE | PC_IN_LR_FLAG:
390 location->sp_location = SP_LOC_IN_R52;
391 return;
392
393 default:
394 {
395 const unsigned int val = info_operand
396 - CALLER_SP_OFFSET_BASE;
397 const unsigned int sp_offset =
398 (val >> NUM_INFO_OP_FLAGS) * 8;
399 if (sp_offset < 32768) {
400
401
402 location->sp_location =
403 SP_LOC_OFFSET;
404 location->sp_offset =
405 sp_offset;
406 return;
407 } else {
408
409
410
411
412
413
414 }
415 }
416 break;
417 }
418 }
419 }
420
421 if (seen_terminating_bundle) {
422
423
424
425 break;
426 }
427
428 if (bundle.bits == 0) {
429
430
431
432 break;
433 }
434
435
436
437
438
439 if (!sp_determined) {
440 int adjust;
441 if (bt_has_addi_sp(&bundle, &adjust)
442#ifdef __tilegx__
443 || bt_has_add_sp(&bundle, &adjust, moveli_args)
444#endif
445 ) {
446 location->sp_location = SP_LOC_OFFSET;
447
448 if (adjust <= 0) {
449
450
451 location->sp_offset = 0;
452 } else {
453
454 location->sp_offset = adjust;
455 }
456
457 sp_determined = true;
458 } else {
459 if (bt_has_move_r52_sp(&bundle)) {
460
461
462
463
464
465 sp_moved_to_r52 = true;
466 }
467
468 if (bt_modifies_sp(&bundle)) {
469 if (sp_moved_to_r52) {
470
471
472
473
474
475
476
477 location->sp_location =
478 SP_LOC_OFFSET;
479 location->sp_offset = 0;
480 } else {
481
482
483
484
485
486 location->sp_location =
487 SP_LOC_IN_R52;
488 }
489 sp_determined = true;
490 }
491 }
492
493#ifdef __tilegx__
494
495 bt_update_moveli(&bundle, moveli_args);
496#endif
497 }
498
499 if (bt_has_iret(&bundle)) {
500
501 seen_terminating_bundle = true;
502 continue;
503 }
504
505
506
507
508
509 jrp_reg = -1;
510 has_jrp = bt_has_jrp(&bundle, &jrp_reg);
511 if (has_jrp)
512 seen_terminating_bundle = true;
513
514 if (location->pc_location == PC_LOC_UNKNOWN) {
515 if (has_jrp) {
516 if (jrp_reg == TREG_LR && !lr_modified) {
517
518
519 location->pc_location =
520 PC_LOC_IN_LR;
521 } else {
522 location->pc_location =
523 PC_LOC_ON_STACK;
524 }
525 } else if (bt_has_sw_sp_lr(&bundle)) {
526
527 location->pc_location = PC_LOC_IN_LR;
528 } else if (bt_modifies_lr(&bundle)) {
529 lr_modified = true;
530 }
531 }
532 }
533}
534
535
536
537
538
539
540
541
542
543
544
545
546
547void backtrace_init(BacktraceIterator *state,
548 BacktraceMemoryReader read_memory_func,
549 void *read_memory_func_extra,
550 unsigned long pc, unsigned long lr,
551 unsigned long sp, unsigned long r52)
552{
553 CallerLocation location;
554 unsigned long fp, initial_frame_caller_pc;
555
556
557 find_caller_pc_and_caller_sp(&location, pc,
558 read_memory_func, read_memory_func_extra);
559
560 switch (location.sp_location) {
561 case SP_LOC_UNKNOWN:
562
563 fp = -1;
564 break;
565
566 case SP_LOC_IN_R52:
567 fp = r52;
568 break;
569
570 case SP_LOC_OFFSET:
571 fp = sp + location.sp_offset;
572 break;
573
574 default:
575
576 fp = -1;
577 break;
578 }
579
580
581
582
583 if (fp % sizeof(bt_int_reg_t) != 0)
584 fp = -1;
585
586
587 initial_frame_caller_pc = -1;
588
589 switch (location.pc_location) {
590 case PC_LOC_UNKNOWN:
591
592 fp = -1;
593 break;
594
595 case PC_LOC_IN_LR:
596 if (lr == 0 || lr % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0) {
597
598 fp = -1;
599 } else {
600 initial_frame_caller_pc = lr;
601 }
602 break;
603
604 case PC_LOC_ON_STACK:
605
606
607
608 break;
609
610 default:
611
612 fp = -1;
613 break;
614 }
615
616 state->pc = pc;
617 state->sp = sp;
618 state->fp = fp;
619 state->initial_frame_caller_pc = initial_frame_caller_pc;
620 state->read_memory_func = read_memory_func;
621 state->read_memory_func_extra = read_memory_func_extra;
622}
623
624
625static bool valid_addr_reg(bt_int_reg_t reg)
626{
627 return ((unsigned long)reg == reg);
628}
629
630
631
632
633bool backtrace_next(BacktraceIterator *state)
634{
635 unsigned long next_fp, next_pc;
636 bt_int_reg_t next_frame[2];
637
638 if (state->fp == -1) {
639
640 return false;
641 }
642
643
644 if (!state->read_memory_func(&next_frame, state->fp, sizeof next_frame,
645 state->read_memory_func_extra)) {
646 return false;
647 }
648
649 next_fp = next_frame[1];
650 if (!valid_addr_reg(next_frame[1]) ||
651 next_fp % sizeof(bt_int_reg_t) != 0) {
652
653 return false;
654 }
655
656 if (state->initial_frame_caller_pc != -1) {
657
658
659
660 next_pc = state->initial_frame_caller_pc;
661
662
663
664
665
666 state->initial_frame_caller_pc = -1;
667 } else {
668
669 next_pc = next_frame[0];
670 if (!valid_addr_reg(next_frame[0]) || next_pc == 0 ||
671 next_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0) {
672
673 return false;
674 }
675 }
676
677
678 state->pc = next_pc;
679 state->sp = state->fp;
680 state->fp = next_fp;
681
682 return true;
683}
684