123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- /*
- * Mach Operating System
- * Copyright (c) 1993,1992 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
- #include <kern/printf.h>
- #include <string.h>
- #include <mach/mach_types.h> /* vm_address_t */
- #include <mach/std_types.h> /* pointer_t */
- #include <mach/pc_sample.h>
- #include <machine/trap.h>
- #include <kern/kalloc.h>
- #include <kern/host.h>
- #include <kern/thread.h>
- #include <kern/pc_sample.h>
- #include <kern/mach_clock.h>
- #if MACH_PCSAMPLE
- #define MAX_PC_SAMPLES 512
- typedef sampled_pc_t sampled_pcs[MAX_PC_SAMPLES];
- void take_pc_sample(
- const thread_t t,
- sample_control_t *cp,
- sampled_pc_flavor_t flavor,
- boolean_t usermode,
- vm_offset_t kern_pc)
- {
- vm_offset_t pc;
- struct sampled_pc *sample;
-
- if (usermode)
- pc = interrupted_pc(t);
- else
- pc = kern_pc;
- cp->seqno++;
- sample = &((sampled_pc_t *)cp->buffer)[cp->seqno % MAX_PC_SAMPLES];
- sample->id = (vm_offset_t)t;
- sample->pc = pc;
- sample->sampletype = flavor;
- }
- kern_return_t
- thread_enable_pc_sampling(
- thread_t thread,
- int *tickp,
- sampled_pc_flavor_t flavors)
- {
- vm_offset_t buf;
- if (thread == THREAD_NULL) {
- return KERN_INVALID_ARGUMENT;
- }
- if (thread->pc_sample.buffer == 0) {
- buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
- if (buf == 0) {
- printf("thread_enable_pc_sampling: kalloc failed\n");
- return KERN_INVALID_ARGUMENT;
- }
- thread->pc_sample.buffer = buf;
- thread->pc_sample.seqno = 0;
- }
- *tickp = tick;
- thread->pc_sample.sampletypes = flavors;
- return KERN_SUCCESS;
- }
- kern_return_t
- task_enable_pc_sampling(
- task_t task,
- int *tickp,
- sampled_pc_flavor_t flavors)
- {
- vm_offset_t buf;
- if (task == TASK_NULL) {
- return KERN_INVALID_ARGUMENT;
- }
- if (task->pc_sample.buffer == 0) {
- buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
- if (buf == 0) {
- printf("task_enable_pc_sampling: kalloc failed\n");
- return KERN_INVALID_ARGUMENT;
- }
- task->pc_sample.buffer = buf;
- task->pc_sample.seqno = 0;
- }
- *tickp = tick;
- task->pc_sample.sampletypes = flavors;
- return KERN_SUCCESS;
- }
- kern_return_t
- thread_disable_pc_sampling(
- thread_t thread,
- int *samplecntp)
- {
- vm_offset_t buf;
- if (thread == THREAD_NULL) {
- return KERN_INVALID_ARGUMENT;
- }
- if ((buf = thread->pc_sample.buffer) != 0)
- kfree(buf, sizeof (sampled_pcs));
- thread->pc_sample.buffer = (vm_offset_t) 0;
- thread->pc_sample.seqno = 0;
- thread->pc_sample.sampletypes = 0; /* shut off sampling */
-
- return KERN_SUCCESS;
- }
- kern_return_t
- task_disable_pc_sampling(
- task_t task,
- int *samplecntp)
- {
- vm_offset_t buf;
- if (task == TASK_NULL) {
- return KERN_INVALID_ARGUMENT;
- }
- if ((buf = task->pc_sample.buffer) != 0)
- kfree(buf, sizeof (sampled_pcs));
- task->pc_sample.buffer = (vm_offset_t) 0;
- task->pc_sample.seqno = 0;
- task->pc_sample.sampletypes = 0; /* shut off sampling */
- return KERN_SUCCESS;
- }
- static kern_return_t
- get_sampled_pcs(
- sample_control_t *cp,
- sampled_pc_seqno_t *seqnop,
- sampled_pc_array_t sampled_pcs_out,
- int *sampled_pcs_cntp)
- {
- int nsamples;
- sampled_pc_seqno_t seqidx1, seqidx2;
- nsamples = cp->seqno - *seqnop;
- seqidx1 = *seqnop % MAX_PC_SAMPLES; /* index of *seqnop */
- seqidx2 = cp->seqno % MAX_PC_SAMPLES; /* index of cp->seqno */
- if (nsamples > MAX_PC_SAMPLES) {
- nsamples = MAX_PC_SAMPLES;
- seqidx1 = (seqidx2 + 1) % MAX_PC_SAMPLES;
- }
- if (nsamples > 0) {
- /*
- * Carefully copy sampled_pcs into sampled_pcs_msgbuf IN ORDER.
- */
- if (seqidx1 < seqidx2) {
- /*
- * Simple case: no wraparound.
- * Copy from seqidx1 to seqidx2.
- */
- memcpy(sampled_pcs_out,
- (sampled_pc_array_t)cp->buffer + seqidx1 + 1,
- nsamples * sizeof(sampled_pc_t));
- } else {
- /* seqidx1 > seqidx2 -- Handle wraparound. */
- memcpy(sampled_pcs_out,
- (sampled_pc_array_t)cp->buffer + seqidx1 + 1,
- (MAX_PC_SAMPLES - seqidx1 - 1) * sizeof(sampled_pc_t));
- memcpy(sampled_pcs_out + (MAX_PC_SAMPLES - seqidx1 - 1),
- (sampled_pc_array_t)cp->buffer,
- (seqidx2 + 1) * sizeof(sampled_pc_t));
- }
- } else if (nsamples < 0) {
- /* Bogus SEQNO supplied. */
- nsamples = 0;
- } else {
- /* could either be zero because of overflow, or because
- * we are being lied to. In either case, return nothing.
- * If overflow, only once in a blue moon. If being lied to,
- * then we have no obligation to return anything useful anyway.
- */
- ;
- }
-
- *sampled_pcs_cntp = nsamples;
- *seqnop = cp->seqno;
- return KERN_SUCCESS;
- }
- kern_return_t
- thread_get_sampled_pcs(
- thread_t thread,
- sampled_pc_seqno_t *seqnop,
- sampled_pc_array_t sampled_pcs_out,
- int *sampled_pcs_cntp)
- {
- if (thread == THREAD_NULL)
- return KERN_INVALID_ARGUMENT;
- if (thread->pc_sample.buffer == 0)
- return KERN_FAILURE;
- return get_sampled_pcs(&thread->pc_sample, seqnop, sampled_pcs_out,
- sampled_pcs_cntp);
- }
- kern_return_t
- task_get_sampled_pcs(
- task_t task,
- sampled_pc_seqno_t *seqnop,
- sampled_pc_array_t sampled_pcs_out,
- int *sampled_pcs_cntp)
- {
- if (task == TASK_NULL)
- return KERN_INVALID_ARGUMENT;
- if (task->pc_sample.buffer == 0)
- return KERN_FAILURE;
- return get_sampled_pcs(&task->pc_sample, seqnop, sampled_pcs_out,
- sampled_pcs_cntp);
- }
- #else /* MACH_PCSAMPLE */
- kern_return_t
- thread_enable_pc_sampling(
- const thread_t thread,
- const int *tickp,
- sampled_pc_flavor_t flavors)
- {
- return KERN_FAILURE; /* not implemented */
- }
- kern_return_t
- task_enable_pc_sampling(
- const task_t task,
- const int *tickp,
- sampled_pc_flavor_t flavors)
- {
- return KERN_FAILURE; /* not implemented */
- }
- kern_return_t
- thread_disable_pc_sampling(
- const thread_t thread,
- const int *samplecntp)
- {
- return KERN_FAILURE; /* not implemented */
- }
- kern_return_t
- task_disable_pc_sampling(
- const task_t task,
- const int *samplecntp)
- {
- return KERN_FAILURE; /* not implemented */
- }
- kern_return_t
- thread_get_sampled_pcs(
- const thread_t thread,
- const sampled_pc_seqno_t *seqnop,
- const sampled_pc_array_t sampled_pcs_out,
- const int *sampled_pcs_cntp)
- {
- return KERN_FAILURE; /* not implemented */
- }
- kern_return_t
- task_get_sampled_pcs(
- const task_t task,
- const sampled_pc_seqno_t *seqnop,
- const sampled_pc_array_t sampled_pcs_out,
- const int *sampled_pcs_cntp)
- {
- return KERN_FAILURE; /* not implemented */
- }
- #endif /* MACH_PCSAMPLE */
|