/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <procfs.h>
#include <msg.h>
#include <_elfdump.h>
#include <struct_layout.h>
#include <conv.h>
/*
* This module contains the code that displays data from the note
* sections found in Solaris core files. The format of these
* note sections are described in the core(4) manpage.
*/
/*
* Much of the code in this file uses the "%*s" format to set
* the left margin indentation. This macro combines the indent
* integer argument and the NULL string that follows it.
*/
/*
* Indent unit, used for each nesting
*/
/*
* The PRINT_ macros are convenience wrappers on print_num(),
* print_subtype(), and print_strbuf(). They reduce code
* clutter by hiding the boilerplate arguments.
*
* Assumptions:
* - A variable named "layout" exists in the compilation
* environment, referencing the layout information for the
* current type.
* - The variable "state" references the current note state.
*/
/*
* Structure used to maintain state data for a core note, or a subregion
* (sub-struct) of a core note. These values would otherwise need to be
* passed to nearly every routine.
*/
typedef struct {
} note_state_t;
/*
* Standard signature for a dump function used to process a note
* or a sub-structure within a note.
*/
/*
* Some core notes contain string buffers of fixed size
* that are expected to contain NULL terminated strings.
* If the NULL is there, we can print these strings directly.
* However, the potential exists for a corrupt file to have
* a non-terminated buffer. This routine examines the given
* string, and if the string is terminated, the string itself
* is returned. Otherwise, it is copied to a static buffer,
* and a pointer to the buffer is returned.
*/
static const char *
{
char *s;
size_t i;
if (n == 0)
return (MSG_ORIG(MSG_STR_EMPTY));
for (i = 0; i < n; i++)
if (str[i] == '\0')
return (str);
s = buf + i;
if (n >= sizeof (buf)) {
*s++ = '.';
*s++ = '.';
*s++ = '.';
}
*s = '\0';
return (buf);
}
/*
* Convenience wrappers on top of the corresponding sl_XXX() functions.
*/
static Word
{
}
static Lword
{
}
static int
{
}
static const char *
{
}
/*
* Return true of the data for the specified field is available.
*/
inline static int
{
}
/*
* indent_enter/exit are used to start/end output for a subitem.
* On entry, a title is output, and the indentation level is raised
* by one unit. On exit, the indentation level is restrored to its
* previous value.
*/
static void
const sl_field_t *first_fdesc)
{
/*
* If the first field offset and extent fall past the end of the
* available data, then return without printing a title. That note
* is from an older core file that doesn't have all the fields
* that we know about.
*/
}
static void
{
}
/*
* print_num outputs a field on one line, in the format:
*
* title: value
*/
static void
{
/*
* If the field offset and extent fall past the end of the
* available data, then return without doing anything. That note
* is from an older core file that doesn't have all the fields
* that we know about.
*/
return;
}
/*
* print_num_2up outputs two fields on one line, in the format:
*
* title1: value1 title2: value2
*/
static void
{
/*
* If the field offset and extent fall past the end of the
* available data, then return without doing anything. That note
* is from an older core file that doesn't have all the fields
* that we know about.
*/
return;
}
/*
* print_strbuf outputs a fixed sized character buffer field
* on one line, in the format:
*
* title: value
*/
static void
const sl_field_t *fdesc)
{
Word n;
/*
* If we are past the end of the data area, then return
* without doing anything. That note is from an older core
* file that doesn't have all the fields that we know about.
*
* Note that we are willing to accept a partial buffer,
* so we don't use data_present() for this test.
*/
return;
/*
* We expect the full buffer to be present, but if there
* is less than that, we will still proceed. The use of safe_str()
* protects us from the effect of printing garbage data.
*/
}
/*
* print_str outputs an arbitrary string value item
* on one line, in the format:
*
* title: str
*/
static void
{
}
/*
* Used when one dump function needs to call another dump function
* in order to display a subitem. This routine constructs a state
* block for the sub-region, and then calls the dump function with it.
* This limits the amount of data visible to the sub-function to that
* for the sub-item.
*/
static void
{
/*
* If there is no data for the sub-item, return immediately.
* Partial data is left to the dump function to handle,
* as that can be a sign of an older core file with less data,
* which can still be interpreted.
*/
return;
/*
* Construct a state block that reflects the sub-item
*/
}
/*
* Output a sequence of array elements, giving each
* element an index, in the format:
*
* [ndx] value
*
* entry:
* state - Current state
* base_desc - Field descriptor for 1st element of array
* nelts - # of array elements to display
* check_nelts - If True (1), nelts is clipped to fdesc->slf_nelts.
* If False (1), nelts is not clipped.
* title - Name of array
*/
static void
{
int i;
if (nelts == 0)
return;
for (i = 0; i < nelts; ) {
if (i == (nelts - 1)) {
/* One final value is left */
break;
i++;
continue;
}
/* There are at least 2 items left. Show 2 up. */
break;
i += 2;
}
}
/*
* Output information from auxv_t structure.
*/
static void
{
union {
} conv_buf;
/*
* Immediate indent_exit() restores the indent level to
* that of the title. We include indentation as part of
* the index string, which is right justified, and don't
* want the usual indentation spacing.
*/
ndx = 0;
Word w;
int type;
switch (type) {
case AT_NULL:
break;
ndx++;
}
break;
case AT_IGNORE:
case AT_SUN_IFLUSH:
break;
case AT_EXECFD:
case AT_PHENT:
case AT_PHNUM:
case AT_PAGESZ:
case AT_SUN_UID:
case AT_SUN_RUID:
case AT_SUN_GID:
case AT_SUN_RGID:
case AT_SUN_LPAGESZ:
break;
case AT_FLAGS: /* processor flags */
0, &conv_buf.ehdr_flags);
break;
case AT_SUN_HWCAP:
/*
* conv_cap_val_hw1() produces output like:
*
* 0xfff [ flg1 flg2 0xff]
*
* where the first hex value is the complete value,
* and the second is the leftover bits. We only
* want the part in brackets, and failing that,
* would rather fall back to formatting the full
* value ourselves.
*/
vstr++;
if (*vstr != '[')
break;
case AT_SUN_HWCAP2:
/*
* conv_cap_val_hw2() produces output like:
*
* 0xfff [ flg1 flg2 0xff]
*
* where the first hex value is the complete value,
* and the second is the leftover bits. We only
* want the part in brackets, and failing that,
* would rather fall back to formatting the full
* value ourselves.
*/
vstr++;
if (*vstr != '[')
break;
case AT_SUN_AUXFLAGS:
break;
}
else
ndx++;
}
}
/*
* Output information from fltset_t structure.
*/
static void
{
int i, nelts;
return;
for (i = 0; i < nelts; i++) {
}
}
/*
* Output information from sigset_t structure.
*/
static void
{
int i, nelts;
return;
for (i = 0; i < nelts; i++) {
}
}
/*
* Output information from sigaction structure.
*/
static void
{
Word w;
conv_cnote_sa_flags(w, 0, &conv_buf));
}
}
/*
* Output information from siginfo structure.
*/
static void
{
Word w;
return;
CONV_FMT_DECIMAL, &inv_buf));
return;
}
/* User generated signals have (si_code <= 0) */
if (v_si_code <= 0) {
switch (v_si_code) {
case SI_QUEUE:
case SI_TIMER:
case SI_ASYNCIO:
case SI_MESGQ:
&layout->f_si_value_int);
break;
}
return;
}
/*
* Remaining cases are kernel generated signals. Output any
* signal or code specific information.
*/
switch (v_si_signo) {
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
break;
case SIGCHLD:
break;
case SIGPOLL:
break;
}
}
/*
* Output information from stack_t structure.
*/
static void
{
Word w;
conv_cnote_ss_flags(w, 0, &conv_buf));
}
}
/*
* Output information from sysset_t structure.
*/
static void
{
int i, nelts;
return;
for (i = 0; i < nelts; i++) {
}
}
/*
* Output information from timestruc_t structure.
*/
static void
{
}
/*
* Output information from prsecflags_t structure.
*/
static void
{
Word w;
if (w != PRSECFLAGS_VERSION_1) {
4, 3);
} else {
}
}
/*
* Output information from utsname structure.
*/
static void
{
}
/*
* Dump register contents
*/
static void
{
Word w;
/* One last register is left */
break;
w++;
continue;
}
/* There are at least 2 more registers left. Show 2 up */
break;
w += 2;
}
}
/*
* Output information from lwpstatus_t structure.
*/
static void
{
int32_t i;
union {
} conv_buf;
}
}
}
}
}
}
}
}
/*
* In order to line up all the values in a single column,
* we would have to set vcol to a very high value, which results
* in ugly looking output that runs off column 80. So, we use
* two levels of vcol, one for the contents so far, and a
* higher one for the pr_reg sub-struct.
*/
/*
* The floating point register state is complex, and highly
* platform dependent. For now, we simply display it as
* a hex dump. This can be replaced if better information
* is required.
*/
}
}
/*
* Output information from pstatus_t structure.
*/
static void
{
Word w;
union {
} conv_buf;
}
}
/*
* In order to line up all the values in a single column,
* we would have to set vcol to a very high value, which results
* in ugly looking output that runs off column 80. So, we use
* two levels of vcol, one for the contents so far, and a
* higher one for the pr_lwp sub-struct.
*/
}
/*
* Output information from prstatus_t (<sys/old_procfs.h>) structure.
*/
static void
{
int i;
union {
} conv_buf;
}
}
}
}
}
}
}
}
/*
* Print percent from 16-bit binary fraction [0 .. 1]
* Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
*
* Note: This routine was copied from ps(1) and then modified.
*/
static const char *
{
if (value >= 1000)
value = 999;
return (buf);
}
/*
* Version of prtpct() used for a 2-up display of two adjacent percentages.
*/
static void
{
return;
}
/*
* The psinfo_t and prpsinfo_t structs have pr_state and pr_sname
* fields that we wish to print in a 2up format. The pr_state is
* an integer, while pr_sname is a single character.
*/
static void
const sl_field_t *state_fdesc,
const sl_field_t *sname_fdesc)
{
int sname;
/*
* If the field slf_offset and extent fall past the end of the
* available data, then return without doing anything. That note
* is from an older core file that doesn't have all the fields
* that we know about.
*/
return;
buf2);
}
/*
* Output information from lwpsinfo_t structure.
*/
static void
{
Word w;
int32_t i;
union {
} conv_buf;
}
}
}
}
}
}
/*
* Output information from psinfo_t structure.
*/
static void
{
Word w;
union {
} conv_buf;
}
}
}
/*
* Output information from prpsinfo_t structure.
*/
static void
{
Word w;
union {
} conv_buf;
}
}
}
}
/*
* Output information from prcred_t structure.
*/
static void
{
}
}
/*
* Output information from prpriv_t structure.
*/
static void
{
0, MSG_ORIG(MSG_CNOTE_T_PR_SETS));
}
}
static void
{
}
/*
* Output information from priv_impl_info_t structure.
*/
static void
{
}
/*
* Dump information from an asrset_t array. This data
* structure is specific to sparcv9, and does not appear
* on any other platform.
*
* typedef int64_t asrset_t[16]; %asr16 - > %asr31
*
* As such, we do not make use of the struct_layout facilities
* for this routine.
*/
static void
{
/* We expect 16 values, but will print whatever is actually there */
if (nelts == 0)
return;
for (w = 0; w < nelts; ) {
if (w == (nelts - 1)) {
/* One last register is left */
w++;
continue;
}
/* There are at least 2 more registers left. Show 2 up */
w += 2;
}
}
{
/*
* Get the per-architecture layout definition
*/
return (CORENOTE_R_BADARCH);
switch (type) {
case NT_PRSTATUS: /* prstatus_t <sys/old_procfs.h> */
return (CORENOTE_R_OK);
case NT_PRFPREG: /* prfpregset_t <sys/procfs_isa.h> */
return (CORENOTE_R_OK_DUMP);
case NT_PRPSINFO: /* prpsinfo_t <sys/old_procfs.h> */
return (CORENOTE_R_OK);
case NT_PRXREG: /* prxregset_t <sys/procfs_isa.h> */
return (CORENOTE_R_OK_DUMP);
case NT_PLATFORM: /* string from sysinfo(SI_PLATFORM) */
return (CORENOTE_R_OK);
return (CORENOTE_R_OK);
case NT_GWINDOWS: /* gwindows_t SPARC only */
return (CORENOTE_R_OK_DUMP);
return (CORENOTE_R_OK);
return (CORENOTE_R_OK_DUMP);
case NT_PSTATUS: /* pstatus_t <sys/procfs.h> */
return (CORENOTE_R_OK);
return (CORENOTE_R_OK);
return (CORENOTE_R_OK);
case NT_UTSNAME: /* struct utsname <sys/utsname.h> */
return (CORENOTE_R_OK);
case NT_LWPSTATUS: /* lwpstatus_t <sys/procfs.h> */
return (CORENOTE_R_OK);
case NT_LWPSINFO: /* lwpsinfo_t <sys/procfs.h> */
return (CORENOTE_R_OK);
return (CORENOTE_R_OK);
case NT_PRPRIVINFO: /* priv_impl_info_t <sys/priv.h> */
return (CORENOTE_R_OK);
case NT_CONTENT: /* core_content_t <sys/corectl.h> */
if (sizeof (core_content_t) > descsz)
return (CORENOTE_R_BADDATA);
{
&fdesc);
indent_exit(&state);
}
return (CORENOTE_R_OK);
case NT_ZONENAME: /* string from getzonenamebyid(3C) */
return (CORENOTE_R_OK);
case NT_FDINFO:
return (CORENOTE_R_OK);
case NT_SPYMASTER:
return (CORENOTE_R_OK);
case NT_SECFLAGS:
return (CORENOTE_R_OK);
}
return (CORENOTE_R_BADTYPE);
}