backtrace.c 2.7 KB

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