root/usr/src/cmd/sgs/liblddbg/common/files.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 (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2022 Oxide Computer Company
 */

#include        <sys/auxv.h>
#include        <string.h>
#include        <unistd.h>
#include        <fcntl.h>
#include        <limits.h>
#include        <stdio.h>
#include        <libld.h>
#include        <rtld.h>
#include        <conv.h>
#include        "msg.h"
#include        "_debug.h"

void
Dbg_file_analyze(Rt_map *lmp)
{
        Conv_dl_mode_buf_t      dl_mode_buf;
        Lm_list                 *lml = LIST(lmp);

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_ANALYZE), NAME(lmp),
            conv_dl_mode(MODE(lmp), 1, &dl_mode_buf));
}

void
Dbg_file_mmapobj(Lm_list *lml, const char *name, mmapobj_result_t *ompp,
    uint_t onum)
{
        mmapobj_result_t        *mpp;
        uint_t                  mnum;

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;
        if (DBG_NOTDETAIL())
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_MMAPOBJ), name, onum);

        for (mnum = 0, mpp = ompp; mnum < onum; mnum++, mpp++) {
                const char      *str;
                uint_t          type = MR_GET_TYPE(mpp->mr_flags);

                if (type == MR_PADDING)
                        str = MSG_ORIG(MSG_MR_PADDING);
                else if (type == MR_HDR_ELF)
                        str = MSG_ORIG(MSG_MR_HDR_ELF);
                else
                        str = MSG_ORIG(MSG_STR_EMPTY);

                dbg_print(lml, MSG_INTL(MSG_FIL_MMAPOBJ_1), mnum,
                    EC_NATPTR(mpp->mr_addr), EC_OFF(mpp->mr_fsize), str);
                dbg_print(lml, MSG_INTL(MSG_FIL_MMAPOBJ_2),
                    EC_OFF(mpp->mr_offset), EC_OFF(mpp->mr_msize));
        }
        Dbg_util_nl(lml, DBG_NL_STD);
}

void
Dbg_file_elf(Lm_list *lml, const char *name, Addr addr, size_t size,
    const char *lmid, Aliste lmco)
{
        const char      *str;

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        if (addr == 0)
                str = MSG_INTL(MSG_STR_TEMPORARY);
        else
                str = MSG_ORIG(MSG_STR_EMPTY);

        dbg_print(lml, MSG_INTL(MSG_FIL_ELF), name, str);
        dbg_print(lml, MSG_INTL(MSG_FIL_DATA_AS), EC_ADDR(addr), EC_OFF(size));
        dbg_print(lml, MSG_INTL(MSG_FIL_DATA_LL), lmid, EC_XWORD(lmco));
}

void
Dbg_file_ldso(Rt_map *lmp, char **envp, auxv_t *auxv, const char *lmid,
    Aliste lmco)
{
        Lm_list *lml = LIST(lmp);

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_LDSO), PATHNAME(lmp));
        dbg_print(lml, MSG_INTL(MSG_FIL_DATA_AS), EC_ADDR(ADDR(lmp)),
            EC_OFF(MSIZE(lmp)));
        dbg_print(lml, MSG_INTL(MSG_FIL_DATA_EA), EC_NATPTR(envp),
            EC_NATPTR(auxv));
        dbg_print(lml, MSG_INTL(MSG_FIL_DATA_LL), lmid, EC_XWORD(lmco));
        Dbg_util_nl(lml, DBG_NL_STD);
}


void
Dbg_file_prot(Rt_map *lmp, int prot)
{
        Lm_list *lml = LIST(lmp);

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_PROT), NAME(lmp), (prot ? '+' : '-'));
}

void
Dbg_file_delete(Rt_map *lmp)
{
        Lm_list *lml = LIST(lmp);

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_DELETE), NAME(lmp));
}

static int      hdl_title = 0;
static Msg      hdl_str = 0;

