root/usr/src/cmd/sgs/liblddbg/common/relocate.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) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include        <sys/elf_SPARC.h>
#include        <debug.h>
#include        <libld.h>
#include        <conv.h>
#include        "_debug.h"
#include        "msg.h"

void
Dbg_reloc_apply_reg(Lm_list *lml, int caller, Half mach, Xword off, Xword value)
{
        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        /*
         * Print the actual relocation being applied to the specified output
         * section, the offset represents the actual relocation address, and the
         * value is the new data being written to that address.
         */
        Elf_reloc_apply_reg(lml, caller, mach, off, value);
}

void
Dbg_reloc_apply_val(Lm_list *lml, int caller, Xword off, Xword value)
{
        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        /*
         * Print the actual relocation being applied to the specified output
         * section, the offset represents the actual relocation address, and the
         * value is the new data being written to that address.
         */
        Elf_reloc_apply_val(lml, caller, off, value);
}

void
Dbg_reloc_error(Lm_list *lml, int caller, Half mach, Word type, void *reloc,
    const char *sname)
{
        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        Elf_reloc_entry_1(lml, caller, MSG_INTL(MSG_STR_IN), mach, type, reloc,
            NULL, sname, MSG_INTL(MSG_REL_BADROFFSET));
}

void
Dbg_reloc_run(Rt_map *lmp, uint_t rtype, int info, int dtype)
{
        Lm_list         *lml = LIST(lmp);
        const char      *str, *name = NAME(lmp);

        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;

        if (dtype == DBG_REL_FINISH) {
                if (info)
                        str = MSG_ORIG(MSG_STR_EMPTY);
                else
                        str = MSG_INTL(MSG_REL_FAIL);
        } else {
                if (info)
                        str = MSG_INTL(MSG_REL_PLT);
                else
                        str = MSG_ORIG(MSG_STR_EMPTY);
        }

        if (dtype == DBG_REL_START) {
                Dbg_util_nl(lml, DBG_NL_STD);
                dbg_print(lml, MSG_INTL(MSG_REL_START), name, str);

                if (DBG_NOTDETAIL())
                        return;

                Elf_reloc_title(lml, ELF_DBG_RTLD, rtype);

        } else {
                if (dtype == DBG_REL_NONE) {
                        dbg_print(lml, MSG_ORIG(MSG_STR_EMPTY));
                        dbg_print(lml, MSG_INTL(MSG_REL_NONE), name, str);
                } else
                        dbg_print(lml, MSG_INTL(MSG_REL_FINISH), name,
                            str);

                Dbg_util_nl(lml, DBG_NL_STD);
        }
}

void
Dbg_reloc_copy(Rt_map *dlmp, Rt_map *nlmp, const char *name, int zero)
{
        const char      *str;

        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        if (zero)
                str = MSG_INTL(MSG_STR_COPYZERO);
        else
                str = MSG_ORIG(MSG_STR_EMPTY);

        dbg_print(LIST(dlmp), MSG_INTL(MSG_REL_COPY), NAME(dlmp), NAME(nlmp),
            name, str);
}

void
Dbg_reloc_generate(Lm_list *lml, Os_desc *osp, Word type)
{
        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_REL_GENERATE), osp->os_name);

        if (DBG_NOTDETAIL())
                return;

        Elf_reloc_title(lml, ELF_DBG_LD, type);
}

/*
 * Issue relocation collecting header message prior to listing
 * each relocation.
 *
 * entry:
 *      lml - Link map control list
 *      osp - If sh_info was non-NULL, output section to which
 *              relocation applies. Otherwise NULL.
 *      isp - If sh_info was non-NULL, input section to which
 *              relocation applies. Otherwise NULL.
 *      risp - Relocation section
 *
 * note: osp and isp must both be NULL, or both non-NULL. risp is never NULL.
 */
void
Dbg_reloc_proc(Lm_list *lml, Os_desc *osp, Is_desc *isp, Is_desc *risp)
{
        const char      *str1, *str2;

        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;

        if (osp && osp->os_name)
                str1 = osp->os_name;
        else
                str1 =  MSG_INTL(MSG_STR_NULL);

        if (isp && isp->is_file)
                str2 = isp->is_file->ifl_name;
        else if (risp && risp->is_file)
                str2 = risp->is_file->ifl_name;
        else
                str2 = MSG_INTL(MSG_STR_NULL);

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_REL_COLLECT), str1, str2);

        if (DBG_NOTDETAIL())
                return;

        Elf_reloc_title(lml, ELF_DBG_LD, risp->is_shdr->sh_type);
}

