1
0
Files
2022-09-29 17:59:04 +03:00

632 lines
14 KiB
C

#ident "$Header: /proj/irix6.5.7m/isms/irix/cmd/icrash_old/lib/libutil/RCS/report.c,v 1.1 1999/05/25 19:19:20 tjm Exp $"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/stat.h>
#include <setjmp.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <sys/dump.h>
#include "icrash.h"
#include "extern.h"
/*
* punderline() -- Draw an underline under a buffer.
*/
void
punderline(char *buf, FILE *ofp)
{
int i;
for (i = 0; i < strlen(buf); i++) {
fprintf(ofp, "=");
}
fprintf(ofp, "\n");
}
/*
* prline() -- Outline a string.
*/
void
prline(char *buf, FILE *ofp)
{
punderline(buf, ofp);
fprintf(ofp, "%s\n", buf);
punderline(buf, ofp);
}
/*
* get_putbuf() -- Get the putbuf into a temporary buffer.
*/
char *
get_putbuf()
{
int i, j;
char *np, *pbuf;
if (K_DUMP_HDR(K)->dmp_version > 2) {
np = (char *)alloc_block(K_DUMP_HDR(K)->dmp_putbuf_size+500, B_TEMP);
pbuf = (char *)alloc_block(K_DUMP_HDR(K)->dmp_putbuf_size+1, B_TEMP);
if (LSEEK(K, K_CORE_FD(K), K_DUMP_HDR(K)->dmp_hdr_sz, SEEK_SET) < 0) {
return ((char *)NULL);
}
read(K_CORE_FD(K), (void *)pbuf, K_DUMP_HDR(K)->dmp_putbuf_size);
for (i = 0, j = 0; i < K_DUMP_HDR(K)->dmp_putbuf_size; i++) {
if (pbuf[i] == '\0') {
/* skip all the NULLs */
}
else {
np[j++] = pbuf[i];
}
}
} else {
np = (char *)alloc_block(1500, B_TEMP);
pbuf = (char *)alloc_block(1001, B_TEMP);
kl_get_block(K, K_PUTBUF(K), 1000, pbuf, "putbuf");
for (i = 0, j = 0; i < 1000; i++) {
if (pbuf[i] == '\0') {
/* skip all the NULLs */
}
else {
np[j++] = pbuf[i];
}
}
}
np[j] = '\0';
free_block((k_ptr_t)pbuf);
return(np);
}
/*
* get_putbuf_eframe() --
*
* Grab the EP address from the putbuf, if it exists. Otherwise,
* return 0 (not -1).
*/
kaddr_t
get_putbuf_eframe()
{
int j = 0;
kaddr_t value;
char *np, *ptr, addrbuf[20];
np = get_putbuf();
if (ptr = strstr(np, "ep: 0x")) {
ptr += 6;
while ((((*ptr >= '0') && (*ptr <= '9')) ||
((*ptr >= 'a') && (*ptr <= 'f'))) && (j < 20)) {
addrbuf[j++] = *ptr++;
}
free_block((k_ptr_t)np);
GET_VALUE(addrbuf, &value);
return(value);
}
free_block((k_ptr_t)np);
return(0);
}
/*
* get_putbuf_pc() --
*
* Grab the PC address from the putbuf, if it exists. Otherwise,
* return 0 (not -1).
*/
kaddr_t
get_putbuf_pc()
{
int j = 0;
kaddr_t value;
char *np, *ptr, addrbuf[20];
np = get_putbuf();
if (ptr = strstr(np, "PC: 0x")) {
ptr += 4;
addrbuf[0] = 0;
strcat(addrbuf, "0x");
ptr += 2;
j = 2;
while ((((*ptr >= '0') && (*ptr <= '9')) ||
((*ptr >= 'a') && (*ptr <= 'f'))) && (j < 20)) {
addrbuf[j++] = *ptr++;
}
addrbuf[j] = 0;
free_block((k_ptr_t)np);
GET_VALUE(addrbuf, &value);
return(value);
}
free_block((k_ptr_t)np);
return(0);
}
/*
* get_putbuf_cpu() --
*
* Get the CPU that crashed from the putbuf, if it exists.
* Otherwise, return -1.
*/
int
get_putbuf_cpu()
{
int i, j = 0;
char *np, *ptr;
np = get_putbuf();
if (ptr = strstr(np, "PANIC: CPU ")) {
ptr += 11;
sscanf(ptr, "%d", &i);
free_block((k_ptr_t)np);
if ((i < 0) || (i >= K_MAXCPUS(K))) {
return(-1);
}
else {
return(i);
}
}
free_block((k_ptr_t)np);
return(-1);
}
/*
* get_putbuf_nmi() -- Get the NMI string from the putbuf, if
* it exists. Otherwise, return -1.
*/
int
get_putbuf_nmi()
{
int i, j = 0;
char *np, *ptr;
np = get_putbuf();
if (ptr = strstr(np, "NMI")) {
free_block((k_ptr_t)np);
return(1);
}
free_block((k_ptr_t)np);
return(-1);
}
/*
* print_repkthread_info() -- Print out report kthread information.
*/
void
print_repkthread_info(kaddr_t curkthread, k_ptr_t ktp, int i, FILE *ofp)
{
k_ptr_t cp, kt_name;
cp = alloc_block(CRED_SIZE(K), B_TEMP);
if (!curkthread) {
fprintf(ofp, " CPU %d did not have a kthread running.\n", i);
}
#ifdef ANON_ITHREADS
else if (IS_ITHREAD(K, ktp)) {
if (kt_name = kl_kthread_name(K, ktp)) {
fprintf(ofp, " The ithread '%s' was running.\n", kt_name);
}
else {
fprintf(ofp, " An ithread was running.\n");
}
}
#endif
else if (IS_STHREAD(K, ktp)) {
if (kt_name = kl_kthread_name(K, ktp)) {
fprintf(ofp, " The sthread '%s' was running.\n", kt_name);
}
else {
fprintf(ofp, " An sthread was running.\n");
}
}
else if (IS_UTHREAD(K, ktp)) {
fprintf(ofp, " The command '%s' was running.", kl_kthread_name(K, ktp));
if (kl_get_struct(K, kl_kaddr(K, ktp, "proc", "p_cred"),
CRED_SIZE(K), cp, "cred")) {
fprintf(ofp, " under UID %lld\n", KL_INT(K, cp, "cred", "cr_ruid"));
}
else {
fprintf(ofp, "\n");
}
}
free_block(cp);
}
/*
* get_report_pda() -- Get PDA information for a process.
*/
k_ptr_t
get_report_pda(int i, int *stkflg, kaddr_t *curkthread)
{
k_ptr_t pdap;
kaddr_t pdaval;
*stkflg = 0;
*curkthread = 0;
pdap = alloc_block(PDA_S_SIZE(K), B_TEMP);
pdaval = kl_get_pda_s(K, (kaddr_t)i, pdap);
if (KL_ERROR) {
free_block(pdap);
return((k_ptr_t)NULL);
}
else {
*stkflg = kl_uint(K, pdap, "pda_s", "p_kstackflag", 0);
*curkthread = kl_kaddr(K, pdap, "pda_s", "p_curkthread");
}
return(pdap);
}
/*
* get_report_kthread()
*/
k_ptr_t
get_report_kthread(kaddr_t curkthread)
{
if (!curkthread) {
return((k_ptr_t)NULL);
}
return(kl_get_kthread(K, curkthread, 0));
}
/*
* free_report_fields() --
*
* Free the appropriate fields assigned to each pointer (if any).
*/
void
free_report_fields(k_ptr_t pdap, k_ptr_t kthreadp)
{
if (pdap) {
free_block(pdap);
}
if (kthreadp) {
free_block(kthreadp);
}
}
/*
* print_cpudata() -- Print out information specific to each CPU
*
* This gives the caller a summary report of what was going on for
* each CPU when the panic/NMI occurred.
*/
void
print_cpudata(FILE *ofp)
{
int i;
for (i = 0; i < K_MAXCPUS(K); i++) {
print_cpu_status(i, ofp);
}
}
/*
* regular_report() -- Report CPU information on an regular dump.
*/
void
regular_report(command_t cb, FILE *ofp)
{
char buf[128];
int i, stkflg, cpunum, first_run = TRUE;
k_ptr_t pdap, ktp;
kaddr_t eaddr, pc, curkthread;
/* Grab the eframe data (if any). We call out to a function
* for now, because we don't have this information stored
* anywhere, except in the putbuf (which means we have to scan
* it out by hand!
*/
fprintf(cb.ofp, "STACK TRACE:\n\n");
get_cmd(&cb, "trace");
checkrun_cmd(cb, ofp);
fprintf(cb.ofp, "\n");
if (pc = get_putbuf_pc()) {
fprintf(cb.ofp, "INSTRUCTIONS AT EXCEPTION:\n\n");
sprintf(buf, "dis -f 0x%llx-32 8", pc);
get_cmd(&cb, buf);
checkrun_cmd(cb, ofp);
sprintf(buf, "dis -f 0x%llx", pc);
get_cmd(&cb, buf);
checkrun_cmd(cb, ofp);
sprintf(buf, "dis -f 0x%llx+4 8", pc);
get_cmd(&cb, buf);
checkrun_cmd(cb, ofp);
fprintf(cb.ofp, "\n");
}
for (i = 0; i < K_MAXCPUS(K); i++) {
pdap = get_report_pda(i, &stkflg, &curkthread);
ktp = get_report_kthread(curkthread);
if (pdap) {
sprintf(buf, "CRASH SUMMARY FOR CPU %d", i);
prline(buf, cb.ofp);
fprintf(cb.ofp, "\n");
if (KL_ERROR) {
kl_print_error(K);
}
else {
print_repkthread_info(curkthread, ktp, i, cb.ofp);
cpu_trace((cpuid_t)i, cb.flags, cb.ofp);
}
fprintf(cb.ofp, "\n");
}
free_report_fields(pdap, ktp);
}
}
/*
* nmi_report() -- Report CPU information on an NMI dump.
*/
void
nmi_report(command_t cb, FILE *ofp)
{
int i, stkflg;
char buf[128];
k_ptr_t pdap = 0, kthreadp = 0;
kaddr_t spage, epc, sp, errorepc, ra, curkthread, hold_defkthread;
hold_defkthread = K_DEFKTHREAD(K);
for (i = 0; i < K_MAXCPUS(K); i++) {
pdap = get_report_pda(i, &stkflg, &curkthread);
if (KL_ERROR) {
if (KL_ERROR != KLE_NO_CPU) {
kl_print_error(K);
}
continue;
}
sprintf(buf, "NMI SUMMARY FOR CPU %d", i);
prline(buf, cb.ofp);
fprintf(cb.ofp, "\n");
if (IS_NMI(K)) {
kl_NMI_saveregs(K, i, &errorepc, &epc, &sp, &ra);
fprintf(cb.ofp, "REGISTERS FOR CPU %d:\n\n"
" ERREPC: 0x%llx\n"
" SP: 0x%llx\n"
" RA: 0x%llx\n\n", i, errorepc, sp, ra);
}
if (pdap) {
fprintf(cb.ofp, "LTICKS FOR CPU %d: %lld\n\n",
i, KL_INT(K, pdap, "pda_s", "p_lticks"));
}
fprintf(cb.ofp, "STACK TRACE FOR CPU %d:\n\n", i);
if (curkthread) {
kthreadp = get_report_kthread(curkthread);
if (KL_ERROR) {
fprintf(ofp, "NOTICE: ");
kl_print_error(K);
}
else if (stkflg == 0) {
fprintf(cb.ofp,
" No stack trace. CPU %d was running in user mode.\n", i);
continue;
}
else {
K_DEFKTHREAD(K) = curkthread;
print_repkthread_info(curkthread, kthreadp, i, cb.ofp);
}
fprintf(cb.ofp, "\n");
}
if (cpu_trace(i, C_SUPRSERR, cb.ofp)) {
fprintf(cb.ofp, " Could not find a valid stack trace for "
"CPU %d\n", i);
}
fprintf(cb.ofp, "\n");
/* Next, print out the disassembly information. Note that this is
* based on the ErrorEPC register value, not the EPC.
*/
fprintf(cb.ofp, "INSTRUCTIONS NEAR PC IN NMI FOR CPU %d:\n\n", i);
if (stkflg == 0) {
fprintf(cb.ofp,
" CPU %d was running in user mode and does not "
"have a PC to disassemble.\n", i);
}
else if (!errorepc) {
fprintf(cb.ofp,
" No valid ERROR_EPC found in NMI registers.\n");
}
else {
sprintf(buf, "dis -f %llx-32 8", errorepc);
get_cmd(&cb, buf);
checkrun_cmd(cb, ofp);
sprintf(buf, "dis -f %llx", errorepc);
get_cmd(&cb, buf);
checkrun_cmd(cb, ofp);
sprintf(buf, "dis -f %llx+4 8", errorepc);
get_cmd(&cb, buf);
checkrun_cmd(cb, ofp);
}
fprintf(cb.ofp, "\n");
free_report_fields(pdap, kthreadp);
kthreadp = (k_ptr_t)NULL;
}
K_DEFKTHREAD(K) = hold_defkthread;
fprintf(cb.ofp, "\n");
prline("SLEEPING PROCESS STATES", cb.ofp);
fprintf(cb.ofp, "\n");
get_cmd(&cb, "slpproc");
checkrun_cmd(cb, ofp);
}
/*
* availmon_report() -- Availability information report.
*/
int
availmon_report()
{
FILE *afp, *tfp;
command_t cmd;
/* Don't dump a report if we don't request one!
*/
if ((!availmon) || (!availmonfile)) {
return(1);
}
/* Open up the availmon report file, dump the information
* requested, close up the file and return. In this particular
* case, we always obliterate any previous availmon report.
*/
if ((afp = fopen(availmonfile, "a")) == (FILE *)NULL) {
return(0);
}
fprintf(afp, " CRASH TIME: %d %s",
K_DUMP_HDR(K)->dmp_crash_time, ctime(&(K_DUMP_HDR(K)->dmp_crash_time)));
fprintf(afp, " PANIC STRING: %s\n", K_DUMP_HDR(K)->dmp_panic_str);
/* If we can't close the file for some reason, we probably are
* going to fail with the analysis report to. Don't bother, just
* exit out here.
*/
if (fclose(afp)) {
return(1);
}
return(0);
}
/*
* dump_header_report() --
*
* Create a dump header report when everything else fails. We do
* what uncompvm -h would do.
*/
int
dump_header_report(FILE *ofp)
{
command_t cb;
if (writeflag) {
cb.ofp = ofp;
}
else {
cb.ofp = stdout;
}
fprintf(cb.ofp,
"No dump data found. Printing dump header and exiting.\n\n");
expand_header(K_DUMP_HDR(K), cb.ofp);
if (writeflag) {
return (fclose(cb.ofp));
}
return(0);
}
/*
* base_report() -- The basic reporting information.
*/
void
base_report(command_t cb, char *p, FILE *ofp)
{
char *ptr;
time_t tloc;
struct stat st;
struct syment *SBE;
/* Give out general icrash information.
*/
fprintf(cb.ofp, "\n");
prline("ICRASH CORE FILE REPORT", cb.ofp);
fprintf(cb.ofp, "\nSYSTEM:\n");
print_utsname(cb.ofp);
tloc = time((time_t *)0);
fprintf(cb.ofp, "\nGENERATED ON:\n %s", ctime(&tloc));
fprintf(cb.ofp, "\nTIME OF CRASH:\n %d %s",
K_DUMP_HDR(K)->dmp_crash_time, ctime(&(K_DUMP_HDR(K)->dmp_crash_time)));
fprintf(cb.ofp, "\nPANIC STRING:\n %s\n", K_DUMP_HDR(K)->dmp_panic_str);
if (stat(namelist, &st) < 0) {
fprintf(cb.ofp, "\nNAMELIST:\n %s\n\n", namelist);
}
else {
ptr = ctime(&(st.st_ctime));
ptr[strlen(ptr)-1] = '\0';
fprintf(cb.ofp, "\nNAMELIST:\n %s [CREATE TIME: %s]\n\n",
namelist, ptr);
}
if (stat(corefile, &st) < 0) {
fprintf(cb.ofp, "COREFILE:\n %s\n", corefile);
}
else {
ptr = ctime(&(st.st_ctime));
ptr[strlen(ptr)-1] = '\0';
fprintf(cb.ofp, "COREFILE:\n %s [CREATE TIME: %s]\n\n",
corefile, ptr);
}
/* Dump out any summary report we can give on the dump.
*/
prline("COREFILE SUMMARY", cb.ofp);
if (IS_NMI(K) && (get_putbuf_nmi() > 0)) {
fprintf(cb.ofp, "\n The system was brought down ");
fprintf(cb.ofp, "in response to a user initiated NMI.\n\n");
}
else if (ACTIVE(K)) {
fprintf(cb.ofp, "\n The system is currently active.\n\n");
}
else {
fprintf(cb.ofp, "\n The system was brought down ");
fprintf(cb.ofp, "due to an internal panic.\n\n");
}
/* General putbuf data.
*/
prline("PUTBUF DUMP", cb.ofp);
print_putbuf(cb.ofp);
if (K_ERROR_DUMPBUF(K)) {
fprintf(cb.ofp, "\n\nERROR DUMPBUF (HARDWARE ERROR STATE):\n\n");
fprintf(cb.ofp, "0x%llx = \"", K_ERROR_DUMPBUF(K));
dump_string(K_ERROR_DUMPBUF(K), cb.flags, cb.ofp);
fprintf(cb.ofp, "\"");
}
fprintf(cb.ofp, "\n\n");
/* Single bit error information, if available.
*/
if ((K_IP(K) == 19) || (K_IP(K) == 21) || (K_IP(K) == 25)) {
SBE = get_sym("sbe_log_errors", B_TEMP);
if (!KL_ERROR) {
if (SBE->n_value != 0) {
prline("SINGLE BIT ERROR LOGGING INFORMATION", cb.ofp);
get_cmd(&cb, "sbe");
checkrun_cmd(cb, ofp);
fprintf(cb.ofp, "\n");
}
free_sym(SBE);
}
}
/* Print out general CPU information.
*/
prline("CPU SUMMARY", cb.ofp);
fprintf(cb.ofp, "\n");
print_cpudata(cb.ofp);
fprintf(cb.ofp, "\n");
/* If we have an NMI, we perform some extra actions. For the most
* part, this will entail grabbing proc information, along with
* trying to get specific NMI trace data (if any).
*/
if (IS_NMI(K)) {
nmi_report(cb, ofp);
}
else {
regular_report(cb, ofp);
}
}