btf_dumper.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) 2018 Facebook */
  3. #include <ctype.h>
  4. #include <stdio.h> /* for (FILE *) used by json_writer */
  5. #include <string.h>
  6. #include <asm/byteorder.h>
  7. #include <linux/bitops.h>
  8. #include <linux/btf.h>
  9. #include <linux/err.h>
  10. #include "btf.h"
  11. #include "json_writer.h"
  12. #include "main.h"
  13. #define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
  14. #define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
  15. #define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
  16. #define BITS_ROUNDUP_BYTES(bits) \
  17. (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
  18. static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
  19. __u8 bit_offset, const void *data);
  20. static void btf_dumper_ptr(const void *data, json_writer_t *jw,
  21. bool is_plain_text)
  22. {
  23. if (is_plain_text)
  24. jsonw_printf(jw, "%p", data);
  25. else
  26. jsonw_printf(jw, "%lu", *(unsigned long *)data);
  27. }
  28. static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id,
  29. __u8 bit_offset, const void *data)
  30. {
  31. int actual_type_id;
  32. actual_type_id = btf__resolve_type(d->btf, type_id);
  33. if (actual_type_id < 0)
  34. return actual_type_id;
  35. return btf_dumper_do_type(d, actual_type_id, bit_offset, data);
  36. }
  37. static void btf_dumper_enum(const void *data, json_writer_t *jw)
  38. {
  39. jsonw_printf(jw, "%d", *(int *)data);
  40. }
  41. static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id,
  42. const void *data)
  43. {
  44. const struct btf_type *t = btf__type_by_id(d->btf, type_id);
  45. struct btf_array *arr = (struct btf_array *)(t + 1);
  46. long long elem_size;
  47. int ret = 0;
  48. __u32 i;
  49. elem_size = btf__resolve_size(d->btf, arr->type);
  50. if (elem_size < 0)
  51. return elem_size;
  52. jsonw_start_array(d->jw);
  53. for (i = 0; i < arr->nelems; i++) {
  54. ret = btf_dumper_do_type(d, arr->type, 0,
  55. data + i * elem_size);
  56. if (ret)
  57. break;
  58. }
  59. jsonw_end_array(d->jw);
  60. return ret;
  61. }
  62. static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
  63. const void *data, json_writer_t *jw,
  64. bool is_plain_text)
  65. {
  66. int left_shift_bits, right_shift_bits;
  67. int nr_bits = BTF_INT_BITS(int_type);
  68. int total_bits_offset;
  69. int bytes_to_copy;
  70. int bits_to_copy;
  71. __u64 print_num;
  72. total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
  73. data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
  74. bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
  75. bits_to_copy = bit_offset + nr_bits;
  76. bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
  77. print_num = 0;
  78. memcpy(&print_num, data, bytes_to_copy);
  79. #if defined(__BIG_ENDIAN_BITFIELD)
  80. left_shift_bits = bit_offset;
  81. #elif defined(__LITTLE_ENDIAN_BITFIELD)
  82. left_shift_bits = 64 - bits_to_copy;
  83. #else
  84. #error neither big nor little endian
  85. #endif
  86. right_shift_bits = 64 - nr_bits;
  87. print_num <<= left_shift_bits;
  88. print_num >>= right_shift_bits;
  89. if (is_plain_text)
  90. jsonw_printf(jw, "0x%llx", print_num);
  91. else
  92. jsonw_printf(jw, "%llu", print_num);
  93. }
  94. static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset,
  95. const void *data, json_writer_t *jw,
  96. bool is_plain_text)
  97. {
  98. __u32 *int_type;
  99. __u32 nr_bits;
  100. int_type = (__u32 *)(t + 1);
  101. nr_bits = BTF_INT_BITS(*int_type);
  102. /* if this is bit field */
  103. if (bit_offset || BTF_INT_OFFSET(*int_type) ||
  104. BITS_PER_BYTE_MASKED(nr_bits)) {
  105. btf_dumper_int_bits(*int_type, bit_offset, data, jw,
  106. is_plain_text);
  107. return 0;
  108. }
  109. switch (BTF_INT_ENCODING(*int_type)) {
  110. case 0:
  111. if (BTF_INT_BITS(*int_type) == 64)
  112. jsonw_printf(jw, "%llu", *(__u64 *)data);
  113. else if (BTF_INT_BITS(*int_type) == 32)
  114. jsonw_printf(jw, "%u", *(__u32 *)data);
  115. else if (BTF_INT_BITS(*int_type) == 16)
  116. jsonw_printf(jw, "%hu", *(__u16 *)data);
  117. else if (BTF_INT_BITS(*int_type) == 8)
  118. jsonw_printf(jw, "%hhu", *(__u8 *)data);
  119. else
  120. btf_dumper_int_bits(*int_type, bit_offset, data, jw,
  121. is_plain_text);
  122. break;
  123. case BTF_INT_SIGNED:
  124. if (BTF_INT_BITS(*int_type) == 64)
  125. jsonw_printf(jw, "%lld", *(long long *)data);
  126. else if (BTF_INT_BITS(*int_type) == 32)
  127. jsonw_printf(jw, "%d", *(int *)data);
  128. else if (BTF_INT_BITS(*int_type) == 16)
  129. jsonw_printf(jw, "%hd", *(short *)data);
  130. else if (BTF_INT_BITS(*int_type) == 8)
  131. jsonw_printf(jw, "%hhd", *(char *)data);
  132. else
  133. btf_dumper_int_bits(*int_type, bit_offset, data, jw,
  134. is_plain_text);
  135. break;
  136. case BTF_INT_CHAR:
  137. if (isprint(*(char *)data))
  138. jsonw_printf(jw, "\"%c\"", *(char *)data);
  139. else
  140. if (is_plain_text)
  141. jsonw_printf(jw, "0x%hhx", *(char *)data);
  142. else
  143. jsonw_printf(jw, "\"\\u00%02hhx\"",
  144. *(char *)data);
  145. break;
  146. case BTF_INT_BOOL:
  147. jsonw_bool(jw, *(int *)data);
  148. break;
  149. default:
  150. /* shouldn't happen */
  151. return -EINVAL;
  152. }
  153. return 0;
  154. }
  155. static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id,
  156. const void *data)
  157. {
  158. const struct btf_type *t;
  159. struct btf_member *m;
  160. const void *data_off;
  161. int ret = 0;
  162. int i, vlen;
  163. t = btf__type_by_id(d->btf, type_id);
  164. if (!t)
  165. return -EINVAL;
  166. vlen = BTF_INFO_VLEN(t->info);
  167. jsonw_start_object(d->jw);
  168. m = (struct btf_member *)(t + 1);
  169. for (i = 0; i < vlen; i++) {
  170. data_off = data + BITS_ROUNDDOWN_BYTES(m[i].offset);
  171. jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off));
  172. ret = btf_dumper_do_type(d, m[i].type,
  173. BITS_PER_BYTE_MASKED(m[i].offset),
  174. data_off);
  175. if (ret)
  176. break;
  177. }
  178. jsonw_end_object(d->jw);
  179. return ret;
  180. }
  181. static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
  182. __u8 bit_offset, const void *data)
  183. {
  184. const struct btf_type *t = btf__type_by_id(d->btf, type_id);
  185. switch (BTF_INFO_KIND(t->info)) {
  186. case BTF_KIND_INT:
  187. return btf_dumper_int(t, bit_offset, data, d->jw,
  188. d->is_plain_text);
  189. case BTF_KIND_STRUCT:
  190. case BTF_KIND_UNION:
  191. return btf_dumper_struct(d, type_id, data);
  192. case BTF_KIND_ARRAY:
  193. return btf_dumper_array(d, type_id, data);
  194. case BTF_KIND_ENUM:
  195. btf_dumper_enum(data, d->jw);
  196. return 0;
  197. case BTF_KIND_PTR:
  198. btf_dumper_ptr(data, d->jw, d->is_plain_text);
  199. return 0;
  200. case BTF_KIND_UNKN:
  201. jsonw_printf(d->jw, "(unknown)");
  202. return 0;
  203. case BTF_KIND_FWD:
  204. /* map key or value can't be forward */
  205. jsonw_printf(d->jw, "(fwd-kind-invalid)");
  206. return -EINVAL;
  207. case BTF_KIND_TYPEDEF:
  208. case BTF_KIND_VOLATILE:
  209. case BTF_KIND_CONST:
  210. case BTF_KIND_RESTRICT:
  211. return btf_dumper_modifier(d, type_id, bit_offset, data);
  212. default:
  213. jsonw_printf(d->jw, "(unsupported-kind");
  214. return -EINVAL;
  215. }
  216. }
  217. int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
  218. const void *data)
  219. {
  220. return btf_dumper_do_type(d, type_id, 0, data);
  221. }