void
Dbg_reloc_doact_title(Lm_list *lml)
{
        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_REL_ACTIVE));
        Elf_reloc_title(lml, ELF_DBG_LD_ACT, 0);
}

void
Dbg_reloc_doact(Lm_list *lml, int caller, Half mach, Word type, Rel_desc *rdesc,
    Xword off, Xword value, rel_desc_sname_func_t rel_desc_sname_func)
{
        Conv_inv_buf_t  inv_buf;
        const char      *secname;
        Os_desc         *osp;

        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        osp = RELAUX_GET_OSDESC(rdesc);
        if (osp) {
                secname = osp->os_name;
                off += osp->os_shdr->sh_offset;
        } else
                secname = MSG_ORIG(MSG_STR_EMPTY);

        Elf_reloc_entry_2(lml, caller, MSG_ORIG(MSG_STR_EMPTY), type,
            conv_reloc_type(mach, rdesc->rel_rtype, 0, &inv_buf),
            off, value, secname, (*rel_desc_sname_func)(rdesc),
            MSG_ORIG(MSG_STR_EMPTY));
}

void
Dbg_reloc_dooutrel(Lm_list *lml, Word type)
{
        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        Dbg_util_nl(lml, DBG_NL_STD);
        dbg_print(lml, MSG_INTL(MSG_REL_CREATING));
        Elf_reloc_title(lml, ELF_DBG_LD, type);
}

void
Dbg_reloc_discard(Lm_list *lml, Half mach, Rel_desc *rsp)
{
        dbg_isec_name_buf_t     buf;
        char                    *alloc_mem;
        Conv_inv_buf_t          inv_buf;
        Is_desc                 *isp;

        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        isp = rsp->rel_isdesc;
        dbg_print(lml, MSG_INTL(MSG_REL_DISCARDED),
            dbg_fmt_isec_name(isp, buf, &alloc_mem), isp->is_file->ifl_name,
            conv_reloc_type(mach, rsp->rel_rtype, 0, &inv_buf),
            EC_OFF(rsp->rel_roffset));
        if (alloc_mem != NULL)
                free(alloc_mem);
}

void
Dbg_reloc_transition(Lm_list *lml, Half mach, Word rtype, Rel_desc *rsp,
    rel_desc_sname_func_t rel_desc_sname_func)
{
        dbg_isec_name_buf_t     buf;
        char                    *alloc_mem;
        Conv_inv_buf_t          inv_buf1, inv_buf2;
        Is_desc                 *isp;

        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;

        isp = rsp->rel_isdesc;
        dbg_print(lml, MSG_INTL(MSG_REL_TRANSITION),
            conv_reloc_type(mach, rsp->rel_rtype, 0, &inv_buf1),
            dbg_fmt_isec_name(isp, buf, &alloc_mem), isp->is_file->ifl_name,
            EC_OFF(rsp->rel_roffset), (*rel_desc_sname_func)(rsp),
            conv_reloc_type(mach, rtype, 0, &inv_buf2));
        if (alloc_mem != NULL)
                free(alloc_mem);
}

void
Dbg_reloc_out(Ofl_desc *ofl, int caller, Word type, void *reloc,
    const char *secname, const char *symname)
{
        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        Elf_reloc_entry_1(ofl->ofl_lml, caller, MSG_ORIG(MSG_STR_EMPTY),
            ofl->ofl_dehdr->e_machine, type, reloc, secname, symname,
            MSG_ORIG(MSG_STR_EMPTY));
}

void
Dbg_reloc_in(Lm_list *lml, int caller, Half mach, Word type, void *reloc,
    const char *secname, Word secndx, const char *symname)
{
        dbg_isec_name_buf_t     buf;
        char                    *alloc_mem;

        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        Elf_reloc_entry_1(lml, caller, MSG_INTL(MSG_STR_IN), mach, type, reloc,
            dbg_fmt_isec_name2(secname, secndx, buf, &alloc_mem), symname,
            MSG_ORIG(MSG_STR_EMPTY));

        if (alloc_mem != NULL)
                free(alloc_mem);
}

/*
 * Used by ld when '-z relaxreloc' is in use and a relocation
 * is redirected to a kept section.
 *
 * entry:
 *      lml - Link map control list
 *      sdp - The replacement symbol to be used with the relocation,
 *              which references the kept section.
 */
