mdb_ctf.c revision e0ad97e30ea0a9af63c42d71690b5f387c763420
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <mdb/mdb_ctf_impl.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_string.h>
#include <mdb/mdb_debug.h>
#include <libctf.h>
#include <string.h>
typedef struct tnarg {
const char *tn_name; /* query string to lookup */
} tnarg_t;
typedef struct type_iter {
void *ti_arg;
} type_iter_t;
typedef struct member_iter {
void *mi_arg;
typedef struct type_visit {
void *tv_arg;
int tv_base_depth; /* used when recursing from type_cb() */
int tv_min_depth;
} type_visit_t;
typedef struct mbr_info {
const char *mbr_member;
} mbr_info_t;
static void
{
}
/*
* Callback function for mdb_tgt_object_iter used from name_to_type, below,
* to search the CTF namespace of each object file for a particular name.
*/
/*ARGSUSED*/
static int
{
ctf_file_t *fp;
/*
* We may have found a forward declaration. If we did, we'll
* note the ID and file pointer, but we'll keep searching in
* an attempt to find the real thing. If we found something
* real (i.e. not a forward), we stop the iteration.
*/
}
return (0);
}
/*
* Convert a string type name with an optional leading object specifier into
* the corresponding CTF file container and type ID. If an error occurs, we
* print an appropriate message and return NULL.
*/
static ctf_file_t *
{
const char *object = MDB_TGT_OBJ_EXEC;
char *p, *s;
char buf[MDB_SYM_NAMLEN];
/*
* We need to shuffle things around a little to support
* type names of the form "struct module`name".
*/
p = name + (p - s);
}
if (*name != '\0')
name = p;
}
/*
* Attempt to look up the name in the primary object file. If this
* fails and the name was unscoped, search all remaining object files.
*/
object == MDB_TGT_OBJ_EXEC) {
}
}
return (NULL); /* errno is set for us */
return (NULL);
}
return (fp);
}
/*
* Check to see if there is ctf data in the given object. This is useful
* so that we don't enter some loop where every call to lookup fails.
*/
int
mdb_ctf_enabled_by_object(const char *object)
{
}
int
{
return (-1); /* errno is set for us */
}
return (0);
}
int
mdb_ctf_id_t *p)
{
}
return (-1); /* errno is set for us */
}
}
return (0);
}
int
{
char name[MDB_SYM_NAMLEN];
const char *obj, *c;
if (p == NULL)
return (-1); /* errno is set for us */
}
} else {
return (-1); /* errno is set for us */
}
c = name;
}
return (-1); /* errno is set for us */
}
}
int
{
ctf_file_t *fp;
return (set_errno(EMDB_NOCTF));
return (0);
}
/*ARGSUSED*/
int
{
char name[MDB_SYM_NAMLEN];
int err;
/*
* In case the input symbol came from a merged or private symbol table,
* re-lookup the address as a symbol, and then perform a fully scoped
* lookup of that symbol name to get the mdb_syminfo_t for its CTF.
*/
return (-1); /* errno is set for us */
else
if (err != 0)
return (-1); /* errno is set for us */
return (0);
}
int
{
ctf_file_t *fp;
int i;
}
return (0);
}
void
{
}
int
{
}
int
{
}
int
{
if (outp)
}
char name[MDB_SYM_NAMLEN];
NULL &&
return (0);
}
}
return (0);
}
char *
{
char *ret;
if (!mdb_ctf_type_valid(id)) {
return (NULL);
}
return (ret);
}
{
/* resolve the type in case there's a forward declaration */
return (ret);
return (ret);
}
int
{
int ret;
return (ret);
}
int
{
if (outp)
}
return (0);
}
int
{
return (0);
}
/*
* callback proxy for mdb_ctf_type_visit
*/
static int
{
int ret;
return (0);
return (ret);
/*
* If the type resolves to a type in a different file, we must have
* followed a forward declaration. We need to recurse into the
* new type.
*/
}
return (ret);
}
int
{
int ret;
tv.tv_base_offset = 0;
tv.tv_base_depth = 0;
tv.tv_min_depth = 0;
return (ret);
}
int
{
return (0);
}
const char *
{
const char *ret;
/* resolve the type in case there's a forward declaration */
return (NULL);
return (ret);
}
/*
* callback proxy for mdb_ctf_member_iter
*/
static int
{
}
int
{
int ret;
/* resolve the type in case there's a forward declaration */
return (ret);
return (ret);
}
int
{
int ret;
/* resolve the type in case there's a forward declaration */
return (ret);
}
/*
* callback proxy for mdb_ctf_type_iter
*/
static int
{
}
int
{
ctf_file_t *fp;
int ret;
return (-1);
return (ret);
}
/* utility functions */
{
}
{
}
static int
{
return (1);
}
return (0);
}
int
{
int rc;
/* couldn't get member list */
if (rc == -1)
return (-1); /* errno is set for us */
/* not a member */
if (rc == 0)
return (set_errno(EMDB_CTFNOMEMB));
return (0);
}
int
{
}
/*ARGSUSED*/
static int
{
return (0);
}
int
{
int count = 0;
return (-1); /* errno is set for us */
return (count);
}
typedef struct mbr_contains {
char **mbc_bufp;
static int
{
size_t n;
return (0);
else
return (0);
return (1);
}
{
size_t n;
if (!mdb_ctf_type_valid(id))
/*
* Quick sanity check to make sure the given offset is within
* this scope of this type.
*/
*buf = '\0';
for (;;) {
/*
* Check for an exact match.
*/
if (off == 0)
break;
/*
* Find the member that contains this offset.
*/
switch (mdb_ctf_type_kind(id)) {
case CTF_K_ARRAY: {
if (n > len)
n = len;
buf += n;
len -= n;
break;
}
case CTF_K_STRUCT: {
int ret;
/*
* Find the member that contains this offset
* and continue.
*/
if (dot) {
if (len != 0) {
*buf++ = '.';
*buf = '\0';
len--;
}
}
if (ret == -1)
return (-1); /* errno is set for us */
/*
* If we did not find a member containing this offset
* (due to holes in the structure), return EINVAL.
*/
if (ret == 0)
break;
}
case CTF_K_UNION:
/*
* Treat unions like atomic entities since we can't
* do more than guess which member of the union
* might be the intended one.
*/
goto done;
case CTF_K_INTEGER:
case CTF_K_FLOAT:
case CTF_K_POINTER:
case CTF_K_ENUM:
goto done;
default:
}
dot = 1;
}
done:
}
/*
* Check if two types are structurally the same rather than logically
* the same. That is to say that two types are equal if they have the
* same logical structure rather than having the same ids in CTF-land.
*/
static int
{
/*
* Look up the corresponding member in the other composite type.
*/
return (1);
/*
* We don't allow members to be shuffled around.
*/
return (1);
}
static int
{
/*
* Resolve both types down to their fundamental types, and make
* sure their sizes and kinds match.
*/
if (mdb_ctf_type_resolve(a, &a) != 0 ||
mdb_ctf_type_resolve(b, &b) != 0 ||
return (0);
}
switch (akind) {
case CTF_K_INTEGER:
case CTF_K_FLOAT:
case CTF_K_POINTER:
/*
* For pointers we could be a little stricter and require
* both pointers to reference types which look vaguely
* similar (for example, we could insist that the two types
* have the same name). However, all we really care about
* here is that the structure of the two types are the same,
* and, in that regard, one pointer is as good as another.
*/
return (1);
case CTF_K_UNION:
case CTF_K_STRUCT:
/*
* The test for the number of members is only strictly
* necessary for unions since we'll find other problems with
* structs. However, the extra check will do no harm.
*/
return (mdb_ctf_num_members(a) == mdb_ctf_num_members(b) &&
mdb_ctf_member_iter(a, type_equals_cb, &b) == 0);
case CTF_K_ARRAY:
return (mdb_ctf_array_info(a, &aar) == 0 &&
mdb_ctf_array_info(b, &bar) == 0 &&
}
return (0);
}
typedef struct member {
char *m_modbuf;
char *m_tgtbuf;
} member_t;
static int
{
return (0);
else
return (set_errno(EMDB_CTFNOMEMB));
}
}
static int
{
int ret;
int i;
/*
* Resolve the types to their canonical form.
*/
return (-1); /* errno is set for us */
return (-1); /* errno is set for us */
return (set_errno(EMDB_INCOMPAT));
switch (modkind) {
case CTF_K_INTEGER:
case CTF_K_FLOAT:
case CTF_K_POINTER:
return (-1); /* errno is set for us */
return (-1); /* errno is set for us */
/*
* If the sizes don't match we need to be tricky to make
* sure that the caller gets the correct data.
*/
if (!(flags & MDB_CTF_VREAD_IGNORE_GROW))
return (set_errno(EMDB_INCOMPAT));
#ifdef _BIG_ENDIAN
#else
#endif
#ifdef _BIG_ENDIAN
#else
#endif
} else {
}
return (0);
case CTF_K_STRUCT:
case CTF_K_UNION:
/*
* Unions are a little tricky. The only time it's truly
* safe to read in a union is if no part of the union or
* any of its component types have changed. We allow the
* consumer to ignore unions. The correct use of this
* feature is to read the containing structure, figure
* out which component of the union is valid, compute
* the location of that in the target and then read in
* that part of the structure.
*/
if (flags & MDB_CTF_VREAD_IGNORE_UNIONS)
return (0);
return (set_errno(EMDB_INCOMPAT));
return (0);
case CTF_K_ARRAY:
return (-1); /* errno is set for us */
return (-1); /* errno is set for us */
return (set_errno(EMDB_INCOMPAT));
return (-1); /* errno is set for us */
return (-1); /* errno is set for us */
for (i = 0; i < tar.mta_nelems; i++) {
if (ret != 0)
return (ret);
}
return (0);
}
return (set_errno(EMDB_INCOMPAT));
}
int
{
void *tgtbuf;
return (set_errno(EMDB_NOCTF));
}
return (set_errno(EMDB_NOCTF));
}
/*
* Read the data out of the target's address space.
*/
return (-1); /* errno is set for us */
return (-1); /* errno is set for us */
}
int
{
return (-1); /* errno is set for us */
}
{
ctdata.cts_offset = 0;
}