1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2013-2018, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7#include "AttributeClasses.h"
8#include "Dwarf.h"
9
10
11enum {
12	AC_ADDRESS		= 1 << (ATTRIBUTE_CLASS_ADDRESS - 1),
13	AC_ADDRPTR		= 1 << (ATTRIBUTE_CLASS_ADDRPTR - 1),
14	AC_BLOCK		= 1 << (ATTRIBUTE_CLASS_BLOCK - 1),
15	AC_CONSTANT		= 1 << (ATTRIBUTE_CLASS_CONSTANT - 1),
16	AC_FLAG			= 1 << (ATTRIBUTE_CLASS_FLAG - 1),
17	AC_LINEPTR		= 1 << (ATTRIBUTE_CLASS_LINEPTR - 1),
18	AC_LOCLIST   	= 1 << (ATTRIBUTE_CLASS_LOCLIST - 1),
19	AC_LOCLISTPTR	= 1 << (ATTRIBUTE_CLASS_LOCLISTPTR - 1),
20	AC_MACPTR		= 1 << (ATTRIBUTE_CLASS_MACPTR - 1),
21	AC_RANGELIST   	= 1 << (ATTRIBUTE_CLASS_RANGELIST - 1),
22	AC_RANGELISTPTR	= 1 << (ATTRIBUTE_CLASS_RANGELISTPTR - 1),
23	AC_REFERENCE	= 1 << (ATTRIBUTE_CLASS_REFERENCE - 1),
24	AC_STRING		= 1 << (ATTRIBUTE_CLASS_STRING - 1),
25	AC_STROFFSETSPTR= 1 << (ATTRIBUTE_CLASS_STROFFSETSPTR - 1),
26};
27
28
29struct attribute_info_entry {
30	const char*	name;
31	uint16		value;
32	uint16		classes;
33};
34
35struct attribute_name_info_entry {
36	const char*				name;
37	DebugInfoEntrySetter	setter;
38	uint16					value;
39	uint16					classes;
40};
41
42
43#undef ENTRY
44#define ENTRY(name)	"DW_AT_" #name, &DebugInfoEntry::AddAttribute_##name, \
45	DW_AT_##name
46
47static const attribute_name_info_entry kAttributeNameInfos[] = {
48	{ ENTRY(sibling),				AC_REFERENCE },
49	{ ENTRY(location),				AC_BLOCK | AC_LOCLIST },
50	{ ENTRY(name),					AC_STRING },
51	{ ENTRY(ordering),				AC_CONSTANT },
52	{ ENTRY(byte_size),				AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
53	{ ENTRY(bit_offset),			AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
54	{ ENTRY(bit_size),				AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
55	{ ENTRY(stmt_list),				AC_LINEPTR },
56	{ ENTRY(low_pc),				AC_ADDRESS | AC_CONSTANT | AC_REFERENCE },
57	{ ENTRY(high_pc),				AC_ADDRESS | AC_CONSTANT | AC_REFERENCE },
58	{ ENTRY(language),				AC_CONSTANT },
59	{ ENTRY(discr),					AC_REFERENCE },
60	{ ENTRY(discr_value),			AC_CONSTANT },
61	{ ENTRY(visibility),			AC_CONSTANT },
62	{ ENTRY(import),				AC_REFERENCE },
63	{ ENTRY(string_length),			AC_BLOCK | AC_LOCLIST },
64	{ ENTRY(common_reference),		AC_REFERENCE },
65	{ ENTRY(comp_dir),				AC_STRING },
66	{ ENTRY(const_value),			AC_BLOCK | AC_CONSTANT | AC_STRING },
67	{ ENTRY(containing_type),		AC_REFERENCE },
68	{ ENTRY(default_value),			AC_REFERENCE | AC_CONSTANT | AC_FLAG },
69	{ ENTRY(inline),				AC_CONSTANT },
70	{ ENTRY(is_optional),			AC_FLAG },
71	{ ENTRY(lower_bound),			AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
72	{ ENTRY(producer),				AC_STRING },
73	{ ENTRY(prototyped),			AC_FLAG },
74	{ ENTRY(return_addr),			AC_BLOCK | AC_LOCLIST },
75	{ ENTRY(start_scope),			AC_CONSTANT },
76	{ ENTRY(bit_stride),			AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
77	{ ENTRY(upper_bound),			AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
78	{ ENTRY(abstract_origin),		AC_REFERENCE },
79	{ ENTRY(accessibility),			AC_CONSTANT },
80	{ ENTRY(address_class),			AC_CONSTANT },
81	{ ENTRY(artificial),			AC_FLAG },
82	{ ENTRY(base_types),			AC_REFERENCE },
83	{ ENTRY(calling_convention),	AC_CONSTANT },
84	{ ENTRY(count),					AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
85	{ ENTRY(data_member_location),	AC_BLOCK | AC_CONSTANT | AC_LOCLIST },
86	{ ENTRY(decl_column),			AC_CONSTANT },
87	{ ENTRY(decl_file),				AC_CONSTANT },
88	{ ENTRY(decl_line),				AC_CONSTANT },
89	{ ENTRY(declaration),			AC_FLAG },
90	{ ENTRY(discr_list),			AC_BLOCK },
91	{ ENTRY(encoding),				AC_CONSTANT },
92	{ ENTRY(external),				AC_FLAG },
93	{ ENTRY(frame_base),			AC_BLOCK | AC_LOCLIST },
94	{ ENTRY(friend),				AC_REFERENCE },
95	{ ENTRY(identifier_case),		AC_CONSTANT },
96	{ ENTRY(macro_info),			AC_MACPTR },
97	{ ENTRY(namelist_item),			AC_BLOCK | AC_REFERENCE },
98	{ ENTRY(priority),				AC_REFERENCE },
99	{ ENTRY(segment),				AC_BLOCK | AC_LOCLIST },
100	{ ENTRY(specification),			AC_REFERENCE },
101	{ ENTRY(static_link),			AC_BLOCK | AC_LOCLIST },
102	{ ENTRY(type),					AC_REFERENCE },
103	{ ENTRY(use_location),			AC_BLOCK | AC_LOCLIST },
104	{ ENTRY(variable_parameter),	AC_FLAG },
105	{ ENTRY(virtuality),			AC_CONSTANT },
106	{ ENTRY(vtable_elem_location),	AC_BLOCK | AC_LOCLIST },
107	{ ENTRY(allocated),				AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
108	{ ENTRY(associated),			AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
109	{ ENTRY(data_location),			AC_BLOCK },
110	{ ENTRY(byte_stride),			AC_BLOCK | AC_CONSTANT | AC_REFERENCE },
111	{ ENTRY(entry_pc),				AC_ADDRESS },
112	{ ENTRY(use_UTF8),				AC_FLAG },
113	{ ENTRY(extension),				AC_REFERENCE },
114	{ ENTRY(ranges),				AC_RANGELIST },
115	{ ENTRY(trampoline),			AC_ADDRESS | AC_FLAG | AC_REFERENCE
116										| AC_STRING },
117	{ ENTRY(call_column),			AC_CONSTANT },
118	{ ENTRY(call_file),				AC_CONSTANT },
119	{ ENTRY(call_line),				AC_CONSTANT },
120	{ ENTRY(description),			AC_STRING },
121	{ ENTRY(binary_scale),			AC_CONSTANT },
122	{ ENTRY(decimal_scale),			AC_CONSTANT },
123	{ ENTRY(small),					AC_REFERENCE },
124	{ ENTRY(decimal_sign),			AC_CONSTANT },
125	{ ENTRY(digit_count),			AC_CONSTANT },
126	{ ENTRY(picture_string),		AC_STRING },
127	{ ENTRY(mutable),				AC_FLAG },
128	{ ENTRY(threads_scaled),		AC_FLAG },
129	{ ENTRY(explicit),				AC_FLAG },
130	{ ENTRY(object_pointer),		AC_REFERENCE },
131	{ ENTRY(endianity),				AC_CONSTANT },
132	{ ENTRY(elemental),				AC_FLAG },
133	{ ENTRY(pure),					AC_FLAG },
134	{ ENTRY(recursive),				AC_FLAG },
135	{ ENTRY(signature),				AC_REFERENCE },
136	{ ENTRY(main_subprogram),		AC_FLAG },
137	{ ENTRY(data_bit_offset),		AC_CONSTANT },
138	{ ENTRY(const_expr),			AC_FLAG },
139	{ ENTRY(enum_class),			AC_FLAG },
140	{ ENTRY(linkage_name),			AC_STRING },
141	{ ENTRY(string_length_bit_size),
142									AC_CONSTANT },
143	{ ENTRY(string_length_byte_size),
144									AC_CONSTANT },
145	{ ENTRY(rank),					AC_CONSTANT | AC_BLOCK },
146	{ ENTRY(str_offsets_base),		AC_STROFFSETSPTR },
147	{ ENTRY(addr_base),				AC_ADDRPTR },
148	{ ENTRY(rnglists_base),			AC_RANGELISTPTR },
149	{ ENTRY(dwo_name),				AC_STRING },
150	{ ENTRY(reference),				AC_FLAG },
151	{ ENTRY(rvalue_reference),		AC_FLAG },
152	{ ENTRY(macros),				AC_MACPTR },
153	{ ENTRY(call_all_calls),		AC_FLAG },
154	{ ENTRY(call_all_source_calls),	AC_FLAG },
155	{ ENTRY(call_all_tail_calls),	AC_FLAG },
156	{ ENTRY(call_return_pc),		AC_ADDRESS },
157	{ ENTRY(call_value),			AC_BLOCK },
158	{ ENTRY(call_origin),			AC_BLOCK },
159	{ ENTRY(call_parameter),		AC_REFERENCE },
160	{ ENTRY(call_pc),				AC_ADDRESS },
161	{ ENTRY(call_tail_call),		AC_FLAG },
162	{ ENTRY(call_target),			AC_BLOCK },
163	{ ENTRY(call_target_clobbered),	AC_BLOCK },
164	{ ENTRY(call_data_location),	AC_BLOCK },
165	{ ENTRY(call_data_value),		AC_BLOCK },
166	{ ENTRY(noreturn),				AC_FLAG },
167	{ ENTRY(alignment),				AC_CONSTANT },
168	{ ENTRY(export_symbols),		AC_FLAG },
169	{ ENTRY(deleted),				AC_FLAG },
170	{ ENTRY(defaulted),				AC_CONSTANT },
171	{ ENTRY(loclists_base),			AC_LOCLISTPTR },
172	{ ENTRY(call_site_value),		AC_BLOCK },
173	{ ENTRY(call_site_data_value),	AC_BLOCK },
174	{ ENTRY(call_site_target),		AC_BLOCK },
175	{ ENTRY(call_site_target_clobbered),
176									AC_BLOCK },
177	{ ENTRY(tail_call),				AC_FLAG },
178	{ ENTRY(all_tail_call_sites),	AC_FLAG },
179	{ ENTRY(all_call_sites),		AC_FLAG },
180	{ ENTRY(all_source_call_sites),	AC_FLAG },
181
182	{}
183};
184
185static const uint32 kAttributeNameInfoCount = DW_AT_loclists_base + 9;
186static attribute_name_info_entry sAttributeNameInfos[kAttributeNameInfoCount];
187
188
189#undef ENTRY
190#define ENTRY(name)	"DW_FORM_" #name, DW_FORM_##name
191
192static const attribute_info_entry kAttributeFormInfos[] = {
193	{ ENTRY(addr),			AC_ADDRESS },
194	{ ENTRY(block2),		AC_BLOCK },
195	{ ENTRY(block4),		AC_BLOCK },
196	{ ENTRY(data2),			AC_CONSTANT },
197	{ ENTRY(data4),			AC_CONSTANT | AC_LINEPTR | AC_LOCLIST
198								| AC_MACPTR | AC_RANGELIST },
199	{ ENTRY(data8),			AC_CONSTANT | AC_LINEPTR | AC_LOCLIST
200								| AC_MACPTR | AC_RANGELIST },
201	{ ENTRY(string),		AC_STRING },
202	{ ENTRY(block),			AC_BLOCK },
203	{ ENTRY(block1),		AC_BLOCK },
204	{ ENTRY(data1),			AC_CONSTANT },
205	{ ENTRY(flag),			AC_FLAG },
206	{ ENTRY(sdata),			AC_CONSTANT },
207	{ ENTRY(strp),			AC_STRING },
208	{ ENTRY(udata),			AC_CONSTANT },
209	{ ENTRY(ref_addr),		AC_REFERENCE },
210	{ ENTRY(ref1),			AC_REFERENCE },
211	{ ENTRY(ref2),			AC_REFERENCE },
212	{ ENTRY(ref4),			AC_REFERENCE },
213	{ ENTRY(ref8),			AC_REFERENCE },
214	{ ENTRY(ref_udata),		AC_REFERENCE },
215	{ ENTRY(indirect),		AC_REFERENCE },
216	{ ENTRY(sec_offset),	AC_ADDRPTR | AC_LINEPTR
217								| AC_LOCLIST | AC_LOCLISTPTR
218								| AC_MACPTR
219								| AC_RANGELIST | AC_RANGELISTPTR
220								| AC_STROFFSETSPTR  },
221	{ ENTRY(exprloc),		AC_BLOCK },
222	{ ENTRY(flag_present),	AC_FLAG },
223	{ ENTRY(strx),			AC_STRING },
224	{ ENTRY(addrx),			AC_ADDRESS },
225	{ ENTRY(ref_sup4),		AC_REFERENCE },
226	{ ENTRY(strp_sup),		AC_STRING },
227	{ ENTRY(data16),		AC_CONSTANT },
228	{ ENTRY(line_strp),		AC_STRING },
229	{ ENTRY(ref_sig8),		AC_REFERENCE },
230	{ ENTRY(implicit_const),
231							AC_CONSTANT },
232	{ ENTRY(loclistx),		AC_LOCLIST },
233	{ ENTRY(rnglistx),		AC_RANGELIST },
234	{ ENTRY(ref_sup8),		AC_REFERENCE },
235	{ ENTRY(strx1),			AC_STRING },
236	{ ENTRY(strx2),			AC_STRING },
237	{ ENTRY(strx3),			AC_STRING },
238	{ ENTRY(strx4),			AC_STRING },
239	{ ENTRY(addrx1),		AC_ADDRESS },
240	{ ENTRY(addrx2),		AC_ADDRESS },
241	{ ENTRY(addrx3),		AC_ADDRESS },
242	{ ENTRY(addrx4),		AC_ADDRESS },
243	{}
244};
245
246static const uint32 kAttributeFormInfoCount = DW_FORM_addrx4 + 1;
247static attribute_info_entry sAttributeFormInfos[kAttributeFormInfoCount];
248
249static struct InitAttributeInfos {
250	InitAttributeInfos()
251	{
252		for (uint32 i = 0; kAttributeNameInfos[i].name != NULL; i++) {
253			const attribute_name_info_entry& entry = kAttributeNameInfos[i];
254			if (entry.value <= DW_AT_loclists_base)
255				sAttributeNameInfos[entry.value] = entry;
256			else {
257				sAttributeNameInfos[DW_AT_loclists_base + 1
258					+ (entry.value - DW_AT_call_site_value)] = entry;
259			}
260		}
261
262		for (uint32 i = 0; kAttributeFormInfos[i].name != NULL; i++) {
263			const attribute_info_entry& entry = kAttributeFormInfos[i];
264			sAttributeFormInfos[entry.value] = entry;
265		}
266	}
267} sInitAttributeInfos;
268
269
270uint16
271get_attribute_name_classes(uint32 name)
272{
273	if (name <= DW_AT_loclists_base)
274		return sAttributeNameInfos[name].classes;
275	else if (name >= DW_AT_call_site_value
276		&& name <= DW_AT_all_source_call_sites) {
277		return sAttributeNameInfos[DW_AT_loclists_base + 1
278			+ (name - DW_AT_call_site_value)].classes;
279	}
280
281	return 0;
282}
283
284
285uint16
286get_attribute_form_classes(uint32 form)
287{
288	return form < kAttributeFormInfoCount
289		? sAttributeFormInfos[form].classes : 0;
290}
291
292
293uint8
294get_attribute_class(uint32 name, uint32 form)
295{
296	uint16 classes = get_attribute_name_classes(name)
297		& get_attribute_form_classes(form);
298
299	int clazz = 0;
300	while (classes != 0) {
301		classes >>= 1;
302		clazz++;
303	}
304
305	return clazz;
306}
307
308
309const char*
310get_attribute_name_name(uint32 name)
311{
312	if (name <= DW_AT_loclists_base)
313		return sAttributeNameInfos[name].name;
314	else if (name >= DW_AT_call_site_value
315		&& name <= DW_AT_all_source_call_sites) {
316		return sAttributeNameInfos[DW_AT_loclists_base + 1 +
317				(name - DW_AT_call_site_value)].name;
318	}
319
320	return NULL;
321}
322
323
324const char*
325get_attribute_form_name(uint32 form)
326{
327	return form < kAttributeFormInfoCount
328		? sAttributeFormInfos[form].name : NULL;
329}
330
331
332DebugInfoEntrySetter
333get_attribute_name_setter(uint32 name)
334{
335	return (name < kAttributeNameInfoCount)
336		? sAttributeNameInfos[name].setter : NULL;
337}
338