void
Dbg_file_hdl_title(int type)
{
        static const Msg titles[] = {
                MSG_FIL_HDL_CREATE,     /* MSG_INTL(MSG_FIL_HDL_CREATE) */
                MSG_FIL_HDL_ADD,        /* MSG_INTL(MSG_FIL_HDL_ADD) */
                MSG_FIL_HDL_DELETE,     /* MSG_INTL(MSG_FIL_HDL_DELETE) */
                MSG_FIL_HDL_ORPHAN,     /* MSG_INTL(MSG_FIL_HDL_ORPHAN) */
                MSG_FIL_HDL_REINST,     /* MSG_INTL(MSG_FIL_HDL_REINST) */
        };

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;
        if (DBG_NOTDETAIL())
                return;

        /*
         * Establish a binding title for later use in Dbg_file_hdl_action.
         */
        if (type <= DBG_HDL_REINST) {
                hdl_str = titles[type];
                hdl_title = 1;
        } else {
                hdl_str = 0;
                hdl_title = 0;
        }
}

void
Dbg_file_hdl_collect(Grp_hdl *ghp, const char *name)
{
        Conv_grphdl_flags_buf_t grphdl_flags_buf;
        Lm_list         *lml = ghp->gh_ownlml;
        const char      *str;

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;
        if (DBG_NOTDETAIL())
                return;

        if (ghp->gh_ownlmp)
                str = NAME(ghp->gh_ownlmp);
        else
                str = MSG_INTL(MSG_STR_ORPHAN);

        if (hdl_title) {
                hdl_title = 0;
                Dbg_util_nl(lml, DBG_NL_STD);
        }
        if (name)
                dbg_print(lml, MSG_INTL(MSG_FIL_HDL_RETAIN), str, name);
        else
                dbg_print(lml, MSG_INTL(MSG_FIL_HDL_COLLECT), str,
                    conv_grphdl_flags(ghp->gh_flags, &grphdl_flags_buf));
}

void
Dbg_file_hdl_action(Grp_hdl *ghp, Rt_map *lmp, int type, uint_t flags)
{
        Conv_grpdesc_flags_buf_t grpdesc_flags_buf;
        const char      *mode, *group;
        Lm_list         *lml = LIST(lmp);
        Msg             str;

        static const Msg fmt[] = {
                MSG_FIL_DEP_ADD,        /* MSG_INTL(MSG_FIL_DEP_ADD) */
                MSG_FIL_DEP_UPDATE,     /* MSG_INTL(MSG_FIL_DEP_UPDATE) */
                MSG_FIL_DEP_DELETE,     /* MSG_INTL(MSG_FIL_DEP_DELETE) */
                MSG_FIL_DEP_REMOVE,     /* MSG_INTL(MSG_FIL_DEP_REMOVE) */
                MSG_FIL_DEP_REMAIN,     /* MSG_INTL(MSG_FIL_DEP_REMAIN) */
                MSG_FIL_DEP_ORPHAN,     /* MSG_INTL(MSG_FIL_DEP_ORPHAN) */
                MSG_FIL_DEP_REINST,     /* MSG_INTL(MSG_FIL_DEP_REINST) */
        };
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;
        if (DBG_NOTDETAIL())
                return;

        if (hdl_title) {
                Dbg_util_nl(lml, DBG_NL_STD);
                if (hdl_str) {
                        Conv_grphdl_flags_buf_t grphdl_flags_buf;
                        const char      *name;

                        /*
                         * Protect ourselves in case this handle has no
                         * originating owner.
                         */
                        if (ghp->gh_ownlmp)
                                name = NAME(ghp->gh_ownlmp);
                        else
                                name = MSG_INTL(MSG_STR_UNKNOWN);

                        dbg_print(lml, MSG_INTL(hdl_str), name,
                            conv_grphdl_flags(ghp->gh_flags, &grphdl_flags_buf),
                            EC_NATPTR(ghp));
                }
                hdl_title = 0;
        }

        /*
         * Establish a binding descriptor format string.
         */
        if (type > DBG_DEP_REINST)
                return;

        str = fmt[type];

        if (((type == DBG_DEP_ADD) || (type == DBG_DEP_UPDATE)) && flags)
                group = conv_grpdesc_flags(flags, &grpdesc_flags_buf);
        else
                group = MSG_ORIG(MSG_STR_EMPTY);

        if ((MODE(lmp) & (RTLD_GLOBAL | RTLD_NODELETE)) ==
            (RTLD_GLOBAL | RTLD_NODELETE))
                mode = MSG_ORIG(MSG_MODE_GLOBNODEL);
        else if (MODE(lmp) & RTLD_GLOBAL)
                mode = MSG_ORIG(MSG_MODE_GLOB);
        else if (MODE(lmp) & RTLD_NODELETE)
                mode = MSG_ORIG(MSG_MODE_NODEL);
        else
                mode = MSG_ORIG(MSG_STR_EMPTY);

        dbg_print(lml, MSG_INTL(str), NAME(lmp), mode, group);
}