void
Dbg_reloc_sloppycomdat(Lm_list *lml, Sym_desc *sdp)
{
        dbg_isec_name_buf_t     buf;
        char                    *alloc_mem;
        const char              *nfname;

        if (DBG_NOTCLASS(DBG_C_RELOC) || DBG_NOTDETAIL())
                return;

        nfname = (sdp && sdp->sd_file && sdp->sd_file->ifl_name)
            ? sdp->sd_file->ifl_name : MSG_INTL(MSG_STR_NULL);

        dbg_print(lml, MSG_INTL(MSG_REL_SLOPPYCOMDAT),
            dbg_fmt_isec_name(sdp->sd_isc, buf, &alloc_mem), nfname);
        if (alloc_mem != NULL)
                free(alloc_mem);
}

/*
 * Print a output relocation structure (Rel_desc).
 */
void
Dbg_reloc_ors_entry(Lm_list *lml, int caller, Word type, Half mach,
    Rel_desc *orsp)
{
        Conv_inv_buf_t  inv_buf;
        const char      *secname, *symname;

        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        if (orsp->rel_flags & (FLG_REL_GOT | FLG_REL_RFPTR1 | FLG_REL_RFPTR2)) {
                secname = MSG_ORIG(MSG_SCN_GOT);
        } else if (orsp->rel_flags & FLG_REL_PLT) {
                secname = MSG_ORIG(MSG_SCN_PLT);
        } else if (orsp->rel_flags & FLG_REL_BSS) {
                secname = MSG_ORIG(MSG_SCN_BSS);
        } else {
                Os_desc *osp = RELAUX_GET_OSDESC(orsp);

                secname = osp ? osp->os_name : MSG_INTL(MSG_STR_NULL);
        }

        /*
         * Register symbols can be relocated/initialized to a constant, which
         * is a special case where the symbol index is 0.
         */
        if (orsp->rel_sym != NULL)
                symname = orsp->rel_sym->sd_name;
        else
                symname = MSG_ORIG(MSG_STR_EMPTY);

        Elf_reloc_entry_2(lml, caller, MSG_INTL(MSG_STR_OUT), type,
            conv_reloc_type(mach, orsp->rel_rtype, 0, &inv_buf),
            orsp->rel_roffset, orsp->rel_raddend, secname, symname,
            MSG_ORIG(MSG_STR_EMPTY));
}

/*
 * Print a Active relocation structure (Rel_desc).
 */
void
Dbg_reloc_ars_entry(Lm_list *lml, int caller, Word type, Half mach,
    Rel_desc *arsp)
{
        Conv_inv_buf_t  inv_buf;
        const char      *secname;

        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        if (arsp->rel_flags & (FLG_REL_GOT | FLG_REL_FPTR))
                secname = MSG_ORIG(MSG_SCN_GOT);
        else
                secname = RELAUX_GET_OSDESC(arsp)->os_name;

        Elf_reloc_entry_2(lml, caller, MSG_INTL(MSG_STR_ACT), type,
            conv_reloc_type(mach, arsp->rel_rtype, 0, &inv_buf),
            arsp->rel_roffset, arsp->rel_raddend, secname,
            arsp->rel_sym->sd_name, MSG_ORIG(MSG_STR_EMPTY));
}

void
Dbg_reloc_entry(Lm_list *lml, const char *prestr, Half mach, Word type,
    void *reloc, const char *secname, const char *symname, const char *poststr)
{
        /*
         * Register relocations can use a constant initializer, in which case
         * the associated symbol is 0.
         */
        if (symname == NULL)
                symname = MSG_ORIG(MSG_STR_EMPTY);

        Elf_reloc_entry_1(lml, ELF_DBG_LD, prestr, mach, type, reloc, secname,
            symname, poststr);
}

#if     defined(_ELF64)

void
Dbg64_pltpad_to(Lm_list *lml, const char *file, Addr pltpad,
    const char *dfile, const char *symname)
{
        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        dbg_print(lml, MSG_INTL(MSG_BND_PLTPAD_TO), EC_ADDR(pltpad), file,
            dfile, symname);
}

void
Dbg64_pltpad_from(Lm_list *lml, const char *file, const char *sname,
    Addr pltpad)
{
        if (DBG_NOTCLASS(DBG_C_RELOC))
                return;
        if (DBG_NOTDETAIL())
                return;

        dbg_print(lml, MSG_INTL(MSG_BND_PLTPAD_FROM), EC_ADDR(pltpad), file,
            Dbg_demangle_name(sname));
}

#endif

