123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- /*
- * Copyright (c) 2012, Chris Andrews. All rights reserved.
- */
-
- #include "usdt_internal.h"
-
- #include <sys/ioctl.h>
-
- static uint8_t
- dof_version(uint8_t header_version)
- {
- uint8_t dof_version;
- /* DOF versioning: Apple always needs version 3, but Solaris can use
- 1 or 2 depending on whether is-enabled probes are needed. */
- #ifdef __APPLE__
- dof_version = DOF_VERSION_3;
- #else
- switch(header_version) {
- case 1:
- dof_version = DOF_VERSION_1;
- break;
- case 2:
- dof_version = DOF_VERSION_2;
- break;
- default:
- dof_version = DOF_VERSION;
- }
- #endif
- return dof_version;
- }
-
- #ifdef __APPLE__
- static const char *helper = "/dev/dtracehelper";
-
- static int
- load_dof(int fd, dof_helper_t *dh)
- {
- int ret;
- uint8_t buffer[sizeof(dof_ioctl_data_t) + sizeof(dof_helper_t)];
- dof_ioctl_data_t* ioctlData = (dof_ioctl_data_t*)buffer;
- user_addr_t val;
-
- ioctlData->dofiod_count = 1;
- memcpy(&ioctlData->dofiod_helpers[0], dh, sizeof(dof_helper_t));
-
- val = (user_addr_t)(unsigned long)ioctlData;
- ret = ioctl(fd, DTRACEHIOC_ADDDOF, &val);
-
- if (ret < 0)
- return ret;
-
- return (int)(ioctlData->dofiod_helpers[0].dofhp_dof);
- }
-
- #else /* Solaris and FreeBSD */
-
- /* ignore Sol10 GA ... */
- static const char *helper = "/dev/dtrace/helper";
-
- static int
- load_dof(int fd, dof_helper_t *dh)
- {
- int ret;
-
- ret = ioctl(fd, DTRACEHIOC_ADDDOF, dh);
- #if defined(__FreeBSD__) && __FreeBSD__ <= 10
- if (ret != -1)
- ret = dh ->gen;
- #endif
- return ret;
- }
-
- #endif
-
- static void
- pad_section(usdt_dof_section_t *sec)
- {
- size_t i, pad;
-
- if (sec->align > 1) {
- i = sec->offset % sec->align;
- if (i > 0) {
- pad = sec->align - i;
- sec->offset = (pad + sec->offset);
- sec->pad = pad;
- }
- }
- }
-
- static void
- dof_header(dof_hdr_t *header)
- {
- int i;
-
- header->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0;
- header->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1;
- header->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2;
- header->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3;
-
- header->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE;
- header->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE;
- header->dofh_ident[DOF_ID_VERSION] = dof_version(2);
- header->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION;
- header->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS;
- header->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS;
-
- for (i = DOF_ID_PAD; i < DOF_ID_SIZE; i++)
- header->dofh_ident[i] = 0;
-
- header->dofh_flags = 0;
-
- header->dofh_hdrsize = sizeof(dof_hdr_t);
- header->dofh_secsize = sizeof(dof_sec_t);
- header->dofh_secoff = sizeof(dof_hdr_t);
-
- header->dofh_loadsz = 0;
- header->dofh_filesz = 0;
- header->dofh_pad = 0;
- }
-
- static size_t
- add_header(usdt_dof_file_t *file, size_t offset, usdt_dof_section_t *section)
- {
- dof_sec_t header;
-
- header.dofs_flags = section->flags;
- header.dofs_type = section->type;
- header.dofs_offset = section->offset;
- header.dofs_size = section->size;
- header.dofs_entsize = section->entsize;
- header.dofs_align = section->align;
-
- memcpy((file->dof + offset), &header, sizeof(dof_sec_t));
- return (offset + sizeof(dof_sec_t));
- }
-
- static size_t
- add_section(usdt_dof_file_t *file, size_t offset, usdt_dof_section_t *section)
- {
- if (section->pad > 0) {
- /* maximum padding required is 7 */
- memcpy((file->dof + offset), "\0\0\0\0\0\0\0", section->pad);
- offset += section->pad;
- }
-
- memcpy((file->dof + offset), section->data, section->size);
- return (offset + section->size);
- }
-
- int
- usdt_dof_file_unload(usdt_dof_file_t *file)
- {
- int fd, ret;
-
- if ((fd = open(helper, O_RDWR)) < 0)
- return (-1);
-
- #ifdef __FreeBSD__
- ret = ioctl(fd, DTRACEHIOC_REMOVE, &file->gen);
- #else
- ret = ioctl(fd, DTRACEHIOC_REMOVE, file->gen);
- #endif
-
- if (ret < 0)
- return (-1);
-
- if ((close(fd)) < 0)
- return (-1);
-
- return (0);
- }
-
- int
- usdt_dof_file_load(usdt_dof_file_t *file, const char *module)
- {
- dof_helper_t dh;
- dof_hdr_t *dof;
- int fd;
-
- dof = (dof_hdr_t *) file->dof;
-
- dh.dofhp_dof = (uintptr_t)dof;
- dh.dofhp_addr = (uintptr_t)dof;
- #if __FreeBSD__ >= 11
- dh.dofhp_pid = getpid();
- #endif
- (void) strncpy(dh.dofhp_mod, module, sizeof (dh.dofhp_mod));
-
- if ((fd = open(helper, O_RDWR)) < 0)
- return (-1);
-
- file->gen = load_dof(fd, &dh);
-
- if ((close(fd)) < 0)
- return (-1);
-
- if (file->gen < 0)
- return (-1);
-
- return (0);
- }
-
- void
- usdt_dof_file_append_section(usdt_dof_file_t *file, usdt_dof_section_t *section)
- {
- usdt_dof_section_t *s;
-
- if (file->sections == NULL) {
- file->sections = section;
- }
- else {
- for (s = file->sections; (s->next != NULL); s = s->next) ;
- s->next = section;
- }
- }
-
- void
- usdt_dof_file_generate(usdt_dof_file_t *file, usdt_strtab_t *strtab)
- {
- dof_hdr_t header;
- uint64_t filesz;
- uint64_t loadsz;
- usdt_dof_section_t *sec;
- size_t offset;
-
- dof_header(&header);
- header.dofh_secnum = 6;
-
- filesz = sizeof(dof_hdr_t) + (sizeof(dof_sec_t) * header.dofh_secnum);
- loadsz = filesz;
-
- strtab->offset = filesz;
- pad_section((usdt_dof_section_t *)strtab);
- filesz += strtab->size + strtab->pad;
-
- if (strtab->flags & 1)
- loadsz += strtab->size + strtab->pad;
-
- for (sec = file->sections; sec != NULL; sec = sec->next) {
- sec->offset = filesz;
- pad_section(sec);
- filesz += sec->size + sec->pad;
- if (sec->flags & 1)
- loadsz += sec->size + sec->pad;
- }
-
- header.dofh_loadsz = loadsz;
- header.dofh_filesz = filesz;
- memcpy(file->dof, &header, sizeof(dof_hdr_t));
-
- offset = sizeof(dof_hdr_t);
-
- offset = add_header(file, offset, (usdt_dof_section_t *)strtab);
-
- for (sec = file->sections; sec != NULL; sec = sec->next)
- offset = add_header(file, offset, sec);
-
- offset = add_section(file, offset, (usdt_dof_section_t *)strtab);
-
- for (sec = file->sections; sec != NULL; sec = sec->next)
- offset = add_section(file, offset, sec);
- }
-
- usdt_dof_file_t *
- usdt_dof_file_init(usdt_provider_t *provider, size_t size)
- {
- usdt_dof_file_t *file;
-
- if ((file = malloc(sizeof(*file))) == NULL) {
- usdt_error(provider, USDT_ERROR_MALLOC);
- return (NULL);
- }
-
- if ((file->dof = valloc(size)) == NULL) {
- usdt_error(provider, USDT_ERROR_VALLOC);
- return (NULL);
- }
-
- file->sections = NULL;
- file->size = size;
-
- return (file);
- }
-
- void
- usdt_dof_file_free(usdt_dof_file_t *file)
- {
- free(file->dof);
- free(file);
- }
|