Blame libipt/src/pt_section.c

Packit b1f7ae
/*
Packit b1f7ae
 * Copyright (c) 2013-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_block_cache.h"
Packit b1f7ae
Packit b1f7ae
#include "intel-pt.h"
Packit b1f7ae
Packit b1f7ae
#include <stdlib.h>
Packit b1f7ae
#include <stdio.h>
Packit b1f7ae
#include <string.h>
Packit b1f7ae
Packit b1f7ae
Packit b1f7ae
static char *dupstr(const char *str)
Packit b1f7ae
{
Packit b1f7ae
	char *dup;
Packit b1f7ae
	size_t len;
Packit b1f7ae
Packit b1f7ae
	if (!str)
Packit b1f7ae
		return NULL;
Packit b1f7ae
Packit b1f7ae
	len = strlen(str);
Packit b1f7ae
	dup = malloc(len + 1);
Packit b1f7ae
	if (!dup)
Packit b1f7ae
		return NULL;
Packit b1f7ae
Packit b1f7ae
	return strcpy(dup, str);
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
struct pt_section *pt_mk_section(const char *filename, uint64_t offset,
Packit b1f7ae
				 uint64_t size)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section *section;
Packit b1f7ae
	uint64_t fsize;
Packit b1f7ae
	void *status;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_section_mk_status(&status, &fsize, filename);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return NULL;
Packit b1f7ae
Packit b1f7ae
	/* Fail if the requested @offset lies beyond the end of @file. */
Packit b1f7ae
	if (fsize <= offset)
Packit b1f7ae
		goto out_status;
Packit b1f7ae
Packit b1f7ae
	/* Truncate @size so the entire range lies within @file. */
Packit b1f7ae
	fsize -= offset;
Packit b1f7ae
	if (fsize < size)
Packit b1f7ae
		size = fsize;
Packit b1f7ae
Packit b1f7ae
	section = malloc(sizeof(*section));
Packit b1f7ae
	if (!section)
Packit b1f7ae
		goto out_status;
Packit b1f7ae
Packit b1f7ae
	memset(section, 0, sizeof(*section));
Packit b1f7ae
Packit b1f7ae
	section->filename = dupstr(filename);
Packit b1f7ae
	section->status = status;
Packit b1f7ae
	section->offset = offset;
Packit b1f7ae
	section->size = size;
Packit b1f7ae
	section->ucount = 1;
Packit b1f7ae
Packit b1f7ae
#if defined(FEATURE_THREADS)
Packit b1f7ae
Packit b1f7ae
	errcode = mtx_init(&section->lock, mtx_plain);