void
Dbg_file_bind_entry(Lm_list *lml, Bnd_desc *bdp)
{
        Conv_bnd_type_buf_t bnd_type_buf;

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;
        if (DBG_NOTDETAIL())
                return;

        /*
         * Print the dependency together with the modes of the binding.
         */
        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_BND_ADD), NAME(bdp->b_caller));
        dbg_print(lml, MSG_INTL(MSG_FIL_BND_FILE), NAME(bdp->b_depend),
            conv_bnd_type(bdp->b_flags, &bnd_type_buf));
}

void
Dbg_file_bindings(Rt_map *lmp, int flag)
{
        Conv_bnd_obj_buf_t      bnd_obj_buf;
        Conv_bnd_type_buf_t     bnd_type_buf;
        const char      *str;
        Rt_map          *tlmp;
        Lm_list         *lml = LIST(lmp);
        int             next = 0;

        if (DBG_NOTCLASS(DBG_C_INIT))
                return;
        if (DBG_NOTDETAIL())
                return;

        if (flag & RT_SORT_REV)
                str = MSG_ORIG(MSG_SCN_INIT);
        else
                str = MSG_ORIG(MSG_SCN_FINI);

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_DEP_TITLE), str,
            conv_bnd_obj(lml->lm_flags, &bnd_obj_buf));

        /* LINTED */
        for (tlmp = lmp; tlmp; tlmp = (Rt_map *)NEXT(tlmp)) {
                Bnd_desc        *bdp;
                Aliste          idx;

                /*
                 * For .init processing, only collect objects that have been
                 * relocated and haven't already been collected.
                 * For .fini processing, only collect objects that have had
                 * their .init collected, and haven't already been .fini
                 * collected.
                 */
                if (flag & RT_SORT_REV) {
                        if ((FLAGS(tlmp) & (FLG_RT_RELOCED |
                            FLG_RT_INITCLCT)) != FLG_RT_RELOCED)
                                continue;

                } else {
                        if ((flag & RT_SORT_DELETE) &&
                            ((FLAGS(tlmp) & FLG_RT_DELETE) == 0))
                                continue;
                        if (((FLAGS(tlmp) &
                            (FLG_RT_INITCLCT | FLG_RT_FINICLCT)) ==
                            FLG_RT_INITCLCT) == 0)
                                continue;
                }

                if (next++)
                        Dbg_util_nl(lml, DBG_NL_STD);

                if (DEPENDS(tlmp) == NULL)
                        dbg_print(lml, MSG_INTL(MSG_FIL_DEP_NONE), NAME(tlmp));
                else {
                        dbg_print(lml, MSG_INTL(MSG_FIL_DEP_ENT), NAME(tlmp));

                        for (APLIST_TRAVERSE(DEPENDS(tlmp), idx, bdp)) {
                                dbg_print(lml, MSG_INTL(MSG_FIL_BND_FILE),
                                    NAME(bdp->b_depend),
                                    conv_bnd_type(bdp->b_flags,
                                    &bnd_type_buf));
                        }
                }
        }
        Dbg_util_nl(lml, DBG_NL_STD);
}

