Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

usdt.c 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * Copyright (c) 2012, Chris Andrews. All rights reserved.
  3. */
  4. #include "usdt_internal.h"
  5. #include <stdarg.h>
  6. #include <string.h>
  7. #include <stdio.h>
  8. char *usdt_errors[] = {
  9. "failed to allocate memory",
  10. "failed to allocate page-aligned memory",
  11. "no probes defined",
  12. "failed to load DOF: %s",
  13. "provider is already enabled",
  14. "failed to unload DOF: %s",
  15. "probe named %s:%s:%s:%s already exists",
  16. "failed to remove probe %s:%s:%s:%s"
  17. };
  18. static void
  19. free_probedef(usdt_probedef_t *pd)
  20. {
  21. int i;
  22. switch (pd->refcnt) {
  23. case 1:
  24. free((char *)pd->function);
  25. free((char *)pd->name);
  26. if (pd->probe) {
  27. usdt_free_tracepoints(pd->probe);
  28. free(pd->probe);
  29. }
  30. for (i = 0; i < pd->argc; i++)
  31. free(pd->types[i]);
  32. free(pd);
  33. break;
  34. case 2:
  35. pd->refcnt = 1;
  36. break;
  37. default:
  38. break;
  39. }
  40. }
  41. usdt_provider_t *
  42. usdt_create_provider(const char *name, const char *module)
  43. {
  44. usdt_provider_t *provider;
  45. if ((provider = malloc(sizeof *provider)) == NULL)
  46. return NULL;
  47. provider->name = strdup(name);
  48. provider->module = strdup(module);
  49. provider->probedefs = NULL;
  50. provider->enabled = 0;
  51. return provider;
  52. }
  53. usdt_probedef_t *
  54. usdt_create_probe(const char *func, const char *name, size_t argc, const char **types)
  55. {
  56. int i;
  57. usdt_probedef_t *p;
  58. if (argc > USDT_ARG_MAX)
  59. argc = USDT_ARG_MAX;
  60. if ((p = malloc(sizeof *p)) == NULL)
  61. return (NULL);
  62. p->refcnt = 2;
  63. p->function = strdup(func);
  64. p->name = strdup(name);
  65. p->argc = argc;
  66. p->probe = NULL;
  67. for (i = 0; i < argc; i++)
  68. p->types[i] = strdup(types[i]);
  69. return (p);
  70. }
  71. void
  72. usdt_probe_release(usdt_probedef_t *probedef)
  73. {
  74. free_probedef(probedef);
  75. }
  76. int
  77. usdt_provider_add_probe(usdt_provider_t *provider, usdt_probedef_t *probedef)
  78. {
  79. usdt_probedef_t *pd;
  80. if (provider->probedefs != NULL) {
  81. for (pd = provider->probedefs; (pd != NULL); pd = pd->next) {
  82. if ((strcmp(pd->name, probedef->name) == 0) &&
  83. (strcmp(pd->function, probedef->function) == 0)) {
  84. usdt_error(provider, USDT_ERROR_DUP_PROBE,
  85. provider->name, provider->module,
  86. probedef->function, probedef->name);
  87. return (-1);
  88. }
  89. }
  90. }
  91. probedef->next = NULL;
  92. if (provider->probedefs == NULL)
  93. provider->probedefs = probedef;
  94. else {
  95. for (pd = provider->probedefs; (pd->next != NULL); pd = pd->next) ;
  96. pd->next = probedef;
  97. }
  98. return (0);
  99. }
  100. int
  101. usdt_provider_remove_probe(usdt_provider_t *provider, usdt_probedef_t *probedef)
  102. {
  103. usdt_probedef_t *pd, *prev_pd = NULL;
  104. if (provider->probedefs == NULL) {
  105. usdt_error(provider, USDT_ERROR_NOPROBES);
  106. return (-1);
  107. }
  108. for (pd = provider->probedefs; (pd != NULL);
  109. prev_pd = pd, pd = pd->next) {
  110. if ((strcmp(pd->name, probedef->name) == 0) &&
  111. (strcmp(pd->function, probedef->function) == 0)) {
  112. if (prev_pd == NULL)
  113. provider->probedefs = pd->next;
  114. else
  115. prev_pd->next = pd->next;
  116. return (0);
  117. }
  118. }
  119. usdt_error(provider, USDT_ERROR_REMOVE_PROBE,
  120. provider->name, provider->module,
  121. probedef->function, probedef->name);
  122. return (-1);
  123. }
  124. int
  125. usdt_provider_enable(usdt_provider_t *provider)
  126. {
  127. usdt_strtab_t strtab;
  128. usdt_dof_file_t *file;
  129. usdt_probedef_t *pd;
  130. int i;
  131. size_t size;
  132. usdt_dof_section_t sects[5];
  133. if (provider->enabled == 1) {
  134. usdt_error(provider, USDT_ERROR_ALREADYENABLED);
  135. return (0); /* not fatal */
  136. }
  137. if (provider->probedefs == NULL) {
  138. usdt_error(provider, USDT_ERROR_NOPROBES);
  139. return (-1);
  140. }
  141. for (pd = provider->probedefs; pd != NULL; pd = pd->next) {
  142. if ((pd->probe = malloc(sizeof(*pd->probe))) == NULL) {
  143. usdt_error(provider, USDT_ERROR_MALLOC);
  144. return (-1);
  145. }
  146. }
  147. if ((usdt_strtab_init(&strtab, 0)) < 0) {
  148. usdt_error(provider, USDT_ERROR_MALLOC);
  149. return (-1);
  150. }
  151. if ((usdt_strtab_add(&strtab, provider->name)) == 0) {
  152. usdt_error(provider, USDT_ERROR_MALLOC);
  153. return (-1);
  154. }
  155. if ((usdt_dof_probes_sect(&sects[0], provider, &strtab)) < 0)
  156. return (-1);
  157. if ((usdt_dof_prargs_sect(&sects[1], provider)) < 0)
  158. return (-1);
  159. size = usdt_provider_dof_size(provider, &strtab);
  160. if ((file = usdt_dof_file_init(provider, size)) == NULL)
  161. return (-1);
  162. if ((usdt_dof_proffs_sect(&sects[2], provider, file->dof)) < 0)
  163. return (-1);
  164. if ((usdt_dof_prenoffs_sect(&sects[3], provider, file->dof)) < 0)
  165. return (-1);
  166. if ((usdt_dof_provider_sect(&sects[4], provider)) < 0)
  167. return (-1);
  168. for (i = 0; i < 5; i++)
  169. usdt_dof_file_append_section(file, &sects[i]);
  170. usdt_dof_file_generate(file, &strtab);
  171. usdt_dof_section_free((usdt_dof_section_t *)&strtab);
  172. for (i = 0; i < 5; i++)
  173. usdt_dof_section_free(&sects[i]);
  174. if ((usdt_dof_file_load(file, provider->module)) < 0) {
  175. usdt_error(provider, USDT_ERROR_LOADDOF, strerror(errno));
  176. return (-1);
  177. }
  178. provider->enabled = 1;
  179. provider->file = file;
  180. return (0);
  181. }
  182. int
  183. usdt_provider_disable(usdt_provider_t *provider)
  184. {
  185. usdt_probedef_t *pd;
  186. if (provider->enabled == 0)
  187. return (0);
  188. if ((usdt_dof_file_unload((usdt_dof_file_t *)provider->file)) < 0) {
  189. usdt_error(provider, USDT_ERROR_UNLOADDOF, strerror(errno));
  190. return (-1);
  191. }
  192. usdt_dof_file_free(provider->file);
  193. provider->file = NULL;
  194. /* We would like to free the tracepoints here too, but OS X
  195. * (and to a lesser extent Illumos) struggle with this:
  196. *
  197. * If a provider is repeatedly disabled and re-enabled, and is
  198. * allowed to reuse the same memory for its tracepoints, *and*
  199. * there's a DTrace consumer running with enablings for these
  200. * probes, tracepoints are not always cleaned up sufficiently
  201. * that the newly-created probes work.
  202. *
  203. * Here, then, we will leak the memory holding the
  204. * tracepoints, which serves to stop us reusing the same
  205. * memory address for new tracepoints, avoiding the bug.
  206. */
  207. for (pd = provider->probedefs; (pd != NULL); pd = pd->next) {
  208. /* may have an as yet never-enabled probe on an
  209. otherwise enabled provider */
  210. if (pd->probe) {
  211. /* usdt_free_tracepoints(pd->probe); */
  212. free(pd->probe);
  213. pd->probe = NULL;
  214. }
  215. }
  216. provider->enabled = 0;
  217. return (0);
  218. }
  219. void
  220. usdt_provider_free(usdt_provider_t *provider)
  221. {
  222. usdt_probedef_t *pd, *next;
  223. for (pd = provider->probedefs; pd != NULL; pd = next) {
  224. next = pd->next;
  225. free_probedef(pd);
  226. }
  227. free((char *)provider->name);
  228. free((char *)provider->module);
  229. free(provider);
  230. }
  231. int
  232. usdt_is_enabled(usdt_probe_t *probe)
  233. {
  234. if (probe != NULL)
  235. return (*probe->isenabled_addr)();
  236. else
  237. return 0;
  238. }
  239. void
  240. usdt_fire_probe(usdt_probe_t *probe, size_t argc, void **nargv)
  241. {
  242. if (probe != NULL)
  243. usdt_probe_args(probe->probe_addr, argc, nargv);
  244. }
  245. static void
  246. usdt_verror(usdt_provider_t *provider, usdt_error_t error, va_list argp)
  247. {
  248. vasprintf(&provider->error, usdt_errors[error], argp);
  249. }
  250. void
  251. usdt_error(usdt_provider_t *provider, usdt_error_t error, ...)
  252. {
  253. va_list argp;
  254. va_start(argp, error);
  255. usdt_verror(provider, error, argp);
  256. va_end(argp);
  257. }
  258. char *
  259. usdt_errstr(usdt_provider_t *provider)
  260. {
  261. return (provider->error);
  262. }