Packit b1f7ae
	if (errcode != thrd_success) {
Packit b1f7ae
		free(section->filename);
Packit b1f7ae
		free(section);
Packit b1f7ae
		goto out_status;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
#endif /* defined(FEATURE_THREADS) */
Packit b1f7ae
Packit b1f7ae
	return section;
Packit b1f7ae
Packit b1f7ae
out_status:
Packit b1f7ae
	free(status);
Packit b1f7ae
	return NULL;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_section_clone(struct pt_section **pclone,
Packit b1f7ae
		     const struct pt_section *section, uint64_t offset,
Packit b1f7ae
		     uint64_t size)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section *clone;
Packit b1f7ae
	uint64_t begin, end, sbegin, send;
Packit b1f7ae
Packit b1f7ae
	if (!pclone || !section)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	begin = offset;
Packit b1f7ae
	end = begin + size;
Packit b1f7ae
Packit b1f7ae
	sbegin = pt_section_offset(section);
Packit b1f7ae
	send = sbegin + pt_section_size(section);
Packit b1f7ae
Packit b1f7ae
	if (begin < sbegin || send < end)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	clone = pt_mk_section(pt_section_filename(section), offset, size);
Packit b1f7ae
	if (!clone)
Packit b1f7ae
		return -pte_nomem;
Packit b1f7ae
Packit b1f7ae
	*pclone = clone;
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_section_lock(struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
#if defined(FEATURE_THREADS)
Packit b1f7ae
	{
Packit b1f7ae
		int errcode;
Packit b1f7ae
Packit b1f7ae
		errcode = mtx_lock(&section->lock);
Packit b1f7ae
		if (errcode != thrd_success)
Packit b1f7ae
			return -pte_bad_lock;
Packit b1f7ae
	}
Packit b1f7ae
#endif /* defined(FEATURE_THREADS) */
Packit b1f7ae
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_section_unlock(struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
#if defined(FEATURE_THREADS)
Packit b1f7ae
	{
Packit b1f7ae
		int errcode;
Packit b1f7ae
Packit b1f7ae
		errcode = mtx_unlock(&section->lock);
Packit b1f7ae
		if (errcode != thrd_success)
Packit b1f7ae
			return -pte_bad_lock;
Packit b1f7ae
	}
Packit b1f7ae
#endif /* defined(FEATURE_THREADS) */
Packit b1f7ae
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
static void pt_section_free(struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return;
Packit b1f7ae
Packit b1f7ae
#if defined(FEATURE_THREADS)
Packit b1f7ae
Packit b1f7ae
	mtx_destroy(&section->lock);
Packit b1f7ae
Packit b1f7ae
#endif /* defined(FEATURE_THREADS) */
Packit b1f7ae
Packit b1f7ae
	free(section->filename);
Packit b1f7ae
	free(section->status);
Packit b1f7ae
	free(section);
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_section_get(struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	uint16_t ucount;
Packit b1f7ae
	int 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
	ucount = section->ucount + 1;
Packit b1f7ae
	if (!ucount) {
Packit b1f7ae
		(void) pt_section_unlock(section);
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	section->ucount = ucount;
Packit b1f7ae
Packit b1f7ae
	return pt_section_unlock(section);
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_section_put(struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	uint16_t ucount, mcount;
Packit b1f7ae
	int 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;
Packit b1f7ae
	ucount = section->ucount;
Packit b1f7ae
	if (ucount > 1) {
Packit b1f7ae
		section->ucount = ucount - 1;
Packit b1f7ae
		return pt_section_unlock(section);
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	errcode = pt_section_unlock(section);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	if (!ucount || mcount)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	pt_section_free(section);
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
const char *pt_section_filename(const struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return NULL;
Packit b1f7ae
Packit b1f7ae
	return section->filename;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
uint64_t pt_section_size(const struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return 0ull;
Packit b1f7ae
Packit b1f7ae
	return section->size;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
uint64_t pt_section_offset(const struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return 0ull;
Packit b1f7ae
Packit b1f7ae
	return section->offset;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_section_add_bcache(struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	uint32_t cache_size;
Packit b1f7ae
Packit b1f7ae
	if (!section || section->bcache)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	if (section->disable_bcache)
Packit b1f7ae
		return 0;
Packit b1f7ae
Packit b1f7ae
	cache_size = (uint32_t) section->size;
Packit b1f7ae
Packit b1f7ae
	/* We do not allocate a cache if it would get too big.
Packit b1f7ae
	 *
Packit b1f7ae
	 * We also do not treat failure to allocate a cache as an error.
Packit b1f7ae
	 * Without the cache, decode will be slower but still correct.
Packit b1f7ae
	 */
Packit b1f7ae
	if (cache_size == section->size)
Packit b1f7ae
		section->bcache = pt_bcache_alloc(cache_size);
Packit b1f7ae
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_section_unmap(struct pt_section *section)
Packit b1f7ae
{
Packit b1f7ae
	uint16_t mcount;
Packit b1f7ae
	int errcode, status;
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;
Packit b1f7ae
Packit b1f7ae
	errcode = -pte_nomap;
Packit b1f7ae
	if (!mcount)
Packit b1f7ae
		goto out_unlock;
Packit b1f7ae
Packit b1f7ae
	section->mcount = mcount -= 1;
Packit b1f7ae
	if (mcount)
Packit b1f7ae
		return pt_section_unlock(section);
Packit b1f7ae
Packit b1f7ae
	errcode = -pte_internal;
Packit b1f7ae
	if (!section->unmap)
Packit b1f7ae
		goto out_unlock;
Packit b1f7ae
Packit b1f7ae
	status = section->unmap(section);
Packit b1f7ae
Packit b1f7ae
	pt_bcache_free(section->bcache);
Packit b1f7ae
	section->bcache = NULL;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_section_unlock(section);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	return status;
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_section_read(const struct pt_section *section, uint8_t *buffer,
Packit b1f7ae
		    uint16_t size, uint64_t offset)
Packit b1f7ae
{
Packit b1f7ae
	uint64_t limit, space;
Packit b1f7ae
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	if (!section->read)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	limit = section->size;
Packit b1f7ae
	if (limit <= offset)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	/* Truncate if we try to read past the end of the section. */
Packit b1f7ae
	space = limit - offset;
Packit b1f7ae
	if (space < size)
Packit b1f7ae
		size = (uint16_t) space;
Packit b1f7ae
Packit b1f7ae
	return section->read(section, buffer, size, offset);
Packit b1f7ae
}