blob: d3657347dae6ca26937fbf87343f24c6d3ff6296 [file] [log] [blame]
/*
* Copyright (c) 2020 Google Inc. All rights reserved
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <lib/backtrace/symbolize.h>
#include <trace.h>
#include "elf_sym.h"
#define LOCAL_TRACE 0
#undef ELF_64BIT
#if !IS_64BIT || USER_32BIT
#define ELF_64BIT 0
#else
#define ELF_64BIT 1
#endif
#if ELF_64BIT
#define ELF_SHDR Elf64_Shdr
#define ELF_EHDR Elf64_Ehdr
#define ELF_SYM Elf64_Sym
#else
#define ELF_SHDR Elf32_Shdr
#define ELF_EHDR Elf32_Ehdr
#define ELF_SYM Elf32_Sym
#endif
static inline bool range_within_app_img(uintptr_t start,
size_t size,
struct trusty_app_img* app_img) {
uintptr_t end;
if (__builtin_add_overflow(start, size, &end)) {
return false;
}
return app_img->img_start <= start && end <= app_img->img_end;
}
static inline bool range_within_range(uintptr_t start0,
size_t size0,
uintptr_t start1,
size_t size1) {
uintptr_t end0;
if (__builtin_add_overflow(start0, size0, &end0)) {
return false;
}
uintptr_t end1;
if (__builtin_add_overflow(start1, size1, &end1)) {
return false;
}
return start1 <= start0 && end0 <= end1;
}
int trusty_app_symbolize(struct trusty_app* app,
uintptr_t pc,
struct pc_symbol_info* info) {
if (!app) {
goto out_no_symbol;
}
/* Adjust pc to be relative to app image */
if (__builtin_sub_overflow(pc, app->load_bias, &pc)) {
goto out_no_symbol;
}
/* pc must be within the app image */
struct trusty_app_img* app_img = &app->app_img;
if (app_img->img_end <= app_img->img_start) {
goto out_no_symbol;
}
if (pc > app_img->img_end - app_img->img_start) {
goto out_no_symbol;
}
ELF_EHDR* ehdr = (ELF_EHDR*)app_img->img_start;
ELF_SHDR* shdr = (ELF_SHDR*)((uintptr_t)ehdr + ehdr->e_shoff);
ELF_SHDR* symtab_shdr = NULL;
ELF_SHDR* strtab_shdr = NULL;
/* Find section headers for .symtab and .strtab */
for (size_t i = 0; i < ehdr->e_shnum; i++) {
if (shdr[i].sh_type == SHT_SYMTAB) {
symtab_shdr = shdr + i;
}
if (shdr[i].sh_type == SHT_STRTAB) {
strtab_shdr = shdr + i;
}
}
/* Handle the case when app is not built with .symtab or .strtab */
if (!symtab_shdr || !strtab_shdr) {
LTRACEF("App built without symbol table\n");
goto out_no_symbol;
}
uintptr_t symtab_start = app_img->img_start + symtab_shdr->sh_offset;
size_t symtab_size = symtab_shdr->sh_size;
uintptr_t strtab_start = app_img->img_start + strtab_shdr->sh_offset;
size_t strtab_size = strtab_shdr->sh_size;
/* Validate .symtab and .strtab locations */
if (!range_within_app_img(symtab_start, symtab_size, app_img)) {
TRACEF(".symtab section is not within the app image\n");
goto out_no_symbol;
}
if (!range_within_app_img(strtab_start, strtab_size, app_img)) {
TRACEF(".strtab section is not within the app image\n");
goto out_no_symbol;
}
/* Find closest symbol preceding pc */
info->offset = ULONG_MAX;
for (uintptr_t curr = symtab_start;
curr < symtab_start + symtab_shdr->sh_size;
curr += symtab_shdr->sh_entsize) {
/* Entry must be within .symtab section */
if (!range_within_range(curr, symtab_shdr->sh_entsize, symtab_start,
symtab_size)) {
TRACEF(".symtab section is malformed\n");
goto out_no_symbol;
}
ELF_SYM* symtab_entry = (ELF_SYM*)curr;
/* We are looking for a symbol of a function */
if (ELF_ST_TYPE(symtab_entry->st_info) != STT_FUNC) {
continue;
}
uintptr_t func_start = symtab_entry->st_value;
if (func_start <= pc && info->offset > pc - func_start) {
/* Offset must be within .strtab section */
if (symtab_entry->st_name >= strtab_size) {
TRACEF(".strtab section is malformed\n");
goto out_no_symbol;
}
info->symbol = (const char*)(strtab_start + symtab_entry->st_name);
info->offset = pc - func_start;
info->size = symtab_entry->st_size;
}
}
if (info->offset == ULONG_MAX) {
goto out_no_symbol;
}
return NO_ERROR;
out_no_symbol:
info->symbol = NULL;
info->offset = 0;
info->size = 0;
return ERR_NOT_FOUND;
}