/*
 * Relocation output can differ depending on the caller and the type of
 * relocation record.  However, the final diagnostic is maintained here so
 * that the various message strings remain consistent.
 *
 * elfdump:
 *               type       offset     addend    section   symbol
 *               X          X          X         X         X              (Rela)
 *
 *               type       offset               section   symbol
 *               X          X                    X         X              (Rel)
 *
 * Note, it could be argued that the section name output with elfdump(1) is
 * unnecessary, as the table itself is identified with a title that reveals
 * the section name.  However, the output does provide for grep(1)'ing for
 * individual entries and obtaining the section name with this type of input.
 *
 * ld.so.1:
 *   (prestr)    type       offset     addend    symbol
 *                                     value
 *       in      X          X          X         X                        (Rela)
 *    apply                 X          X
 *
 *   (prestr)    type       offset     value     symbol
 *       in      X          X                    X                        (Rel)
 *    apply                 X          X
 *
 * ld:
 *   (prestr)    type       offset     addend    section   symbol
 *       in      X          X          X         X         X              (Rela)
 *      act      X          X                    X         X
 *      out      X          X                    X         X
 *
 *   (prestr)    type       offset               section   symbol
 *       in      X          X                    X         X              (Rel)
 *      act      X          X                    X         X
 *      out      X          X                    X         X
 *
 * Both Rela and Rel active relocations are printed as:
 *
 *               type       offset     value     section   symbol
 *               X          X          X         X         X
 */
void
Elf_reloc_title(Lm_list *lml, int caller, Word type)
{
        if (caller == ELF_DBG_ELFDUMP) {
                if (type == SHT_RELA) {
                        if (DBG_NOTLONG())
                                dbg_print(lml, MSG_INTL(MSG_REL_EFSA_TITLE));
                        else
                                dbg_print(lml, MSG_INTL(MSG_REL_EFLA_TITLE));
                } else {
                        if (DBG_NOTLONG())
                                dbg_print(lml, MSG_INTL(MSG_REL_EFSN_TITLE));
                        else
                                dbg_print(lml, MSG_INTL(MSG_REL_EFLN_TITLE));
                }
                return;
        }
        if (caller == ELF_DBG_RTLD) {
                if (type == SHT_RELA) {
                        dbg_print(lml, MSG_INTL(MSG_REL_RTA_TITLE));
                        dbg_print(lml, MSG_INTL(MSG_REL_RTV_TITLE));
                } else
                        dbg_print(lml, MSG_INTL(MSG_REL_RTN_TITLE));
                return;
        }
        if (caller == ELF_DBG_LD) {
                if (type == SHT_RELA) {
                        if (DBG_NOTLONG())
                                dbg_print(lml, MSG_INTL(MSG_REL_LDSA_TITLE));
                        else
                                dbg_print(lml, MSG_INTL(MSG_REL_LDLA_TITLE));
                } else {
                        if (DBG_NOTLONG())
                                dbg_print(lml, MSG_INTL(MSG_REL_LDSN_TITLE));
                        else
                                dbg_print(lml, MSG_INTL(MSG_REL_LDLN_TITLE));
                }
                return;
        }
        if (caller == ELF_DBG_LD_ACT) {
                if (DBG_NOTLONG())
                        dbg_print(lml, MSG_INTL(MSG_REL_LDSV_TITLE));
                else
                        dbg_print(lml, MSG_INTL(MSG_REL_LDLV_TITLE));
                return;
        }
}

