mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-22 07:20:00 +00:00
ddb: Add CTF-based pretty printing
Add basic CTF support and a CTF-powered pretty-printer to ddb. The db_ctf.* files expose a basic interface for fetching type data for ELF symbols, interacting with the CTF string table, and translating type identifiers to type data. The db_pprint.c file uses those interfaces to implement a pretty-printer for all kernel ELF symbols. The pretty-printer works with symbol names and arbitrary addresses: pprint struct thread 0xffffffff8194ad90 Pretty-printing currently only works after the root filesystem gets mounted because the CTF info is not available during early boot. Differential Revision: https://reviews.freebsd.org/D37899 Approved by: markj (mentor)
This commit is contained in:
parent
312a05c39e
commit
c21bc6f3c2
@ -289,6 +289,32 @@ eax = xxxxxx
|
||||
ecx = yyyyyy
|
||||
.Ed
|
||||
.Pp
|
||||
.It Ic pprint Ns Oo Li / Ns Cm d depth Oc Oo Ar name Oc
|
||||
Pretty-print symbol specified by
|
||||
.Ar name
|
||||
using CTF debugging data. Works for all symbols exported by the kernel and loaded kernel modules.
|
||||
.Pp
|
||||
If the
|
||||
.Cm d
|
||||
modifier has been specified, contents of structs nested up to
|
||||
.Ar depth
|
||||
levels deep will also be included in the output.
|
||||
.Ed
|
||||
.Pp
|
||||
.It Ic pprint struct Ns Oo Li / Ns Cm d depth Ic Oc Oo Ar name Oc Ns Op Ns Ar addr
|
||||
Print memory at
|
||||
.Ar addr
|
||||
as struct
|
||||
.Ar name Ns .
|
||||
Works for all structs defined by the kernel and loaded kernel modules.
|
||||
.Pp
|
||||
If the
|
||||
.Cm d
|
||||
modifier has been specified, contents of structs nested up to
|
||||
.Ar depth
|
||||
levels deep will also be included in the output.
|
||||
.Ed
|
||||
.Pp
|
||||
.It Xo
|
||||
.Ic write Ns Op Li / Ns Cm bhl
|
||||
.Ar addr expr1 Op Ar expr2 ...
|
||||
|
@ -718,12 +718,14 @@ ddb/db_access.c optional ddb
|
||||
ddb/db_break.c optional ddb
|
||||
ddb/db_capture.c optional ddb
|
||||
ddb/db_command.c optional ddb
|
||||
ddb/db_ctf.c optional ddb
|
||||
ddb/db_examine.c optional ddb
|
||||
ddb/db_expr.c optional ddb
|
||||
ddb/db_input.c optional ddb
|
||||
ddb/db_lex.c optional ddb
|
||||
ddb/db_main.c optional ddb
|
||||
ddb/db_output.c optional ddb
|
||||
ddb/db_pprint.c optional ddb
|
||||
ddb/db_print.c optional ddb
|
||||
ddb/db_ps.c optional ddb
|
||||
ddb/db_run.c optional ddb
|
||||
|
@ -163,6 +163,7 @@ static struct db_command db_cmds[] = {
|
||||
DB_CMD("capture", db_capture_cmd, CS_OWN|DB_CMD_MEMSAFE),
|
||||
DB_CMD("textdump", db_textdump_cmd, CS_OWN|DB_CMD_MEMSAFE),
|
||||
DB_CMD("findstack", db_findstack_cmd, 0),
|
||||
DB_CMD("pprint", db_pprint_cmd, CS_OWN),
|
||||
};
|
||||
struct db_command_table db_cmd_table = LIST_HEAD_INITIALIZER(db_cmd_table);
|
||||
|
||||
|
326
sys/ddb/db_ctf.c
Normal file
326
sys/ddb/db_ctf.c
Normal file
@ -0,0 +1,326 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2023 Bojan Novković <bnovkov@freebsd.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_ctf.h>
|
||||
|
||||
static const ctf_header_t *
|
||||
db_ctf_fetch_cth(linker_ctf_t *lc)
|
||||
{
|
||||
return (const ctf_header_t *)lc->ctftab;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to look up the ELF symbol -> CTF type identifier mapping by scanning
|
||||
* the CTF object section.
|
||||
*/
|
||||
static uint32_t
|
||||
sym_to_objtoff(linker_ctf_t *lc, const Elf_Sym *sym, const Elf_Sym *symtab,
|
||||
const Elf_Sym *symtab_end)
|
||||
{
|
||||
const ctf_header_t *hp = db_ctf_fetch_cth(lc);
|
||||
uint32_t objtoff = hp->cth_objtoff;
|
||||
const size_t idwidth = 4;
|
||||
|
||||
/* Ignore non-object symbols */
|
||||
if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) {
|
||||
return (DB_CTF_INVALID_OFF);
|
||||
}
|
||||
/* Sanity check */
|
||||
if (!(sym >= symtab && sym <= symtab_end)) {
|
||||
return (DB_CTF_INVALID_OFF);
|
||||
}
|
||||
|
||||
for (const Elf_Sym *symp = symtab; symp < symtab_end; symp++) {
|
||||
/* Make sure we do not go beyond the objtoff section */
|
||||
if (objtoff >= hp->cth_funcoff) {
|
||||
objtoff = DB_CTF_INVALID_OFF;
|
||||
break;
|
||||
}
|
||||
if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) {
|
||||
continue;
|
||||
}
|
||||
if (symp->st_shndx == SHN_ABS && symp->st_value == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip non-object symbols */
|
||||
if (ELF_ST_TYPE(symp->st_info) != STT_OBJECT) {
|
||||
continue;
|
||||
}
|
||||
if (symp == sym) {
|
||||
break;
|
||||
}
|
||||
objtoff += idwidth;
|
||||
}
|
||||
|
||||
return (objtoff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the size of CTF type 't'.
|
||||
*/
|
||||
static u_int
|
||||
db_ctf_type_size(struct ctf_type_v3 *t)
|
||||
{
|
||||
u_int vlen, kind, ssize;
|
||||
u_int type_struct_size, kind_size;
|
||||
|
||||
vlen = CTF_V3_INFO_VLEN(t->ctt_info);
|
||||
kind = CTF_V3_INFO_KIND(t->ctt_info);
|
||||
ssize = ((t->ctt_size == CTF_V3_LSIZE_SENT) ? CTF_TYPE_LSIZE(t) :
|
||||
t->ctt_size);
|
||||
type_struct_size = ((t->ctt_size == CTF_V3_LSIZE_SENT) ?
|
||||
sizeof(struct ctf_type_v3) :
|
||||
sizeof(struct ctf_stype_v3));
|
||||
|
||||
switch (kind) {
|
||||
case CTF_K_INTEGER:
|
||||
case CTF_K_FLOAT:
|
||||
kind_size = sizeof(uint32_t);
|
||||
break;
|
||||
case CTF_K_ARRAY:
|
||||
kind_size = sizeof(struct ctf_array_v3);
|
||||
break;
|
||||
case CTF_K_UNION:
|
||||
case CTF_K_STRUCT:
|
||||
kind_size = vlen *
|
||||
((ssize < CTF_V3_LSTRUCT_THRESH) ?
|
||||
sizeof(struct ctf_member_v3) :
|
||||
sizeof(struct ctf_lmember_v3));
|
||||
break;
|
||||
case CTF_K_ENUM:
|
||||
kind_size = vlen * sizeof(struct ctf_enum);
|
||||
break;
|
||||
case CTF_K_FUNCTION:
|
||||
kind_size = vlen * sizeof(uint32_t);
|
||||
break;
|
||||
case CTF_K_UNKNOWN:
|
||||
case CTF_K_FORWARD:
|
||||
case CTF_K_POINTER:
|
||||
case CTF_K_TYPEDEF:
|
||||
case CTF_K_VOLATILE:
|
||||
case CTF_K_CONST:
|
||||
case CTF_K_RESTRICT:
|
||||
kind_size = 0;
|
||||
break;
|
||||
default:
|
||||
db_printf("Error: invalid CTF type kind encountered\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (type_struct_size + kind_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks up type name 'name' in the CTF string table and returns the
|
||||
* corresponding CTF type struct, if any.
|
||||
*/
|
||||
struct ctf_type_v3 *
|
||||
db_ctf_typename_to_type(linker_ctf_t *lc, const char *name)
|
||||
{
|
||||
const ctf_header_t *hp = db_ctf_fetch_cth(lc);
|
||||
char *start, *cur, *end;
|
||||
uint32_t stroff = hp->cth_stroff;
|
||||
uint32_t typeoff = hp->cth_typeoff;
|
||||
uint32_t name_stroff;
|
||||
const uint8_t *ctfstart = (const uint8_t *)hp + sizeof(ctf_header_t);
|
||||
|
||||
u_int skiplen;
|
||||
|
||||
/* Scan ctf strtab for typename. */
|
||||
start = cur = __DECONST(char *, hp) + sizeof(ctf_header_t) +
|
||||
hp->cth_stroff;
|
||||
end = cur + hp->cth_strlen;
|
||||
while (cur < end) {
|
||||
if (strcmp(cur, name) == 0)
|
||||
break;
|
||||
cur += strlen(cur) + 1;
|
||||
}
|
||||
if (cur >= end)
|
||||
return (NULL);
|
||||
name_stroff = (uint32_t)(cur - start);
|
||||
|
||||
/* Scan for type containing the found stroff. */
|
||||
while (typeoff < stroff) {
|
||||
struct ctf_type_v3 *t =
|
||||
(struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
|
||||
typeoff);
|
||||
/* We found the type struct */
|
||||
if (t->ctt_name == name_stroff) {
|
||||
break;
|
||||
}
|
||||
if ((skiplen = db_ctf_type_size(t)) == -1) {
|
||||
return (NULL);
|
||||
}
|
||||
typeoff += skiplen;
|
||||
}
|
||||
if (typeoff < stroff) {
|
||||
return (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
|
||||
typeoff);
|
||||
} else { /* A type struct was not found */
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper used by the kernel linker CTF routines.
|
||||
* Currently used to implement lookup of CTF types accross all loaded kernel
|
||||
* modules.
|
||||
*/
|
||||
bool
|
||||
db_ctf_lookup_typename(linker_ctf_t *lc, const char *typename)
|
||||
{
|
||||
return (db_ctf_typename_to_type(lc, typename) != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the type corresponding to the 'typeid' parameter from the CTF type
|
||||
* section.
|
||||
*/
|
||||
struct ctf_type_v3 *
|
||||
db_ctf_typeid_to_type(db_ctf_sym_data_t sd, uint32_t typeid)
|
||||
{
|
||||
const ctf_header_t *hp = db_ctf_fetch_cth(&sd->lc);
|
||||
const uint8_t *ctfstart = (const uint8_t *)hp + sizeof(ctf_header_t);
|
||||
uint32_t typeoff = hp->cth_typeoff;
|
||||
uint32_t stroff = hp->cth_stroff;
|
||||
/* CTF typeids start at 0x1 */
|
||||
size_t cur_typeid = 1;
|
||||
u_int skiplen;
|
||||
|
||||
/* Find corresponding type */
|
||||
while (typeoff < stroff) {
|
||||
struct ctf_type_v3 *t =
|
||||
(struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
|
||||
typeoff);
|
||||
|
||||
/* We found the type struct */
|
||||
if (cur_typeid == typeid) {
|
||||
break;
|
||||
}
|
||||
cur_typeid++;
|
||||
if ((skiplen = db_ctf_type_size(t)) == -1) {
|
||||
return (NULL);
|
||||
}
|
||||
typeoff += skiplen;
|
||||
}
|
||||
if (typeoff < stroff) {
|
||||
return (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
|
||||
typeoff);
|
||||
} else { /* A type struct was not found */
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
db_ctf_stroff_to_str(db_ctf_sym_data_t sd, uint32_t off)
|
||||
{
|
||||
const ctf_header_t *hp = db_ctf_fetch_cth(&sd->lc);
|
||||
uint32_t stroff = hp->cth_stroff + off;
|
||||
const char *ret;
|
||||
|
||||
if (stroff >= (hp->cth_stroff + hp->cth_strlen)) {
|
||||
return ("invalid");
|
||||
}
|
||||
ret = ((const char *)hp + sizeof(ctf_header_t)) + stroff;
|
||||
if (*ret == '\0') {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to find the type of the symbol specified in 'sd->sym'.
|
||||
*/
|
||||
struct ctf_type_v3 *
|
||||
db_ctf_sym_to_type(db_ctf_sym_data_t sd)
|
||||
{
|
||||
uint32_t objtoff, typeid;
|
||||
const Elf_Sym *symtab, *symtab_end;
|
||||
|
||||
if (sd->sym == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
symtab = sd->lc.symtab;
|
||||
symtab_end = symtab + sd->lc.nsym;
|
||||
|
||||
objtoff = sym_to_objtoff(&sd->lc, sd->sym, symtab, symtab_end);
|
||||
/* Sanity check - should not happen */
|
||||
if (objtoff == DB_CTF_INVALID_OFF) {
|
||||
db_printf("Could not find CTF object offset.\n");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
typeid = *(
|
||||
const uint32_t *)(sd->lc.ctftab + sizeof(ctf_header_t) + objtoff);
|
||||
|
||||
return (db_ctf_typeid_to_type(sd, typeid));
|
||||
}
|
||||
|
||||
/*
|
||||
* Scans the kernel file and all loaded module for symbol 'name'.
|
||||
*/
|
||||
int
|
||||
db_ctf_find_symbol(const char *name, db_ctf_sym_data_t sd)
|
||||
{
|
||||
int error;
|
||||
c_linker_sym_t lsym = NULL;
|
||||
|
||||
error = linker_ctf_lookup_sym_ddb(name, &lsym, &sd->lc);
|
||||
if (error != 0) {
|
||||
db_printf(
|
||||
"failed to look up symbol and CTF info for %s: error %d\n",
|
||||
name, error);
|
||||
return (error);
|
||||
}
|
||||
sd->sym = __DECONST(Elf_Sym *, lsym);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scans the kernel file and all loaded module for type specified by 'typename'.
|
||||
*/
|
||||
struct ctf_type_v3 *
|
||||
db_ctf_find_typename(db_ctf_sym_data_t sd, const char *typename)
|
||||
{
|
||||
if (linker_ctf_lookup_typename_ddb(&sd->lc, typename) != 0) {
|
||||
return (NULL);
|
||||
}
|
||||
return (db_ctf_typename_to_type(&sd->lc, typename));
|
||||
}
|
64
sys/ddb/db_ctf.h
Normal file
64
sys/ddb/db_ctf.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2023 Bojan Novković <bnovkov@freebsd.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _DDB_DB_CTF_H_
|
||||
#define _DDB_DB_CTF_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ctf.h>
|
||||
#include <sys/linker.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_sym.h>
|
||||
|
||||
#define DB_CTF_INVALID_OFF 0xffffffff
|
||||
|
||||
struct db_ctf_sym_data {
|
||||
linker_ctf_t lc;
|
||||
Elf_Sym *sym;
|
||||
};
|
||||
|
||||
typedef struct db_ctf_sym_data *db_ctf_sym_data_t;
|
||||
|
||||
/*
|
||||
* Routines for finding symbols and CTF info accross all loaded linker files.
|
||||
*/
|
||||
int db_ctf_find_symbol(const char *name, db_ctf_sym_data_t sd);
|
||||
struct ctf_type_v3 *db_ctf_find_typename(db_ctf_sym_data_t sd,
|
||||
const char *typename);
|
||||
bool db_ctf_lookup_typename(linker_ctf_t *lc, const char *typename);
|
||||
|
||||
/*
|
||||
* Routines for working with CTF data.
|
||||
*/
|
||||
struct ctf_type_v3 *db_ctf_sym_to_type(db_ctf_sym_data_t sd);
|
||||
const char *db_ctf_stroff_to_str(db_ctf_sym_data_t sd, uint32_t off);
|
||||
struct ctf_type_v3 *db_ctf_typename_to_type(linker_ctf_t *lc, const char *name);
|
||||
struct ctf_type_v3 *db_ctf_typeid_to_type(db_ctf_sym_data_t sd,
|
||||
uint32_t typeid);
|
||||
|
||||
#endif /* !_DDB_DB_CTF_H_ */
|
450
sys/ddb/db_pprint.c
Normal file
450
sys/ddb/db_pprint.c
Normal file
@ -0,0 +1,450 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2022 Bojan Novković <bnovkov@freebsd.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/linker.h>
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_ctf.h>
|
||||
#include <ddb/db_lex.h>
|
||||
#include <ddb/db_sym.h>
|
||||
#include <ddb/db_access.h>
|
||||
|
||||
#define DB_PPRINT_DEFAULT_DEPTH 1
|
||||
|
||||
static void db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type,
|
||||
u_int depth);
|
||||
|
||||
static u_int max_depth = DB_PPRINT_DEFAULT_DEPTH;
|
||||
static struct db_ctf_sym_data sym_data;
|
||||
|
||||
/*
|
||||
* Pretty-prints a CTF_INT type.
|
||||
*/
|
||||
static inline void
|
||||
db_pprint_int(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
|
||||
{
|
||||
uint32_t data;
|
||||
size_t type_struct_size;
|
||||
|
||||
type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ?
|
||||
sizeof(struct ctf_type_v3) :
|
||||
sizeof(struct ctf_stype_v3);
|
||||
|
||||
data = db_get_value((db_expr_t)type + type_struct_size,
|
||||
sizeof(uint32_t), 0);
|
||||
u_int bits = CTF_INT_BITS(data);
|
||||
boolean_t sign = !!(CTF_INT_ENCODING(data) & CTF_INT_SIGNED);
|
||||
|
||||
if (db_pager_quit) {
|
||||
return;
|
||||
}
|
||||
if (bits > 64) {
|
||||
db_printf("Invalid size '%d' found for integer type\n", bits);
|
||||
return;
|
||||
}
|
||||
db_printf("0x%lx",
|
||||
db_get_value(addr, (bits / 8) ? (bits / 8) : 1, sign));
|
||||
}
|
||||
|
||||
/*
|
||||
* Pretty-prints a struct. Nested structs are pretty-printed up 'depth' nested
|
||||
* levels.
|
||||
*/
|
||||
static inline void
|
||||
db_pprint_struct(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
|
||||
{
|
||||
size_t type_struct_size;
|
||||
size_t struct_size;
|
||||
struct ctf_type_v3 *mtype;
|
||||
const char *mname;
|
||||
db_addr_t maddr;
|
||||
u_int vlen;
|
||||
|
||||
type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ?
|
||||
sizeof(struct ctf_type_v3) :
|
||||
sizeof(struct ctf_stype_v3);
|
||||
struct_size = ((type->ctt_size == CTF_V3_LSIZE_SENT) ?
|
||||
CTF_TYPE_LSIZE(type) :
|
||||
type->ctt_size);
|
||||
vlen = CTF_V3_INFO_VLEN(type->ctt_info);
|
||||
|
||||
if (db_pager_quit) {
|
||||
return;
|
||||
}
|
||||
if (depth > max_depth) {
|
||||
db_printf("{ ... }");
|
||||
return;
|
||||
}
|
||||
db_printf("{\n");
|
||||
|
||||
if (struct_size < CTF_V3_LSTRUCT_THRESH) {
|
||||
struct ctf_member_v3 *mp, *endp;
|
||||
|
||||
mp = (struct ctf_member_v3 *)((db_addr_t)type +
|
||||
type_struct_size);
|
||||
endp = mp + vlen;
|
||||
for (; mp < endp; mp++) {
|
||||
if (db_pager_quit) {
|
||||
return;
|
||||
}
|
||||
mtype = db_ctf_typeid_to_type(&sym_data, mp->ctm_type);
|
||||
maddr = addr + mp->ctm_offset;
|
||||
mname = db_ctf_stroff_to_str(&sym_data, mp->ctm_name);
|
||||
db_indent = depth;
|
||||
if (mname != NULL) {
|
||||
db_iprintf("%s = ", mname);
|
||||
} else {
|
||||
db_iprintf("");
|
||||
}
|
||||
|
||||
db_pprint_type(maddr, mtype, depth + 1);
|
||||
db_printf(",\n");
|
||||
}
|
||||
} else {
|
||||
struct ctf_lmember_v3 *mp, *endp;
|
||||
|
||||
mp = (struct ctf_lmember_v3 *)((db_addr_t)type +
|
||||
type_struct_size);
|
||||
endp = mp + vlen;
|
||||
for (; mp < endp; mp++) {
|
||||
if (db_pager_quit) {
|
||||
return;
|
||||
}
|
||||
mtype = db_ctf_typeid_to_type(&sym_data, mp->ctlm_type);
|
||||
maddr = addr + CTF_LMEM_OFFSET(mp);
|
||||
mname = db_ctf_stroff_to_str(&sym_data, mp->ctlm_name);
|
||||
db_indent = depth;
|
||||
if (mname != NULL) {
|
||||
db_iprintf("%s = ", mname);
|
||||
} else {
|
||||
db_iprintf("");
|
||||
}
|
||||
|
||||
db_pprint_type(maddr, mtype, depth + 1);
|
||||
db_printf(",");
|
||||
}
|
||||
}
|
||||
db_indent = depth - 1;
|
||||
db_iprintf("}");
|
||||
}
|
||||
|
||||
/*
|
||||
* Pretty-prints an array. Each array member is printed out in a separate line
|
||||
* indented with 'depth' spaces.
|
||||
*/
|
||||
static inline void
|
||||
db_pprint_arr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
|
||||
{
|
||||
struct ctf_type_v3 *elem_type;
|
||||
struct ctf_array_v3 *arr;
|
||||
db_addr_t elem_addr, end;
|
||||
size_t type_struct_size;
|
||||
size_t elem_size;
|
||||
|
||||
type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ?
|
||||
sizeof(struct ctf_type_v3) :
|
||||
sizeof(struct ctf_stype_v3);
|
||||
arr = (struct ctf_array_v3 *)((db_addr_t)type + type_struct_size);
|
||||
elem_type = db_ctf_typeid_to_type(&sym_data, arr->cta_contents);
|
||||
elem_size = ((elem_type->ctt_size == CTF_V3_LSIZE_SENT) ?
|
||||
CTF_TYPE_LSIZE(elem_type) :
|
||||
elem_type->ctt_size);
|
||||
elem_addr = addr;
|
||||
end = addr + (arr->cta_nelems * elem_size);
|
||||
|
||||
db_indent = depth;
|
||||
db_printf("[\n");
|
||||
/* Loop through and print individual elements. */
|
||||
for (; elem_addr < end; elem_addr += elem_size) {
|
||||
if (db_pager_quit) {
|
||||
return;
|
||||
}
|
||||
db_iprintf("");
|
||||
db_pprint_type(elem_addr, elem_type, depth);
|
||||
if ((elem_addr + elem_size) < end) {
|
||||
db_printf(",\n");
|
||||
}
|
||||
}
|
||||
db_printf("\n");
|
||||
db_indent = depth - 1;
|
||||
db_iprintf("]");
|
||||
}
|
||||
|
||||
/*
|
||||
* Pretty-prints an enum value. Also prints out symbolic name of value, if any.
|
||||
*/
|
||||
static inline void
|
||||
db_pprint_enum(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
|
||||
{
|
||||
struct ctf_enum *ep, *endp;
|
||||
size_t type_struct_size;
|
||||
const char *valname;
|
||||
db_expr_t val;
|
||||
u_int vlen;
|
||||
|
||||
type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ?
|
||||
sizeof(struct ctf_type_v3) :
|
||||
sizeof(struct ctf_stype_v3);
|
||||
vlen = CTF_V3_INFO_VLEN(type->ctt_info);
|
||||
val = db_get_value(addr, sizeof(int), 0);
|
||||
|
||||
if (db_pager_quit) {
|
||||
return;
|
||||
}
|
||||
ep = (struct ctf_enum *)((db_addr_t)type + type_struct_size);
|
||||
endp = ep + vlen;
|
||||
for (; ep < endp; ep++) {
|
||||
if (val == ep->cte_value) {
|
||||
valname = db_ctf_stroff_to_str(&sym_data, ep->cte_name);
|
||||
if (valname != NULL)
|
||||
db_printf("%s (0x%lx)", valname, val);
|
||||
else
|
||||
db_printf("(0x%lx)", val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pretty-prints a pointer. If the 'depth' parameter is less than the
|
||||
* 'max_depth' global var, the pointer is "dereference", i.e. the contents of
|
||||
* the memory it points to are also printed. The value of the pointer is printed
|
||||
* otherwise.
|
||||
*/
|
||||
static inline void
|
||||
db_pprint_ptr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
|
||||
{
|
||||
struct ctf_type_v3 *ref_type;
|
||||
const char *qual = "";
|
||||
const char *name;
|
||||
db_addr_t val;
|
||||
u_int kind;
|
||||
|
||||
ref_type = db_ctf_typeid_to_type(&sym_data, type->ctt_type);
|
||||
kind = CTF_V3_INFO_KIND(ref_type->ctt_info);
|
||||
switch (kind) {
|
||||
case CTF_K_STRUCT:
|
||||
qual = "struct ";
|
||||
break;
|
||||
case CTF_K_VOLATILE:
|
||||
qual = "volatile ";
|
||||
break;
|
||||
case CTF_K_CONST:
|
||||
qual = "const ";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
val = db_get_value(addr, sizeof(db_addr_t), false);
|
||||
if (depth < max_depth) {
|
||||
/* Print contents of memory pointed to by this pointer. */
|
||||
db_pprint_type(addr, ref_type, depth + 1);
|
||||
} else {
|
||||
name = db_ctf_stroff_to_str(&sym_data, ref_type->ctt_name);
|
||||
db_indent = depth;
|
||||
if (name != NULL)
|
||||
db_printf("(%s%s *) 0x%lx", qual, name, val);
|
||||
else
|
||||
db_printf("0x%lx", val);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pretty-print dispatching function.
|
||||
*/
|
||||
static void
|
||||
db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, u_int depth)
|
||||
{
|
||||
|
||||
if (db_pager_quit) {
|
||||
return;
|
||||
}
|
||||
if (type == NULL) {
|
||||
db_printf("unknown type");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (CTF_V3_INFO_KIND(type->ctt_info)) {
|
||||
case CTF_K_INTEGER:
|
||||
db_pprint_int(addr, type, depth);
|
||||
break;
|
||||
case CTF_K_UNION:
|
||||
case CTF_K_STRUCT:
|
||||
db_pprint_struct(addr, type, depth);
|
||||
break;
|
||||
case CTF_K_FUNCTION:
|
||||
case CTF_K_FLOAT:
|
||||
db_indent = depth;
|
||||
db_iprintf("0x%lx", addr);
|
||||
break;
|
||||
case CTF_K_POINTER:
|
||||
db_pprint_ptr(addr, type, depth);
|
||||
break;
|
||||
case CTF_K_TYPEDEF:
|
||||
case CTF_K_VOLATILE:
|
||||
case CTF_K_RESTRICT:
|
||||
case CTF_K_CONST: {
|
||||
struct ctf_type_v3 *ref_type = db_ctf_typeid_to_type(&sym_data,
|
||||
type->ctt_type);
|
||||
db_pprint_type(addr, ref_type, depth);
|
||||
break;
|
||||
}
|
||||
case CTF_K_ENUM:
|
||||
db_pprint_enum(addr, type, depth);
|
||||
break;
|
||||
case CTF_K_ARRAY:
|
||||
db_pprint_arr(addr, type, depth);
|
||||
break;
|
||||
case CTF_K_UNKNOWN:
|
||||
case CTF_K_FORWARD:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Symbol pretty-printing command.
|
||||
* Syntax: pprint [/d depth] <sym_name>
|
||||
*/
|
||||
static void
|
||||
db_pprint_symbol_cmd(const char *name)
|
||||
{
|
||||
db_addr_t addr;
|
||||
int db_indent_old;
|
||||
const char *type_name = NULL;
|
||||
struct ctf_type_v3 *type = NULL;
|
||||
|
||||
if (db_pager_quit) {
|
||||
return;
|
||||
}
|
||||
/* Clear symbol and CTF info */
|
||||
memset(&sym_data, 0, sizeof(struct db_ctf_sym_data));
|
||||
if (db_ctf_find_symbol(name, &sym_data) != 0) {
|
||||
db_error("Symbol not found\n");
|
||||
}
|
||||
if (ELF_ST_TYPE(sym_data.sym->st_info) != STT_OBJECT) {
|
||||
db_error("Symbol is not a variable\n");
|
||||
}
|
||||
addr = sym_data.sym->st_value;
|
||||
type = db_ctf_sym_to_type(&sym_data);
|
||||
if (type == NULL) {
|
||||
db_error("Can't find CTF type info\n");
|
||||
}
|
||||
type_name = db_ctf_stroff_to_str(&sym_data, type->ctt_name);
|
||||
if (type_name != NULL)
|
||||
db_printf("%s ", type_name);
|
||||
db_printf("%s = ", name);
|
||||
|
||||
db_indent_old = db_indent;
|
||||
db_pprint_type(addr, type, 0);
|
||||
db_indent = db_indent_old;
|
||||
}
|
||||
|
||||
/*
|
||||
* Command for pretty-printing arbitrary addresses.
|
||||
* Syntax: pprint [/d depth] struct <struct_name> <addr>
|
||||
*/
|
||||
static void
|
||||
db_pprint_struct_cmd(db_expr_t addr, const char *struct_name)
|
||||
{
|
||||
int db_indent_old;
|
||||
struct ctf_type_v3 *type = NULL;
|
||||
|
||||
type = db_ctf_find_typename(&sym_data, struct_name);
|
||||
if (type == NULL) {
|
||||
db_error("Can't find CTF type info\n");
|
||||
return;
|
||||
}
|
||||
|
||||
db_printf("struct %s ", struct_name);
|
||||
db_printf("%p = ", (void *)addr);
|
||||
|
||||
db_indent_old = db_indent;
|
||||
db_pprint_type(addr, type, 0);
|
||||
db_indent = db_indent_old;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pretty print an address or a symbol.
|
||||
*/
|
||||
void
|
||||
db_pprint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
|
||||
{
|
||||
int t = 0;
|
||||
const char *name;
|
||||
|
||||
/* Set default depth */
|
||||
max_depth = DB_PPRINT_DEFAULT_DEPTH;
|
||||
/* Parse print modifiers */
|
||||
t = db_read_token();
|
||||
if (t == tSLASH) {
|
||||
t = db_read_token();
|
||||
if (t != tIDENT) {
|
||||
db_error("Invalid flag passed\n");
|
||||
}
|
||||
/* Parse desired depth level */
|
||||
if (strcmp(db_tok_string, "d") == 0) {
|
||||
t = db_read_token();
|
||||
if (t != tNUMBER) {
|
||||
db_error("Invalid depth provided\n");
|
||||
}
|
||||
max_depth = db_tok_number;
|
||||
} else {
|
||||
db_error("Invalid flag passed\n");
|
||||
}
|
||||
/* Fetch next token */
|
||||
t = db_read_token();
|
||||
}
|
||||
/* Parse subcomannd */
|
||||
if (t == tIDENT) {
|
||||
if (strcmp(db_tok_string, "struct") == 0) {
|
||||
t = db_read_token();
|
||||
|
||||
if (t != tIDENT) {
|
||||
db_error("Invalid struct type name provided\n");
|
||||
}
|
||||
name = db_tok_string;
|
||||
|
||||
if (db_expression(&addr) == 0) {
|
||||
db_error("Address not provided\n");
|
||||
}
|
||||
db_pprint_struct_cmd(addr, name);
|
||||
} else {
|
||||
name = db_tok_string;
|
||||
db_pprint_symbol_cmd(name);
|
||||
}
|
||||
} else {
|
||||
db_error("Invalid subcommand\n");
|
||||
}
|
||||
db_skip_to_eol();
|
||||
}
|
@ -297,6 +297,7 @@ db_cmdfcn_t db_trace_until_matching_cmd;
|
||||
db_cmdfcn_t db_unscript_cmd;
|
||||
db_cmdfcn_t db_watchpoint_cmd;
|
||||
db_cmdfcn_t db_write_cmd;
|
||||
db_cmdfcn_t db_pprint_cmd;
|
||||
|
||||
/*
|
||||
* Interface between DDB and the DDB output capture facility.
|
||||
|
@ -27,6 +27,10 @@
|
||||
*/
|
||||
|
||||
#include <sys/ctf.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/linker.h>
|
||||
|
||||
#include <ddb/db_ctf.h>
|
||||
|
||||
/*
|
||||
* Note this file is included by both link_elf.c and link_elf_obj.c.
|
||||
@ -86,6 +90,9 @@ link_elf_ctf_get(linker_file_t lf, linker_ctf_t *lc)
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (panicstr != NULL || kdb_active)
|
||||
return (ENXIO);
|
||||
|
||||
/*
|
||||
* We need to try reading the CTF data. Flag no CTF data present
|
||||
* by default and if we actually succeed in reading it, we'll
|
||||
@ -288,3 +295,36 @@ link_elf_ctf_get(linker_file_t lf, linker_ctf_t *lc)
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
link_elf_ctf_get_ddb(linker_file_t lf, linker_ctf_t *lc)
|
||||
{
|
||||
elf_file_t ef = (elf_file_t)lf;
|
||||
|
||||
/*
|
||||
* Check whether CTF data was loaded or if a
|
||||
* previous loading attempt failed (ctfcnt == -1).
|
||||
*/
|
||||
if (ef->ctfcnt <= 0) {
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
lc->ctftab = ef->ctftab;
|
||||
lc->ctfcnt = ef->ctfcnt;
|
||||
lc->symtab = ef->ddbsymtab;
|
||||
lc->strtab = ef->ddbstrtab;
|
||||
lc->strcnt = ef->ddbstrcnt;
|
||||
lc->nsym = ef->ddbsymcnt;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
link_elf_ctf_lookup_typename(linker_file_t lf, linker_ctf_t *lc,
|
||||
const char *typename)
|
||||
{
|
||||
if (link_elf_ctf_get_ddb(lf, lc))
|
||||
return (ENOENT);
|
||||
|
||||
return (db_ctf_lookup_typename(lc, typename) ? 0 : ENOENT);
|
||||
}
|
||||
|
@ -328,6 +328,26 @@ linker_file_register_sysctls(linker_file_t lf, bool enable)
|
||||
sx_xlock(&kld_sx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke the LINKER_CTF_GET implementation for this file. Existing
|
||||
* implementations will load CTF info from the filesystem upon the first call
|
||||
* and cache it in the kernel thereafter.
|
||||
*/
|
||||
static void
|
||||
linker_ctf_load_file(linker_file_t file)
|
||||
{
|
||||
linker_ctf_t lc;
|
||||
int error;
|
||||
|
||||
error = linker_ctf_get(file, &lc);
|
||||
if (error == 0)
|
||||
return;
|
||||
if (bootverbose) {
|
||||
printf("failed to load CTF for %s: %d\n", file->filename,
|
||||
error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
linker_file_enable_sysctls(linker_file_t lf)
|
||||
{
|
||||
@ -490,6 +510,11 @@ linker_load_file(const char *filename, linker_file_t *result)
|
||||
return (ENOEXEC);
|
||||
}
|
||||
linker_file_enable_sysctls(lf);
|
||||
|
||||
/*
|
||||
* Ask the linker to load CTF data for this file.
|
||||
*/
|
||||
linker_ctf_load_file(lf);
|
||||
EVENTHANDLER_INVOKE(kld_load, lf);
|
||||
*result = lf;
|
||||
return (0);
|
||||
@ -782,6 +807,35 @@ linker_ctf_get(linker_file_t file, linker_ctf_t *lc)
|
||||
return (LINKER_CTF_GET(file, lc));
|
||||
}
|
||||
|
||||
int
|
||||
linker_ctf_lookup_typename_ddb(linker_ctf_t *lc, const char *typename)
|
||||
{
|
||||
#ifdef DDB
|
||||
linker_file_t lf;
|
||||
|
||||
TAILQ_FOREACH (lf, &linker_files, link){
|
||||
if (LINKER_CTF_LOOKUP_TYPENAME(lf, lc, typename) == 0)
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
int
|
||||
linker_ctf_lookup_sym_ddb(const char *symname, c_linker_sym_t *sym,
|
||||
linker_ctf_t *lc)
|
||||
{
|
||||
#ifdef DDB
|
||||
linker_file_t lf;
|
||||
|
||||
TAILQ_FOREACH (lf, &linker_files, link){
|
||||
if (LINKER_LOOKUP_DEBUG_SYMBOL_CTF(lf, symname, sym, lc) == 0)
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static int
|
||||
linker_file_add_dependency(linker_file_t file, linker_file_t dep)
|
||||
{
|
||||
@ -1781,9 +1835,21 @@ linker_preload(void *arg)
|
||||
sx_xunlock(&kld_sx);
|
||||
/* woohoo! we made it! */
|
||||
}
|
||||
|
||||
SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, NULL);
|
||||
|
||||
static void
|
||||
linker_mountroot(void *arg __unused)
|
||||
{
|
||||
linker_file_t lf;
|
||||
|
||||
sx_xlock(&kld_sx);
|
||||
TAILQ_FOREACH (lf, &linker_files, link) {
|
||||
linker_ctf_load_file(lf);
|
||||
}
|
||||
sx_xunlock(&kld_sx);
|
||||
}
|
||||
EVENTHANDLER_DEFINE(mountroot, linker_mountroot, NULL, 0);
|
||||
|
||||
/*
|
||||
* Handle preload files that failed to load any modules.
|
||||
*/
|
||||
|
@ -68,6 +68,10 @@
|
||||
|
||||
#include "linker_if.h"
|
||||
|
||||
#ifdef DDB_CTF
|
||||
#include <ddb/db_ctf.h>
|
||||
#endif
|
||||
|
||||
#define MAXSEGS 4
|
||||
|
||||
typedef struct elf_file {
|
||||
@ -141,6 +145,9 @@ static int link_elf_lookup_symbol(linker_file_t, const char *,
|
||||
c_linker_sym_t *);
|
||||
static int link_elf_lookup_debug_symbol(linker_file_t, const char *,
|
||||
c_linker_sym_t *);
|
||||
static int link_elf_lookup_debug_symbol_ctf(linker_file_t lf,
|
||||
const char *name, c_linker_sym_t *sym, linker_ctf_t *lc);
|
||||
|
||||
static int link_elf_symbol_values(linker_file_t, c_linker_sym_t,
|
||||
linker_symval_t *);
|
||||
static int link_elf_debug_symbol_values(linker_file_t, c_linker_sym_t,
|
||||
@ -167,6 +174,7 @@ static int elf_lookup(linker_file_t, Elf_Size, int, Elf_Addr *);
|
||||
static kobj_method_t link_elf_methods[] = {
|
||||
KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol),
|
||||
KOBJMETHOD(linker_lookup_debug_symbol, link_elf_lookup_debug_symbol),
|
||||
KOBJMETHOD(linker_lookup_debug_symbol_ctf, link_elf_lookup_debug_symbol_ctf),
|
||||
KOBJMETHOD(linker_symbol_values, link_elf_symbol_values),
|
||||
KOBJMETHOD(linker_debug_symbol_values, link_elf_debug_symbol_values),
|
||||
KOBJMETHOD(linker_search_symbol, link_elf_search_symbol),
|
||||
@ -178,6 +186,7 @@ static kobj_method_t link_elf_methods[] = {
|
||||
KOBJMETHOD(linker_each_function_name, link_elf_each_function_name),
|
||||
KOBJMETHOD(linker_each_function_nameval, link_elf_each_function_nameval),
|
||||
KOBJMETHOD(linker_ctf_get, link_elf_ctf_get),
|
||||
KOBJMETHOD(linker_ctf_lookup_typename, link_elf_ctf_lookup_typename),
|
||||
KOBJMETHOD(linker_symtab_get, link_elf_symtab_get),
|
||||
KOBJMETHOD(linker_strtab_get, link_elf_strtab_get),
|
||||
#ifdef VIMAGE
|
||||
@ -1587,6 +1596,34 @@ link_elf_lookup_debug_symbol(linker_file_t lf, const char *name,
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static int
|
||||
link_elf_lookup_debug_symbol_ctf(linker_file_t lf, const char *name,
|
||||
c_linker_sym_t *sym, linker_ctf_t *lc)
|
||||
{
|
||||
elf_file_t ef = (elf_file_t)lf;
|
||||
const Elf_Sym *symp;
|
||||
const char *strp;
|
||||
int i;
|
||||
|
||||
for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
|
||||
strp = ef->ddbstrtab + symp->st_name;
|
||||
if (strcmp(name, strp) == 0) {
|
||||
if (symp->st_shndx != SHN_UNDEF ||
|
||||
(symp->st_value != 0 &&
|
||||
(ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
|
||||
ELF_ST_TYPE(symp->st_info) ==
|
||||
STT_GNU_IFUNC))) {
|
||||
*sym = (c_linker_sym_t)symp;
|
||||
break;
|
||||
}
|
||||
return (ENOENT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate CTF info structure if symbol was found. */
|
||||
return (i < ef->ddbsymcnt ? link_elf_ctf_get_ddb(lf, lc) : ENOENT);
|
||||
}
|
||||
|
||||
static int
|
||||
link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
|
||||
linker_symval_t *symval, bool see_local)
|
||||
|
@ -131,6 +131,8 @@ static int link_elf_lookup_symbol(linker_file_t, const char *,
|
||||
c_linker_sym_t *);
|
||||
static int link_elf_lookup_debug_symbol(linker_file_t, const char *,
|
||||
c_linker_sym_t *);
|
||||
static int link_elf_lookup_debug_symbol_ctf(linker_file_t lf,
|
||||
const char *name, c_linker_sym_t *sym, linker_ctf_t *lc);
|
||||
static int link_elf_symbol_values(linker_file_t, c_linker_sym_t,
|
||||
linker_symval_t *);
|
||||
static int link_elf_debug_symbol_values(linker_file_t, c_linker_sym_t,
|
||||
@ -159,6 +161,7 @@ static int elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps,
|
||||
static kobj_method_t link_elf_methods[] = {
|
||||
KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol),
|
||||
KOBJMETHOD(linker_lookup_debug_symbol, link_elf_lookup_debug_symbol),
|
||||
KOBJMETHOD(linker_lookup_debug_symbol_ctf, link_elf_lookup_debug_symbol_ctf),
|
||||
KOBJMETHOD(linker_symbol_values, link_elf_symbol_values),
|
||||
KOBJMETHOD(linker_debug_symbol_values, link_elf_debug_symbol_values),
|
||||
KOBJMETHOD(linker_search_symbol, link_elf_search_symbol),
|
||||
@ -170,6 +173,7 @@ static kobj_method_t link_elf_methods[] = {
|
||||
KOBJMETHOD(linker_each_function_name, link_elf_each_function_name),
|
||||
KOBJMETHOD(linker_each_function_nameval, link_elf_each_function_nameval),
|
||||
KOBJMETHOD(linker_ctf_get, link_elf_ctf_get),
|
||||
KOBJMETHOD(linker_ctf_lookup_typename, link_elf_ctf_lookup_typename),
|
||||
KOBJMETHOD(linker_symtab_get, link_elf_symtab_get),
|
||||
KOBJMETHOD(linker_strtab_get, link_elf_strtab_get),
|
||||
#ifdef VIMAGE
|
||||
@ -1475,6 +1479,16 @@ link_elf_lookup_debug_symbol(linker_file_t lf, const char *name,
|
||||
return (link_elf_lookup_symbol1(lf, name, sym, true));
|
||||
}
|
||||
|
||||
static int
|
||||
link_elf_lookup_debug_symbol_ctf(linker_file_t lf, const char *name,
|
||||
c_linker_sym_t *sym, linker_ctf_t *lc)
|
||||
{
|
||||
if (link_elf_lookup_debug_symbol(lf, name, sym))
|
||||
return (ENOENT);
|
||||
|
||||
return (link_elf_ctf_get_ddb(lf, lc));
|
||||
}
|
||||
|
||||
static int
|
||||
link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
|
||||
linker_symval_t *symval, bool see_local)
|
||||
|
@ -115,6 +115,29 @@ METHOD int ctf_get {
|
||||
linker_ctf_t *lc;
|
||||
};
|
||||
|
||||
#
|
||||
# Look up a CTF type in the file's CTF section
|
||||
# and return CTF info in the linker CTF structure.
|
||||
# Return ENOENT if typename is not found, otherwise zero.
|
||||
#
|
||||
METHOD int ctf_lookup_typename {
|
||||
linker_file_t file;
|
||||
linker_ctf_t *lc;
|
||||
const char *typename;
|
||||
};
|
||||
|
||||
#
|
||||
# Lookup a symbol in the file's symbol table and the file's CTF info.
|
||||
# Return ENOENT if either the symbol or its CTF
|
||||
# data is not loaded, otherwise return zero.
|
||||
#
|
||||
METHOD int lookup_debug_symbol_ctf {
|
||||
linker_file_t file;
|
||||
const char *name;
|
||||
c_linker_sym_t *sym;
|
||||
linker_ctf_t *lc;
|
||||
};
|
||||
|
||||
#
|
||||
# Get the symbol table, returning it in **symtab. Return the
|
||||
# number of symbols, otherwise zero.
|
||||
|
@ -319,6 +319,9 @@ typedef struct linker_ctf {
|
||||
} linker_ctf_t;
|
||||
|
||||
int linker_ctf_get(linker_file_t, linker_ctf_t *);
|
||||
int linker_ctf_lookup_sym_ddb(const char *symname, c_linker_sym_t *sym,
|
||||
linker_ctf_t *lc);
|
||||
int linker_ctf_lookup_typename_ddb(linker_ctf_t *lc, const char *typename);
|
||||
|
||||
int elf_cpu_load_file(linker_file_t);
|
||||
int elf_cpu_unload_file(linker_file_t);
|
||||
|
Loading…
Reference in New Issue
Block a user