void
Dbg_file_bindings_done(Lm_list *lml)
{
        if (DBG_NOTCLASS(DBG_C_INIT))
                return;
        if (DBG_NOTDETAIL())
                return;

        DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
}

void
Dbg_file_lazyload(Rt_map *clmp, const char *fname, const char *sname)
{
        Lm_list *lml = LIST(clmp);

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_LAZYLOAD), fname, NAME(clmp),
            Dbg_demangle_name(sname));
}

void
Dbg_file_preload(Lm_list *lml, const char *name)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_PRELOAD), name);
}

void
Dbg_file_needed(Rt_map *lmp, const char *name)
{
        Lm_list *lml = LIST(lmp);

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_NEEDED), name, NAME(lmp));
}

void
Dbg_file_filter(Lm_list *lml, const char *filter, const char *filtee,
    int config)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        if (config)
                dbg_print(lml, MSG_INTL(MSG_FIL_FILTER_1), filter, filtee);
        else
                dbg_print(lml, MSG_INTL(MSG_FIL_FILTER_2), filter, filtee);
}

void
Dbg_file_filtee(Lm_list *lml, const char *filter, const char *filtee, int audit)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);

        if (audit)
                dbg_print(lml, MSG_INTL(MSG_FIL_FILTEE_3), filtee);
        else if (filter)
                dbg_print(lml, MSG_INTL(MSG_FIL_FILTEE_1), filtee, filter);
        else
                dbg_print(lml, MSG_INTL(MSG_FIL_FILTEE_2), filtee);
}

void
Dbg_file_fixname(Lm_list *lml, const char *oname, const char *nname)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_FIXNAME), oname, nname);
}

void
Dbg_file_output(Ofl_desc *ofl)
{
        const char      *prefix = MSG_ORIG(MSG_PTH_OBJECT);
        char            *oname, *nname, *ofile;
        int             fd;

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;
        if (DBG_NOTDETAIL())
                return;

        /*
         * Obtain the present input object filename for concatenation to the
         * prefix name.
         */
        oname = (char *)ofl->ofl_name;
        if ((ofile = strrchr(oname, '/')) == NULL)
                ofile = oname;
        else
                ofile++;

        /*
         * Concatenate the prefix with the object filename, open the file and
         * write out the present Elf memory image.  As this is debugging we
         * ignore all errors.
         */
        if ((nname = malloc(strlen(prefix) + strlen(ofile) + 1)) != 0) {
                (void) strcpy(nname, prefix);
                (void) strcat(nname, ofile);
                if ((fd = open(nname, O_RDWR | O_CREAT | O_TRUNC,
                    0666)) != -1) {
                        (void) write(fd, ofl->ofl_nehdr, ofl->ofl_size);
                        (void) close(fd);
                }
                free(nname);
        }
}

void
Dbg_file_config_dis(Lm_list *lml, const char *config, int features)
{
        Conv_config_feat_buf_t  config_feat_buf;
        const char              *str;

        if (features == 0)
                return;

        switch (features & ~CONF_FEATMSK) {
        case DBG_CONF_IGNORE:
                str = MSG_INTL(MSG_FIL_CONFIG_ERR_1);
                break;
        case DBG_CONF_VERSION:
                str = MSG_INTL(MSG_FIL_CONFIG_ERR_2);
                break;
        case DBG_CONF_PRCFAIL:
                str = MSG_INTL(MSG_FIL_CONFIG_ERR_3);
                break;
        case DBG_CONF_CORRUPT:
                str = MSG_INTL(MSG_FIL_CONFIG_ERR_4);
                break;
        case DBG_CONF_ABIMISMATCH:
                str = MSG_INTL(MSG_FIL_CONFIG_ERR_5);
                break;
        default:
                str = conv_config_feat(features, &config_feat_buf);
                break;
        }

        Dbg_util_nl(lml, DBG_NL_FRC);
        dbg_print(lml, MSG_INTL(MSG_FIL_CONFIG_ERR), config, str);
        Dbg_util_nl(lml, DBG_NL_FRC);
}

