pc_sample.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * Mach Operating System
  3. * Copyright (c) 1993,1992 Carnegie Mellon University
  4. * All Rights Reserved.
  5. *
  6. * Permission to use, copy, modify and distribute this software and its
  7. * documentation is hereby granted, provided that both the copyright
  8. * notice and this permission notice appear in all copies of the
  9. * software, derivative works or modified versions, and any portions
  10. * thereof, and that both notices appear in supporting documentation.
  11. *
  12. * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13. * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14. * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15. *
  16. * Carnegie Mellon requests users of this software to return to
  17. *
  18. * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
  19. * School of Computer Science
  20. * Carnegie Mellon University
  21. * Pittsburgh PA 15213-3890
  22. *
  23. * any improvements or extensions that they make and grant Carnegie Mellon
  24. * the rights to redistribute these changes.
  25. */
  26. #include <kern/printf.h>
  27. #include <string.h>
  28. #include <mach/mach_types.h> /* vm_address_t */
  29. #include <mach/std_types.h> /* pointer_t */
  30. #include <mach/pc_sample.h>
  31. #include <machine/trap.h>
  32. #include <kern/kalloc.h>
  33. #include <kern/host.h>
  34. #include <kern/thread.h>
  35. #include <kern/pc_sample.h>
  36. #include <kern/mach_clock.h>
  37. #if MACH_PCSAMPLE
  38. #define MAX_PC_SAMPLES 512
  39. typedef sampled_pc_t sampled_pcs[MAX_PC_SAMPLES];
  40. void take_pc_sample(
  41. const thread_t t,
  42. sample_control_t *cp,
  43. sampled_pc_flavor_t flavor,
  44. boolean_t usermode,
  45. vm_offset_t kern_pc)
  46. {
  47. vm_offset_t pc;
  48. struct sampled_pc *sample;
  49. if (usermode)
  50. pc = interrupted_pc(t);
  51. else
  52. pc = kern_pc;
  53. cp->seqno++;
  54. sample = &((sampled_pc_t *)cp->buffer)[cp->seqno % MAX_PC_SAMPLES];
  55. sample->id = (vm_offset_t)t;
  56. sample->pc = pc;
  57. sample->sampletype = flavor;
  58. }
  59. kern_return_t
  60. thread_enable_pc_sampling(
  61. thread_t thread,
  62. int *tickp,
  63. sampled_pc_flavor_t flavors)
  64. {
  65. vm_offset_t buf;
  66. if (thread == THREAD_NULL) {
  67. return KERN_INVALID_ARGUMENT;
  68. }
  69. if (thread->pc_sample.buffer == 0) {
  70. buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
  71. if (buf == 0) {
  72. printf("thread_enable_pc_sampling: kalloc failed\n");
  73. return KERN_INVALID_ARGUMENT;
  74. }
  75. thread->pc_sample.buffer = buf;
  76. thread->pc_sample.seqno = 0;
  77. }
  78. *tickp = tick;
  79. thread->pc_sample.sampletypes = flavors;
  80. return KERN_SUCCESS;
  81. }
  82. kern_return_t
  83. task_enable_pc_sampling(
  84. task_t task,
  85. int *tickp,
  86. sampled_pc_flavor_t flavors)
  87. {
  88. vm_offset_t buf;
  89. if (task == TASK_NULL) {
  90. return KERN_INVALID_ARGUMENT;
  91. }
  92. if (task->pc_sample.buffer == 0) {
  93. buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
  94. if (buf == 0) {
  95. printf("task_enable_pc_sampling: kalloc failed\n");
  96. return KERN_INVALID_ARGUMENT;
  97. }
  98. task->pc_sample.buffer = buf;
  99. task->pc_sample.seqno = 0;
  100. }
  101. *tickp = tick;
  102. task->pc_sample.sampletypes = flavors;
  103. return KERN_SUCCESS;
  104. }
  105. kern_return_t
  106. thread_disable_pc_sampling(
  107. thread_t thread,
  108. int *samplecntp)
  109. {
  110. vm_offset_t buf;
  111. if (thread == THREAD_NULL) {
  112. return KERN_INVALID_ARGUMENT;
  113. }
  114. if ((buf = thread->pc_sample.buffer) != 0)
  115. kfree(buf, sizeof (sampled_pcs));
  116. thread->pc_sample.buffer = (vm_offset_t) 0;
  117. thread->pc_sample.seqno = 0;
  118. thread->pc_sample.sampletypes = 0; /* shut off sampling */
  119. return KERN_SUCCESS;
  120. }
  121. kern_return_t
  122. task_disable_pc_sampling(
  123. task_t task,
  124. int *samplecntp)
  125. {
  126. vm_offset_t buf;
  127. if (task == TASK_NULL) {
  128. return KERN_INVALID_ARGUMENT;
  129. }
  130. if ((buf = task->pc_sample.buffer) != 0)
  131. kfree(buf, sizeof (sampled_pcs));
  132. task->pc_sample.buffer = (vm_offset_t) 0;
  133. task->pc_sample.seqno = 0;
  134. task->pc_sample.sampletypes = 0; /* shut off sampling */
  135. return KERN_SUCCESS;
  136. }
  137. static kern_return_t
  138. get_sampled_pcs(
  139. sample_control_t *cp,
  140. sampled_pc_seqno_t *seqnop,
  141. sampled_pc_array_t sampled_pcs_out,
  142. int *sampled_pcs_cntp)
  143. {
  144. int nsamples;
  145. sampled_pc_seqno_t seqidx1, seqidx2;
  146. nsamples = cp->seqno - *seqnop;
  147. seqidx1 = *seqnop % MAX_PC_SAMPLES; /* index of *seqnop */
  148. seqidx2 = cp->seqno % MAX_PC_SAMPLES; /* index of cp->seqno */
  149. if (nsamples > MAX_PC_SAMPLES) {
  150. nsamples = MAX_PC_SAMPLES;
  151. seqidx1 = (seqidx2 + 1) % MAX_PC_SAMPLES;
  152. }
  153. if (nsamples > 0) {
  154. /*
  155. * Carefully copy sampled_pcs into sampled_pcs_msgbuf IN ORDER.
  156. */
  157. if (seqidx1 < seqidx2) {
  158. /*
  159. * Simple case: no wraparound.
  160. * Copy from seqidx1 to seqidx2.
  161. */
  162. memcpy(sampled_pcs_out,
  163. (sampled_pc_array_t)cp->buffer + seqidx1 + 1,
  164. nsamples * sizeof(sampled_pc_t));
  165. } else {
  166. /* seqidx1 > seqidx2 -- Handle wraparound. */
  167. memcpy(sampled_pcs_out,
  168. (sampled_pc_array_t)cp->buffer + seqidx1 + 1,
  169. (MAX_PC_SAMPLES - seqidx1 - 1) * sizeof(sampled_pc_t));
  170. memcpy(sampled_pcs_out + (MAX_PC_SAMPLES - seqidx1 - 1),
  171. (sampled_pc_array_t)cp->buffer,
  172. (seqidx2 + 1) * sizeof(sampled_pc_t));
  173. }
  174. } else if (nsamples < 0) {
  175. /* Bogus SEQNO supplied. */
  176. nsamples = 0;
  177. } else {
  178. /* could either be zero because of overflow, or because
  179. * we are being lied to. In either case, return nothing.
  180. * If overflow, only once in a blue moon. If being lied to,
  181. * then we have no obligation to return anything useful anyway.
  182. */
  183. ;
  184. }
  185. *sampled_pcs_cntp = nsamples;
  186. *seqnop = cp->seqno;
  187. return KERN_SUCCESS;
  188. }
  189. kern_return_t
  190. thread_get_sampled_pcs(
  191. thread_t thread,
  192. sampled_pc_seqno_t *seqnop,
  193. sampled_pc_array_t sampled_pcs_out,
  194. int *sampled_pcs_cntp)
  195. {
  196. if (thread == THREAD_NULL)
  197. return KERN_INVALID_ARGUMENT;
  198. if (thread->pc_sample.buffer == 0)
  199. return KERN_FAILURE;
  200. return get_sampled_pcs(&thread->pc_sample, seqnop, sampled_pcs_out,
  201. sampled_pcs_cntp);
  202. }
  203. kern_return_t
  204. task_get_sampled_pcs(
  205. task_t task,
  206. sampled_pc_seqno_t *seqnop,
  207. sampled_pc_array_t sampled_pcs_out,
  208. int *sampled_pcs_cntp)
  209. {
  210. if (task == TASK_NULL)
  211. return KERN_INVALID_ARGUMENT;
  212. if (task->pc_sample.buffer == 0)
  213. return KERN_FAILURE;
  214. return get_sampled_pcs(&task->pc_sample, seqnop, sampled_pcs_out,
  215. sampled_pcs_cntp);
  216. }
  217. #else /* MACH_PCSAMPLE */
  218. kern_return_t
  219. thread_enable_pc_sampling(
  220. const thread_t thread,
  221. const int *tickp,
  222. sampled_pc_flavor_t flavors)
  223. {
  224. return KERN_FAILURE; /* not implemented */
  225. }
  226. kern_return_t
  227. task_enable_pc_sampling(
  228. const task_t task,
  229. const int *tickp,
  230. sampled_pc_flavor_t flavors)
  231. {
  232. return KERN_FAILURE; /* not implemented */
  233. }
  234. kern_return_t
  235. thread_disable_pc_sampling(
  236. const thread_t thread,
  237. const int *samplecntp)
  238. {
  239. return KERN_FAILURE; /* not implemented */
  240. }
  241. kern_return_t
  242. task_disable_pc_sampling(
  243. const task_t task,
  244. const int *samplecntp)
  245. {
  246. return KERN_FAILURE; /* not implemented */
  247. }
  248. kern_return_t
  249. thread_get_sampled_pcs(
  250. const thread_t thread,
  251. const sampled_pc_seqno_t *seqnop,
  252. const sampled_pc_array_t sampled_pcs_out,
  253. const int *sampled_pcs_cntp)
  254. {
  255. return KERN_FAILURE; /* not implemented */
  256. }
  257. kern_return_t
  258. task_get_sampled_pcs(
  259. const task_t task,
  260. const sampled_pc_seqno_t *seqnop,
  261. const sampled_pc_array_t sampled_pcs_out,
  262. const int *sampled_pcs_cntp)
  263. {
  264. return KERN_FAILURE; /* not implemented */
  265. }
  266. #endif /* MACH_PCSAMPLE */