|
Packit |
b1f7ae |
/*
|
|
Packit |
b1f7ae |
* Copyright (c) 2016-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_image_section_cache.h"
|
|
Packit |
b1f7ae |
#include "pt_section.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include "intel-pt.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include <stdlib.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 |
int pt_iscache_init(struct pt_image_section_cache *iscache, const char *name)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!iscache)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
memset(iscache, 0, sizeof(*iscache));
|
|
Packit |
b1f7ae |
if (name) {
|
|
Packit |
b1f7ae |
iscache->name = dupstr(name);
|
|
Packit |
b1f7ae |
if (!iscache->name)
|
|
Packit |
b1f7ae |
return -pte_nomem;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#if defined(FEATURE_THREADS)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = mtx_init(&iscache->lock, mtx_plain);
|
|
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 |
void pt_iscache_fini(struct pt_image_section_cache *iscache)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!iscache)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
(void) pt_iscache_clear(iscache);
|
|
Packit |
b1f7ae |
free(iscache->name);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#if defined(FEATURE_THREADS)
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
mtx_destroy(&iscache->lock);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#endif /* defined(FEATURE_THREADS) */
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int pt_iscache_lock(struct pt_image_section_cache *iscache)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!iscache)
|
|
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(&iscache->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 inline int pt_iscache_unlock(struct pt_image_section_cache *iscache)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!iscache)
|
|
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(&iscache->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 inline int isid_from_index(uint16_t index)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return index + 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int pt_iscache_expand(struct pt_image_section_cache *iscache)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_iscache_entry *entries;
|
|
Packit |
b1f7ae |
uint16_t capacity, target;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!iscache)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
capacity = iscache->capacity;
|
|
Packit |
b1f7ae |
target = capacity + 8;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Check for overflows. */
|
|
Packit |
b1f7ae |
if (target < capacity)
|
|
Packit |
b1f7ae |
return -pte_nomem;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
entries = realloc(iscache->entries, target * sizeof(*entries));
|
|
Packit |
b1f7ae |
if (!entries)
|
|
Packit |
b1f7ae |
return -pte_nomem;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
iscache->capacity = target;
|
|
Packit |
b1f7ae |
iscache->entries = entries;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int pt_iscache_find_locked(struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
const char *filename, uint64_t offset,
|
|
Packit |
b1f7ae |
uint64_t size, uint64_t laddr)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint16_t idx, end;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!iscache || !filename)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
end = iscache->size;
|
|
Packit |
b1f7ae |
for (idx = 0; idx < end; ++idx) {
|
|
Packit |
b1f7ae |
const struct pt_iscache_entry *entry;
|
|
Packit |
b1f7ae |
const struct pt_section *section;
|
|
Packit |
b1f7ae |
const char *sec_filename;
|
|
Packit |
b1f7ae |
uint64_t sec_offset, sec_size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
entry = &iscache->entries[idx];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We do not zero-initialize the array - a NULL check is
|
|
Packit |
b1f7ae |
* pointless.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
section = entry->section;
|
|
Packit |
b1f7ae |
sec_filename = pt_section_filename(section);
|
|
Packit |
b1f7ae |
sec_offset = pt_section_offset(section);
|
|
Packit |
b1f7ae |
sec_size = pt_section_size(section);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (entry->laddr != laddr)
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (sec_offset != offset)
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (sec_size != size)
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We should not have a section without a filename. */
|
|
Packit |
b1f7ae |
if (!sec_filename)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (strcmp(sec_filename, filename) != 0)
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return isid_from_index(idx);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int section_match(const struct pt_section *lhs,
|
|
Packit |
b1f7ae |
const struct pt_section *rhs)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
const char *lfilename, *rfilename;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!lhs || !rhs)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (pt_section_offset(lhs) != pt_section_offset(rhs))
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (pt_section_size(lhs) != pt_section_size(rhs))
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
lfilename = pt_section_filename(lhs);
|
|
Packit |
b1f7ae |
rfilename = pt_section_filename(rhs);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!lfilename || !rfilename)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (strcmp(lfilename, rfilename) != 0)
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_iscache_add(struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
struct pt_section *section, uint64_t laddr)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint16_t idx, end;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!iscache || !section)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We must have a filename for @section. */
|
|
Packit |
b1f7ae |
if (!pt_section_filename(section))
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_lock(iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
end = iscache->size;
|
|
Packit |
b1f7ae |
for (idx = 0; idx < end; ++idx) {
|
|
Packit |
b1f7ae |
const struct pt_iscache_entry *entry;
|
|
Packit |
b1f7ae |
struct pt_section *sec;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
entry = &iscache->entries[idx];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We do not zero-initialize the array - a NULL check is
|
|
Packit |
b1f7ae |
* pointless.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
sec = entry->section;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = section_match(section, sec);
|
|
Packit |
b1f7ae |
if (errcode <= 0) {
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Use the cached section instead of the argument section.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* We'll be able to drop the argument section in this case and
|
|
Packit |
b1f7ae |
* only keep one copy around and, more importantly, mapped.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
section = sec;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If we also find a matching load address, we're done. */
|
|
Packit |
b1f7ae |
if (laddr == entry->laddr)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If we have not found a matching entry, add one. */
|
|
Packit |
b1f7ae |
if (idx == end) {
|
|
Packit |
b1f7ae |
struct pt_iscache_entry *entry;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Expand the cache, if necessary. */
|
|
Packit |
b1f7ae |
if (iscache->capacity <= iscache->size) {
|
|
Packit |
b1f7ae |
/* We must never exceed the capacity. */
|
|
Packit |
b1f7ae |
if (iscache->capacity < iscache->size) {
|
|
Packit |
b1f7ae |
errcode = -pte_internal;
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_expand(iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Make sure it is big enough, now. */
|
|
Packit |
b1f7ae |
if (iscache->capacity <= iscache->size) {
|
|
Packit |
b1f7ae |
errcode = -pte_internal;
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_section_get(section);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
goto out_unlock;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
idx = iscache->size++;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
entry = &iscache->entries[idx];
|
|
Packit |
b1f7ae |
entry->section = section;
|
|
Packit |
b1f7ae |
entry->laddr = laddr;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_unlock(iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return isid_from_index(idx);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
out_unlock:
|
|
Packit |
b1f7ae |
(void) pt_iscache_unlock(iscache);
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_iscache_find(struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
const char *filename, uint64_t offset, uint64_t size,
|
|
Packit |
b1f7ae |
uint64_t laddr)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
int errcode, isid;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_lock(iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
isid = pt_iscache_find_locked(iscache, filename, offset, size, laddr);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_unlock(iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return isid;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_iscache_lookup(struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
struct pt_section **section, uint64_t *laddr, int isid)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint16_t index;
|
|
Packit |
b1f7ae |
int errcode, status;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!iscache || !section || !laddr)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (isid <= 0)
|
|
Packit |
b1f7ae |
return -pte_bad_image;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
isid -= 1;
|
|
Packit |
b1f7ae |
if (isid > UINT16_MAX)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
index = (uint16_t) isid;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_lock(iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (iscache->size <= index)
|
|
Packit |
b1f7ae |
status = -pte_bad_image;
|
|
Packit |
b1f7ae |
else {
|
|
Packit |
b1f7ae |
const struct pt_iscache_entry *entry;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
entry = &iscache->entries[index];
|
|
Packit |
b1f7ae |
*section = entry->section;
|
|
Packit |
b1f7ae |
*laddr = entry->laddr;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
status = pt_section_get(*section);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_unlock(iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return status;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_iscache_clear(struct pt_image_section_cache *iscache)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_iscache_entry *entries;
|
|
Packit |
b1f7ae |
uint16_t idx, end;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!iscache)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_lock(iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
entries = iscache->entries;
|
|
Packit |
b1f7ae |
end = iscache->size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
iscache->entries = NULL;
|
|
Packit |
b1f7ae |
iscache->capacity = 0;
|
|
Packit |
b1f7ae |
iscache->size = 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_unlock(iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
for (idx = 0; idx < end; ++idx) {
|
|
Packit |
b1f7ae |
const struct pt_iscache_entry *entry;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
entry = &entries[idx];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We do not zero-initialize the array - a NULL check is
|
|
Packit |
b1f7ae |
* pointless.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
errcode = pt_section_put(entry->section);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
free(entries);
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
struct pt_image_section_cache *pt_iscache_alloc(const char *name)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_image_section_cache *iscache;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
iscache = malloc(sizeof(*iscache));
|
|
Packit |
b1f7ae |
if (iscache)
|
|
Packit |
b1f7ae |
pt_iscache_init(iscache, name);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return iscache;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
void pt_iscache_free(struct pt_image_section_cache *iscache)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!iscache)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
pt_iscache_fini(iscache);
|
|
Packit |
b1f7ae |
free(iscache);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
const char *pt_iscache_name(const struct pt_image_section_cache *iscache)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!iscache)
|
|
Packit |
b1f7ae |
return NULL;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return iscache->name;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_iscache_add_file(struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
const char *filename, uint64_t offset, uint64_t size,
|
|
Packit |
b1f7ae |
uint64_t vaddr)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_section *section;
|
|
Packit |
b1f7ae |
int isid, errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!iscache || !filename)
|
|
Packit |
b1f7ae |
return -pte_invalid;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
isid = pt_iscache_find(iscache, filename, offset, size, vaddr);
|
|
Packit |
b1f7ae |
if (isid != 0)
|
|
Packit |
b1f7ae |
return isid;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
section = pt_mk_section(filename, offset, size);
|
|
Packit |
b1f7ae |
if (!section)
|
|
Packit |
b1f7ae |
return -pte_invalid;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
isid = pt_iscache_add(iscache, section, vaddr);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We grab a reference when we add the section. Drop the one we
|
|
Packit |
b1f7ae |
* obtained when creating the section.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
errcode = pt_section_put(section);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return isid;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_iscache_read(struct pt_image_section_cache *iscache, uint8_t *buffer,
|
|
Packit |
b1f7ae |
uint64_t size, int isid, uint64_t vaddr)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_section *section;
|
|
Packit |
b1f7ae |
uint64_t laddr;
|
|
Packit |
b1f7ae |
int errcode, status;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!iscache || !buffer || !size)
|
|
Packit |
b1f7ae |
return -pte_invalid;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_iscache_lookup(iscache, §ion, &laddr, isid);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (vaddr < laddr) {
|
|
Packit |
b1f7ae |
(void) pt_section_put(section);
|
|
Packit |
b1f7ae |
return -pte_nomap;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
vaddr -= laddr;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_section_map(section);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
(void) pt_section_put(section);
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We truncate the read if it gets too big. The user is expected to
|
|
Packit |
b1f7ae |
* issue further reads for the remaining part.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (UINT16_MAX < size)
|
|
Packit |
b1f7ae |
size = UINT16_MAX;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
status = pt_section_read(section, buffer, (uint16_t) size, vaddr);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_section_unmap(section);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
(void) pt_section_put(section);
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_section_put(section);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return status;
|
|
Packit |
b1f7ae |
}
|