ctf-util.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /* Miscellaneous utilities.
  2. Copyright (C) 2019-2022 Free Software Foundation, Inc.
  3. This file is part of libctf.
  4. libctf is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU General Public License as published by the Free
  6. Software Foundation; either version 3, or (at your option) any later
  7. version.
  8. This program is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. See the GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; see the file COPYING. If not see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <ctf-impl.h>
  16. #include <string.h>
  17. #include "ctf-endian.h"
  18. /* Simple doubly-linked list append routine. This implementation assumes that
  19. each list element contains an embedded ctf_list_t as the first member.
  20. An additional ctf_list_t is used to store the head (l_next) and tail
  21. (l_prev) pointers. The current head and tail list elements have their
  22. previous and next pointers set to NULL, respectively. */
  23. void
  24. ctf_list_append (ctf_list_t *lp, void *newp)
  25. {
  26. ctf_list_t *p = lp->l_prev; /* p = tail list element. */
  27. ctf_list_t *q = newp; /* q = new list element. */
  28. lp->l_prev = q;
  29. q->l_prev = p;
  30. q->l_next = NULL;
  31. if (p != NULL)
  32. p->l_next = q;
  33. else
  34. lp->l_next = q;
  35. }
  36. /* Prepend the specified existing element to the given ctf_list_t. The
  37. existing pointer should be pointing at a struct with embedded ctf_list_t. */
  38. void
  39. ctf_list_prepend (ctf_list_t * lp, void *newp)
  40. {
  41. ctf_list_t *p = newp; /* p = new list element. */
  42. ctf_list_t *q = lp->l_next; /* q = head list element. */
  43. lp->l_next = p;
  44. p->l_prev = NULL;
  45. p->l_next = q;
  46. if (q != NULL)
  47. q->l_prev = p;
  48. else
  49. lp->l_prev = p;
  50. }
  51. /* Delete the specified existing element from the given ctf_list_t. The
  52. existing pointer should be pointing at a struct with embedded ctf_list_t. */
  53. void
  54. ctf_list_delete (ctf_list_t *lp, void *existing)
  55. {
  56. ctf_list_t *p = existing;
  57. if (p->l_prev != NULL)
  58. p->l_prev->l_next = p->l_next;
  59. else
  60. lp->l_next = p->l_next;
  61. if (p->l_next != NULL)
  62. p->l_next->l_prev = p->l_prev;
  63. else
  64. lp->l_prev = p->l_prev;
  65. }
  66. /* Return 1 if the list is empty. */
  67. int
  68. ctf_list_empty_p (ctf_list_t *lp)
  69. {
  70. return (lp->l_next == NULL && lp->l_prev == NULL);
  71. }
  72. /* Splice one entire list onto the end of another one. The existing list is
  73. emptied. */
  74. void
  75. ctf_list_splice (ctf_list_t *lp, ctf_list_t *append)
  76. {
  77. if (ctf_list_empty_p (append))
  78. return;
  79. if (lp->l_prev != NULL)
  80. lp->l_prev->l_next = append->l_next;
  81. else
  82. lp->l_next = append->l_next;
  83. append->l_next->l_prev = lp->l_prev;
  84. lp->l_prev = append->l_prev;
  85. append->l_next = NULL;
  86. append->l_prev = NULL;
  87. }
  88. /* Convert a 32-bit ELF symbol to a ctf_link_sym_t. */
  89. ctf_link_sym_t *
  90. ctf_elf32_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf32_Sym *src,
  91. uint32_t symidx)
  92. {
  93. Elf32_Sym tmp;
  94. int needs_flipping = 0;
  95. #ifdef WORDS_BIGENDIAN
  96. if (fp->ctf_symsect_little_endian)
  97. needs_flipping = 1;
  98. #else
  99. if (!fp->ctf_symsect_little_endian)
  100. needs_flipping = 1;
  101. #endif
  102. memcpy (&tmp, src, sizeof (Elf32_Sym));
  103. if (needs_flipping)
  104. {
  105. swap_thing (tmp.st_name);
  106. swap_thing (tmp.st_size);
  107. swap_thing (tmp.st_shndx);
  108. swap_thing (tmp.st_value);
  109. }
  110. /* The name must be in the external string table. */
  111. if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len)
  112. dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name;
  113. else
  114. dst->st_name = _CTF_NULLSTR;
  115. dst->st_nameidx_set = 0;
  116. dst->st_symidx = symidx;
  117. dst->st_shndx = tmp.st_shndx;
  118. dst->st_type = ELF32_ST_TYPE (tmp.st_info);
  119. dst->st_value = tmp.st_value;
  120. return dst;
  121. }
  122. /* Convert a 64-bit ELF symbol to a ctf_link_sym_t. */
  123. ctf_link_sym_t *
  124. ctf_elf64_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf64_Sym *src,
  125. uint32_t symidx)
  126. {
  127. Elf64_Sym tmp;
  128. int needs_flipping = 0;
  129. #ifdef WORDS_BIGENDIAN
  130. if (fp->ctf_symsect_little_endian)
  131. needs_flipping = 1;
  132. #else
  133. if (!fp->ctf_symsect_little_endian)
  134. needs_flipping = 1;
  135. #endif
  136. memcpy (&tmp, src, sizeof (Elf64_Sym));
  137. if (needs_flipping)
  138. {
  139. swap_thing (tmp.st_name);
  140. swap_thing (tmp.st_size);
  141. swap_thing (tmp.st_shndx);
  142. swap_thing (tmp.st_value);
  143. }
  144. /* The name must be in the external string table. */
  145. if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len)
  146. dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name;
  147. else
  148. dst->st_name = _CTF_NULLSTR;
  149. dst->st_nameidx_set = 0;
  150. dst->st_symidx = symidx;
  151. dst->st_shndx = tmp.st_shndx;
  152. dst->st_type = ELF32_ST_TYPE (tmp.st_info);
  153. /* We only care if the value is zero, so avoid nonzeroes turning into
  154. zeroes. */
  155. if (_libctf_unlikely_ (tmp.st_value != 0 && ((uint32_t) tmp.st_value == 0)))
  156. dst->st_value = 1;
  157. else
  158. dst->st_value = (uint32_t) tmp.st_value;
  159. return dst;
  160. }
  161. /* A string appender working on dynamic strings. Returns NULL on OOM. */
  162. char *
  163. ctf_str_append (char *s, const char *append)
  164. {
  165. size_t s_len = 0;
  166. if (append == NULL)
  167. return s;
  168. if (s != NULL)
  169. s_len = strlen (s);
  170. size_t append_len = strlen (append);
  171. if ((s = realloc (s, s_len + append_len + 1)) == NULL)
  172. return NULL;
  173. memcpy (s + s_len, append, append_len);
  174. s[s_len + append_len] = '\0';
  175. return s;
  176. }
  177. /* A version of ctf_str_append that returns the old string on OOM. */
  178. char *
  179. ctf_str_append_noerr (char *s, const char *append)
  180. {
  181. char *new_s;
  182. new_s = ctf_str_append (s, append);
  183. if (!new_s)
  184. return s;
  185. return new_s;
  186. }
  187. /* A realloc() that fails noisily if called with any ctf_str_num_users. */
  188. void *
  189. ctf_realloc (ctf_dict_t *fp, void *ptr, size_t size)
  190. {
  191. if (fp->ctf_str_num_refs > 0)
  192. {
  193. ctf_dprintf ("%p: attempt to realloc() string table with %lu active refs\n",
  194. (void *) fp, (unsigned long) fp->ctf_str_num_refs);
  195. return NULL;
  196. }
  197. return realloc (ptr, size);
  198. }
  199. /* Store the specified error code into errp if it is non-NULL, and then
  200. return NULL for the benefit of the caller. */
  201. void *
  202. ctf_set_open_errno (int *errp, int error)
  203. {
  204. if (errp != NULL)
  205. *errp = error;
  206. return NULL;
  207. }
  208. /* Store the specified error code into the CTF dict, and then return CTF_ERR /
  209. -1 for the benefit of the caller. */
  210. unsigned long
  211. ctf_set_errno (ctf_dict_t *fp, int err)
  212. {
  213. fp->ctf_errno = err;
  214. return CTF_ERR;
  215. }
  216. /* Create a ctf_next_t. */
  217. ctf_next_t *
  218. ctf_next_create (void)
  219. {
  220. return calloc (1, sizeof (struct ctf_next));
  221. }
  222. /* Destroy a ctf_next_t, for early exit from iterators. */
  223. void
  224. ctf_next_destroy (ctf_next_t *i)
  225. {
  226. if (i == NULL)
  227. return;
  228. if (i->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted)
  229. free (i->u.ctn_sorted_hkv);
  230. if (i->ctn_next)
  231. ctf_next_destroy (i->ctn_next);
  232. free (i);
  233. }
  234. /* Copy a ctf_next_t. */
  235. ctf_next_t *
  236. ctf_next_copy (ctf_next_t *i)
  237. {
  238. ctf_next_t *i2;
  239. if ((i2 = ctf_next_create()) == NULL)
  240. return NULL;
  241. memcpy (i2, i, sizeof (struct ctf_next));
  242. if (i2->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted)
  243. {
  244. size_t els = ctf_dynhash_elements ((ctf_dynhash_t *) i->cu.ctn_h);
  245. if ((i2->u.ctn_sorted_hkv = calloc (els, sizeof (ctf_next_hkv_t))) == NULL)
  246. {
  247. free (i2);
  248. return NULL;
  249. }
  250. memcpy (i2->u.ctn_sorted_hkv, i->u.ctn_sorted_hkv,
  251. els * sizeof (ctf_next_hkv_t));
  252. }
  253. return i2;
  254. }