root/usr/src/cmd/sgs/elfdump/common/gen_struct_layout.c
/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2015 Nexenta Systems, Inc.  All rights reserved.
 * Copyright 2018 Joyent, Inc.
 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
 */

/*
 * This program is used to generate the contents of the
 * struct_layout_XXX.c files that contain per-architecture
 * structure layout information.
 *
 * Although not part of elfdump, it is built by the makefile
 * along with it. Note, the Makefile only builds versions that
 * are natively supported and therefore you must manually run
 * this for other architectures.
 *
 * To use it:
 *
 *      1) Run it, capturing the output in a file.
 *      2) If this is a replacement for an existing file,
 *              diff the new and old copies to ensure only
 *              the changes you expected are present.
 *      3) Put the new file in the common directory under the name
 *              struct_layout_XXX.c, where XXX is the name of
 *              the architecture (i386, amd64, sparc, sparcv9, etc).
 *      2) Add any necessary header and copyright comments.
 *      3) If this is a new architecture:
 *              - Add an extern statement for struct_layout_XXX()
 *                      to struct_layout.h
 *              - Add a case for it to the function sl_struct_layout()
 *                      in struct_layout.c.
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <err.h>
#include <sys/types.h>
#include <libctf.h>

/*
 * This extracts CTF information from a temporary object file.
 *
 * START and END bracket a struct layout definition. They issue
 * the typedef boilerplate, and the standard first element (sizeof)
 * which captures the overall size of the structure.
 *
 * SCALAR_FIELD is for scalar struct fields
 *
 * ARRAY_FIELD is for  array struct fields
 *
 * ARRAY_TYPE is for plain (non-struct) array types
 */
