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 struct match {
42 tdesc_t *m_ret;
43 const char *m_name;
44 };
45
46 static int
matching_iidesc(void * arg1,void * arg2)47 matching_iidesc(void *arg1, void *arg2)
48 {
49 iidesc_t *iidesc = arg1;
50 struct match *match = arg2;
51 if (!streq(iidesc->ii_name, match->m_name))
52 return (0);
53
54 if (iidesc->ii_type != II_TYPE && iidesc->ii_type != II_SOU)
55 return (0);
56
57 match->m_ret = iidesc->ii_dtype;
58 return (-1);
59 }
60
61 static tdesc_t *
lookup_tdesc(tdata_t * td,char const * name)62 lookup_tdesc(tdata_t *td, char const *name)
63 {
64 struct match match = { NULL, name };
65 iter_iidescs_by_name(td, name, matching_iidesc, &match);
66 return (match.m_ret);
67 }
68
69 /*
70 * The cpu structure grows, with the addition of a machcpu member, if
71 * _MACHDEP is defined. This means that, for example, the cpu structure
72 * in unix is different from the cpu structure in genunix. As one might
73 * expect, this causes merges to fail. Since everyone indirectly contains
74 * a pointer to a CPU structure, the failed merges can cause massive amounts
75 * of duplication. In the case of unix uniquifying against genunix, upwards
76 * of 50% of the structures were unmerged due to this problem. We fix this
77 * by adding a cpu_m member. If machcpu hasn't been defined in our module,
78 * we make a forward node for it.
79 */
80 static void
fix_small_cpu_struct(tdata_t * td,size_t ptrsize)81 fix_small_cpu_struct(tdata_t *td, size_t ptrsize)
82 {
83 tdesc_t *cput, *cpu;
84 tdesc_t *machcpu;
85 mlist_t *ml, *lml;
86 mlist_t *cpum;
87 int foundcpucyc = 0;
88
89 /*
90 * We're going to take the circuitous route finding the cpu structure,
91 * because we want to make sure that we find the right one. It would
92 * be nice if we could verify the header name too. DWARF might not
93 * have the cpu_t, so we let this pass.
94 */
95 if ((cput = lookup_tdesc(td, "cpu_t")) != NULL) {
96 if (cput->t_type != TYPEDEF)
97 return;
98 cpu = cput->t_tdesc;
99 } else {
100 cpu = lookup_tdesc(td, "cpu");
101 }
102
103 if (cpu == NULL)
104 return;
105
106 if (!streq(cpu->t_name, "cpu") || cpu->t_type != STRUCT)
107 return;
108
109 for (ml = cpu->t_members, lml = NULL; ml;
110 lml = ml, ml = ml->ml_next) {
111 if (strcmp(ml->ml_name, "cpu_cyclic") == 0)
112 foundcpucyc = 1;
113 }
114
115 if (foundcpucyc == 0 || lml == NULL ||
116 strcmp(lml->ml_name, "cpu_m") == 0)
117 return;
118
119 /*
120 * We need to derive the right offset for the fake cpu_m member. To do
121 * that, we require a special unused member to be the last member
122 * before the 'cpu_m', that we encode knowledge of here. ABI alignment
123 * on all platforms is such that we only need to add a pointer-size
124 * number of bits to get the right offset for cpu_m. This would most
125 * likely break if gcc's -malign-double were ever used, but that option
126 * breaks the ABI anyway.
127 */
128 if (!streq(lml->ml_name, "cpu_m_pad") &&
129 getenv("CTFCONVERT_PERMISSIVE") == NULL) {
130 terminate("last cpu_t member before cpu_m is %s; "
131 "it must be cpu_m_pad.\n", lml->ml_name);
132 }
133
134 if ((machcpu = lookup_tdesc(td, "machcpu")) == NULL) {
135 machcpu = xcalloc(sizeof (*machcpu));
136 machcpu->t_name = xstrdup("machcpu");
137 machcpu->t_id = td->td_nextid++;
138 machcpu->t_type = FORWARD;
139 } else if (machcpu->t_type != STRUCT) {
140 return;
141 }
142
143 debug(3, "Adding cpu_m machcpu %s to cpu struct\n",
144 (machcpu->t_type == FORWARD ? "forward" : "struct"));
145
146 cpum = xmalloc(sizeof (*cpum));
147 cpum->ml_offset = lml->ml_offset + (ptrsize * NBBY);
148 cpum->ml_size = 0;
149 cpum->ml_name = xstrdup("cpu_m");
150 cpum->ml_type = machcpu;
151 cpum->ml_next = NULL;
152
153 lml->ml_next = cpum;
154 }
155
156 void
cvt_fixups(tdata_t * td,size_t ptrsize)157 cvt_fixups(tdata_t *td, size_t ptrsize)
158 {
159 fix_small_cpu_struct(td, ptrsize);
160 }
161