void
Dbg_file_config_obj(Lm_list *lml, const char *dir, const char *file,
    const char *config)
{
        char    *name, _name[PATH_MAX];

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        if (file) {
                (void) snprintf(_name, PATH_MAX, MSG_ORIG(MSG_FMT_PATH),
                    dir, file);
                name = _name;
        } else
                name = (char *)dir;

        dbg_print(lml, MSG_INTL(MSG_FIL_CONFIG), name, config);
}

void
Dbg_file_del_rescan(Lm_list *lml)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_DEL_RESCAN));
}

void
Dbg_file_mode_promote(Rt_map *lmp, int mode)
{
        Conv_dl_mode_buf_t      dl_mode_buf;
        Lm_list                 *lml = LIST(lmp);

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_PROMOTE), NAME(lmp),
            conv_dl_mode(mode, 0, &dl_mode_buf));
        Dbg_util_nl(lml, DBG_NL_STD);
}

void
Dbg_file_deferred(Lm_list *lml, const char *oname, const char *nname)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_DEFERRED), oname, nname);
}

void
Dbg_file_cntl(Lm_list *lml, Aliste flmco, Aliste tlmco)
{
        Lm_cntl *lmc;
        Aliste  off;

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;
        if (DBG_NOTDETAIL())
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_CNTL_TITLE), EC_XWORD(flmco),
            EC_XWORD(tlmco));

        for (ALIST_TRAVERSE_BY_OFFSET(lml->lm_lists, off, lmc)) {
                Rt_map  *lmp;

                /* LINTED */
                for (lmp = lmc->lc_head; lmp; lmp = (Rt_map *)NEXT(lmp))
                        dbg_print(lml, MSG_ORIG(MSG_CNTL_ENTRY), EC_XWORD(off),
                            NAME(lmp));
        }
        Dbg_util_nl(lml, DBG_NL_STD);
}

/*
 * Report archive rescan operation.
 *      argv_start_ndx, argv_end_ndx - Index range of command line arguments
 *              from which archives are to be reprocessed.
 */
void
Dbg_file_ar_rescan(Lm_list *lml, int argv_start_ndx, int argv_end_ndx)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_AR_RESCAN),
            argv_start_ndx, argv_end_ndx);
        Dbg_util_nl(lml, DBG_NL_STD);
}

void
Dbg_file_ar(Lm_list *lml, const char *name, Boolean again)
{
        const char      *str;

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        if (again)
                str = MSG_INTL(MSG_STR_AGAIN);
        else
                str = MSG_ORIG(MSG_STR_EMPTY);

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_ARCHIVE), name, str);
}

void
Dbg_file_generic(Lm_list *lml, Ifl_desc *ifl)
{
        Conv_inv_buf_t inv_buf;

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_BASIC), ifl->ifl_name,
            conv_ehdr_type(ifl->ifl_ehdr->e_ident[EI_OSABI],
            ifl->ifl_ehdr->e_type, 0, &inv_buf));
}

#if SGS_REJ_NUM != (SGS_REJ_HWCAP_3 + 1)
#error SGS_REJ_NUM has changed
#endif

