|
Packit |
b1f7ae |
/*
|
|
Packit |
b1f7ae |
* Copyright (c) 2015-2017, Intel Corporation
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
b1f7ae |
* modification, are permitted provided that the following conditions are met:
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* * Redistributions of source code must retain the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer.
|
|
Packit |
b1f7ae |
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer in the documentation
|
|
Packit |
b1f7ae |
* and/or other materials provided with the distribution.
|
|
Packit |
b1f7ae |
* * Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
b1f7ae |
* may be used to endorse or promote products derived from this software
|
|
Packit |
b1f7ae |
* without specific prior written permission.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
b1f7ae |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
b1f7ae |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
b1f7ae |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
Packit |
b1f7ae |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
Packit |
b1f7ae |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
Packit |
b1f7ae |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
Packit |
b1f7ae |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
Packit |
b1f7ae |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
b1f7ae |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
Packit |
b1f7ae |
* POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include "pt_section.h"
|
|
Packit |
b1f7ae |
#include "pt_section_windows.h"
|
|
Packit |
b1f7ae |
#include "pt_section_file.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include "intel-pt.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include <stdlib.h>
|
|
Packit |
b1f7ae |
#include <stdio.h>
|
|
Packit |
b1f7ae |
#include <fcntl.h>
|
|
Packit |
b1f7ae |
#include <io.h>
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int pt_sec_windows_fstat(const char *filename, struct _stat *stat)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
int fd, errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!filename || !stat)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fd = _open(filename, _O_RDONLY);
|
|
Packit |
b1f7ae |
if (fd == -1)
|
|
Packit |
b1f7ae |
return -pte_bad_image;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = _fstat(fd, stat);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
_close(fd);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (errcode)
|
|
Packit |
b1f7ae |
return -pte_bad_image;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_sec_windows_status *status;
|
|
Packit |
b1f7ae |
struct _stat stat;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!pstatus || !psize)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_sec_windows_fstat(filename, &stat;;
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (stat.st_size < 0)
|
|
Packit |
b1f7ae |
return -pte_bad_image;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
status = malloc(sizeof(*status));
|
|
Packit |
b1f7ae |
if (!status)
|
|
Packit |
b1f7ae |
return -pte_nomem;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
status->stat = stat;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*pstatus = status;
|
|
Packit |
b1f7ae |
*psize = stat.st_size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int check_file_status(struct pt_section *section, int fd)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_sec_windows_status *status;
|
|
Packit |
b1f7ae |
struct _stat stat;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!section)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = _fstat(fd, &stat;;
|
|
Packit |
b1f7ae |
if (errcode)
|
|
Packit |
b1f7ae |
return -pte_bad_image;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
status = section->status;
|
|
Packit |
b1f7ae |
if (!status)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (stat.st_size != status->stat.st_size)
|
|
Packit |
b1f7ae |
return -pte_bad_image;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (stat.st_mtime != status->stat.st_mtime)
|
|
Packit |
b1f7ae |
return -pte_bad_image;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static DWORD granularity(void)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct _SYSTEM_INFO sysinfo;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
GetSystemInfo(&sysinfo);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return sysinfo.dwAllocationGranularity;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_sec_windows_map(struct pt_section *section, int fd)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_sec_windows_mapping *mapping;
|
|
Packit |
b1f7ae |
uint64_t offset, size, adjustment;
|
|
Packit |
b1f7ae |
HANDLE fh, mh;
|
|
Packit |
b1f7ae |
DWORD dsize;
|
|
Packit |
b1f7ae |
uint8_t *base;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!section)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
offset = section->offset;
|
|
Packit |
b1f7ae |
size = section->size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
adjustment = offset % granularity();
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
offset -= adjustment;
|
|
Packit |
b1f7ae |
size += adjustment;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* The section is supposed to fit into the file so we shouldn't
|
|
Packit |
b1f7ae |
* see any overflows, here.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (size < section->size)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
dsize = (DWORD) size;
|
|
Packit |
b1f7ae |
if ((uint64_t) dsize != size)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fh = (HANDLE) _get_osfhandle(fd);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
mh = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
Packit |
b1f7ae |
if (!mh)
|
|
Packit |
b1f7ae |
return -pte_bad_image;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
base = MapViewOfFile(mh, FILE_MAP_READ, (DWORD) (offset >> 32),
|
|
Packit |
b1f7ae |
(DWORD) (uint32_t) offset, dsize);
|
|
Packit |
b1f7ae |
if (!base)
|
|
Packit |
b1f7ae |
goto out_mh;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
mapping = malloc(sizeof(*mapping));
|
|
Packit |
b1f7ae |
if (!mapping)
|
|
Packit |
b1f7ae |
goto out_map;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
mapping->fd = fd;
|
|
Packit |
b1f7ae |
mapping->mh = mh;
|
|
Packit |
b1f7ae |
mapping->base = base;
|
|
Packit |
b1f7ae |
mapping->begin = base + adjustment;
|
|
Packit |
b1f7ae |
mapping->end = base + size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
section->mapping = mapping;
|
|
Packit |
b1f7ae |
section->unmap = pt_sec_windows_unmap;
|
|
Packit |
b1f7ae |
section->read = pt_sec_windows_read;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return pt_section_add_bcache(section);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
out_map:
|
|
Packit |
b1f7ae |
UnmapViewOfFile(base);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
out_mh:
|
|
Packit |
b1f7ae |
CloseHandle(mh);
|
|
Packit |
b1f7ae |
return -pte_bad_image;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_section_map(struct pt_section *section)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
const char *filename;
|
|
Packit |
b1f7ae |
uint16_t mcount;
|
|
Packit |
b1f7ae |
HANDLE fh;
|
|
Packit |
b1f7ae |
FILE *file;
|
|
Packit |
b1f7ae |
int fd, errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!section)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_section_lock(section);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
mcount = section->mcount + 1;
|
|
Packit |
b1f7ae |
if (mcount > 1) {
|
|
Packit |
b1f7ae |
section->mcount = mcount;
|
|
Packit |
b1f7ae |
return pt_section_unlock(section);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!mcount) {
|
|
Packit |
b1f7ae |
errcode = -pte_internal;
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (section->mapping) {
|
|
Packit |
b1f7ae |
errcode = -pte_internal;
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
filename = section->filename;
|
|
Packit |
b1f7ae |
if (!filename) {
|
|
Packit |
b1f7ae |
errcode = -pte_internal;
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fh = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
Packit |
b1f7ae |
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
Packit |
b1f7ae |
if (fh == INVALID_HANDLE_VALUE) {
|
|
Packit |
b1f7ae |
/* We failed to open the file read-only. Let's try to open it
|
|
Packit |
b1f7ae |
* read-write; maybe our user has the file open for writing.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* We will detect changes to the file via fstat().
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fh = CreateFile(filename, GENERIC_READ, FILE_SHARE_WRITE, NULL,
|
|
Packit |
b1f7ae |
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
Packit |
b1f7ae |
if (fh == INVALID_HANDLE_VALUE) {
|
|
Packit |
b1f7ae |
errcode = -pte_bad_image;
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fd = _open_osfhandle((intptr_t) fh, _O_RDONLY);
|
|
Packit |
b1f7ae |
if (fd == -1) {
|
|
Packit |
b1f7ae |
errcode = -pte_bad_image;
|
|
Packit |
b1f7ae |
goto out_fh;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = check_file_status(section, fd);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
errcode = -pte_bad_image;
|
|
Packit |
b1f7ae |
goto out_fd;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We leave the file open on success. It will be closed when the
|
|
Packit |
b1f7ae |
* section is unmapped.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
errcode = pt_sec_windows_map(section, fd);
|
|
Packit |
b1f7ae |
if (!errcode) {
|
|
Packit |
b1f7ae |
section->mcount = 1;
|
|
Packit |
b1f7ae |
return pt_section_unlock(section);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Fall back to file based sections - report the original error
|
|
Packit |
b1f7ae |
* if we fail to convert the file descriptor.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
file = _fdopen(fd, "rb");
|
|
Packit |
b1f7ae |
if (!file) {
|
|
Packit |
b1f7ae |
errcode = -pte_bad_image;
|
|
Packit |
b1f7ae |
goto out_fd;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We need to keep the file open on success. It will be closed when
|
|
Packit |
b1f7ae |
* the section is unmapped.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
errcode = pt_sec_file_map(section, file);
|
|
Packit |
b1f7ae |
if (!errcode) {
|
|
Packit |
b1f7ae |
section->mcount = 1;
|
|
Packit |
b1f7ae |
return pt_section_unlock(section);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fclose(file);
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
out_fd:
|
|
Packit |
b1f7ae |
_close(fd);
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
out_fh:
|
|
Packit |
b1f7ae |
CloseHandle(fh);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
out_unlock:
|
|
Packit |
b1f7ae |
(void) pt_section_unlock(section);
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_sec_windows_unmap(struct pt_section *section)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_sec_windows_mapping *mapping;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!section)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
mapping = section->mapping;
|
|
Packit |
b1f7ae |
if (!mapping || !section->unmap || !section->read)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
section->mapping = NULL;
|
|
Packit |
b1f7ae |
section->unmap = NULL;
|
|
Packit |
b1f7ae |
section->read = NULL;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
UnmapViewOfFile(mapping->begin);
|
|
Packit |
b1f7ae |
CloseHandle(mapping->mh);
|
|
Packit |
b1f7ae |
_close(mapping->fd);
|
|
Packit |
b1f7ae |
free(mapping);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_sec_windows_read(const struct pt_section *section, uint8_t *buffer,
|
|
Packit |
b1f7ae |
uint16_t size, uint64_t offset)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_sec_windows_mapping *mapping;
|
|
Packit |
b1f7ae |
const uint8_t *begin;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!buffer || !section)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
mapping = section->mapping;
|
|
Packit |
b1f7ae |
if (!mapping)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We already checked in pt_section_read() that the requested memory
|
|
Packit |
b1f7ae |
* lies within the section's boundaries.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* And we checked that the entire section was mapped. There's no need
|
|
Packit |
b1f7ae |
* to check for overflows, again.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
begin = mapping->begin + offset;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
memcpy(buffer, begin, size);
|
|
Packit |
b1f7ae |
return (int) size;
|
|
Packit |
b1f7ae |
}
|