1468 lines
33 KiB
C
1468 lines
33 KiB
C
/**
|
|
* \file executer/user/mcinspect.c
|
|
* License details are found in the file LICENSE.
|
|
*
|
|
* \brief
|
|
* A DWARF based inspection tool for McKernel.
|
|
*
|
|
* \author Balazs Gerofi <bgerofi@riken.jp> \par
|
|
* Copyright (C) 2019 RIKEN
|
|
*/
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ioctl.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <strings.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <dwarf.h>
|
|
#include <libdwarf-0/libdwarf.h>
|
|
#include <getopt.h>
|
|
#include <libgen.h>
|
|
#include <bfd.h>
|
|
|
|
void usage(char **argv)
|
|
{
|
|
printf("Usage: %s <options>\n", basename(argv[0]));
|
|
printf("Inspect internal state of McKernel.\n");
|
|
printf("\n");
|
|
printf("Mandatory arguments to long options are mandatory for short options too.\n");
|
|
printf(" --help Display this help message.\n");
|
|
printf(" --kernel PATH Path to kernel image.\n");
|
|
printf(" --ps List processes running on LWK.\n");
|
|
printf(" --vtop Dump page tables.\n");
|
|
printf(" -v, --va ADDR Dump page tables for ADDR only.\n");
|
|
printf(" -p, --pid PID Use process PID for vtop.\n");
|
|
printf(" --debug Enable debug mode.\n");
|
|
printf("\n");
|
|
printf("Examples: \n");
|
|
printf(" %s --kernel=smp-x86/kernel/mckernel.img --ps\n", basename(argv[0]));
|
|
printf(" %s --kernel=smp-x86/kernel/mckernel.img --vtop --pid 100 --va 0x3fffff800000\n",
|
|
basename(argv[0]));
|
|
}
|
|
|
|
int debug;
|
|
int mcfd;
|
|
|
|
/*
|
|
* BFD based symbol table
|
|
*/
|
|
bfd *symbfd = NULL;
|
|
asymbol **symtab = NULL;
|
|
ssize_t nsyms;
|
|
#define NOSYMBOL (-1UL)
|
|
|
|
unsigned long int lookup_bfd_symbol(char *name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nsyms; ++i) {
|
|
if (!strcmp(symtab[i]->name, name)) {
|
|
return (symtab[i]->section->vma + symtab[i]->value);
|
|
}
|
|
}
|
|
|
|
return NOSYMBOL;
|
|
}
|
|
|
|
int init_bfd_symbols(char *fname) {
|
|
ssize_t needs;
|
|
bfd_boolean ok;
|
|
|
|
symbfd = bfd_openr(fname, NULL);
|
|
|
|
if (!symbfd) {
|
|
bfd_perror("bfd_openr");
|
|
return -1;
|
|
}
|
|
|
|
ok = bfd_check_format(symbfd, bfd_object);
|
|
if (!ok) {
|
|
bfd_perror("bfd_check_format");
|
|
return -1;
|
|
}
|
|
|
|
needs = bfd_get_symtab_upper_bound(symbfd);
|
|
if (needs < 0) {
|
|
bfd_perror("bfd_get_symtab_upper_bound");
|
|
return -1;
|
|
}
|
|
|
|
if (!needs) {
|
|
printf("no symbols\n");
|
|
return -1;
|
|
}
|
|
|
|
symtab = malloc(needs);
|
|
if (!symtab) {
|
|
perror("malloc");
|
|
return -1;
|
|
}
|
|
|
|
nsyms = bfd_canonicalize_symtab(symbfd, symtab);
|
|
if (nsyms < 0) {
|
|
bfd_perror("bfd_canonicalize_symtab");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Walk DWARF tree and call func with arg for each Die
|
|
*/
|
|
int dwarf_walk_tree(Dwarf_Debug dbg,
|
|
int (*func)(Dwarf_Debug dbg, Dwarf_Die die, void *arg), void *arg)
|
|
{
|
|
Dwarf_Bool is_info;
|
|
Dwarf_Unsigned cu_length;
|
|
Dwarf_Half cu_version;
|
|
Dwarf_Off cu_abbrev_offset;
|
|
Dwarf_Half cu_pointer_size;
|
|
Dwarf_Half cu_offset_size;
|
|
Dwarf_Half cu_extension_size;
|
|
Dwarf_Sig8 type_signature;
|
|
Dwarf_Unsigned type_offset;
|
|
Dwarf_Unsigned cu_next_offset;
|
|
Dwarf_Error err;
|
|
Dwarf_Die unit;
|
|
Dwarf_Die die;
|
|
Dwarf_Half header_cu_type;
|
|
int rc;
|
|
|
|
/* Iterate compile and type units */
|
|
for (is_info = 0; is_info < 2; ++is_info) {
|
|
rc = dwarf_next_cu_header_d(dbg, is_info, &cu_length,
|
|
&cu_version, &cu_abbrev_offset, &cu_pointer_size,
|
|
&cu_offset_size, &cu_extension_size, &type_signature,
|
|
&type_offset, &cu_next_offset, &header_cu_type, &err);
|
|
|
|
while (rc != DW_DLV_NO_ENTRY) {
|
|
char *name = NULL;
|
|
const char *tag_name;
|
|
Dwarf_Half tag;
|
|
Dwarf_Die next;
|
|
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "error: dwarf_next_cu_header_c: %d %s\n",
|
|
rc, dwarf_errmsg(err));
|
|
return -1;
|
|
}
|
|
|
|
rc = dwarf_siblingof_b(dbg, NULL, is_info, &unit, &err);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "error: dwarf_siblingof_b failed: %d %s\n",
|
|
rc, dwarf_errmsg(err));
|
|
return -1;
|
|
}
|
|
|
|
if (debug) {
|
|
rc = dwarf_diename(unit, &name, &err);
|
|
if (rc == DW_DLV_NO_ENTRY) {
|
|
name = NULL;
|
|
}
|
|
else if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "error: dwarf_diename error: %d %s\n",
|
|
rc, dwarf_errmsg(err));
|
|
return -1;
|
|
}
|
|
|
|
rc = dwarf_tag(unit, &tag, &err);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "dwarf_tag error: %d %s\n",
|
|
rc, dwarf_errmsg(err));
|
|
return -1;
|
|
}
|
|
|
|
rc = dwarf_get_TAG_name(tag, &tag_name);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"dwarf_get_TAG_name error: %d\n", rc);
|
|
return -1;
|
|
}
|
|
|
|
printf("%p <%d> %s: %s\n", unit, tag,
|
|
tag_name, name ? name : "<no name>");
|
|
}
|
|
|
|
/* Iterate entries in this unit */
|
|
rc = dwarf_child(unit, &die, &err);
|
|
if (rc == DW_DLV_ERROR) {
|
|
fprintf(stderr, "dwarf_child error: %d %s\n",
|
|
rc, dwarf_errmsg(err));
|
|
return -1;
|
|
}
|
|
|
|
while (die) {
|
|
if (debug) {
|
|
char *name = NULL;
|
|
const char *tag_name;
|
|
Dwarf_Half tag;
|
|
|
|
rc = dwarf_diename(die, &name, &err);
|
|
if (rc == DW_DLV_NO_ENTRY) {
|
|
name = NULL;
|
|
}
|
|
else if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "error: dwarf_diename error: %d %s\n",
|
|
rc, dwarf_errmsg(err));
|
|
return -1;
|
|
}
|
|
|
|
rc = dwarf_tag(die, &tag, &err);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "dwarf_tag error: %d %s\n",
|
|
rc, dwarf_errmsg(err));
|
|
return -1;
|
|
}
|
|
|
|
rc = dwarf_get_TAG_name(tag, &tag_name);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"dwarf_get_TAG_name error: %d\n", rc);
|
|
return -1;
|
|
}
|
|
|
|
printf(" %p <%d> %s: %s\n", die, tag,
|
|
tag_name, name ? name : "<no name>");
|
|
}
|
|
|
|
if (func) {
|
|
rc = func(dbg, die, arg);
|
|
/* Stop when DW_DLV_OK reached */
|
|
if (rc == DW_DLV_OK) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
rc = dwarf_siblingof_b(dbg, die, is_info, &next, &err);
|
|
dwarf_dealloc(dbg, die, DW_DLA_DIE);
|
|
if (name)
|
|
dwarf_dealloc(dbg, name, DW_DLA_STRING);
|
|
|
|
if (rc != DW_DLV_OK)
|
|
break;
|
|
|
|
die = next;
|
|
}
|
|
|
|
rc = dwarf_next_cu_header_d(dbg, is_info, &cu_length,
|
|
&cu_version, &cu_abbrev_offset, &cu_pointer_size,
|
|
&cu_offset_size, &cu_extension_size, &type_signature,
|
|
&type_offset, &cu_next_offset, &header_cu_type, &err);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int dwarf_get_size(Dwarf_Debug dbg,
|
|
Dwarf_Die die,
|
|
unsigned long *psize,
|
|
Dwarf_Error *perr)
|
|
{
|
|
Dwarf_Attribute attr;
|
|
Dwarf_Unsigned size;
|
|
Dwarf_Half form;
|
|
int rc;
|
|
|
|
rc = dwarf_attr(die, DW_AT_byte_size, &attr, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
return rc;
|
|
}
|
|
|
|
rc = dwarf_whatform(attr, &form, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: getting whatform: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
return rc;
|
|
}
|
|
|
|
if (form == DW_FORM_data1 ||
|
|
form == DW_FORM_data2 ||
|
|
form == DW_FORM_data2 ||
|
|
form == DW_FORM_data4 ||
|
|
form == DW_FORM_data8 ||
|
|
form == DW_FORM_udata) {
|
|
dwarf_formudata(attr, &size, 0);
|
|
}
|
|
else if (form == DW_FORM_sdata) {
|
|
Dwarf_Signed ssize;
|
|
dwarf_formsdata(attr, &ssize, 0);
|
|
|
|
if (ssize < 0) {
|
|
fprintf(stderr, "%s: unsupported negative size\n",
|
|
__func__);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
size = (Dwarf_Unsigned) ssize;
|
|
}
|
|
else {
|
|
Dwarf_Loc_Head_c loclist_head = 0;
|
|
Dwarf_Unsigned lcount = 0;
|
|
Dwarf_Locdesc_c locdesc_entry = 0;
|
|
Dwarf_Small op;
|
|
Dwarf_Unsigned opd1, opd2, opd3;
|
|
Dwarf_Unsigned offsetforbranch;
|
|
int lres;
|
|
|
|
|
|
lres = dwarf_get_loclist_c(attr, &loclist_head, &lcount, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: unsupported member size\n",
|
|
__func__);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
if (lcount != 1) {
|
|
fprintf(stderr,
|
|
"%s: unsupported location expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
lres = dwarf_get_locdesc_entry_d(loclist_head, 0, 0, 0, 0, 0, 0, 0, 0, &locdesc_entry, 0, 0, 0, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"%s: unsupported location expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
lres = dwarf_get_location_op_value_d(locdesc_entry, 0, &op, &opd1, &opd2, &opd3, NULL, NULL, NULL, &offsetforbranch, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"%s: unsupported location expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
if (op != DW_OP_plus_uconst) {
|
|
fprintf(stderr,
|
|
"%s: unsupported location expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
size = opd1;
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
}
|
|
dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
|
|
|
|
*psize = (unsigned long)size;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/*
|
|
* Find the size of a type.
|
|
*/
|
|
struct dwarf_size_arg {
|
|
char *name;
|
|
unsigned long *sizep;
|
|
};
|
|
|
|
int dwarf_size(Dwarf_Debug dbg, Dwarf_Die die, void *arg)
|
|
{
|
|
struct dwarf_size_arg *ds =
|
|
(struct dwarf_size_arg *)arg;
|
|
Dwarf_Half tag;
|
|
Dwarf_Error err;
|
|
char *name = NULL;
|
|
int rc;
|
|
unsigned long size;
|
|
|
|
rc = dwarf_tag(die, &tag, &err);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: dwarf_tag: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
rc = dwarf_diename(die, &name, &err);
|
|
if (rc == DW_DLV_NO_ENTRY) {
|
|
name = NULL;
|
|
}
|
|
else if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: dwarf_diename: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
if (!name || strcasecmp(name, ds->name)) {
|
|
rc = DW_DLV_NO_ENTRY;
|
|
goto out;
|
|
}
|
|
|
|
rc = dwarf_get_size(dbg, die, &size, &err);
|
|
if (rc == DW_DLV_NO_ENTRY) {
|
|
goto out;
|
|
}
|
|
else if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: getting size: %s\n",
|
|
__func__, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
if (debug) {
|
|
fprintf(stdout, "size of type \"%s\": %lu\n",
|
|
ds->name, size);
|
|
}
|
|
|
|
*ds->sizep = size;
|
|
rc = DW_DLV_OK;
|
|
|
|
out:
|
|
if (name)
|
|
dwarf_dealloc(dbg, name, DW_DLA_STRING);
|
|
|
|
return rc;
|
|
}
|
|
|
|
#define DWARF_GET_SIZE(__name__) \
|
|
({ \
|
|
unsigned long size; \
|
|
int rc; \
|
|
struct dwarf_size_arg ds = { \
|
|
.name = #__name__, \
|
|
.sizep = &size, \
|
|
}; \
|
|
rc = dwarf_walk_tree(dbg, dwarf_size, &ds); \
|
|
if (rc != DW_DLV_OK) { \
|
|
fprintf(stderr, "%s: error: finding size of %s\n", \
|
|
__func__, ds.name); \
|
|
exit(1); \
|
|
} \
|
|
size; \
|
|
})
|
|
|
|
|
|
int dwarf_get_offset(Dwarf_Debug dbg,
|
|
Dwarf_Die die,
|
|
unsigned long *poffset,
|
|
Dwarf_Error *perr)
|
|
{
|
|
Dwarf_Attribute attr;
|
|
Dwarf_Unsigned offset;
|
|
Dwarf_Half form;
|
|
int rc;
|
|
|
|
rc = dwarf_attr(die, DW_AT_data_member_location, &attr, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
return rc;
|
|
}
|
|
|
|
rc = dwarf_whatform(attr, &form, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: getting whatform: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
return rc;
|
|
}
|
|
|
|
if (form == DW_FORM_data1 ||
|
|
form == DW_FORM_data2 ||
|
|
form == DW_FORM_data2 ||
|
|
form == DW_FORM_data4 ||
|
|
form == DW_FORM_data8 ||
|
|
form == DW_FORM_udata) {
|
|
dwarf_formudata(attr, &offset, 0);
|
|
}
|
|
else if (form == DW_FORM_sdata) {
|
|
Dwarf_Signed soffset;
|
|
dwarf_formsdata(attr, &soffset, 0);
|
|
|
|
if (soffset < 0) {
|
|
fprintf(stderr, "%s: unsupported negative offset\n",
|
|
__func__);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
offset = (Dwarf_Unsigned) soffset;
|
|
}
|
|
else {
|
|
Dwarf_Loc_Head_c loclist_head = 0;
|
|
Dwarf_Unsigned lcount = 0;
|
|
Dwarf_Locdesc_c locdesc_entry = 0;
|
|
Dwarf_Small op;
|
|
Dwarf_Unsigned opd1, opd2, opd3;
|
|
Dwarf_Unsigned offsetforbranch;
|
|
int lres;
|
|
|
|
|
|
lres = dwarf_get_loclist_c(attr, &loclist_head, &lcount, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: unsupported member offset\n",
|
|
__func__);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
if (lcount != 1) {
|
|
fprintf(stderr,
|
|
"%s: unsupported location expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
lres = dwarf_get_locdesc_entry_d(loclist_head, 0, 0, 0, 0, 0, 0, 0, 0, &locdesc_entry, 0, 0, 0, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"%s: unsupported location expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
lres = dwarf_get_location_op_value_d(locdesc_entry, 0, &op, &opd1, &opd2, &opd3, NULL, NULL, NULL, &offsetforbranch, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"%s: unsupported location expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
if (op != DW_OP_plus_uconst) {
|
|
fprintf(stderr,
|
|
"%s: unsupported location expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
offset = opd1;
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
}
|
|
dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
|
|
|
|
*poffset = (unsigned long)offset;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/*
|
|
* Find the offset of a field in a struct.
|
|
*/
|
|
struct dwarf_struct_field_offset_arg {
|
|
char *struct_name;
|
|
char *field_name;
|
|
unsigned long *offp;
|
|
};
|
|
|
|
int dwarf_struct_field_offset(Dwarf_Debug dbg, Dwarf_Die die, void *arg)
|
|
{
|
|
struct dwarf_struct_field_offset_arg *dsfo =
|
|
(struct dwarf_struct_field_offset_arg *)arg;
|
|
Dwarf_Half tag;
|
|
Dwarf_Error err;
|
|
Dwarf_Die child, next;
|
|
char *name = NULL;
|
|
int rc;
|
|
unsigned long offset;
|
|
int found = 0;
|
|
|
|
rc = dwarf_tag(die, &tag, &err);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: dwarf_tag: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
rc = dwarf_diename(die, &name, &err);
|
|
if (rc == DW_DLV_NO_ENTRY) {
|
|
name = NULL;
|
|
}
|
|
else if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: dwarf_diename: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
if (tag != DW_TAG_structure_type || !name ||
|
|
strcasecmp(name, dsfo->struct_name)) {
|
|
rc = DW_DLV_NO_ENTRY;
|
|
goto out;
|
|
}
|
|
|
|
rc = dwarf_child(die, &child, &err);
|
|
if (rc == DW_DLV_ERROR) {
|
|
fprintf(stderr, "%s: dwarf_child error: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
rc = DW_DLV_NO_ENTRY;
|
|
goto out;
|
|
}
|
|
|
|
while (child) {
|
|
rc = dwarf_diename(child, &name, &err);
|
|
if (rc == DW_DLV_NO_ENTRY) {
|
|
name = NULL;
|
|
}
|
|
else if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: dwarf_diename: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
rc = dwarf_tag(child, &tag, &err);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: dwarf_tag: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
if (tag != DW_TAG_member || !name ||
|
|
strcasecmp(name, dsfo->field_name)) {
|
|
goto next_child;
|
|
}
|
|
|
|
rc = dwarf_get_offset(dbg, child, &offset, &err);
|
|
if (rc == DW_DLV_NO_ENTRY) {
|
|
offset = 0;
|
|
}
|
|
else if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: getting dwarf attr offset: %s\n",
|
|
__func__, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
if (debug) {
|
|
fprintf(stdout, "offset of field \"%s\" in struct \"%s\": %lu\n",
|
|
dsfo->field_name, dsfo->struct_name, offset);
|
|
}
|
|
|
|
*dsfo->offp = offset;
|
|
dwarf_dealloc(dbg, child, DW_DLA_DIE);
|
|
found = 1;
|
|
break;
|
|
|
|
next_child:
|
|
rc = dwarf_siblingof_b(dbg, child, 1, &next, &err);
|
|
dwarf_dealloc(dbg, child, DW_DLA_DIE);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: dwarf_siblingof_b: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
rc = DW_DLV_NO_ENTRY;
|
|
goto out;
|
|
}
|
|
|
|
child = next;
|
|
}
|
|
|
|
if (found) {
|
|
rc = DW_DLV_OK;
|
|
}
|
|
else {
|
|
rc = DW_DLV_NO_ENTRY;
|
|
}
|
|
|
|
out:
|
|
if (name)
|
|
dwarf_dealloc(dbg, name, DW_DLA_STRING);
|
|
|
|
return rc;
|
|
}
|
|
|
|
#define DWARF_GET_OFFSET_IN_STRUCT(__struct_name__, __field_name__) \
|
|
({ \
|
|
unsigned long offset; \
|
|
int rc; \
|
|
struct dwarf_struct_field_offset_arg dsfo = { \
|
|
.struct_name = #__struct_name__, \
|
|
.field_name = #__field_name__, \
|
|
.offp = &offset, \
|
|
}; \
|
|
rc = dwarf_walk_tree(dbg, dwarf_struct_field_offset, &dsfo); \
|
|
if (rc != DW_DLV_OK) { \
|
|
fprintf(stderr, "%s: error: finding %s in struct %s\n", \
|
|
__func__, dsfo.field_name, dsfo.struct_name); \
|
|
exit(1); \
|
|
} \
|
|
offset; \
|
|
})
|
|
|
|
|
|
/*
|
|
* Find the address of a global variable.
|
|
*/
|
|
int dwarf_get_address(Dwarf_Debug dbg,
|
|
Dwarf_Die die,
|
|
unsigned long *paddr,
|
|
Dwarf_Error *perr)
|
|
{
|
|
Dwarf_Unsigned addr;
|
|
Dwarf_Half form;
|
|
Dwarf_Half directform = 0;
|
|
int rc, i;
|
|
int found = 0;
|
|
|
|
Dwarf_Signed atcnt = 0;
|
|
Dwarf_Attribute *atlist = 0;
|
|
|
|
#if 0
|
|
Dwarf_Attribute attr;
|
|
|
|
rc = dwarf_attr(die, DW_AT_location, &attr, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: warning: no location attr: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
return rc;
|
|
}
|
|
#endif
|
|
|
|
rc = dwarf_attrlist(die, &atlist, &atcnt, perr);
|
|
if (rc == DW_DLV_ERROR) {
|
|
fprintf(stderr, "%s: error: getting attrlist: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
return rc;
|
|
}
|
|
else if (rc == DW_DLV_NO_ENTRY) {
|
|
/* indicates there are no attrs. It is not an error. */
|
|
return rc;
|
|
}
|
|
|
|
for (i = 0; i < atcnt; i++) {
|
|
Dwarf_Half attr_i;
|
|
Dwarf_Attribute attr;
|
|
|
|
rc = dwarf_whatattr(atlist[i], &attr_i, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: getting attr: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
goto dealloc_out;
|
|
}
|
|
attr = atlist[i];
|
|
|
|
if (attr_i != DW_AT_location) {
|
|
continue;
|
|
}
|
|
printf("%s: DW_AT_location\n", __func__);
|
|
|
|
rc = dwarf_whatform(attr, &form, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: getting whatform: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
goto dealloc_out;
|
|
}
|
|
dwarf_whatform_direct(attr, &directform, perr);
|
|
|
|
if (form == DW_FORM_block1 ||
|
|
form == DW_FORM_block2 ||
|
|
form == DW_FORM_block4 ||
|
|
form == DW_FORM_block ||
|
|
form == DW_FORM_data4 ||
|
|
form == DW_FORM_data8 ||
|
|
form == DW_FORM_sec_offset) {
|
|
|
|
Dwarf_Loc_Head_c loclist_head = 0;
|
|
Dwarf_Unsigned lcount = 0;
|
|
Dwarf_Locdesc_c locdesc_entry = 0;
|
|
Dwarf_Small op;
|
|
Dwarf_Unsigned opd1, opd2, opd3;
|
|
Dwarf_Unsigned offsetforbranch;
|
|
int lres;
|
|
|
|
lres = dwarf_get_loclist_c(attr, &loclist_head, &lcount, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: dwarf_get_loclist_c: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
rc = DW_DLV_ERROR;
|
|
goto dealloc_out;
|
|
}
|
|
|
|
if (lcount != 1) {
|
|
fprintf(stderr,
|
|
"%s: unsupported addr expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
rc = DW_DLV_ERROR;
|
|
goto dealloc_out;
|
|
}
|
|
|
|
lres = dwarf_get_locdesc_entry_d(loclist_head, 0, 0, 0, 0, 0, 0, 0, 0, &locdesc_entry, 0, 0, 0, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"%s: unsupported addr expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
rc = DW_DLV_ERROR;
|
|
goto dealloc_out;
|
|
}
|
|
|
|
lres = dwarf_get_location_op_value_d(locdesc_entry, 0, &op, &opd1, &opd2, &opd3, NULL, NULL, NULL, &offsetforbranch, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"%s: unsupported addr expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
rc = DW_DLV_ERROR;
|
|
goto dealloc_out;
|
|
}
|
|
|
|
if (op != DW_OP_addr) {
|
|
fprintf(stderr,
|
|
"%s: unsupported addr expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
rc = DW_DLV_ERROR;
|
|
goto dealloc_out;
|
|
}
|
|
addr = opd1;
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
}
|
|
else if (form == DW_FORM_exprloc) {
|
|
Dwarf_Half address_size = 0;
|
|
Dwarf_Ptr x = 0;
|
|
Dwarf_Unsigned tempud = 0;
|
|
Dwarf_Loc_Head_c loclist_head = 0;
|
|
Dwarf_Unsigned lcount = 0;
|
|
Dwarf_Locdesc_c locdesc_entry = 0;
|
|
Dwarf_Small op;
|
|
Dwarf_Unsigned opd1, opd2, opd3;
|
|
Dwarf_Unsigned offsetforbranch;
|
|
int lres;
|
|
Dwarf_Half version;
|
|
Dwarf_Half offset_size;
|
|
|
|
rc = dwarf_formexprloc(attr, &tempud, &x, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: dwarf_formexprloc(): %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
goto dealloc_out;
|
|
}
|
|
|
|
rc = dwarf_get_die_address_size(die, &address_size, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: dwarf_get_die_address_size: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
goto dealloc_out;
|
|
}
|
|
|
|
rc = dwarf_get_version_of_die(die, &version, &offset_size);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: dwarf_get_version_of_die: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
goto dealloc_out;
|
|
}
|
|
|
|
rc = dwarf_loclist_from_expr_c(dbg, x, tempud, address_size, offset_size, version,
|
|
&loclist_head, &lcount, perr);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: dwarf_loclist_from_expr_c: %s\n",
|
|
__func__, dwarf_errmsg(*perr));
|
|
goto dealloc_out;
|
|
}
|
|
|
|
if (lcount != 1) {
|
|
fprintf(stderr,
|
|
"%s: unsupported addr expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
rc = DW_DLV_ERROR;
|
|
goto dealloc_out;
|
|
}
|
|
|
|
lres = dwarf_get_locdesc_entry_d(loclist_head, 0, 0, 0, 0, 0, 0, 0, 0, &locdesc_entry, 0, 0, 0, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"%s: unsupported addr expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
rc = DW_DLV_ERROR;
|
|
goto dealloc_out;
|
|
}
|
|
|
|
lres = dwarf_get_location_op_value_d(locdesc_entry, 0, &op, &opd1, &opd2, &opd3, NULL, NULL, NULL, &offsetforbranch, perr);
|
|
if (lres != DW_DLV_OK) {
|
|
fprintf(stderr,
|
|
"%s: unsupported addr expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
rc = DW_DLV_ERROR;
|
|
goto dealloc_out;
|
|
}
|
|
|
|
if (op != DW_OP_addr) {
|
|
fprintf(stderr,
|
|
"%s: unsupported addr expression\n",
|
|
__func__);
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
rc = DW_DLV_ERROR;
|
|
goto dealloc_out;
|
|
}
|
|
addr = opd1;
|
|
dwarf_loc_head_c_dealloc(loclist_head);
|
|
}
|
|
else {
|
|
fprintf(stderr, "%s: unsupported form type?\n",
|
|
__func__);
|
|
goto dealloc_out;
|
|
}
|
|
|
|
*paddr = (unsigned long)addr;
|
|
if (debug) {
|
|
printf("%s: addr: 0x%lx\n", __func__, (unsigned long)addr);
|
|
}
|
|
|
|
found = 1;
|
|
break;
|
|
}
|
|
|
|
dealloc_out:
|
|
for (i = 0; i < atcnt; i++) {
|
|
dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR);
|
|
}
|
|
|
|
dwarf_dealloc(dbg, atlist, DW_DLA_LIST);
|
|
|
|
if (found) {
|
|
rc = DW_DLV_OK;
|
|
}
|
|
else {
|
|
rc = DW_DLV_NO_ENTRY;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
struct dwarf_global_var_addr_arg {
|
|
char *variable;
|
|
unsigned long *addrp;
|
|
};
|
|
|
|
int dwarf_global_var_addr(Dwarf_Debug dbg, Dwarf_Die die, void *arg)
|
|
{
|
|
struct dwarf_global_var_addr_arg *gva =
|
|
(struct dwarf_global_var_addr_arg *)arg;
|
|
Dwarf_Half tag;
|
|
Dwarf_Error err;
|
|
char *name = NULL;
|
|
unsigned long addr;
|
|
int rc;
|
|
|
|
rc = dwarf_tag(die, &tag, &err);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: dwarf_tag: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
rc = dwarf_diename(die, &name, &err);
|
|
if (rc == DW_DLV_NO_ENTRY) {
|
|
name = NULL;
|
|
}
|
|
else if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: dwarf_diename: %d %s\n",
|
|
__func__, rc, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
if (tag != DW_TAG_variable || !name ||
|
|
strcasecmp(name, gva->variable)) {
|
|
rc = DW_DLV_NO_ENTRY;
|
|
goto out;
|
|
}
|
|
|
|
printf("%s: inspecting %s\n", __func__, name);
|
|
|
|
rc = dwarf_get_address(dbg, die, &addr, &err);
|
|
if (rc == DW_DLV_NO_ENTRY) {
|
|
printf("%s: inspecting %s -> DW_DLV_NO_ENTRY for addr?\n", __func__, name);
|
|
goto out;
|
|
}
|
|
else if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "%s: error: getting dwarf addr location: %s\n",
|
|
__func__, dwarf_errmsg(err));
|
|
goto out;
|
|
}
|
|
|
|
if (debug) {
|
|
fprintf(stdout, "%s: found %s @ 0x%lx\n", __func__, name, addr);
|
|
}
|
|
|
|
*gva->addrp = addr;
|
|
rc = DW_DLV_OK;
|
|
|
|
out:
|
|
if (name)
|
|
dwarf_dealloc(dbg, name, DW_DLA_STRING);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
#define DWARF_GET_VARIABLE_ADDRESS(__variable__) \
|
|
({ \
|
|
unsigned long addr; \
|
|
int rc; \
|
|
struct dwarf_global_var_addr_arg gva = { \
|
|
.variable = #__variable__, \
|
|
.addrp = &addr, \
|
|
}; \
|
|
addr = lookup_bfd_symbol(gva.variable); \
|
|
if (addr == NOSYMBOL) { \
|
|
rc = dwarf_walk_tree(dbg, dwarf_global_var_addr, &gva); \
|
|
if (rc != DW_DLV_OK) { \
|
|
fprintf(stderr, "%s: error: finding addr of %s\n", \
|
|
__func__, gva.variable); \
|
|
exit(1); \
|
|
} \
|
|
} \
|
|
addr; \
|
|
})
|
|
|
|
|
|
/* IHK kernel inspection I/F */
|
|
#define IHK_OS_READ_KADDR 0x112a39
|
|
|
|
#define IHK_OS_READ_KADDR_VIRT 0
|
|
#define IHK_OS_READ_KADDR_PHYS 1
|
|
struct ihk_os_read_kaddr_desc {
|
|
unsigned long kaddr;
|
|
unsigned long len;
|
|
void *ubuf;
|
|
int flags;
|
|
};
|
|
|
|
|
|
void ihk_read_kernel(unsigned long addr,
|
|
unsigned long len, void *buf, int flags)
|
|
{
|
|
struct ihk_os_read_kaddr_desc desc;
|
|
|
|
desc.kaddr = addr;
|
|
desc.len = len;
|
|
desc.ubuf = buf;
|
|
desc.flags = flags;
|
|
|
|
if (ioctl(mcfd, IHK_OS_READ_KADDR, &desc) != 0) {
|
|
fprintf(stderr, "%s: error: accessing kernel addr 0x%lx\n",
|
|
__func__, addr);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
#define ihk_read_val(addr, pval) \
|
|
ihk_read_kernel(addr, sizeof(*pval), (void *)pval, \
|
|
IHK_OS_READ_KADDR_VIRT)
|
|
|
|
#define ihk_read_val_phys(addr, pval) \
|
|
ihk_read_kernel(addr, sizeof(*pval), (void *)pval, \
|
|
IHK_OS_READ_KADDR_PHYS)
|
|
|
|
#define get_pointer_symbol_val(__variable__, pval) \
|
|
({ \
|
|
unsigned long addr; \
|
|
addr = DWARF_GET_VARIABLE_ADDRESS(__variable__); \
|
|
ihk_read_kernel(addr, sizeof(*pval), (void *)pval, \
|
|
IHK_OS_READ_KADDR_VIRT); \
|
|
})
|
|
|
|
|
|
#define PS_RUNNING 0x1
|
|
#define PS_INTERRUPTIBLE 0x2
|
|
#define PS_UNINTERRUPTIBLE 0x4
|
|
#define PS_ZOMBIE 0x8
|
|
#define PS_EXITED 0x10
|
|
#define PS_STOPPED 0x20
|
|
|
|
/*
|
|
* Globals
|
|
*/
|
|
int nr_cpus;
|
|
unsigned long clv;
|
|
unsigned long clv_size;
|
|
unsigned long clv_runq_offset;
|
|
unsigned long clv_idle_offset;
|
|
unsigned long clv_current_offset;
|
|
unsigned long thread_tid_offset;
|
|
unsigned long thread_sched_list_offset;
|
|
unsigned long thread_proc_offset;
|
|
unsigned long thread_status_offset;
|
|
unsigned long process_pid_offset;
|
|
unsigned long process_vm_offset;
|
|
unsigned long process_saved_cmdline_offset;
|
|
unsigned long process_saved_cmdline_len_offset;
|
|
unsigned long vm_address_space_offset;
|
|
unsigned long address_space_page_table_offset;
|
|
|
|
void init_globals(Dwarf_Debug dbg)
|
|
{
|
|
unsigned long num_processors_addr;
|
|
|
|
num_processors_addr = DWARF_GET_VARIABLE_ADDRESS(mck_num_processors);
|
|
ihk_read_val(num_processors_addr, &num_processors_addr);
|
|
ihk_read_val(num_processors_addr, &nr_cpus);
|
|
ihk_read_val(DWARF_GET_VARIABLE_ADDRESS(clv), &clv);
|
|
clv_size = DWARF_GET_SIZE(cpu_local_var);
|
|
|
|
clv_runq_offset = DWARF_GET_OFFSET_IN_STRUCT(cpu_local_var, runq);
|
|
clv_idle_offset = DWARF_GET_OFFSET_IN_STRUCT(cpu_local_var, idle);
|
|
clv_current_offset = DWARF_GET_OFFSET_IN_STRUCT(cpu_local_var, current);
|
|
thread_tid_offset = DWARF_GET_OFFSET_IN_STRUCT(thread, tid);
|
|
thread_proc_offset = DWARF_GET_OFFSET_IN_STRUCT(thread, proc);
|
|
thread_status_offset = DWARF_GET_OFFSET_IN_STRUCT(thread, status);
|
|
thread_sched_list_offset =
|
|
DWARF_GET_OFFSET_IN_STRUCT(thread, sched_list);
|
|
process_pid_offset = DWARF_GET_OFFSET_IN_STRUCT(process, pid);
|
|
process_saved_cmdline_offset =
|
|
DWARF_GET_OFFSET_IN_STRUCT(process, saved_cmdline);
|
|
process_saved_cmdline_len_offset =
|
|
DWARF_GET_OFFSET_IN_STRUCT(process, saved_cmdline_len);
|
|
process_vm_offset =
|
|
DWARF_GET_OFFSET_IN_STRUCT(process, vm);
|
|
vm_address_space_offset =
|
|
DWARF_GET_OFFSET_IN_STRUCT(process_vm, address_space);
|
|
address_space_page_table_offset =
|
|
DWARF_GET_OFFSET_IN_STRUCT(address_space, page_table);
|
|
}
|
|
|
|
void print_thread(int cpu,
|
|
unsigned long thread,
|
|
unsigned long idle,
|
|
int active)
|
|
{
|
|
int tid;
|
|
int pid;
|
|
int status;
|
|
unsigned long proc;
|
|
char *comm = "(unknown)";
|
|
char *cmd_line = NULL;
|
|
long cmd_line_len;
|
|
long cmd_line_addr;
|
|
|
|
ihk_read_val(thread + thread_tid_offset, &tid);
|
|
ihk_read_val(thread + thread_proc_offset, &proc);
|
|
ihk_read_val(thread + thread_status_offset, &status);
|
|
ihk_read_val(proc + process_pid_offset, &pid);
|
|
ihk_read_val(proc + process_saved_cmdline_len_offset,
|
|
&cmd_line_len);
|
|
|
|
if (thread == idle) {
|
|
comm = "(idle)";
|
|
}
|
|
|
|
if (cmd_line_len) {
|
|
cmd_line = malloc(cmd_line_len + 1);
|
|
if (!cmd_line) {
|
|
fprintf(stderr, "%s: error: allocating cmdline\n",
|
|
__func__);
|
|
exit(1);
|
|
}
|
|
memset(cmd_line, 0, cmd_line_len + 1);
|
|
|
|
ihk_read_val(proc + process_saved_cmdline_offset, &cmd_line_addr);
|
|
ihk_read_kernel(cmd_line_addr, cmd_line_len, cmd_line,
|
|
IHK_OS_READ_KADDR_VIRT);
|
|
comm = basename(cmd_line);
|
|
}
|
|
|
|
printf("%3d %s%6d %6d 0x%16lx %2s %s\n",
|
|
cpu, active ? ">" : " ", tid, pid, thread,
|
|
//"DS",
|
|
status == PS_RUNNING ? "R" :
|
|
status == PS_INTERRUPTIBLE ? "IN" :
|
|
status == PS_UNINTERRUPTIBLE ? "UN" :
|
|
status == PS_ZOMBIE ? "Z" :
|
|
status == PS_EXITED ? "E" :
|
|
status == PS_STOPPED ? "S" : "U",
|
|
comm);
|
|
|
|
if (cmd_line)
|
|
free(cmd_line);
|
|
}
|
|
|
|
int mcps(Dwarf_Debug dbg)
|
|
{
|
|
int cpu;
|
|
|
|
printf("%3s %s%6s %6s %18s %2s %s\n",
|
|
"CPU", " ", "TID", "PID", "Thread", "ST", "exe");
|
|
printf("-----------------------------------------------\n");
|
|
|
|
/* Iterate CPUs */
|
|
for (cpu = 0; cpu < nr_cpus; ++cpu) {
|
|
unsigned long per_cpu;
|
|
unsigned long runq;
|
|
unsigned long thread;
|
|
unsigned long thread_sched_list;
|
|
unsigned long idle;
|
|
unsigned long current;
|
|
|
|
per_cpu = clv + (clv_size * cpu);
|
|
runq = per_cpu + clv_runq_offset;
|
|
idle = per_cpu + clv_idle_offset;
|
|
ihk_read_val(per_cpu + clv_current_offset, ¤t);
|
|
ihk_read_val(per_cpu + clv_runq_offset, &thread_sched_list);
|
|
|
|
print_thread(cpu, current, idle, 1);
|
|
|
|
/* Iterate threads */
|
|
for (; thread_sched_list != runq;
|
|
ihk_read_val(thread_sched_list, &thread_sched_list)) {
|
|
thread = thread_sched_list - thread_sched_list_offset;
|
|
|
|
if (thread == current)
|
|
continue;
|
|
|
|
print_thread(cpu, thread, idle, 0);
|
|
}
|
|
|
|
if (current != idle) {
|
|
print_thread(cpu, idle, idle, 0);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int find_proc(Dwarf_Debug dbg, int pid, unsigned long *rproc)
|
|
{
|
|
int cpu;
|
|
|
|
/* Iterate CPUs */
|
|
for (cpu = 0; cpu < nr_cpus; ++cpu) {
|
|
unsigned long per_cpu;
|
|
unsigned long runq;
|
|
unsigned long thread;
|
|
unsigned long thread_sched_list;
|
|
int ipid;
|
|
|
|
per_cpu = clv + (clv_size * cpu);
|
|
runq = per_cpu + clv_runq_offset;
|
|
ihk_read_val(per_cpu + clv_runq_offset, &thread_sched_list);
|
|
|
|
/* Iterate threads */
|
|
for (; thread_sched_list != runq;
|
|
ihk_read_val(thread_sched_list, &thread_sched_list)) {
|
|
unsigned long proc;
|
|
|
|
thread = thread_sched_list - thread_sched_list_offset;
|
|
|
|
ihk_read_val(thread + thread_proc_offset, &proc);
|
|
ihk_read_val(proc + process_pid_offset, &ipid);
|
|
|
|
if (pid == ipid) {
|
|
*rproc = proc;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
#if 0
|
|
void do_pte_walk_single(Dwarf_Debug dbg,
|
|
unsigned long pt, int level, unsigned long va)
|
|
{
|
|
unsigned long pte;
|
|
int idx = va >> ptl_shift(level);
|
|
|
|
ihk_read_val(pt + idx * sizeof(pte), &pte);
|
|
if (pte_is_type_page(pte, level)) {
|
|
|
|
}
|
|
|
|
if (level > 1) {
|
|
pt =
|
|
do_pte_walk_single();
|
|
}
|
|
}
|
|
|
|
|
|
int print_pte_single(Dwarf_Debug dbg,
|
|
unsigned long pt, unsigned long va)
|
|
{
|
|
int level = PGTABLE_LEVELS;
|
|
printf("VA: 0x%lx -> \n", va);
|
|
do_pte_walk_single(dbg, pt, PGTABLE_LEVELS, va);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
int mcvtop(Dwarf_Debug dbg, int pid, unsigned long vtop_addr)
|
|
{
|
|
unsigned long proc = 0;
|
|
unsigned long init_pt;
|
|
unsigned long vm, ap, pt = 0;
|
|
|
|
if (pid != 0) {
|
|
if (find_proc(dbg, pid, &proc) < 0) {
|
|
fprintf(stderr, "%s: error: finding PID %d\n",
|
|
__func__, pid);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
get_pointer_symbol_val(swapper_page_table, &init_pt);
|
|
printf("%s: init_pt: 0x%lx\n", __func__, init_pt);
|
|
|
|
if (proc) {
|
|
ihk_read_val(proc + process_vm_offset, &vm);
|
|
ihk_read_val(vm + vm_address_space_offset, &ap);
|
|
ihk_read_val(ap + address_space_page_table_offset, &pt);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int help;
|
|
int ps;
|
|
int vtop;
|
|
int pid;
|
|
unsigned long vtop_addr;
|
|
|
|
struct option mcinspect_options[] = {
|
|
{
|
|
.name = "kernel",
|
|
.has_arg = required_argument,
|
|
.flag = NULL,
|
|
.val = 'k',
|
|
},
|
|
{
|
|
.name = "ps",
|
|
.has_arg = no_argument,
|
|
.flag = &ps,
|
|
.val = 1,
|
|
},
|
|
{
|
|
.name = "help",
|
|
.has_arg = no_argument,
|
|
.flag = &help,
|
|
.val = 1,
|
|
},
|
|
{
|
|
.name = "debug",
|
|
.has_arg = no_argument,
|
|
.flag = &debug,
|
|
.val = 1,
|
|
},
|
|
{
|
|
.name = "vtop",
|
|
.has_arg = no_argument,
|
|
.flag = &vtop,
|
|
.val = 1,
|
|
},
|
|
{
|
|
.name = "va",
|
|
.has_arg = required_argument,
|
|
.flag = NULL,
|
|
.val = 'v',
|
|
},
|
|
{
|
|
.name = "pid",
|
|
.has_arg = required_argument,
|
|
.flag = NULL,
|
|
.val = 'p',
|
|
},
|
|
/* end */
|
|
{ NULL, 0, NULL, 0, },
|
|
};
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
Dwarf_Debug dbg = 0;
|
|
int dwarffd = -1;
|
|
int rc = DW_DLV_ERROR;
|
|
char *kernel_path = NULL;
|
|
Dwarf_Error error;
|
|
Dwarf_Handler errhand = 0;
|
|
Dwarf_Ptr errarg = 0;
|
|
int opt;
|
|
|
|
debug = 0;
|
|
mcfd = -1;
|
|
help = 0;
|
|
ps = 0;
|
|
vtop = 0;
|
|
vtop_addr = -1UL;
|
|
pid = 0;
|
|
|
|
while ((opt = getopt_long(argc, argv, "+k:v:p:",
|
|
mcinspect_options, NULL)) != -1) {
|
|
switch (opt) {
|
|
case 'k':
|
|
kernel_path = optarg;
|
|
break;
|
|
|
|
case 'v':
|
|
vtop_addr = strtoul(optarg, 0, 16);
|
|
if (vtop_addr == 0 ||
|
|
errno == EINVAL || errno == ERANGE) {
|
|
fprintf(stderr, "error: invalid VA? (expected format: 0xXXXX)\n\n");
|
|
usage(argv);
|
|
exit(1);
|
|
}
|
|
break;
|
|
|
|
case 'p':
|
|
pid = atoi(optarg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (help) {
|
|
usage(argv);
|
|
exit(0);
|
|
}
|
|
|
|
if (!kernel_path) {
|
|
fprintf(stderr, "error: you must specify the kernel image\n\n");
|
|
usage(argv);
|
|
exit(1);
|
|
}
|
|
|
|
if (!ps && !vtop) {
|
|
printf("PID: %d\n", pid);
|
|
usage(argv);
|
|
exit(1);
|
|
}
|
|
|
|
if (init_bfd_symbols(kernel_path) < 0) {
|
|
fprintf(stderr, "error: accessing ELF image %s\n", kernel_path);
|
|
exit(1);
|
|
}
|
|
|
|
mcfd = open("/dev/mcos0", O_RDONLY);
|
|
if (mcfd < 0) {
|
|
fprintf(stderr, "error: opening IHK OS device file\n");
|
|
exit(1);
|
|
}
|
|
|
|
dwarffd = open(kernel_path, O_RDONLY);
|
|
if (dwarffd < 0) {
|
|
fprintf(stderr, "error: opening %s\n", kernel_path);
|
|
exit(1);
|
|
}
|
|
|
|
rc = dwarf_init_b(dwarffd, DW_DLA_WEAK, errhand, errarg, &dbg, &error);
|
|
if (rc != DW_DLV_OK) {
|
|
fprintf(stderr, "error: accessing DWARF information\n");
|
|
exit(1);
|
|
}
|
|
|
|
init_globals(dbg);
|
|
|
|
if (ps)
|
|
mcps(dbg);
|
|
|
|
if (vtop) {
|
|
mcvtop(dbg, pid, vtop_addr);
|
|
}
|
|
|
|
dwarf_finish(dbg);
|
|
close(dwarffd);
|
|
close(mcfd);
|
|
return 0;
|
|
}
|
|
|
|
|