void
Elf_reloc_entry_2(Lm_list *lml, int caller, const char *prestr, Word type,
    const char *typestr, Addr off, Sxword add, const char *secname,
    const char *symname, const char *poststr)
{
        if (symname)
                symname = Elf_demangle_name(symname);
        else
                symname = MSG_ORIG(MSG_STR_EMPTY);

        if (caller == ELF_DBG_ELFDUMP) {
                if (type == SHT_RELA) {
                        if (DBG_NOTLONG())
                                dbg_print(lml, MSG_INTL(MSG_REL_EFSA_ENTRY),
                                    typestr, EC_OFF(off), EC_SXWORD(add),
                                    secname, symname);
                        else
                                dbg_print(lml, MSG_INTL(MSG_REL_EFLA_ENTRY),
                                    typestr, EC_OFF(off), EC_SXWORD(add),
                                    secname, symname);
                } else {
                        if (DBG_NOTLONG())
                                dbg_print(lml, MSG_INTL(MSG_REL_EFSN_ENTRY),
                                    typestr, EC_OFF(off), secname, symname);
                        else
                                dbg_print(lml, MSG_INTL(MSG_REL_EFLN_ENTRY),
                                    typestr, EC_OFF(off), secname, symname);
                }
                return;
        }
        if (caller == ELF_DBG_RTLD) {
                if (type == SHT_RELA)
                        dbg_print(lml, MSG_INTL(MSG_REL_RTA_ENTRY), prestr,
                            typestr, EC_OFF(off), EC_SXWORD(add), symname,
                            poststr);
                else
                        dbg_print(lml, MSG_INTL(MSG_REL_RTN_ENTRY), prestr,
                            typestr, EC_OFF(off), symname, poststr);
                return;
        }
        if (caller == ELF_DBG_LD) {
                if (type == SHT_RELA) {
                        if (DBG_NOTLONG())
                                dbg_print(lml, MSG_INTL(MSG_REL_LDSA_ENTRY),
                                    prestr, typestr, EC_OFF(off),
                                    EC_SXWORD(add), secname, symname, poststr);
                        else
                                dbg_print(lml, MSG_INTL(MSG_REL_LDLA_ENTRY),
                                    prestr, typestr, EC_OFF(off),
                                    EC_SXWORD(add), secname, symname, poststr);
                } else {
                        if (DBG_NOTLONG())
                                dbg_print(lml, MSG_INTL(MSG_REL_LDSN_ENTRY),
                                    prestr, typestr, EC_OFF(off), secname,
                                    symname, poststr);
                        else
                                dbg_print(lml, MSG_INTL(MSG_REL_LDLN_ENTRY),
                                    prestr, typestr, EC_OFF(off), secname,
                                    symname, poststr);
                }
                return;
        }
        if (caller == ELF_DBG_LD_ACT) {
                longlong_t      value = EC_SXWORD(add);

                /*
                 * The following diagnostics are used to create active
                 * relocation output.  A "value" field is specified in the
                 * same column as a RELA addend.
                 *
                 * We have to work around an issue caused by the use of a
                 * common format string to handle both the 32-bit and 64-bit
                 * cases.  'add' is a signed value.  In the ELFCLASS32 case
                 * where add is a 32-bit value, the EC_SXWORD() macro widens
                 * it to a 64-bit signed value, which will cause sign extension
                 * in the upper 32-bits.  As we are displaying the value in hex,
                 * this causes our 32-bit value to be displayed with 16 hex
                 * digits instead of 8, as would be appropriate for ELFCLASS32.
                 *
                 * The solution is to mask off the unwanted bits before
                 * formatting the value.  The use of 'longlong_t' instead of
                 * Elf64_Sxword (used by the EC_SXWORD macro) is for the
                 * benefit of lint.
                 */
#if     !defined(_ELF64)
                value &= 0xffffffff;
#endif
                if (DBG_NOTLONG())
                        dbg_print(lml, MSG_INTL(MSG_REL_LDSA_ENTRY),
                            prestr, typestr, EC_OFF(off),
                            value, secname, symname, poststr);
                else
                        dbg_print(lml, MSG_INTL(MSG_REL_LDLA_ENTRY),
                            prestr, typestr, EC_OFF(off),
                            value, secname, symname, poststr);
        }
}

void
Elf_reloc_entry_1(Lm_list *lml, int caller, const char *prestr, Half mach,
    Word type, void *reloc, const char *secname, const char *symname,
    const char *poststr)
{
        Conv_inv_buf_t  inv_buf;
        Addr            off;
        Sxword          add;
        const char      *str;

        if (type == SHT_RELA) {
                Rela    *rela = (Rela *)reloc;

                str = conv_reloc_type(mach, ELF_R_TYPE(rela->r_info, mach),
                    0, &inv_buf);
                off = rela->r_offset;
                add = rela->r_addend;
        } else {
                Rel     *rel = (Rel *)reloc;

                str = conv_reloc_type(mach, ELF_R_TYPE(rel->r_info, mach),
                    0, &inv_buf);
                off = rel->r_offset;
                add = 0;
        }
        Elf_reloc_entry_2(lml, caller, prestr, type, str, off, add, secname,
            symname, poststr);
}

/*
 * Display any applied relocations.  Presently, these are only called from
 * ld.so.1, but the interfaces are maintained here to insure consistency with
 * other relocation diagnostics.
 */
void
Elf_reloc_apply_val(Lm_list *lml, int caller, Xword offset, Xword value)
{
        if (caller == ELF_DBG_RTLD)
                dbg_print(lml, MSG_INTL(MSG_REL_RT_APLVAL), EC_XWORD(offset),
                    EC_XWORD(value));
}
void
Elf_reloc_apply_reg(Lm_list *lml, int caller, Half mach, Xword offset,
    Xword value)
{
        Conv_inv_buf_t inv_buf;

        if (caller == ELF_DBG_RTLD)
                dbg_print(lml, MSG_INTL(MSG_REL_RT_APLREG),
                    conv_sym_value(mach, STT_SPARC_REGISTER,
                    offset, &inv_buf), EC_XWORD(value));
}