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 */
40const char *
41conv_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 */
105const char *
106conv_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