backtrace.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. */
  9. #include <rtthread.h>
  10. #ifdef RT_USING_SMART
  11. #include <lwp_arch.h>
  12. #define TRANCE_LEVEL 20
  13. extern rt_ubase_t __text_start[];
  14. extern rt_ubase_t __text_end[];
  15. static char *_get_elf_name(size_t sepc);
  16. void rt_hw_backtrace(rt_uint32_t *ffp, rt_ubase_t sepc)
  17. {
  18. rt_ubase_t *ra;
  19. rt_ubase_t *fp;
  20. rt_ubase_t vas, vae;
  21. int i, j;
  22. rt_kprintf("riscv64-unknown-linux-musl-addr2line -e %s -a -f", _get_elf_name(sepc));
  23. fp = (rt_ubase_t *)ffp;
  24. if (!fp)
  25. {
  26. asm volatile("mv %0, s0"
  27. : "=r"(fp));
  28. }
  29. if (sepc)
  30. {
  31. rt_kprintf(" %p", sepc - 0x4);
  32. }
  33. if (fp > (rt_ubase_t *)USER_VADDR_START && fp < (rt_ubase_t *)USER_VADDR_TOP)
  34. {
  35. vas = USER_VADDR_START;
  36. vae = USER_VADDR_TOP;
  37. }
  38. else
  39. {
  40. vas = (rt_ubase_t)&__text_start;
  41. vae = (rt_ubase_t)&__text_end;
  42. }
  43. for (i = j = 0; i < TRANCE_LEVEL; i++)
  44. {
  45. if (RT_ALIGN((rt_ubase_t)fp, sizeof(void *)) != (rt_ubase_t)fp)
  46. {
  47. break;
  48. }
  49. ra = fp - 1;
  50. if (!rt_kmem_v2p(ra) || *ra < vas || *ra > vae)
  51. break;
  52. rt_kprintf(" %p", *ra - 0x04);
  53. fp = fp - 2;
  54. if (!rt_kmem_v2p(fp))
  55. break;
  56. fp = (rt_ubase_t *)(*fp);
  57. if (!fp)
  58. break;
  59. }
  60. rt_kputs("\r\n");
  61. }
  62. static void _assert_backtrace_cb(const char *ex, const char *func, rt_size_t line)
  63. {
  64. rt_hw_interrupt_disable();
  65. rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex, func, line);
  66. rt_hw_backtrace(0, 0);
  67. rt_hw_cpu_shutdown();
  68. }
  69. static int rt_hw_backtrace_init(void)
  70. {
  71. rt_assert_set_hook(_assert_backtrace_cb);
  72. return 0;
  73. }
  74. INIT_BOARD_EXPORT(rt_hw_backtrace_init);
  75. static void backtrace_test(int args, char *argv[])
  76. {
  77. int *p = (void *)-1;
  78. init_fn_t ft = 0;
  79. if (args < 2)
  80. {
  81. rt_kprintf("backtrace_test usage:backtrace_test a(assert)/m(invalid memory)/i(illegal instruction)\r\n");
  82. return;
  83. }
  84. if (!rt_strcmp(argv[1], "a"))
  85. {
  86. rt_kprintf("Assert test:\r\n", argv[1]);
  87. RT_ASSERT(0);
  88. }
  89. else if (!rt_strcmp(argv[1], "m"))
  90. {
  91. rt_kprintf("Access invalid memory:\r\n", argv[1]);
  92. *p = 0;
  93. }
  94. else if (!rt_strcmp(argv[1], "i"))
  95. {
  96. rt_kprintf("Illegal instruction:\r\n", argv[1]);
  97. ft();
  98. }
  99. else
  100. {
  101. rt_kprintf("Unknown cmd :%s.\r\n", argv[1]);
  102. }
  103. }
  104. MSH_CMD_EXPORT(backtrace_test, backtrace test case);
  105. extern struct rt_thread *rt_current_thread;
  106. #define IN_USERSPACE (sepc > USER_VADDR_START && sepc < USER_VADDR_TOP)
  107. static char *_get_elf_name(size_t sepc)
  108. {
  109. return IN_USERSPACE ? rt_current_thread->parent.name : "rtthread.elf";
  110. }
  111. #endif /* RT_USING_SMART */