debug_symbol.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * kallsyms.c: in-kernel printing of symbolic oopses and stack traces.
  4. *
  5. * Rewritten and vastly simplified by Rusty Russell for in-kernel
  6. * module loader:
  7. * Copyright 2002 Rusty Russell <[email protected]> IBM Corporation
  8. *
  9. * ChangeLog:
  10. *
  11. * (25/Aug/2004) Paulo Marques <[email protected]>
  12. * Changed the compression method from stem compression to "table lookup"
  13. * compression (see scripts/kallsyms.c for a more complete description)
  14. *
  15. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  16. * This driver is based on Google Debug Kinfo Driver
  17. */
  18. #define pr_fmt(fmt) "DebugSymbol: " fmt
  19. #include <linux/init.h>
  20. #include <linux/kernel.h>
  21. #include <linux/module.h>
  22. #include <linux/string.h>
  23. #include <linux/of.h>
  24. #include <linux/of_address.h>
  25. #include <linux/of_reserved_mem.h>
  26. #include <linux/kallsyms.h>
  27. #include "debug_symbol.h"
  28. #include "../../android/debug_kinfo.h"
  29. struct debug_symbol_data {
  30. const unsigned long *addresses;
  31. const int *offsets;
  32. const u8 *names;
  33. unsigned int num_syms;
  34. unsigned long relative_base;
  35. const char *token_table;
  36. const u16 *token_index;
  37. const unsigned int *markers;
  38. };
  39. static struct debug_symbol_data debug_symbol;
  40. static void *debug_symbol_vaddr;
  41. static void fill_ds_entries(void);
  42. struct ds_entry {
  43. char *name;
  44. unsigned long addr;
  45. };
  46. #define DS_ENTRY(symbol) \
  47. { .name = #symbol, .addr = 0 }
  48. static struct ds_entry ds_entries[] = {
  49. DS_ENTRY(_sdata),
  50. DS_ENTRY(__bss_stop),
  51. DS_ENTRY(__per_cpu_start),
  52. DS_ENTRY(__per_cpu_end),
  53. DS_ENTRY(__start_ro_after_init),
  54. DS_ENTRY(__end_ro_after_init),
  55. DS_ENTRY(prb),
  56. DS_ENTRY(linux_banner),
  57. DS_ENTRY(irq_stack_ptr),
  58. DS_ENTRY(tick_cpu_device),
  59. DS_ENTRY(modules),
  60. };
  61. bool debug_symbol_available(void)
  62. {
  63. struct kernel_all_info *kainfo;
  64. struct kernel_info *kinfo;
  65. if (!debug_symbol_vaddr)
  66. return false;
  67. kainfo = (struct kernel_all_info *)debug_symbol_vaddr;
  68. kinfo = &(kainfo->info);
  69. if (kainfo->magic_number != DEBUG_KINFO_MAGIC) {
  70. pr_debug("debug_symbol is not available now\n");
  71. return false;
  72. }
  73. if (!debug_symbol.addresses) {
  74. debug_symbol.addresses = (unsigned long *)
  75. __phys_to_kimg(kinfo->_addresses_pa);
  76. debug_symbol.offsets = (int *)
  77. __phys_to_kimg(kinfo->_offsets_pa);
  78. debug_symbol.names = (u8 *)
  79. __phys_to_kimg(kinfo->_names_pa);
  80. debug_symbol.num_syms = kinfo->num_syms;
  81. debug_symbol.relative_base =
  82. __phys_to_kimg(kinfo->_relative_pa);
  83. debug_symbol.token_table = (char *)
  84. __phys_to_kimg(kinfo->_token_table_pa);
  85. debug_symbol.token_index = (u16 *)
  86. __phys_to_kimg(kinfo->_token_index_pa);
  87. debug_symbol.markers = (unsigned int *)
  88. __phys_to_kimg(kinfo->_markers_pa);
  89. fill_ds_entries();
  90. }
  91. return true;
  92. }
  93. EXPORT_SYMBOL(debug_symbol_available);
  94. /* In line with kallsyms_expand_symbol from kernel/kallsyms.c */
  95. static unsigned int debug_symbol_expand_symbol(unsigned int off,
  96. char *result, size_t maxlen)
  97. {
  98. int len, skipped_first = 0;
  99. const char *tptr;
  100. const u8 *data;
  101. data = &debug_symbol.names[off];
  102. len = *data;
  103. data++;
  104. off++;
  105. if ((len & 0x80) != 0) {
  106. len = (len & 0x7F) | (*data << 7);
  107. data++;
  108. off++;
  109. }
  110. off += len;
  111. while (len) {
  112. tptr = &debug_symbol.token_table[debug_symbol.token_index[*data]];
  113. data++;
  114. len--;
  115. while (*tptr) {
  116. if (skipped_first) {
  117. if (maxlen <= 1)
  118. goto tail;
  119. *result = *tptr;
  120. result++;
  121. maxlen--;
  122. } else
  123. skipped_first = 1;
  124. tptr++;
  125. }
  126. }
  127. tail:
  128. if (maxlen)
  129. *result = '\0';
  130. return off;
  131. }
  132. /* In line with kallsyms_sym_address from kernel/kallsyms.c */
  133. static unsigned long debug_symbol_sym_address(int idx)
  134. {
  135. if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
  136. return debug_symbol.addresses[idx];
  137. if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
  138. return debug_symbol.relative_base + (u32)debug_symbol.offsets[idx];
  139. if (debug_symbol.offsets[idx] >= 0)
  140. return debug_symbol.offsets[idx];
  141. return debug_symbol.relative_base - 1 - debug_symbol.offsets[idx];
  142. }
  143. /* In line with cleanup_symbol_name from kernel/kallsyms.c */
  144. static bool cleanup_symbol_name(char *s)
  145. {
  146. char *res;
  147. if (!IS_ENABLED(CONFIG_LTO_CLANG))
  148. return false;
  149. res = strchr(s, '.');
  150. if (res) {
  151. *res = '\0';
  152. return true;
  153. }
  154. return false;
  155. }
  156. static unsigned long find_in_ds_entries(const char *name)
  157. {
  158. int i;
  159. for (i = 0; i < ARRAY_SIZE(ds_entries); i++)
  160. if (strcmp(name, ds_entries[i].name) == 0)
  161. return ds_entries[i].addr;
  162. return 0;
  163. }
  164. /* In line with kallsyms_lookup_name from kernel/kallsyms.c */
  165. unsigned long debug_symbol_lookup_name(const char *name)
  166. {
  167. char namebuf[KSYM_NAME_LEN];
  168. unsigned long i, ret;
  169. unsigned int off;
  170. if (!*name)
  171. return 0;
  172. ret = find_in_ds_entries(name);
  173. if (ret)
  174. return ret;
  175. for (i = 0, off = 0; i < debug_symbol.num_syms; i++) {
  176. off = debug_symbol_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
  177. if (strcmp(namebuf, name) == 0 ||
  178. (cleanup_symbol_name(namebuf) &&
  179. strcmp(namebuf, name) == 0)) {
  180. return debug_symbol_sym_address(i);
  181. }
  182. }
  183. return 0;
  184. }
  185. EXPORT_SYMBOL(debug_symbol_lookup_name);
  186. static void fill_ds_entries(void)
  187. {
  188. char namebuf[KSYM_NAME_LEN];
  189. unsigned long i;
  190. unsigned int off;
  191. int index;
  192. for (i = 0, off = 0; i < debug_symbol.num_syms; i++) {
  193. off = debug_symbol_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
  194. for (index = 0; index < ARRAY_SIZE(ds_entries); index++) {
  195. if (ds_entries[index].addr != 0)
  196. continue;
  197. if (strcmp(namebuf, ds_entries[index].name) == 0 ||
  198. (cleanup_symbol_name(namebuf) &&
  199. strcmp(namebuf, ds_entries[index].name) == 0)) {
  200. ds_entries[index].addr = debug_symbol_sym_address(i);
  201. continue;
  202. }
  203. }
  204. }
  205. }
  206. static int __init debug_symbol_init(void)
  207. {
  208. struct device_node *rmem_node;
  209. struct reserved_mem *rmem;
  210. rmem_node = of_find_compatible_node(NULL, NULL, "google,debug-kinfo");
  211. if (!rmem_node) {
  212. pr_err("cannot get compatible node\n");
  213. goto out;
  214. }
  215. rmem_node = of_parse_phandle(rmem_node, "memory-region", 0);
  216. if (!rmem_node) {
  217. pr_err("cannot get memory region\n");
  218. goto out;
  219. }
  220. rmem = of_reserved_mem_lookup(rmem_node);
  221. if (!rmem) {
  222. pr_err("cannot get reserved memory\n");
  223. goto out;
  224. }
  225. debug_symbol_vaddr = memremap(rmem->base, rmem->size, MEMREMAP_WB);
  226. if (!debug_symbol_vaddr) {
  227. pr_err("failed to map reserved memory\n");
  228. goto out;
  229. }
  230. memset(debug_symbol_vaddr, 0, sizeof(struct kernel_all_info));
  231. rmem->priv = debug_symbol_vaddr;
  232. out:
  233. return 0;
  234. }
  235. arch_initcall(debug_symbol_init);
  236. MODULE_DESCRIPTION("QCOM Debug Symbol driver");
  237. MODULE_LICENSE("GPL");