|
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(§ion->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(§ion->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(§ion->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(§ion->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 |
}
|