1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 #include        <stdio.h>
  27 #include        "_debug.h"
  28 #include        "msg.h"
  29 #include        "libld.h"
  30 
  31 static const char *
  32 fmt_human_units(size_t bytes, char *buf, size_t bufsize)
  33 {
  34         static int      unit_arr[] = { 'K', 'M', 'G', 'T' };
  35 
  36         int             i, unit_ch;
  37         size_t          unit_bytes = bytes;
  38 
  39         /* Convert to human readable units */
  40         for (i = 0; i < sizeof (unit_arr) / sizeof (unit_arr[0]); i++) {
  41                 if (unit_bytes < 1024)
  42                         break;
  43                 unit_ch = unit_arr[i];
  44                 unit_bytes /= 1024;
  45         }
  46         if (unit_bytes == bytes)
  47                 buf[0] = '\0';
  48         else
  49                 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_MEMUNIT),
  50                     EC_XWORD(unit_bytes), unit_ch);
  51 
  52         return (buf);
  53 }
  54 
  55 /*
  56  * Generate a relocation cache statistics line for the active or
  57  * output relocation cache.
  58  *
  59  * entry:
  60  *      ofl - output file descriptor
  61  *      alp - One of ofl->ofl_actrels or ofl->ofl_outrels.
  62  */
  63 static void
  64 rel_cache_statistics(Ofl_desc *ofl, const char *title, APlist *alp)
  65 {
  66         Lm_list         *lml = ofl->ofl_lml;
  67         size_t          desc_cnt = 0, desc_used = 0, bytes;
  68         Aliste          idx;
  69         Rel_cachebuf    *rcp;
  70         char            unit_buf[CONV_INV_BUFSIZE + 10];
  71 
  72         /* Sum the total memory allocated across all the buffers */
  73         for (APLIST_TRAVERSE(alp, idx, rcp)) {
  74                 desc_cnt += rcp->rc_end - rcp->rc_arr;
  75                 desc_used += rcp->rc_free - rcp->rc_arr;
  76         }
  77         bytes = desc_cnt * sizeof (Rel_desc);
  78 
  79         dbg_print(lml, MSG_INTL(MSG_STATS_REL_CACHE), title,
  80             EC_WORD(aplist_nitems(alp)),
  81             EC_XWORD(desc_used), EC_XWORD(desc_cnt),
  82             (desc_cnt == 0) ? 100 : EC_WORD((desc_used * 100) / desc_cnt),
  83             EC_XWORD(bytes),
  84             fmt_human_units(bytes, unit_buf, sizeof (unit_buf)));
  85 }
  86 
  87 
  88 /*
  89  * Generate a statistics line for the auxiliary relocation descriptor cache.
  90  *
  91  * entry:
  92  *      ofl - output file descriptor
  93  */
  94 static void
  95 rel_aux_cache_statistics(Ofl_desc *ofl)
  96 {
  97         Rel_aux_cachebuf        *racp;
  98         Lm_list *lml = ofl->ofl_lml;
  99         size_t  desc_cnt = 0, desc_used = 0, bytes;
 100         Aliste  idx;
 101         char    unit_buf[CONV_INV_BUFSIZE + 10];
 102 
 103         /* Sum the total memory allocated across all the buffers */
 104         for (APLIST_TRAVERSE(ofl->ofl_relaux, idx, racp)) {
 105                 desc_cnt += racp->rac_end - racp->rac_arr;
 106                 desc_used += racp->rac_free - racp->rac_arr;
 107         }
 108         bytes = desc_cnt * sizeof (Rel_desc);
 109 
 110         dbg_print(lml, MSG_INTL(MSG_STATS_REL_ACACHE),
 111             EC_WORD(aplist_nitems(ofl->ofl_relaux)),
 112             EC_XWORD(desc_used), EC_XWORD(desc_cnt),
 113             (desc_cnt == 0) ? 100 : EC_WORD((desc_used * 100) / desc_cnt),
 114             EC_XWORD(bytes),
 115             fmt_human_units(bytes, unit_buf, sizeof (unit_buf)));
 116 }
 117 
 118 
 119 void
 120 Dbg_statistics_ld(Ofl_desc *ofl)
 121 {
 122         Lm_list *lml = ofl->ofl_lml;
 123 
 124         if (DBG_NOTCLASS(DBG_C_STATS))
 125                 return;
 126 
 127         Dbg_util_nl(lml, DBG_NL_STD);
 128         dbg_print(lml, MSG_INTL(MSG_STATS_GENERAL));
 129 
 130         if (ofl->ofl_objscnt || ofl->ofl_soscnt || ofl->ofl_arscnt) {
 131                 dbg_print(lml, MSG_INTL(MSG_STATS_FILES),
 132                     EC_XWORD(ofl->ofl_objscnt), EC_XWORD(ofl->ofl_soscnt),
 133                     EC_XWORD(ofl->ofl_arscnt));
 134         }
 135 
 136         if (ofl->ofl_locscnt || ofl->ofl_globcnt) {
 137                 dbg_print(lml, MSG_INTL(MSG_STATS_SYMBOLS_OUT),
 138                     EC_XWORD(ofl->ofl_globcnt), EC_XWORD(ofl->ofl_locscnt));
 139         }
 140         if (ofl->ofl_entercnt || ofl->ofl_scopecnt || ofl->ofl_elimcnt) {
 141                 dbg_print(lml, MSG_INTL(MSG_STATS_SYMBOLS_IN),
 142                     EC_XWORD(ofl->ofl_entercnt), EC_XWORD(ofl->ofl_scopecnt),
 143                     EC_XWORD(ofl->ofl_elimcnt));
 144         }
 145 
 146         dbg_print(lml, MSG_INTL(MSG_STATS_REL_OUT),
 147             EC_XWORD(ofl->ofl_outrels.rc_cnt));
 148 
 149         dbg_print(lml, MSG_INTL(MSG_STATS_REL_IN),
 150             EC_XWORD(ofl->ofl_entrelscnt), EC_XWORD(ofl->ofl_actrels.rc_cnt));
 151 
 152         dbg_print(lml, MSG_INTL(MSG_STATS_REL_TICACHE));
 153         rel_cache_statistics(ofl, MSG_INTL(MSG_STATS_REL_TIOUT),
 154             ofl->ofl_outrels.rc_list);
 155         rel_cache_statistics(ofl, MSG_INTL(MSG_STATS_REL_TIACT),
 156             ofl->ofl_actrels.rc_list);
 157         rel_aux_cache_statistics(ofl);
 158 }
 159 
 160 void
 161 Dbg_statistics_ar(Ofl_desc *ofl)
 162 {
 163         Aliste          idx;
 164         Ar_desc         *adp;
 165         Elf_Arsym       *arsym;
 166         Ar_aux          *aux;
 167         Lm_list         *lml = ofl->ofl_lml;
 168 
 169         if (DBG_NOTCLASS(DBG_C_STATS | DBG_C_UNUSED))
 170                 return;
 171 
 172         Dbg_util_nl(lml, DBG_NL_STD);
 173         for (APLIST_TRAVERSE(ofl->ofl_ars, idx, adp)) {
 174                 size_t  poffset = 0;
 175                 uint_t  count = 0, used = 0;
 176 
 177                 if ((adp->ad_flags & FLG_ARD_EXTRACT) == 0) {
 178                         Dbg_unused_file(lml, adp->ad_name, 0, 0);
 179                         continue;
 180                 }
 181 
 182                 if (DBG_NOTCLASS(DBG_C_STATS))
 183                         continue;
 184 
 185                 arsym = adp->ad_start;
 186                 aux = adp->ad_aux;
 187                 while ((arsym != NULL) && (arsym->as_off != NULL)) {
 188                         /*
 189                          * Assume that symbols from the same member file are
 190                          * adjacent within the archive symbol table.
 191                          */
 192                         if (poffset != arsym->as_off) {
 193                                 count++;
 194                                 poffset = arsym->as_off;
 195                                 if (aux->au_mem == FLG_ARMEM_PROC)
 196                                         used++;
 197                         }
 198                         aux++, arsym++;
 199                 }
 200                 if ((count == 0) || (used == 0))
 201                         continue;
 202 
 203                 dbg_print(lml, MSG_INTL(MSG_STATS_AR), adp->ad_name, count,
 204                     used, ((used * 100) / count));
 205         }
 206         Dbg_util_nl(lml, DBG_NL_STD);
 207 }