|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- /*
- * Copyright (c) 2012, Chris Andrews. All rights reserved.
- */
-
- #include "usdt_internal.h"
-
- #ifdef __APPLE__
-
- uint32_t
- usdt_probe_offset(usdt_probe_t *probe, char *dof, uint8_t argc)
- {
- uint32_t offset;
- #ifdef __x86_64__
- offset = ((uint64_t) probe->probe_addr - (uint64_t) dof + 2);
- #elif __i386__
- offset = ((uint32_t) probe->probe_addr - (uint32_t) dof + 2);
- #else
- #error "only x86_64 and i386 supported"
- #endif
- return (offset);
- }
-
- uint32_t
- usdt_is_enabled_offset(usdt_probe_t *probe, char *dof)
- {
- uint32_t offset;
- #ifdef __x86_64__
- offset = ((uint64_t) probe->isenabled_addr - (uint64_t) dof + 6);
- #elif __i386__
- offset = ((uint32_t) probe->isenabled_addr - (uint32_t) dof + 6);
- #else
- #error "only x86_64 and i386 supported"
- #endif
- return (offset);
- }
-
- #elif defined __linux__
-
- uint32_t
- usdt_probe_offset(usdt_probe_t *probe, char *dof, uint8_t argc)
- {
- return (16);
- }
-
- uint32_t
- usdt_is_enabled_offset(usdt_probe_t *probe, char *dof)
- {
- return (10);
- }
-
- #else /* solaris and freebsd */
-
- uint32_t
- usdt_probe_offset(usdt_probe_t *probe, char *dof, uint8_t argc)
- {
- return (16);
- }
-
- uint32_t
- usdt_is_enabled_offset(usdt_probe_t *probe, char *dof)
- {
- return (8);
- }
-
- #endif
-
- int
- usdt_create_tracepoints(usdt_probe_t *probe)
- {
- /* Prepare the tracepoints - for each probe, a separate chunk
- * of memory with the tracepoint code copied into it, to give
- * us unique addresses for each tracepoint.
- *
- * On Oracle Linux, this must be an mmapped file because USDT
- * probes there are implemented as uprobes, which are
- * addressed by inode and offset. The file used is a small
- * mkstemp'd file we immediately unlink.
- *
- * Elsewhere, we can use the heap directly because USDT will
- * instrument any memory mapped by the process.
- */
-
- size_t size;
- #ifdef __linux__
- int fd;
- char tmp[20] = "/tmp/libusdtXXXXXX";
-
- if ((fd = mkstemp(tmp)) < 0)
- return (-1);
- if (unlink(tmp) < 0)
- return (-1);
- if (write(fd, "\0", FUNC_SIZE) < FUNC_SIZE)
- return (-1);
-
- probe->isenabled_addr = (int (*)())mmap(NULL, FUNC_SIZE,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE, fd, 0);
- #else
- probe->isenabled_addr = (int (*)())valloc(FUNC_SIZE);
- #endif
- if (probe->isenabled_addr == NULL)
- return (-1);
-
- /* ensure that the tracepoints will fit the heap we're allocating */
- size = ((char *)usdt_tracepoint_end - (char *)usdt_tracepoint_isenabled);
- assert(size < FUNC_SIZE);
-
- size = ((char *)usdt_tracepoint_probe - (char *)usdt_tracepoint_isenabled);
- probe->probe_addr = (char *)probe->isenabled_addr + size;
-
- memcpy((void *)probe->isenabled_addr,
- (const void *)usdt_tracepoint_isenabled, FUNC_SIZE);
-
- #ifdef __linux__
- mprotect((void *)probe->isenabled_addr, FUNC_SIZE,
- PROT_READ | PROT_EXEC);
- #else
- mprotect((void *)probe->isenabled_addr, FUNC_SIZE,
- PROT_READ | PROT_WRITE | PROT_EXEC);
- #endif
-
- return (0);
- }
-
- void
- usdt_free_tracepoints(usdt_probe_t *probe)
- {
- #ifdef __linux__
- (void) munmap(probe->isenabled_addr, FUNC_SIZE);
- #else
- free(probe->isenabled_addr);
- #endif
- }
|