static const Msg reject[SGS_REJ_NUM] = {
        MSG_STR_EMPTY,
        MSG_REJ_MACH,           /* MSG_INTL(MSG_REJ_MACH) */
        MSG_REJ_CLASS,          /* MSG_INTL(MSG_REJ_CLASS) */
        MSG_REJ_DATA,           /* MSG_INTL(MSG_REJ_DATA) */
        MSG_REJ_TYPE,           /* MSG_INTL(MSG_REJ_TYPE) */
        MSG_REJ_BADFLAG,        /* MSG_INTL(MSG_REJ_BADFLAG) */
        MSG_REJ_MISFLAG,        /* MSG_INTL(MSG_REJ_MISFLAG) */
        MSG_REJ_VERSION,        /* MSG_INTL(MSG_REJ_VERSION) */
        MSG_REJ_HAL,            /* MSG_INTL(MSG_REJ_HAL) */
        MSG_REJ_US3,            /* MSG_INTL(MSG_REJ_US3) */
        MSG_REJ_STR,            /* MSG_INTL(MSG_REJ_STR) */
        MSG_REJ_UNKFILE,        /* MSG_INTL(MSG_REJ_UNKFILE) */
        MSG_REJ_UNKCAP,         /* MSG_INTL(MSG_REJ_UNKCAP) */
        MSG_REJ_HWCAP_1,        /* MSG_INTL(MSG_REJ_HWCAP_1) */
        MSG_REJ_SFCAP_1,        /* MSG_INTL(MSG_REJ_SFCAP_1) */
        MSG_REJ_MACHCAP,        /* MSG_INTL(MSG_REJ_MACHCAP) */
        MSG_REJ_PLATCAP,        /* MSG_INTL(MSG_REJ_PLATCAP) */
        MSG_REJ_HWCAP_2,        /* MSG_INTL(MSG_REJ_HWCAP_2) */
        MSG_REJ_ARCHIVE,        /* MSG_INTL(MSG_REJ_ARCHIVE) */
        MSG_REJ_KMOD,           /* MSG_INTL(MSG_REJ_KMOD) */
        MSG_REJ_HWCAP_3         /* MSG_INTL(MSG_REJ_HWCAP_3) */
};

void
Dbg_file_rejected(Lm_list *lml, Rej_desc *rej, Half mach)
{
        Conv_reject_desc_buf_t rej_buf;

        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(reject[rej->rej_type]), rej->rej_name ?
            rej->rej_name : MSG_INTL(MSG_STR_UNKNOWN),
            conv_reject_desc(rej, &rej_buf, mach));
        Dbg_util_nl(lml, DBG_NL_STD);
}

void
Dbg_file_reuse(Lm_list *lml, const char *nname, const char *oname)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_REUSE), nname, oname);
}

void
Dbg_file_skip(Lm_list *lml, const char *oname, const char *nname)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        if (oname && strcmp(nname, oname))
                dbg_print(lml, MSG_INTL(MSG_FIL_SKIP_1), nname, oname);
        else
                dbg_print(lml, MSG_INTL(MSG_FIL_SKIP_2), nname);
}

void
Dbg_file_modified(Lm_list *lml, const char *obj, const char *oname,
    const char *nname, int ofd, int nfd, Elf *oelf, Elf *nelf)
{
        const char      *str;

        if (DBG_NOTCLASS(DBG_C_FILES | DBG_C_SUPPORT))
                return;
        if (DBG_NOTDETAIL())
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_MODIFIED), oname, obj);

        if (nname != oname)
                dbg_print(lml, MSG_INTL(MSG_FIL_NAMECHANGE), nname);
        if (nfd != ofd) {
                if (nfd == -1)
                        str = MSG_INTL(MSG_FIL_IGNORE);
                else
                        str = MSG_ORIG(MSG_STR_EMPTY);
                dbg_print(lml, MSG_INTL(MSG_FIL_FDCHANGE), ofd, nfd, str);
        }
        if (nelf != oelf) {
                if (nelf == 0)
                        str = MSG_INTL(MSG_FIL_IGNORE);
                else
                        str = MSG_ORIG(MSG_STR_EMPTY);
                dbg_print(lml, MSG_INTL(MSG_FIL_ELFCHANGE), EC_NATPTR(oelf),
                    EC_NATPTR(nelf), str);
        }
        Dbg_util_nl(lml, DBG_NL_STD);
}

void
Dbg_file_cleanup(Lm_list *lml, const char *name, Aliste lmco)
{
        if (DBG_NOTCLASS(DBG_C_FILES))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_FIL_CLEANUP), name, EC_XWORD(lmco));
}