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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 /*
  29  * Workarounds for stabs generation bugs in the compiler and general needed
  30  * fixups.
  31  */
  32 
  33 #include <stdio.h>
  34 #include <strings.h>
  35 
  36 #include "ctf_headers.h"
  37 #include "ctftools.h"
  38 #include "hash.h"
  39 #include "memory.h"
  40 
  41 /*
  42  * Due to 4432619, the 6.1 compiler will sometimes incorrectly generate pointer
  43  * stabs.  Given a struct foo, and a corresponding typedef struct foo foo_t.
  44  * In some cases, when faced with a pointer to a foo_t, the compiler will
  45  * sometimes generate a stab that describes a pointer to a struct foo.
  46  * Regardless of correctness, this breaks merges, as it occurs inconsistently
  47  * by file.  The following two routines know how to recognize and repair foo_t *
  48  * and foo_t ** bugs in a specific set of cases.  There is no general way to
  49  * solve this problem without a fix to the compiler.  In general, cases should
  50  * only be added to these routines to fix merging problems in genunix.
  51  */
  52 static void
  53 fix_ptrptr_to_struct(tdata_t *td)
  54 {
  55         char *strs[2] = { "as", "fdbuffer" };
  56         char *mems[2] = { "a_objectdir", "fd_shadow" };
  57         char *acts[2] = { "vnode", "page" };
  58         char *tgts[2] = { "vnode_t", "page_t" };
  59         tdesc_t *str;
  60         tdesc_t *act, *tgt;
  61         tdesc_t *p1, *p2;
  62         mlist_t *ml;
  63         int i;
  64 
  65         for (i = 0; i < sizeof (strs) / sizeof (strs[0]); i++) {
  66                 if (!(str = lookupname(strs[i])) || str->t_type != STRUCT)
  67                         continue;
  68 
  69                 for (ml = str->t_members; ml; ml = ml->ml_next) {
  70                         if (streq(ml->ml_name, mems[i]))
  71                                 break;
  72                 }
  73                 if (!ml)
  74                         continue;
  75 
  76                 if (ml->ml_type->t_type != POINTER || ml->ml_type->t_name ||
  77                     ml->ml_type->t_tdesc->t_type != POINTER ||
  78                     ml->ml_type->t_tdesc->t_name)
  79                         continue;
  80 
  81                 act = ml->ml_type->t_tdesc->t_tdesc;
  82                 if (act->t_type != STRUCT || !streq(act->t_name, acts[i]))
  83                         continue;
  84 
  85                 if (!(tgt = lookupname(tgts[i])) || tgt->t_type != TYPEDEF)
  86                         continue;
  87 
  88                 /* We have an instance of the bug */
  89                 p2 = xcalloc(sizeof (*p2));
  90                 p2->t_type = POINTER;
  91                 p2->t_id = td->td_nextid++;
  92                 p2->t_tdesc = tgt;
  93 
  94                 p1 = xcalloc(sizeof (*p1));
  95                 p1->t_type = POINTER;
  96                 p1->t_id = td->td_nextid++;
  97                 p1->t_tdesc = p2;
  98 
  99                 ml->ml_type = p1;
 100 
 101                 debug(3, "Fixed %s->%s => ptrptr struct %s bug\n",
 102                     strs[i], mems[i], acts[i]);
 103         }
 104 }
 105 
 106 static void
 107 fix_ptr_to_struct(tdata_t *td)
 108 {
 109         char *strs[2] = { "vmem", "id_space" };
 110         char *mems[2] = { NULL, "is_vmem" };
 111         tdesc_t *ptr = NULL;
 112         tdesc_t *str, *vmt;
 113         mlist_t *ml;
 114         int i;
 115 
 116         if ((vmt = lookupname("vmem_t")) == NULL || vmt->t_type != TYPEDEF)
 117                 return;
 118 
 119         for (i = 0; i < sizeof (strs) / sizeof (strs[0]); i++) {
 120                 if (!(str = lookupname(strs[i])) || str->t_type != STRUCT)
 121                         continue;
 122 
 123                 for (ml = str->t_members; ml; ml = ml->ml_next) {
 124                         if (mems[i] && !streq(ml->ml_name, mems[i]))
 125                                 continue;
 126 
 127                         if (ml->ml_type->t_type != POINTER ||
 128                             ml->ml_type->t_name ||
 129                             (ml->ml_type->t_tdesc->t_type != STRUCT &&
 130                             ml->ml_type->t_tdesc->t_type != FORWARD) ||
 131                             !streq(ml->ml_type->t_tdesc->t_name, "vmem"))
 132                                 continue;
 133 
 134                         debug(3, "Fixed %s->%s => ptr struct vmem bug\n",
 135                             strs[i], ml->ml_name);
 136 
 137                         if (!ptr) {
 138                                 ptr = xcalloc(sizeof (*ptr));
 139                                 ptr->t_type = POINTER;
 140                                 ptr->t_id = td->td_nextid++;
 141                                 ptr->t_tdesc = vmt;
 142                         }
 143 
 144                         ml->ml_type = ptr;
 145                 }
 146         }
 147 }
 148 
 149 /*
 150  * Fix stabs generation bugs.  These routines must be run before the
 151  * post-conversion merge
 152  */
 153 void
 154 cvt_fixstabs(tdata_t *td)
 155 {
 156         fix_ptrptr_to_struct(td);
 157         fix_ptr_to_struct(td);
 158 }
 159 
 160 struct match {
 161         tdesc_t *m_ret;
 162         const char *m_name;
 163 };
 164 
 165 static int
 166 matching_iidesc(iidesc_t *iidesc, struct match *match)
 167 {
 168         if (!streq(iidesc->ii_name, match->m_name))
 169                 return (0);
 170 
 171         if (iidesc->ii_type != II_TYPE && iidesc->ii_type != II_SOU)
 172                 return (0);
 173 
 174         match->m_ret = iidesc->ii_dtype;
 175         return (-1);
 176 }
 177 
 178 static tdesc_t *
 179 lookup_tdesc(tdata_t *td, const char *name)
 180 {
 181         struct match match = { NULL, name };
 182         iter_iidescs_by_name(td, name, (int (*)())matching_iidesc, &match);
 183         return (match.m_ret);
 184 }
 185 
 186 /*
 187  * The cpu structure grows, with the addition of a machcpu member, if
 188  * _MACHDEP is defined.  This means that, for example, the cpu structure
 189  * in unix is different from the cpu structure in genunix.  As one might
 190  * expect, this causes merges to fail.  Since everyone indirectly contains
 191  * a pointer to a CPU structure, the failed merges can cause massive amounts
 192  * of duplication.  In the case of unix uniquifying against genunix, upwards
 193  * of 50% of the structures were unmerged due to this problem.  We fix this
 194  * by adding a cpu_m member.  If machcpu hasn't been defined in our module,
 195  * we make a forward node for it.
 196  */
 197 static void
 198 fix_small_cpu_struct(tdata_t *td, size_t ptrsize)
 199 {
 200         tdesc_t *cput, *cpu;
 201         tdesc_t *machcpu;
 202         mlist_t *ml, *lml;
 203         mlist_t *cpum;
 204         int foundcpucyc = 0;
 205 
 206         /*
 207          * We're going to take the circuitous route finding the cpu structure,
 208          * because we want to make sure that we find the right one.  It would
 209          * be nice if we could verify the header name too.  DWARF might not
 210          * have the cpu_t, so we let this pass.
 211          */
 212         if ((cput = lookup_tdesc(td, "cpu_t")) != NULL) {
 213                 if (cput->t_type != TYPEDEF)
 214                         return;
 215                 cpu = cput->t_tdesc;
 216         } else {
 217                 cpu = lookup_tdesc(td, "cpu");
 218         }
 219 
 220         if (cpu == NULL)
 221                 return;
 222 
 223         if (!streq(cpu->t_name, "cpu") || cpu->t_type != STRUCT)
 224                 return;
 225 
 226         for (ml = cpu->t_members, lml = NULL; ml;
 227             lml = ml, ml = ml->ml_next) {
 228                 if (strcmp(ml->ml_name, "cpu_cyclic") == 0)
 229                         foundcpucyc = 1;
 230         }
 231 
 232         if (foundcpucyc == 0 || lml == NULL ||
 233             strcmp(lml->ml_name, "cpu_m") == 0)
 234                 return;
 235 
 236         /*
 237          * We need to derive the right offset for the fake cpu_m member.  To do
 238          * that, we require a special unused member to be the last member
 239          * before the 'cpu_m', that we encode knowledge of here.  ABI alignment
 240          * on all platforms is such that we only need to add a pointer-size
 241          * number of bits to get the right offset for cpu_m.  This would most
 242          * likely break if gcc's -malign-double were ever used, but that option
 243          * breaks the ABI anyway.
 244          */
 245         if (!streq(lml->ml_name, "cpu_m_pad") &&
 246             getenv("CTFCONVERT_PERMISSIVE") == NULL) {
 247                 terminate("last cpu_t member before cpu_m is %s; "
 248                     "it must be cpu_m_pad.\n", lml->ml_name);
 249         }
 250 
 251         if ((machcpu = lookup_tdesc(td, "machcpu")) == NULL) {
 252                 machcpu = xcalloc(sizeof (*machcpu));
 253                 machcpu->t_name = xstrdup("machcpu");
 254                 machcpu->t_id = td->td_nextid++;
 255                 machcpu->t_type = FORWARD;
 256         } else if (machcpu->t_type != STRUCT) {
 257                 return;
 258         }
 259 
 260         debug(3, "Adding cpu_m machcpu %s to cpu struct\n",
 261             (machcpu->t_type == FORWARD ? "forward" : "struct"));
 262 
 263         cpum = xmalloc(sizeof (*cpum));
 264         cpum->ml_offset = lml->ml_offset + (ptrsize * NBBY);
 265         cpum->ml_size = 0;
 266         cpum->ml_name = xstrdup("cpu_m");
 267         cpum->ml_type = machcpu;
 268         cpum->ml_next = NULL;
 269 
 270         lml->ml_next = cpum;
 271 }
 272 
 273 void
 274 cvt_fixups(tdata_t *td, size_t ptrsize)
 275 {
 276         fix_small_cpu_struct(td, ptrsize);
 277 }