#define START(_name, _type) \
        do_start(#_name, #_type)
#define END (void) \
        do_end()
#define SCALAR_FIELD(_type, _field, _sign) \
        do_scalar_field(#_type, #_field, _sign, NULL)
#define SCALAR_FIELD4(_type, _field, _sign, _rtype) \
        do_scalar_field(#_type, #_field, _sign, _rtype)
#define ARRAY_FIELD(_type, _field, _sign) \
        do_array_field(#_type, #_field, _sign, NULL)
#define ARRAY_TYPE(_type, _sign) \
        do_array_type(#_type, "elt0", _sign)

static void do_start(char *_name, char *_type);
static void do_end(void);
static void do_start_name(char *name);
static void do_start_sizeof(char *_type, char *realtype);
static void do_scalar_field(char *_type, char *_field,
        int _sign, char *dotfield);
static void do_array_field(char *_type, char *_field,
        int _sign, char *dotfield);
static void do_array_type(char *_type, char *_field, int _sign);

static void get_ctf_file(char *fname);
static int get_field_info(char *tname, char *fname, char *dotname,
        int *offp, int *sizep);

static ctf_file_t *ctf;
static char *objfile;
static char *machname;

/* auxv_t, <sys/auxv.h> */
static void
gen_auxv(void)
{
        START(auxv, auxv_t);

        SCALAR_FIELD(auxv_t,    a_type, 1);
        SCALAR_FIELD(auxv_t,    a_un.a_val,     1);
        SCALAR_FIELD(auxv_t,    a_un.a_ptr,     0);
        SCALAR_FIELD(auxv_t,    a_un.a_fcn,     0);

        END;
}


/* prgregset_t, <sys/prgregset.h> */
static void
gen_prgregset(void)
{
        START(prgregset, prgregset_t);

        ARRAY_TYPE(prgregset_t, 0);

        END;
}


/* lwpstatus_t, <sys/procfs.h> */
static void
gen_lwpstatus(void)
{
        START(lwpstatus, lwpstatus_t);

        SCALAR_FIELD(lwpstatus_t,       pr_flags,       0);
        SCALAR_FIELD(lwpstatus_t,       pr_lwpid,       0);
        SCALAR_FIELD(lwpstatus_t,       pr_why,         0);
        SCALAR_FIELD(lwpstatus_t,       pr_what,        0);
        SCALAR_FIELD(lwpstatus_t,       pr_cursig,      0);
        SCALAR_FIELD(lwpstatus_t,       pr_info,        0);
        SCALAR_FIELD(lwpstatus_t,       pr_lwppend,     0);
        SCALAR_FIELD(lwpstatus_t,       pr_lwphold,     0);
        SCALAR_FIELD(lwpstatus_t,       pr_action,      0);
        SCALAR_FIELD(lwpstatus_t,       pr_altstack,    0);
        SCALAR_FIELD(lwpstatus_t,       pr_oldcontext,  0);
        SCALAR_FIELD(lwpstatus_t,       pr_syscall,     0);
        SCALAR_FIELD(lwpstatus_t,       pr_nsysarg,     0);
        SCALAR_FIELD(lwpstatus_t,       pr_errno,       0);
        ARRAY_FIELD(lwpstatus_t,        pr_sysarg,      0);
        SCALAR_FIELD(lwpstatus_t,       pr_rval1,       0);
        SCALAR_FIELD(lwpstatus_t,       pr_rval2,       0);
        ARRAY_FIELD(lwpstatus_t,        pr_clname,      0);
        SCALAR_FIELD(lwpstatus_t,       pr_tstamp,      0);
        SCALAR_FIELD(lwpstatus_t,       pr_utime,       0);
        SCALAR_FIELD(lwpstatus_t,       pr_stime,       0);
        SCALAR_FIELD(lwpstatus_t,       pr_errpriv,     0);
        SCALAR_FIELD(lwpstatus_t,       pr_ustack,      0);
        SCALAR_FIELD(lwpstatus_t,       pr_instr,       0);
        SCALAR_FIELD(lwpstatus_t,       pr_reg,         0);
        SCALAR_FIELD(lwpstatus_t,       pr_fpreg,       0);

        END;
}


/* pstatus_t, <sys/procfs.h> */
static void
gen_pstatus(void)
{
        START(pstatus, pstatus_t);

        SCALAR_FIELD(pstatus_t,         pr_flags,       1);
        SCALAR_FIELD(pstatus_t,         pr_nlwp,        1);
        SCALAR_FIELD(pstatus_t,         pr_pid,         0);
        SCALAR_FIELD(pstatus_t,         pr_ppid,        0);
        SCALAR_FIELD(pstatus_t,         pr_pgid,        0);
        SCALAR_FIELD(pstatus_t,         pr_sid,         0);
        SCALAR_FIELD(pstatus_t,         pr_aslwpid,     1);
        SCALAR_FIELD(pstatus_t,         pr_agentid,     1);
        SCALAR_FIELD(pstatus_t,         pr_sigpend,     0);
        SCALAR_FIELD(pstatus_t,         pr_brkbase,     0);
        SCALAR_FIELD(pstatus_t,         pr_brksize,     0);
        SCALAR_FIELD(pstatus_t,         pr_stkbase,     0);
        SCALAR_FIELD(pstatus_t,         pr_stksize,     0);
        SCALAR_FIELD(pstatus_t,         pr_utime,       0);
        SCALAR_FIELD(pstatus_t,         pr_stime,       0);
        SCALAR_FIELD(pstatus_t,         pr_cutime,      0);
        SCALAR_FIELD(pstatus_t,         pr_cstime,      0);
        SCALAR_FIELD(pstatus_t,         pr_sigtrace,    0);
        SCALAR_FIELD(pstatus_t,         pr_flttrace,    0);
        SCALAR_FIELD(pstatus_t,         pr_sysentry,    0);
        SCALAR_FIELD(pstatus_t,         pr_sysexit,     0);
        SCALAR_FIELD(pstatus_t,         pr_dmodel,      0);
        SCALAR_FIELD(pstatus_t,         pr_taskid,      1);
        SCALAR_FIELD(pstatus_t,         pr_projid,      1);
        SCALAR_FIELD(pstatus_t,         pr_nzomb,       1);
        SCALAR_FIELD(pstatus_t,         pr_zoneid,      1);
        SCALAR_FIELD(pstatus_t,         pr_lwp,         0);

        END;
}


/* prstatus_t, <sys/old_procfs.h> */
static void
gen_prstatus(void)
{
        START(prstatus, prstatus_t);

        SCALAR_FIELD(prstatus_t,        pr_flags,       1);
        SCALAR_FIELD(prstatus_t,        pr_why,         1);
        SCALAR_FIELD(prstatus_t,        pr_what,        1);
        SCALAR_FIELD(prstatus_t,        pr_info,        0);
        SCALAR_FIELD(prstatus_t,        pr_cursig,      1);
        SCALAR_FIELD(prstatus_t,        pr_nlwp,        0);
        SCALAR_FIELD(prstatus_t,        pr_sigpend,     0);
        SCALAR_FIELD(prstatus_t,        pr_sighold,     0);
        SCALAR_FIELD(prstatus_t,        pr_altstack,    0);
        SCALAR_FIELD(prstatus_t,        pr_action,      0);
        SCALAR_FIELD(prstatus_t,        pr_pid,         0);
        SCALAR_FIELD(prstatus_t,        pr_ppid,        0);
        SCALAR_FIELD(prstatus_t,        pr_pgrp,        0);
        SCALAR_FIELD(prstatus_t,        pr_sid,         0);
        SCALAR_FIELD(prstatus_t,        pr_utime,       0);
        SCALAR_FIELD(prstatus_t,        pr_stime,       0);
        SCALAR_FIELD(prstatus_t,        pr_cutime,      0);
        SCALAR_FIELD(prstatus_t,        pr_cstime,      0);
        ARRAY_FIELD(prstatus_t,         pr_clname,      0);
        SCALAR_FIELD(prstatus_t,        pr_syscall,     1);
        SCALAR_FIELD(prstatus_t,        pr_nsysarg,     1);
        ARRAY_FIELD(prstatus_t,         pr_sysarg,      1);
        SCALAR_FIELD(prstatus_t,        pr_who,         0);
        SCALAR_FIELD(prstatus_t,        pr_lwppend,     0);
        SCALAR_FIELD(prstatus_t,        pr_oldcontext,  0);
        SCALAR_FIELD(prstatus_t,        pr_brkbase,     0);
        SCALAR_FIELD(prstatus_t,        pr_brksize,     0);
        SCALAR_FIELD(prstatus_t,        pr_stkbase,     0);
        SCALAR_FIELD(prstatus_t,        pr_stksize,     0);
        SCALAR_FIELD(prstatus_t,        pr_processor,   1);
        SCALAR_FIELD(prstatus_t,        pr_bind,        1);
        SCALAR_FIELD(prstatus_t,        pr_instr,       1);
        SCALAR_FIELD(prstatus_t,        pr_reg,         0);

        END;
}


/* psinfo_t, <sys/procfs.h> */
static void
gen_psinfo(void)
{
        START(psinfo, psinfo_t);

        SCALAR_FIELD(psinfo_t,          pr_flag,        1);
        SCALAR_FIELD(psinfo_t,          pr_nlwp,        1);
        SCALAR_FIELD(psinfo_t,          pr_pid,         0);
        SCALAR_FIELD(psinfo_t,          pr_ppid,        0);
        SCALAR_FIELD(psinfo_t,          pr_pgid,        0);
        SCALAR_FIELD(psinfo_t,          pr_sid,         0);
        SCALAR_FIELD(psinfo_t,          pr_uid,         0);
        SCALAR_FIELD(psinfo_t,          pr_euid,        0);
        SCALAR_FIELD(psinfo_t,          pr_gid,         0);
        SCALAR_FIELD(psinfo_t,          pr_egid,        0);
        SCALAR_FIELD(psinfo_t,          pr_addr,        0);
        SCALAR_FIELD(psinfo_t,          pr_size,        0);
        SCALAR_FIELD(psinfo_t,          pr_rssize,      0);
        SCALAR_FIELD(psinfo_t,          pr_ttydev,      0);
        SCALAR_FIELD(psinfo_t,          pr_pctcpu,      0);
        SCALAR_FIELD(psinfo_t,          pr_pctmem,      0);
        SCALAR_FIELD(psinfo_t,          pr_start,       0);
        SCALAR_FIELD(psinfo_t,          pr_time,        0);
        SCALAR_FIELD(psinfo_t,          pr_ctime,       0);
        ARRAY_FIELD(psinfo_t,           pr_fname,       0);
        ARRAY_FIELD(psinfo_t,           pr_psargs,      0);
        SCALAR_FIELD(psinfo_t,          pr_wstat,       1);
        SCALAR_FIELD(psinfo_t,          pr_argc,        1);
        SCALAR_FIELD(psinfo_t,          pr_argv,        0);
        SCALAR_FIELD(psinfo_t,          pr_envp,        0);
        SCALAR_FIELD(psinfo_t,          pr_dmodel,      0);
        SCALAR_FIELD(psinfo_t,          pr_taskid,      0);
        SCALAR_FIELD(psinfo_t,          pr_projid,      0);
        SCALAR_FIELD(psinfo_t,          pr_nzomb,       1);
        SCALAR_FIELD(psinfo_t,          pr_poolid,      0);
        SCALAR_FIELD(psinfo_t,          pr_zoneid,      0);
        SCALAR_FIELD(psinfo_t,          pr_contract,    0);
        SCALAR_FIELD(psinfo_t,          pr_lwp,         0);

        END;
}

/* prpsinfo_t, <sys/old_procfs.h> */
static void
gen_prpsinfo(void)
{
        START(prpsinfo, prpsinfo_t);

        SCALAR_FIELD(prpsinfo_t,        pr_state,       0);
        SCALAR_FIELD(prpsinfo_t,        pr_sname,       0);
        SCALAR_FIELD(prpsinfo_t,        pr_zomb,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_nice,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_flag,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_uid,         0);
        SCALAR_FIELD(prpsinfo_t,        pr_gid,         0);
        SCALAR_FIELD(prpsinfo_t,        pr_pid,         0);
        SCALAR_FIELD(prpsinfo_t,        pr_ppid,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_pgrp,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_sid,         0);
        SCALAR_FIELD(prpsinfo_t,        pr_addr,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_size,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_rssize,      0);
        SCALAR_FIELD(prpsinfo_t,        pr_wchan,       0);
        SCALAR_FIELD(prpsinfo_t,        pr_start,       0);
        SCALAR_FIELD(prpsinfo_t,        pr_time,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_pri,         1);
        SCALAR_FIELD(prpsinfo_t,        pr_oldpri,      0);
        SCALAR_FIELD(prpsinfo_t,        pr_cpu,         0);
        SCALAR_FIELD(prpsinfo_t,        pr_ottydev,     0);
        SCALAR_FIELD(prpsinfo_t,        pr_lttydev,     0);
        ARRAY_FIELD(prpsinfo_t,         pr_clname,      0);
        ARRAY_FIELD(prpsinfo_t,         pr_fname,       0);
        ARRAY_FIELD(prpsinfo_t,         pr_psargs,      0);
        SCALAR_FIELD(prpsinfo_t,        pr_syscall,     1);
        SCALAR_FIELD(prpsinfo_t,        pr_ctime,       0);
        SCALAR_FIELD(prpsinfo_t,        pr_bysize,      0);
        SCALAR_FIELD(prpsinfo_t,        pr_byrssize,    0);
        SCALAR_FIELD(prpsinfo_t,        pr_argc,        1);
        SCALAR_FIELD(prpsinfo_t,        pr_argv,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_envp,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_wstat,       1);
        SCALAR_FIELD(prpsinfo_t,        pr_pctcpu,      0);
        SCALAR_FIELD(prpsinfo_t,        pr_pctmem,      0);
        SCALAR_FIELD(prpsinfo_t,        pr_euid,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_egid,        0);
        SCALAR_FIELD(prpsinfo_t,        pr_aslwpid,     0);
        SCALAR_FIELD(prpsinfo_t,        pr_dmodel,      0);

        END;
}

/* lwpsinfo_t, <sys/procfs.h> */
static void
gen_lwpsinfo(void)
{
        START(lwpsinfo, lwpsinfo_t);

        SCALAR_FIELD(lwpsinfo_t,        pr_flag,        1);
        SCALAR_FIELD(lwpsinfo_t,        pr_lwpid,       0);
        SCALAR_FIELD(lwpsinfo_t,        pr_addr,        0);
        SCALAR_FIELD(lwpsinfo_t,        pr_wchan,       0);
        SCALAR_FIELD(lwpsinfo_t,        pr_stype,       0);
        SCALAR_FIELD(lwpsinfo_t,        pr_state,       0);
        SCALAR_FIELD(lwpsinfo_t,        pr_sname,       0);
        SCALAR_FIELD(lwpsinfo_t,        pr_nice,        0);
        SCALAR_FIELD(lwpsinfo_t,        pr_syscall,     0);
        SCALAR_FIELD(lwpsinfo_t,        pr_oldpri,      0);
        SCALAR_FIELD(lwpsinfo_t,        pr_cpu,         0);
        SCALAR_FIELD(lwpsinfo_t,        pr_pri,         1);
        SCALAR_FIELD(lwpsinfo_t,        pr_pctcpu,      0);
        SCALAR_FIELD(lwpsinfo_t,        pr_start,       0);
        SCALAR_FIELD(lwpsinfo_t,        pr_time,        0);
        ARRAY_FIELD(lwpsinfo_t,         pr_clname,      0);
        ARRAY_FIELD(lwpsinfo_t,         pr_name,        0);
        SCALAR_FIELD(lwpsinfo_t,        pr_onpro,       1);
        SCALAR_FIELD(lwpsinfo_t,        pr_bindpro,     1);
        SCALAR_FIELD(lwpsinfo_t,        pr_bindpset,    1);
        SCALAR_FIELD(lwpsinfo_t,        pr_lgrp,        1);

        END;
}

/* prcred_t, <sys/procfs.h> */
static void
gen_prcred(void)
{
        START(prcred, prcred_t);

        SCALAR_FIELD(prcred_t,          pr_euid,        0);
        SCALAR_FIELD(prcred_t,          pr_ruid,        0);
        SCALAR_FIELD(prcred_t,          pr_suid,        0);
        SCALAR_FIELD(prcred_t,          pr_egid,        0);
        SCALAR_FIELD(prcred_t,          pr_rgid,        0);
        SCALAR_FIELD(prcred_t,          pr_sgid,        0);
        SCALAR_FIELD(prcred_t,          pr_ngroups,     1);
        ARRAY_FIELD(prcred_t,           pr_groups,      0);

        END;
}

/* prpriv_t, <sys/procfs.h> */
static void
gen_prpriv(void)
{
        START(prpriv, prpriv_t);

        SCALAR_FIELD(prpriv_t,          pr_nsets,       0);
        SCALAR_FIELD(prpriv_t,          pr_setsize,     0);
        SCALAR_FIELD(prpriv_t,          pr_infosize,    0);
        ARRAY_FIELD(prpriv_t,           pr_sets,        0);

        END;
}


/* priv_impl_info_t, <sys/priv.h> */
static void
gen_priv_impl_info(void)
{
        START(priv_impl_info, priv_impl_info_t);

        SCALAR_FIELD(priv_impl_info_t,  priv_headersize,        0);
        SCALAR_FIELD(priv_impl_info_t,  priv_flags,             0);
        SCALAR_FIELD(priv_impl_info_t,  priv_nsets,             0);
        SCALAR_FIELD(priv_impl_info_t,  priv_setsize,           0);
        SCALAR_FIELD(priv_impl_info_t,  priv_max,               0);
        SCALAR_FIELD(priv_impl_info_t,  priv_infosize,          0);
        SCALAR_FIELD(priv_impl_info_t,  priv_globalinfosize,    0);

        END;
}


/* fltset_t, <sys/fault.h> */
static void
gen_fltset(void)
{
        START(fltset, fltset_t);

        ARRAY_FIELD(fltset_t,   word,   0);

        END;
}

/*
 * Layout description of siginfo_t, <sys/siginfo.h>
 *
 * Note: many siginfo_t members are #defines mapping to
 * long dotted members of sub-structs or unions, and
 * we need the full member spec (with dots) for those.
 */
static void
gen_siginfo(void)
{
        START(siginfo, siginfo_t);

        SCALAR_FIELD(siginfo_t,         si_signo,               0);
        SCALAR_FIELD(siginfo_t,         si_errno,               0);
        SCALAR_FIELD(siginfo_t,         si_code,                1);

        SCALAR_FIELD4(siginfo_t,        si_value.sival_int,     0,
            "__data.__proc.__pdata.__kill.__value.sival_int");

        SCALAR_FIELD4(siginfo_t,        si_value.sival_ptr,     0,
            "__data.__proc.__pdata.__kill.__value.sival_ptr");

        SCALAR_FIELD4(siginfo_t,        si_pid,                 0,
            "__data.__proc.__pid");

        SCALAR_FIELD4(siginfo_t,        si_uid,                 0,
            "__data.__proc.__pdata.__kill.__uid");

        SCALAR_FIELD4(siginfo_t,        si_ctid,                0,
            "__data.__proc.__ctid");

        SCALAR_FIELD4(siginfo_t,        si_zoneid,              0,
            "__data.__proc.__zoneid");

        SCALAR_FIELD4(siginfo_t,        si_entity,              0,
            "__data.__rctl.__entity");

        SCALAR_FIELD4(siginfo_t,        si_addr,                0,
            "__data.__fault.__addr");

        SCALAR_FIELD4(siginfo_t,        si_status,              0,
            "__data.__proc.__pdata.__cld.__status");

        SCALAR_FIELD4(siginfo_t,        si_band,                0,
            "__data.__file.__band");

        END;
}

/* sigset_t, <sys/signal.h> */
static void
gen_sigset(void)
{
        START(sigset, sigset_t);

        ARRAY_FIELD(sigset_t,   __sigbits,      0);

        END;
}


/* struct sigaction, <sys/signal.h> */
static void
gen_sigaction(void)
{
        START(sigaction, struct sigaction);

        SCALAR_FIELD(struct sigaction,  sa_flags,       0);

        SCALAR_FIELD4(struct sigaction, sa_handler,     0,
            "_funcptr._handler");

        SCALAR_FIELD4(struct sigaction, sa_sigaction,   0,
            "_funcptr._sigaction");

        SCALAR_FIELD(struct sigaction,  sa_mask,        0);

        END;
}

/* stack_t, <sys/signal.h> */
static void
gen_stack(void)
{
        START(stack, stack_t);

        SCALAR_FIELD(stack_t,   ss_sp,          0);
        SCALAR_FIELD(stack_t,   ss_size,        0);
        SCALAR_FIELD(stack_t,   ss_flags,       0);

        END;
}

/* sysset_t, <sys/syscall.h> */
static void
gen_sysset(void)
{
        START(sysset, sysset_t);

        ARRAY_FIELD(sysset_t,   word,   0);

        END;
}

/* timestruc_t, <sys/time_impl.h> */
static void
gen_timestruc(void)
{
        START(timestruc, timestruc_t);

        SCALAR_FIELD(timestruc_t,       tv_sec,         0);
        SCALAR_FIELD(timestruc_t,       tv_nsec,        0);

        END;
}

/* struct utsname, <sys/utsname.h> */
static void
gen_utsname(void)
{
        START(utsname, struct utsname);

        ARRAY_FIELD(struct utsname,     sysname,        0);
        ARRAY_FIELD(struct utsname,     nodename,       0);
        ARRAY_FIELD(struct utsname,     release,        0);
        ARRAY_FIELD(struct utsname,     version,        0);
        ARRAY_FIELD(struct utsname,     machine,        0);

        END;
}

static void
gen_prfdinfo(void)
{
        START(prfdinfo, prfdinfo_core_t);

        SCALAR_FIELD(prfdinfo_core_t,   pr_fd,          0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_mode,        0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_uid,         0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_gid,         0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_major,       0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_minor,       0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_rmajor,      0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_rminor,      0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_ino,         0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_offset,      0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_size,        0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_fileflags,   0);
        SCALAR_FIELD(prfdinfo_core_t,   pr_fdflags,     0);
        ARRAY_FIELD(prfdinfo_core_t,    pr_path,        0);

        END;
}

static void
gen_prsecflags(void)
{
        START(prsecflags, prsecflags_t);
        SCALAR_FIELD(prsecflags_t, pr_version, 0);
        SCALAR_FIELD(prsecflags_t, pr_effective, 0);
        SCALAR_FIELD(prsecflags_t, pr_inherit, 0);
        SCALAR_FIELD(prsecflags_t, pr_lower, 0);
        SCALAR_FIELD(prsecflags_t, pr_upper, 0);
        END;
}

static void
gen_prlwpname(void)
{
        START(prlwpname, prlwpname_t);
        SCALAR_FIELD(prlwpname_t, pr_lwpid, 0);
        ARRAY_FIELD(prlwpname_t, pr_lwpname, 0);
        END;
}

static void
gen_prupanic(void)
{
        START(prupanic, prupanic_t);
        SCALAR_FIELD(prupanic_t, pru_version, 0);
        SCALAR_FIELD(prupanic_t, pru_flags, 0);
        ARRAY_FIELD(prupanic_t, pru_data, 0);
        END;
}

static void
gen_prcwd(void)
{
        START(prcwd, prcwd_t);
        SCALAR_FIELD(prcwd_t, prcwd_fsid, 0);
        ARRAY_FIELD(prcwd_t, prcwd_fsname, 0);
        ARRAY_FIELD(prcwd_t, prcwd_mntpt, 0);
        ARRAY_FIELD(prcwd_t, prcwd_mntspec, 0);
        ARRAY_FIELD(prcwd_t, prcwd_cwd, 0);
        END;
}

/*ARGSUSED*/
int
main(int argc, char *argv[])
{
        const char *fmt = "\t&%s_layout,\n";

        /* get obj file for input */
        if (argc < 3) {
                (void) fprintf(stderr,
                    "usage: %s {object_file} {MACH}\n", argv[0]);
                exit(1);
        }

        objfile = argv[1];
        machname = argv[2];

        get_ctf_file(objfile);

        (void) printf("#include <struct_layout.h>\n");

        gen_auxv();
        gen_prgregset();
        gen_lwpstatus();
        gen_pstatus();
        gen_prstatus();
        gen_psinfo();
        gen_prpsinfo();
        gen_lwpsinfo();
        gen_prcred();
        gen_prpriv();
        gen_priv_impl_info();
        gen_fltset();
        gen_siginfo();
        gen_sigset();
        gen_sigaction();
        gen_stack();
        gen_sysset();
        gen_timestruc();
        gen_utsname();
        gen_prfdinfo();
        gen_prsecflags();
        gen_prlwpname();
        gen_prupanic();
        gen_prcwd();

        /*
         * Generate the full arch_layout description
         */
        (void) printf(
            "\n\n\n\nstatic const sl_arch_layout_t layout_%s = {\n",
            machname);
        (void) printf(fmt, "auxv");
        (void) printf(fmt, "fltset");
        (void) printf(fmt, "lwpsinfo");
        (void) printf(fmt, "lwpstatus");
        (void) printf(fmt, "prcred");
        (void) printf(fmt, "priv_impl_info");
        (void) printf(fmt, "prpriv");
        (void) printf(fmt, "psinfo");
        (void) printf(fmt, "pstatus");
        (void) printf(fmt, "prgregset");
        (void) printf(fmt, "prpsinfo");
        (void) printf(fmt, "prstatus");
        (void) printf(fmt, "sigaction");
        (void) printf(fmt, "siginfo");
        (void) printf(fmt, "sigset");
        (void) printf(fmt, "stack");
        (void) printf(fmt, "sysset");
        (void) printf(fmt, "timestruc");
        (void) printf(fmt, "utsname");
        (void) printf(fmt, "prfdinfo");
        (void) printf(fmt, "prsecflags");
        (void) printf(fmt, "prlwpname");
        (void) printf(fmt, "prupanic");
        (void) printf(fmt, "prcwd");
        (void) printf("};\n");

        /*
         * A public function, to make the information available
         */
        (void) printf("\n\nconst sl_arch_layout_t *\n");
        (void) printf("struct_layout_%s(void)\n", machname);
        (void) printf("{\n\treturn (&layout_%s);\n}\n", machname);

        return (0);
}

/*
 * Helper functions using the CTF library to get type info.
 */

static void
get_ctf_file(char *fname)
{
        int ctferr;

        objfile = fname;
        if ((ctf = ctf_open(objfile, &ctferr)) == NULL) {
                errx(1, "Couldn't open object file %s: %s\n", objfile,
                    ctf_errmsg(ctferr));
        }
}

static void
print_row(int boff, int eltlen, int nelts, int issigned, char *comment)
{
        (void) printf("\t{ %d,\t%d,\t%d,\t%d },\t\t/* %s */\n",
            boff, eltlen, nelts, issigned, comment);
}

static void
do_start(char *sname, char *tname)
{
        do_start_name(sname);
        do_start_sizeof(tname, NULL);
}

static void
do_start_name(char *sname)
{
        (void) printf("\n\nstatic const sl_%s_layout_t %s_layout = {\n",
            sname, sname);
}

static void
do_end(void)
{
        (void) printf("};\n");
}

static void
do_start_sizeof(char *tname, char *rtname)
{
        char comment[100];
        ctf_id_t stype;
        int sz;

        if (rtname == NULL)
                rtname = tname;

        if ((stype = ctf_lookup_by_name(ctf, rtname)) == CTF_ERR)
                errx(1, "Couldn't find type %s", rtname);
        if ((stype = ctf_type_resolve(ctf, stype)) == CTF_ERR)
                errx(1, "Couldn't resolve type %s", tname);

        if ((sz = (int)ctf_type_size(ctf, stype)) < 0) {
                errx(1, "Couldn't get size for type %s", tname);
        } else if (sz == 0) {
                errx(1, "Invalid type size 0 for %s", tname);
        }

        (void) snprintf(comment, sizeof (comment), "sizeof (%s)", tname);
        print_row(0, sz, 0, 0, comment);
}

static void
do_scalar_field(char *tname, char *fname, int _sign, char *dotfield)
{
        int rc, off, sz, ftype;

        rc = get_field_info(tname, fname, dotfield, &off, &ftype);
        if (rc < 0)
                errx(1, "Can't get field info for %s->%s", tname, fname);

        if ((ftype = ctf_type_resolve(ctf, ftype)) == CTF_ERR)
                errx(1, "Couldn't resolve type of %s->%s", tname, fname);

        if ((sz = (int)ctf_type_size(ctf, ftype)) < 0) {
                errx(1, "Couldn't get size for type ID %d", ftype);
        } else if (sz == 0) {
                errx(1, "Invalid type size 0 for type ID %d", ftype);
        }

        print_row(off, sz, 0, _sign, fname);
}

static void
do_array_field(char *tname, char *fname,
    int _sign, char *dotfield)
{
        char comment[100];
        ctf_arinfo_t ai;
        int typekind;
        int esz, rc, off, ftype;

        rc = get_field_info(tname, fname, dotfield, &off, &ftype);
        if (rc < 0)
                errx(1, "Can't get field info for %s->%s", tname, fname);

        if ((ftype = ctf_type_resolve(ctf, ftype)) == CTF_ERR)
                errx(1, "Couldn't resolve type of %s->%s", tname, fname);

        typekind = ctf_type_kind(ctf, ftype);
        if (typekind != CTF_K_ARRAY)
                errx(1, "Wrong type for %s->%s", tname, fname);

        rc = ctf_array_info(ctf, ftype, &ai);
        if (rc != 0)
                errx(1, "Can't get array info for %s->%s\n", tname, fname);
        esz = ctf_type_size(ctf, ai.ctr_contents);
        if (esz < 0)
                errx(1, "Can't get element size for %s->%s\n", tname, fname);

        (void) snprintf(comment, sizeof (comment), "%s[]", fname);
        print_row(off, esz, ai.ctr_nelems, _sign, comment);
}

static void
do_array_type(char *tname, char *fname, int _sign)
{
        ctf_arinfo_t ai;
        int stype, typekind;
        int esz, rc;

        if ((stype = ctf_lookup_by_name(ctf, tname)) == CTF_ERR)
                errx(1, "Couldn't find type %s", tname);
        if ((stype = ctf_type_resolve(ctf, stype)) == CTF_ERR)
                errx(1, "Couldn't resolve type %s", tname);

        typekind = ctf_type_kind(ctf, stype);
        if (typekind != CTF_K_ARRAY)
                errx(1, "Wrong type for %s->%s", tname, fname);

        rc = ctf_array_info(ctf, stype, &ai);
        if (rc != 0)
                errx(1, "Can't get array info for %s->%s\n", tname, fname);
        esz = ctf_type_size(ctf, ai.ctr_contents);
        if (esz < 0)
                errx(1, "Can't get element size for %s->%s\n", tname, fname);

        print_row(0, esz, ai.ctr_nelems, _sign, fname);
}


struct gfinfo {
        char *tname;    /* top type name, i.e. the struct */
        char *fname;    /* field name */
        char *dotname;  /* full field name with dots (optional) */
        char *prefix;   /* current field search prefix */
        int base_off;
        int fld_off;
        int fld_type;
};

static int gfi_iter(const char *fname, ctf_id_t mbrtid,
        ulong_t off, void *varg);

/*
 * Lookup field "fname" in type "tname".  If "dotname" is non-NULL,
 * that's the full field name with dots, i.e. a_un.un_foo, which
 * we must search for by walking the struct CTF recursively.
 */
static int
get_field_info(char *tname, char *fname, char *dotname,
    int *offp, int *tidp)
{
        struct gfinfo gfi;
        ctf_id_t stype;
        int typekind;
        int rc;

        if ((stype = ctf_lookup_by_name(ctf, tname)) == CTF_ERR)
                errx(1, "Couldn't find type %s", tname);
        if ((stype = ctf_type_resolve(ctf, stype)) == CTF_ERR)
                errx(1, "Couldn't resolve type %s", tname);

        /* If fname has a dot, use it as dotname too. */
        if (dotname == NULL && strchr(fname, '.') != NULL)
                dotname = fname;

        gfi.tname = tname;
        gfi.fname = fname;
        gfi.dotname = dotname;
        gfi.prefix = "";
        gfi.base_off = 0;
        gfi.fld_off = 0;
        gfi.fld_type = 0;

        typekind = ctf_type_kind(ctf, stype);
        switch (typekind) {

        case CTF_K_STRUCT:
        case CTF_K_UNION:
                rc = ctf_member_iter(ctf, stype, gfi_iter, &gfi);
                break;

        default:
                errx(1, "Unexpected top-level type for %s", tname);
                break;
        }

        if (rc < 0)
                errx(1, "Error getting info for %s.%s", tname, fname);
        if (rc == 0)
                errx(1, "Did not find %s.%s", tname, fname);

        *offp = gfi.fld_off;
        *tidp = gfi.fld_type;

        return (0);
}

/*
 * Iteration callback for ctf_member_iter
 * Return <0 on error, 0 to keep looking, >0 for found.
 *
 * If no dotname, simple search for fieldname.
 * If we're asked to search with dotname, we need to do a full
 * recursive walk of the types under the dotname.
 */
int
gfi_iter(const char *fieldname, ctf_id_t mbrtid, ulong_t off, void *varg)
{
        char namebuf[100];
        struct gfinfo *gfi = varg;
        char *saveprefix;
        int saveoff;
        int typekind;
        int byteoff;
        int len, rc;

        byteoff = gfi->base_off + (int)(off >> 3);

        /* Easy cases first: no dotname */
        if (gfi->dotname == NULL) {
                if (strcmp(gfi->fname, fieldname) == 0) {
                        gfi->fld_off = byteoff;
                        gfi->fld_type = mbrtid;
                        return (1);
                }
                return (0);
        }

        /* Exact match on the dotname? */
        (void) snprintf(namebuf, sizeof (namebuf), "%s%s",
            gfi->prefix, fieldname);
        if (strcmp(gfi->dotname, namebuf) == 0) {
                gfi->fld_off = byteoff;
                gfi->fld_type = mbrtid;
                return (1);
        }

        /*
         * May need to recurse under this field, but
         * only if there's a match through '.'
         */
        (void) strlcat(namebuf, ".", sizeof (namebuf));
        len = strlen(namebuf);
        if (strncmp(gfi->dotname, namebuf, len) != 0)
                return (0);

        typekind = ctf_type_kind(ctf, mbrtid);
        switch (typekind) {
        case CTF_K_STRUCT:
        case CTF_K_UNION:
                break;
        default:
                return (0);
        }

        /* Recursively walk members */
        saveprefix = gfi->prefix;
        saveoff = gfi->base_off;
        gfi->prefix = namebuf;
        gfi->base_off = byteoff;
        rc = ctf_member_iter(ctf, mbrtid, gfi_iter, gfi);
        gfi->prefix = saveprefix;
        gfi->base_off = saveoff;

        return (rc);
}