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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <strings.h>
28 #include <dwarf.h>
29 #include "_conv.h"
30 #include <dwarf_msg.h>
31
32 /*
33 * This code is primarily of interest to elfdump. Separating it from dwarf_ehe
34 * allows other tools to use dwarf_ehe without also pulling this in.
35 */
36
37 /*
38 * Translate DW_CFA_ codes, used to identify Call Frame Instructions.
39 */
40 const char *
conv_dwarf_cfa(uchar_t op,Conv_fmt_flags_t fmt_flags,Conv_inv_buf_t * inv_buf)41 conv_dwarf_cfa(uchar_t op, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf)
42 {
43 static const Msg cfa[] = {
44 MSG_DW_CFA_NOP, MSG_DW_CFA_SET_LOC,
45 MSG_DW_CFA_ADVANCE_LOC_1, MSG_DW_CFA_ADVANCE_LOC_2,
46 MSG_DW_CFA_ADVANCE_LOC_4, MSG_DW_CFA_OFFSET_EXTENDED,
47 MSG_DW_CFA_RESTORE_EXTENDED, MSG_DW_CFA_UNDEFINED,
48 MSG_DW_CFA_SAME_VALUE, MSG_DW_CFA_REGISTER,
49 MSG_DW_CFA_REMEMBER_STATE, MSG_DW_CFA_RESTORE_STATE,
50 MSG_DW_CFA_DEF_CFA, MSG_DW_CFA_DEF_CFA_REGISTER,
51 MSG_DW_CFA_DEF_CFA_OFFSET, MSG_DW_CFA_DEF_CFA_EXPRESSION,
52 MSG_DW_CFA_EXPRESSION, MSG_DW_CFA_OFFSET_EXTENDED_SF,
53 MSG_DW_CFA_DEF_CFA_SF, MSG_DW_CFA_DEF_CFA_OFFSET_SF,
54 MSG_DW_CFA_VAL_OFFSET, MSG_DW_CFA_VAL_OFFSET_SF,
55 MSG_DW_CFA_VAL_EXPRESSION
56 };
57 static const Msg cfa_mips[] = { MSG_DW_CFA_MIPS_ADV_LOC8 };
58 static const Msg cfa_gnu[] = {
59 MSG_DW_CFA_GNU_WINDOW_SAVE, MSG_DW_CFA_GNU_ARGS_SIZE,
60 MSG_DW_CFA_GNU_NEGATIVE_OFF_X
61 };
62 static const conv_ds_msg_t ds_msg_cfa = {
63 CONV_DS_MSG_INIT(0, cfa) };
64 static const conv_ds_msg_t ds_msg_cfa_mips = {
65 CONV_DS_MSG_INIT(0x1d, cfa_mips) };
66 static const conv_ds_msg_t ds_msg_cfa_gnu = {
67 CONV_DS_MSG_INIT(0x2d, cfa_gnu) };
68 static const conv_ds_t *ds_cfa[] = { CONV_DS_ADDR(ds_msg_cfa),
69 CONV_DS_ADDR(ds_msg_cfa_mips), CONV_DS_ADDR(ds_msg_cfa_gnu), NULL };
70
71
72 /*
73 * DWARF CFA opcodes are bytes. The top 2 bits are a primary
74 * opcode, and if zero, the lower 6 bits specify a sub-opcode
75 */
76 switch (op >> 6) {
77 case 0x1:
78 return (MSG_ORIG(MSG_DW_CFA_ADVANCE_LOC));
79 case 0x2:
80 return (MSG_ORIG(MSG_DW_CFA_OFFSET));
81 case 0x3:
82 return (MSG_ORIG(MSG_DW_CFA_RESTORE));
83 }
84
85 return (conv_map_ds(ELFOSABI_NONE, EM_NONE, op, ds_cfa,
86 fmt_flags, inv_buf));
87 }
88
89 /*
90 * Translate DWARF register numbers to hardware specific names
91 *
92 * If good_name is non-NULL, conv_dwarf_regname() will set the variable to
93 * True(1) if the returned string is considered to be a good name to
94 * display, and False(0) otherwise. To be considered "good":
95 *
96 * - The name must be a well known mnemonic for a register
97 * from the machine type in question.
98 *
99 * - The name must be different than the DWARF name for
100 * the same register.
101 *
102 * The returned string is usable, regardless of the value returned in
103 * *good_name.
104 */
105 const char *
conv_dwarf_regname(Half mach,Word regno,Conv_fmt_flags_t fmt_flags,int * good_name,Conv_inv_buf_t * inv_buf)106 conv_dwarf_regname(Half mach, Word regno, Conv_fmt_flags_t fmt_flags,
107 int *good_name, Conv_inv_buf_t *inv_buf)
108 {
109 static const Msg reg_amd64[67] = {
110 MSG_REG_RAX, MSG_REG_RDX,
111 MSG_REG_RCX, MSG_REG_RBX,
112 MSG_REG_RSI, MSG_REG_RDI,
113 MSG_REG_RBP, MSG_REG_RSP,
114 MSG_REG_R8, MSG_REG_R9,
115 MSG_REG_R10, MSG_REG_R11,
116 MSG_REG_R12, MSG_REG_R13,
117 MSG_REG_R14, MSG_REG_R15,
118 MSG_REG_RA, MSG_REG_PERXMM0,
119 MSG_REG_PERXMM1, MSG_REG_PERXMM2,
120 MSG_REG_PERXMM3, MSG_REG_PERXMM4,
121 MSG_REG_PERXMM5, MSG_REG_PERXMM6,
122 MSG_REG_PERXMM7, MSG_REG_PERXMM8,
123 MSG_REG_PERXMM9, MSG_REG_PERXMM10,
124 MSG_REG_PERXMM11, MSG_REG_PERXMM12,
125 MSG_REG_PERXMM13, MSG_REG_PERXMM14,
126 MSG_REG_PERXMM15, MSG_REG_PERST0,
127 MSG_REG_PERST1, MSG_REG_PERST2,
128 MSG_REG_PERST3, MSG_REG_PERST4,
129 MSG_REG_PERST5, MSG_REG_PERST6,
130 MSG_REG_PERST7, MSG_REG_PERMM0,
131 MSG_REG_PERMM1, MSG_REG_PERMM2,
132 MSG_REG_PERMM3, MSG_REG_PERMM4,
133 MSG_REG_PERMM5, MSG_REG_PERMM6,
134 MSG_REG_PERMM7, MSG_REG_PERRFLAGS,
135 MSG_REG_PERES, MSG_REG_PERCS,
136 MSG_REG_PERSS, MSG_REG_PERDS,
137 MSG_REG_PERFS, MSG_REG_PERGS,
138 MSG_REG_RESERVED, MSG_REG_RESERVED,
139 MSG_REG_PERFSDOTBASE, MSG_REG_PERGSDOTBASE,
140 MSG_REG_RESERVED, MSG_REG_RESERVED,
141 MSG_REG_PERTR, MSG_REG_PERLDTR,
142 MSG_REG_PERMXCSR, MSG_REG_PERFCW,
143 MSG_REG_PERFSW
144 };
145 static const conv_ds_msg_t ds_msg_reg_amd64 = {
146 CONV_DS_MSG_INIT(0, reg_amd64) };
147 static const conv_ds_t *ds_reg_amd64[] = {
148 CONV_DS_ADDR(ds_msg_reg_amd64), NULL };
149
150 static const Msg reg_i386[8] = {
151 MSG_REG_EAX, MSG_REG_ECX,
152 MSG_REG_EDX, MSG_REG_EBX,
153 MSG_REG_UESP, MSG_REG_EBP,
154 MSG_REG_ESI, MSG_REG_EDI
155 };
156 static const conv_ds_msg_t ds_msg_reg_i386 = {
157 CONV_DS_MSG_INIT(0, reg_i386) };
158 static const conv_ds_t *ds_reg_i386[] = {
159 CONV_DS_ADDR(ds_msg_reg_i386), NULL };
160
161 static const Msg reg_sparc[64] = {
162 MSG_REG_G0, MSG_REG_G1,
163 MSG_REG_G2, MSG_REG_G3,
164 MSG_REG_G4, MSG_REG_G5,
165 MSG_REG_G6, MSG_REG_G7,
166 MSG_REG_O0, MSG_REG_O1,
167 MSG_REG_O2, MSG_REG_O3,
168 MSG_REG_O4, MSG_REG_O5,
169 MSG_REG_O6, MSG_REG_O7,
170 MSG_REG_L0, MSG_REG_L1,
171 MSG_REG_L2, MSG_REG_L3,
172 MSG_REG_L4, MSG_REG_L5,
173 MSG_REG_L6, MSG_REG_L7,
174 MSG_REG_I0, MSG_REG_I1,
175 MSG_REG_I2, MSG_REG_I3,
176 MSG_REG_I4, MSG_REG_I5,
177 MSG_REG_I6, MSG_REG_I7,
178 MSG_REG_F0, MSG_REG_F1,
179 MSG_REG_F2, MSG_REG_F3,
180 MSG_REG_F4, MSG_REG_F5,
181 MSG_REG_F6, MSG_REG_F7,
182 MSG_REG_F8, MSG_REG_F9,
183 MSG_REG_F10, MSG_REG_F11,
184 MSG_REG_F12, MSG_REG_F13,
185 MSG_REG_F14, MSG_REG_F15,
186 MSG_REG_F16, MSG_REG_F17,
187 MSG_REG_F18, MSG_REG_F19,
188 MSG_REG_F20, MSG_REG_F21,
189 MSG_REG_F22, MSG_REG_F23,
190 MSG_REG_F24, MSG_REG_F25,
191 MSG_REG_F26, MSG_REG_F27,
192 MSG_REG_F28, MSG_REG_F29,
193 MSG_REG_F30, MSG_REG_F31
194 };
195 static const conv_ds_msg_t ds_msg_reg_sparc = {
196 CONV_DS_MSG_INIT(0, reg_sparc) };
197 static const conv_ds_t *ds_reg_sparc[] = {
198 CONV_DS_ADDR(ds_msg_reg_sparc), NULL };
199
200 switch (mach) {
201 case EM_AMD64:
202 /*
203 * amd64 has several in-bounds names we'd rather not
204 * use. R8-R15 have the same name as their DWARF counterparts.
205 * 56-57, and 60-61 are reserved, and don't have a good name.
206 */
207 if (good_name)
208 *good_name = ((regno < 8) || (regno > 15)) &&
209 (regno != 56) && (regno != 57) &&
210 (regno != 60) && (regno != 61) &&
211 (regno < ARRAY_NELTS(reg_amd64));
212 return (conv_map_ds(ELFOSABI_NONE, EM_NONE, regno,
213 ds_reg_amd64, fmt_flags, inv_buf));
214
215 case EM_386:
216 case EM_486:
217 if (good_name)
218 *good_name = (regno < ARRAY_NELTS(reg_i386));
219 return (conv_map_ds(ELFOSABI_NONE, EM_NONE, regno,
220 ds_reg_i386, fmt_flags, inv_buf));
221
222 case EM_SPARC:
223 case EM_SPARC32PLUS:
224 case EM_SPARCV9:
225 if (good_name)
226 *good_name = (regno < ARRAY_NELTS(reg_sparc));
227 return (conv_map_ds(ELFOSABI_NONE, EM_NONE, regno,
228 ds_reg_sparc, fmt_flags, inv_buf));
229 }
230
231 if (good_name)
232 *good_name = 0;
233 return (conv_invalid_val(inv_buf, regno, 0));
234 }
235