dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * CDDL HEADER START
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * The contents of this file are subject to the terms of the
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Common Development and Distribution License (the "License").
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * You may not use this file except in compliance with the License.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * or http://www.opensolaris.org/os/licensing.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * See the License for the specific language governing permissions
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * and limitations under the License.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * When distributing Covered Code, include this CDDL HEADER in each
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * If applicable, add the following below this CDDL HEADER, with the
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * fields enclosed by brackets "[]" replaced with your own identifying
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * information: Portions Copyright [yyyy] [name of copyright owner]
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * CDDL HEADER END
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
23a1ccea6aac035f084a7a4cdc968687d1b02dafRoger A. Faulkner * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King *
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * Copyright 2011 Jason King. All rights reserved.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <assert.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <errno.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <fcntl.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <gelf.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <libelf.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <stdlib.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <string.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <unistd.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <sys/fcntl.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include <sys/stat.h>
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King#include <sys/sysmacros.h>
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King#include <sys/types.h>
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include "dis_target.h"
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#include "dis_util.h"
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Standard ELF disassembler target.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * We only support disassembly of ELF files, though this target interface could
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * be extended in the future. Each basic type (target, func, section) contains
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * enough information to uniquely identify the location within the file. The
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * interfaces use libelf(3LIB) to do the actual processing of the file.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Symbol table entry type. We maintain our own symbol table sorted by address,
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * with the symbol name already resolved against the ELF symbol table.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrocktypedef struct sym_entry {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock GElf_Sym se_sym; /* value of symbol */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock char *se_name; /* name of symbol */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int se_shndx; /* section where symbol is located */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock} sym_entry_t;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King/*
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * Create a map of the virtual address ranges of every section. This will
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * allow us to create dummpy mappings for unassigned addresses. Otherwise
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * multiple sections with unassigned addresses will appear to overlap and
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * mess up symbol resolution (which uses the virtual address).
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason Kingtypedef struct dis_shnmap {
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King const char *dm_name; /* name of section */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King uint64_t dm_start; /* virtual address of section */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King size_t dm_length; /* address length */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King boolean_t dm_mapped; /* did we assign the mapping */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King} dis_shnmap_t;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Target data structure. This structure keeps track of the ELF file
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * information, a few bits of pre-processed section index information, and
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * sorted versions of the symbol table. We also keep track of the last symbol
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * looked up, as the majority of lookups remain within the same symbol.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockstruct dis_tgt {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf *dt_elf; /* libelf handle */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf *dt_elf_root; /* main libelf handle (for archives) */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock const char *dt_filename; /* name of file */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int dt_fd; /* underlying file descriptor */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock size_t dt_shstrndx; /* section index of .shstrtab */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock size_t dt_symidx; /* section index of symbol table */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym_entry_t *dt_symcache; /* last symbol looked up */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym_entry_t *dt_symtab; /* sorted symbol table */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int dt_symcount; /* # of symbol table entries */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock struct dis_tgt *dt_next; /* next target (for archives) */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf_Arhdr *dt_arhdr; /* archive header (for archives) */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King dis_shnmap_t *dt_shnmap; /* section address map */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King size_t dt_shncount; /* # of sections in target */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock};
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Function data structure. We resolve the symbol and lookup the associated ELF
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * data when building this structure. The offset is calculated based on the
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * section's starting address.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockstruct dis_func {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym_entry_t *df_sym; /* symbol table reference */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf_Data *df_data; /* associated ELF data */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock size_t df_offset; /* offset within data */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock};
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Section data structure. We store the entire section header so that we can
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * determine some properties (such as whether or not it contains text) after
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * building the structure.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockstruct dis_scn {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock GElf_Shdr ds_shdr;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock const char *ds_name;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf_Data *ds_data;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock};
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
23a1ccea6aac035f084a7a4cdc968687d1b02dafRoger A. Faulkner/* Lifted from Psymtab.c, omitting STT_TLS */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#define DATA_TYPES \
23a1ccea6aac035f084a7a4cdc968687d1b02dafRoger A. Faulkner ((1 << STT_OBJECT) | (1 << STT_FUNC) | (1 << STT_COMMON))
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock#define IS_DATA_TYPE(tp) (((1 << (tp)) & DATA_TYPES) != 0)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * Save the virtual address range for this section and select the
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * best section to use as the symbol table. We prefer SHT_SYMTAB
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * over SHT_DYNSYM.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/* ARGSUSED */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockstatic void
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason Kingtgt_scn_init(dis_tgt_t *tgt, dis_scn_t *scn, void *data)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int *index = data;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *index += 1;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King tgt->dt_shnmap[*index].dm_name = scn->ds_name;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King tgt->dt_shnmap[*index].dm_start = scn->ds_shdr.sh_addr;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King tgt->dt_shnmap[*index].dm_length = scn->ds_shdr.sh_size;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King tgt->dt_shnmap[*index].dm_mapped = B_FALSE;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Prefer SHT_SYMTAB over SHT_DYNSYM
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (scn->ds_shdr.sh_type == SHT_DYNSYM && tgt->dt_symidx == 0)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_symidx = *index;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock else if (scn->ds_shdr.sh_type == SHT_SYMTAB)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_symidx = *index;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockstatic int
dc0093f44ee4fac928e006850f8ed53f68277af5eschrocksym_compare(const void *a, const void *b)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock const sym_entry_t *syma = a;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock const sym_entry_t *symb = b;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock const char *aname = syma->se_name;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock const char *bname = symb->se_name;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (syma->se_sym.st_value < symb->se_sym.st_value)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (-1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (syma->se_sym.st_value > symb->se_sym.st_value)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Prefer functions over non-functions
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (GELF_ST_TYPE(syma->se_sym.st_info) !=
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock GELF_ST_TYPE(symb->se_sym.st_info)) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (GELF_ST_TYPE(syma->se_sym.st_info) == STT_FUNC)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (-1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (GELF_ST_TYPE(symb->se_sym.st_info) == STT_FUNC)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * For symbols with the same address and type, we sort them according to
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * a hierarchy:
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * 1. weak symbols (common name)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * 2. global symbols (external name)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * 3. local symbols
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (GELF_ST_BIND(syma->se_sym.st_info) !=
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock GELF_ST_BIND(symb->se_sym.st_info)) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (GELF_ST_BIND(syma->se_sym.st_info) == STB_WEAK)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (-1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (GELF_ST_BIND(symb->se_sym.st_info) == STB_WEAK)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (GELF_ST_BIND(syma->se_sym.st_info) == STB_GLOBAL)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (-1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (GELF_ST_BIND(symb->se_sym.st_info) == STB_GLOBAL)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * As a last resort, if we have multiple symbols of the same type at the
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * same address, prefer the version with the fewest leading underscores.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (aname == NULL)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (-1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (bname == NULL)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock while (*aname == '_' && *bname == '_') {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock aname++;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock bname++;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (*bname == '_')
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (-1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (*aname == '_')
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Prefer the symbol with the smaller size.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (syma->se_sym.st_size < symb->se_sym.st_size)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (-1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (syma->se_sym.st_size > symb->se_sym.st_size)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * We really do have two identical symbols for some reason. Just report
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * them as equal, and to the lucky one go the spoils.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (0);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Construct an optimized symbol table sorted by starting address.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockstatic void
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockconstruct_symtab(dis_tgt_t *tgt)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf_Scn *scn;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock GElf_Shdr shdr;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf_Data *symdata;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int i;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock GElf_Word *symshndx = NULL;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int symshndx_size;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym_entry_t *sym;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym_entry_t *p_symtab = NULL;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int nsym = 0; /* count of symbols we're not interested in */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Find the symshndx section, if any
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock for (scn = elf_nextscn(tgt->dt_elf, NULL); scn != NULL;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock scn = elf_nextscn(tgt->dt_elf, scn)) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (gelf_getshdr(scn, &shdr) == NULL)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock break;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (shdr.sh_type == SHT_SYMTAB_SHNDX &&
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock shdr.sh_link == tgt->dt_symidx) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf_Data *data;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((data = elf_getdata(scn, NULL)) != NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock symshndx = (GElf_Word *)data->d_buf;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock symshndx_size = data->d_size /
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sizeof (GElf_Word);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock break;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((scn = elf_getscn(tgt->dt_elf, tgt->dt_symidx)) == NULL)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock die("%s: failed to get section information", tgt->dt_filename);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (gelf_getshdr(scn, &shdr) == NULL)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock die("%s: failed to get section header", tgt->dt_filename);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (shdr.sh_entsize == 0)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock die("%s: symbol table has zero size", tgt->dt_filename);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((symdata = elf_getdata(scn, NULL)) == NULL)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock die("%s: failed to get symbol table", tgt->dt_filename);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_symcount = symdata->d_size / gelf_fsize(tgt->dt_elf, ELF_T_SYM,
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp 1, EV_CURRENT);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock p_symtab = safe_malloc(tgt->dt_symcount * sizeof (sym_entry_t));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock for (i = 0, sym = p_symtab; i < tgt->dt_symcount; i++) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (gelf_getsym(symdata, i, &(sym->se_sym)) == NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: gelf_getsym returned NULL for %d",
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp tgt->dt_filename, i);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock nsym++;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * We're only interested in data symbols.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (!IS_DATA_TYPE(GELF_ST_TYPE(sym->se_sym.st_info))) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock nsym++;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (sym->se_sym.st_shndx == SHN_XINDEX && symshndx != NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (i > symshndx_size) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: bad SHNX_XINDEX %d",
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp tgt->dt_filename, i);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym->se_shndx = -1;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock } else {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym->se_shndx = symshndx[i];
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock } else {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym->se_shndx = sym->se_sym.st_shndx;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King /* Deal with symbols with special section indicies */
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King if (sym->se_shndx == SHN_ABS) {
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King /*
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * If st_value == 0, references to these
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * symbols in code are modified in situ
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * thus we will never attempt to look
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * them up.
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King */
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King if (sym->se_sym.st_value == 0) {
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King /*
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * References to these symbols in code
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * are modified in situ by the runtime
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * linker and no code on disk will ever
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * attempt to look them up.
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King */
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King nsym++;
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King continue;
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King } else {
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King /*
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * If st_value != 0, (such as examining
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * something in /system/object/.../object)
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * the values should resolve to a value
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * within an existing section (such as
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * .data). This also means it never needs
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * to have st_value mapped.
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King */
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King sym++;
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King continue;
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King }
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King }
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King /*
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * Ignore the symbol if it has some other special
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * section index
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King */
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King if (sym->se_shndx == SHN_UNDEF ||
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King sym->se_shndx >= SHN_LORESERVE) {
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King nsym++;
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King continue;
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King }
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((sym->se_name = elf_strptr(tgt->dt_elf, shdr.sh_link,
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (size_t)sym->se_sym.st_name)) == NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: failed to lookup symbol %d name",
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp tgt->dt_filename, i);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock nsym++;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King /*
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * If we had to map this section, its symbol value
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * also needs to be mapped.
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King if (tgt->dt_shnmap[sym->se_shndx].dm_mapped)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King sym->se_sym.st_value +=
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King tgt->dt_shnmap[sym->se_shndx].dm_start;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym++;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_symcount -= nsym;
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp tgt->dt_symtab = realloc(p_symtab, tgt->dt_symcount *
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp sizeof (sym_entry_t));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock qsort(tgt->dt_symtab, tgt->dt_symcount, sizeof (sym_entry_t),
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym_compare);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King/*
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * Assign virtual address ranges for sections that need it
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason Kingstatic void
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason Kingcreate_addrmap(dis_tgt_t *tgt)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King{
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King uint64_t addr;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King int i;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King if (tgt->dt_shnmap == NULL)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King return;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King /* find the greatest used address */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King for (addr = 0, i = 1; i < tgt->dt_shncount; i++)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King if (tgt->dt_shnmap[i].dm_start > addr)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King addr = tgt->dt_shnmap[i].dm_start +
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King tgt->dt_shnmap[i].dm_length;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King addr = P2ROUNDUP(addr, 0x1000);
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King /*
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * Assign section a starting address beyond the largest mapped section
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * if no address was given.
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King for (i = 1; i < tgt->dt_shncount; i++) {
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King if (tgt->dt_shnmap[i].dm_start != 0)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King continue;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King tgt->dt_shnmap[i].dm_start = addr;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King tgt->dt_shnmap[i].dm_mapped = B_TRUE;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King addr = P2ROUNDUP(addr + tgt->dt_shnmap[i].dm_length, 0x1000);
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King }
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King}
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Create a target backed by an ELF file.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_t *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_create(const char *file)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_tgt_t *tgt, *current;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int idx;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf *elf;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock GElf_Ehdr ehdr;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf_Arhdr *arhdr = NULL;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int cmd;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (elf_version(EV_CURRENT) == EV_NONE)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock die("libelf(3ELF) out of date");
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt = safe_malloc(sizeof (dis_tgt_t));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((tgt->dt_fd = open(file, O_RDONLY)) < 0) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: failed opening file, reason: %s", file,
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp strerror(errno));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock free(tgt);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (NULL);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((tgt->dt_elf_root =
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock elf_begin(tgt->dt_fd, ELF_C_READ, NULL)) == NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: invalid or corrupt ELF file", file);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_tgt_destroy(tgt);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (NULL);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock current = tgt;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock cmd = ELF_C_READ;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock while ((elf = elf_begin(tgt->dt_fd, cmd, tgt->dt_elf_root)) != NULL) {
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe size_t shnum = 0;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (elf_kind(tgt->dt_elf_root) == ELF_K_AR &&
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (arhdr = elf_getarhdr(elf)) == NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: malformed archive", file);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_tgt_destroy(tgt);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (NULL);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Make sure that this Elf file is sane
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (gelf_getehdr(elf, &ehdr) == NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (arhdr != NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * For archives, we drive on in the face of bad
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * members. The "/" and "//" members are
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * special, and should be silently ignored.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (strcmp(arhdr->ar_name, "/") != 0 &&
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock strcmp(arhdr->ar_name, "//") != 0)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s[%s]: invalid file type",
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock file, arhdr->ar_name);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock cmd = elf_next(elf);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (void) elf_end(elf);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: invalid file type", file);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_tgt_destroy(tgt);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (NULL);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * If we're seeing a new Elf object, then we have an
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * archive. In this case, we create a new target, and chain it
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * off the master target. We can later iterate over these
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * targets using dis_tgt_next().
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (current->dt_elf != NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_tgt_t *next = safe_malloc(sizeof (dis_tgt_t));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock next->dt_elf_root = tgt->dt_elf_root;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock next->dt_fd = -1;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock current->dt_next = next;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock current = next;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock current->dt_elf = elf;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock current->dt_arhdr = arhdr;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
62b628a68db596a2d75a316dc7ffef658079231fAli Bahrami if (elf_getshdrstrndx(elf, &current->dt_shstrndx) == -1) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: failed to get section string table for "
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock "file", file);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_tgt_destroy(tgt);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (NULL);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe if (elf_getshdrnum(elf, &shnum) == -1) {
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe warn("%s: failed to get number of sections in file",
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe file);
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe dis_tgt_destroy(tgt);
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe return (NULL);
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe }
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King current->dt_shnmap = safe_malloc(sizeof (dis_shnmap_t) *
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe shnum);
27553b5c56d9e74e5a8c65c2338ad06e94ab3aedRichard Lowe current->dt_shncount = shnum;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock idx = 0;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King dis_tgt_section_iter(current, tgt_scn_init, &idx);
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King current->dt_filename = file;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King create_addrmap(current);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (current->dt_symidx != 0)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock construct_symtab(current);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock cmd = elf_next(elf);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Final sanity check. If we had an archive with no members, then bail
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * out with a nice message.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (tgt->dt_elf == NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: empty archive\n", file);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_tgt_destroy(tgt);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (NULL);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (tgt);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the filename associated with the target.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockconst char *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_name(dis_tgt_t *tgt)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (tgt->dt_filename);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the archive member name, if any.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockconst char *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_member(dis_tgt_t *tgt)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (tgt->dt_arhdr)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (tgt->dt_arhdr->ar_name);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock else
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (NULL);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the Elf_Ehdr associated with this target. Needed to determine which
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * disassembler to use.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockvoid
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_ehdr(dis_tgt_t *tgt, GElf_Ehdr *ehdr)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (void) gelf_getehdr(tgt->dt_elf, ehdr);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the next target in the list, if this is an archive.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_t *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_next(dis_tgt_t *tgt)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (tgt->dt_next);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Destroy a target and free up any associated memory.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockvoid
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_destroy(dis_tgt_t *tgt)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_tgt_t *current, *next;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock current = tgt->dt_next;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock while (current != NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock next = current->dt_next;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (current->dt_elf)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (void) elf_end(current->dt_elf);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (current->dt_symtab)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock free(current->dt_symtab);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock free(current);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock current = next;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (tgt->dt_elf)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (void) elf_end(tgt->dt_elf);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (tgt->dt_elf_root)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (void) elf_end(tgt->dt_elf_root);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (tgt->dt_symtab)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock free(tgt->dt_symtab);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock free(tgt);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King/*
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * Given an address, return the section it is in and set the offset within
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * the section.
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason Kingconst char *
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason Kingdis_find_section(dis_tgt_t *tgt, uint64_t addr, off_t *offset)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King{
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King int i;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King for (i = 1; i < tgt->dt_shncount; i++) {
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King if ((addr >= tgt->dt_shnmap[i].dm_start) &&
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King (addr < tgt->dt_shnmap[i].dm_start +
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King tgt->dt_shnmap[i].dm_length)) {
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King *offset = addr - tgt->dt_shnmap[i].dm_start;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King return (tgt->dt_shnmap[i].dm_name);
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King }
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King }
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King *offset = 0;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King return (NULL);
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King}
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Given an address, returns the name of the corresponding symbol, as well as
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * the offset within that symbol. If no matching symbol is found, then NULL is
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * returned.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * If 'cache_result' is specified, then we keep track of the resulting symbol.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * This cached result is consulted first on subsequent lookups in order to avoid
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * unecessary lookups. This flag should be used for resolving the current PC,
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * as the majority of addresses stay within the current function.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockconst char *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result,
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock size_t *size, int *isfunc)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int lo, hi, mid;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym_entry_t *sym, *osym, *match;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int found;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe *offset = 0;
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe *size = 0;
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe if (isfunc != NULL)
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe *isfunc = 0;
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (tgt->dt_symcache != NULL &&
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock addr >= tgt->dt_symcache->se_sym.st_value &&
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock addr < tgt->dt_symcache->se_sym.st_value +
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_symcache->se_sym.st_size) {
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe sym = tgt->dt_symcache;
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe *offset = addr - sym->se_sym.st_value;
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe *size = sym->se_sym.st_size;
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe if (isfunc != NULL)
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) ==
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe STT_FUNC);
dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9Richard Lowe return (sym->se_name);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock lo = 0;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock hi = (tgt->dt_symcount - 1);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock found = 0;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock match = osym = NULL;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock while (lo <= hi) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock mid = (lo + hi) / 2;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym = &tgt->dt_symtab[mid];
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (addr >= sym->se_sym.st_value &&
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock addr < sym->se_sym.st_value + sym->se_sym.st_size &&
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (!found || sym->se_sym.st_value > osym->se_sym.st_value)) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock osym = sym;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock found = 1;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock } else if (addr == sym->se_sym.st_value) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Particularly for .plt objects, it's possible to have
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * a zero sized object. We want to return this, but we
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * want it to be a last resort.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock match = sym;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (addr < sym->se_sym.st_value)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock hi = mid - 1;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock else
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock lo = mid + 1;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (!found) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (match)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock osym = match;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock else
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (NULL);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Walk backwards to find the best match.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock do {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym = osym;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (osym == tgt->dt_symtab)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock break;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock osym = osym - 1;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock } while ((sym->se_sym.st_value == osym->se_sym.st_value) &&
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp (addr >= osym->se_sym.st_value) &&
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp (addr < osym->se_sym.st_value + osym->se_sym.st_size));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (cache_result)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_symcache = sym;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *offset = addr - sym->se_sym.st_value;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *size = sym->se_sym.st_size;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (isfunc)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == STT_FUNC);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (sym->se_name);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Given an address, return the starting offset of the next symbol in the file.
6e6df3cf62ece86f43c1a3218dc4b7797d9ce731Jason King * Only needed on variable length instruction architectures.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockoff_t
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King sym_entry_t *sym;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
edd4ab01432cfb07428329ad6e8071e8923d0b20Richard Lowe sym = (tgt->dt_symcache != NULL) ? tgt->dt_symcache : tgt->dt_symtab;
edd4ab01432cfb07428329ad6e8071e8923d0b20Richard Lowe
edd4ab01432cfb07428329ad6e8071e8923d0b20Richard Lowe while (sym != (tgt->dt_symtab + tgt->dt_symcount)) {
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King if (sym->se_sym.st_value >= addr)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King return (sym->se_sym.st_value - addr);
edd4ab01432cfb07428329ad6e8071e8923d0b20Richard Lowe sym++;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King return (0);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Iterate over all sections in the target, executing the given callback for
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * each.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockvoid
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_scn_t sdata;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf_Scn *scn;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int idx;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock for (scn = elf_nextscn(tgt->dt_elf, NULL), idx = 1; scn != NULL;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock scn = elf_nextscn(tgt->dt_elf, scn), idx++) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (gelf_getshdr(scn, &sdata.ds_shdr) == NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: failed to get section %d header",
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_filename, idx);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((sdata.ds_name = elf_strptr(tgt->dt_elf, tgt->dt_shstrndx,
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sdata.ds_shdr.sh_name)) == NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: failed to get section %d name",
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_filename, idx);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((sdata.ds_data = elf_getdata(scn, NULL)) == NULL) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: failed to get data for section '%s'",
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_filename, sdata.ds_name);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King /*
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * dis_tgt_section_iter is also used before the section map
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * is initialized, so only check when we need to. If the
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * section map is uninitialized, it will return 0 and have
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King * no net effect.
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King */
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King if (sdata.ds_shdr.sh_addr == 0)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King sdata.ds_shdr.sh_addr = tgt->dt_shnmap[idx].dm_start;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock func(tgt, &sdata, data);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return 1 if the given section contains text, 0 otherwise.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockint
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_section_istext(dis_scn_t *scn)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return ((scn->ds_shdr.sh_type == SHT_PROGBITS) &&
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (scn->ds_shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR)));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return a pointer to the section data.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockvoid *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_section_data(dis_scn_t *scn)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (scn->ds_data->d_buf);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the size of the section data.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrocksize_t
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_section_size(dis_scn_t *scn)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (scn->ds_data->d_size);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the address for the given section.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockuint64_t
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_section_addr(dis_scn_t *scn)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (scn->ds_shdr.sh_addr);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the name of the current section.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockconst char *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_section_name(dis_scn_t *scn)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (scn->ds_name);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Create an allocated copy of the given section
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_scn_t *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_section_copy(dis_scn_t *scn)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_scn_t *new;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock new = safe_malloc(sizeof (dis_scn_t));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (void) memcpy(new, scn, sizeof (dis_scn_t));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (new);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Free section memory
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockvoid
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_section_free(dis_scn_t *scn)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock free(scn);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Iterate over all functions in the target, executing the given callback for
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * each one.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockvoid
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock int i;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock sym_entry_t *sym;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_func_t df;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock Elf_Scn *scn;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock GElf_Shdr shdr;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock for (i = 0, sym = tgt->dt_symtab; i < tgt->dt_symcount; i++, sym++) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /* ignore non-functions */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((GELF_ST_TYPE(sym->se_sym.st_info) != STT_FUNC) ||
161d9479d65efe70fd8e3fb443027646ce1a5990rie (sym->se_name == NULL) ||
161d9479d65efe70fd8e3fb443027646ce1a5990rie (sym->se_sym.st_size == 0) ||
161d9479d65efe70fd8e3fb443027646ce1a5990rie (sym->se_shndx >= SHN_LORESERVE))
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /* get the ELF data associated with this function */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if ((scn = elf_getscn(tgt->dt_elf, sym->se_shndx)) == NULL ||
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock gelf_getshdr(scn, &shdr) == NULL ||
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (df.df_data = elf_getdata(scn, NULL)) == NULL ||
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock df.df_data->d_size == 0) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: failed to read section %d",
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock tgt->dt_filename, sym->se_shndx);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King if (tgt->dt_shnmap[sym->se_shndx].dm_mapped)
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King shdr.sh_addr = tgt->dt_shnmap[sym->se_shndx].dm_start;
b5f3c6ffe7f93e6132a702a851a69b5ecd78c066Jason King
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock /*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Verify that the address lies within the section that we think
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * it does.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock if (sym->se_sym.st_value < shdr.sh_addr ||
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (sym->se_sym.st_value + sym->se_sym.st_size) >
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (shdr.sh_addr + shdr.sh_size)) {
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock warn("%s: bad section %d for address %p",
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp tgt->dt_filename, sym->se_sym.st_shndx,
7a65609ec233a8e7a8ea8ec9c0476d86cdbc92ebjmcp sym->se_sym.st_value);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock continue;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock df.df_sym = sym;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock df.df_offset = sym->se_sym.st_value - shdr.sh_addr;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock func(tgt, &df, data);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock }
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the data associated with a given function.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockvoid *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_function_data(dis_func_t *func)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return ((char *)func->df_data->d_buf + func->df_offset);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the size of a function.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrocksize_t
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_function_size(dis_func_t *func)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (func->df_sym->se_sym.st_size);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the address of a function.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockuint64_t
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_function_addr(dis_func_t *func)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (func->df_sym->se_sym.st_value);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return the name of the function
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockconst char *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_function_name(dis_func_t *func)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (func->df_sym->se_name);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Return a copy of a function.
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_func_t *
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_function_copy(dis_func_t *func)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock dis_func_t *new;
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock new = safe_malloc(sizeof (dis_func_t));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock (void) memcpy(new, func, sizeof (dis_func_t));
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock return (new);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock/*
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock * Free function memory
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock */
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockvoid
dc0093f44ee4fac928e006850f8ed53f68277af5eschrockdis_function_free(dis_func_t *func)
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock{
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock free(func);
dc0093f44ee4fac928e006850f8ed53f68277af5eschrock}