1 | //===-- ABISysV_msp430.cpp --------------------------------------*- C++ -*-===// |
2 | // |
3 | // The LLVM Compiler Infrastructure |
4 | // |
5 | // This file is distributed under the University of Illinois Open Source |
6 | // License. See LICENSE.TXT for details. |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #include "ABISysV_msp430.h" |
11 | |
12 | #include "lldb/Core/Module.h" |
13 | #include "lldb/Core/PluginManager.h" |
14 | #include "lldb/Core/Value.h" |
15 | #include "lldb/Core/ValueObjectConstResult.h" |
16 | #include "lldb/Core/ValueObjectMemory.h" |
17 | #include "lldb/Core/ValueObjectRegister.h" |
18 | #include "lldb/Symbol/UnwindPlan.h" |
19 | #include "lldb/Target/Process.h" |
20 | #include "lldb/Target/RegisterContext.h" |
21 | #include "lldb/Target/StackFrame.h" |
22 | #include "lldb/Target/Target.h" |
23 | #include "lldb/Target/Thread.h" |
24 | #include "lldb/Utility/ConstString.h" |
25 | #include "lldb/Utility/DataExtractor.h" |
26 | #include "lldb/Utility/Log.h" |
27 | #include "lldb/Utility/RegisterValue.h" |
28 | |
29 | #include "llvm/IR/DerivedTypes.h" |
30 | #include "llvm/TargetParser/Triple.h" |
31 | |
32 | using namespace lldb; |
33 | using namespace lldb_private; |
34 | |
35 | LLDB_PLUGIN_DEFINE_ADV(ABISysV_msp430, ABIMSP430) |
36 | |
37 | enum dwarf_regnums { |
38 | dwarf_pc = 0, |
39 | dwarf_sp, |
40 | dwarf_r2, |
41 | dwarf_r3, |
42 | dwarf_fp, |
43 | dwarf_r5, |
44 | dwarf_r6, |
45 | dwarf_r7, |
46 | dwarf_r8, |
47 | dwarf_r9, |
48 | dwarf_r10, |
49 | dwarf_r11, |
50 | dwarf_r12, |
51 | dwarf_r13, |
52 | dwarf_r14, |
53 | dwarf_r15, |
54 | }; |
55 | |
56 | static const RegisterInfo g_register_infos[] = { |
57 | {.name: "r0" , |
58 | .alt_name: "pc" , |
59 | .byte_size: 2, |
60 | .byte_offset: 0, |
61 | .encoding: eEncodingUint, |
62 | .format: eFormatHex, |
63 | .kinds: {dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, |
64 | LLDB_INVALID_REGNUM}, |
65 | .value_regs: nullptr, |
66 | .invalidate_regs: nullptr, |
67 | .flags_type: nullptr, |
68 | }, |
69 | {.name: "r1" , |
70 | .alt_name: "sp" , |
71 | .byte_size: 2, |
72 | .byte_offset: 0, |
73 | .encoding: eEncodingUint, |
74 | .format: eFormatHex, |
75 | .kinds: {dwarf_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, |
76 | LLDB_INVALID_REGNUM}, |
77 | .value_regs: nullptr, |
78 | .invalidate_regs: nullptr, |
79 | .flags_type: nullptr, |
80 | }, |
81 | {.name: "r2" , |
82 | .alt_name: "" , |
83 | .byte_size: 2, |
84 | .byte_offset: 0, |
85 | .encoding: eEncodingUint, |
86 | .format: eFormatHex, |
87 | .kinds: {dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
88 | LLDB_INVALID_REGNUM}, |
89 | .value_regs: nullptr, |
90 | .invalidate_regs: nullptr, |
91 | .flags_type: nullptr, |
92 | }, |
93 | {.name: "r3" , |
94 | .alt_name: "" , |
95 | .byte_size: 2, |
96 | .byte_offset: 0, |
97 | .encoding: eEncodingUint, |
98 | .format: eFormatHex, |
99 | .kinds: {dwarf_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
100 | LLDB_INVALID_REGNUM}, |
101 | .value_regs: nullptr, |
102 | .invalidate_regs: nullptr, |
103 | .flags_type: nullptr, |
104 | }, |
105 | {.name: "r4" , |
106 | .alt_name: "fp" , |
107 | .byte_size: 2, |
108 | .byte_offset: 0, |
109 | .encoding: eEncodingUint, |
110 | .format: eFormatHex, |
111 | .kinds: {dwarf_fp, dwarf_fp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, |
112 | LLDB_INVALID_REGNUM}, |
113 | .value_regs: nullptr, |
114 | .invalidate_regs: nullptr, |
115 | .flags_type: nullptr, |
116 | }, |
117 | {.name: "r5" , |
118 | .alt_name: "" , |
119 | .byte_size: 2, |
120 | .byte_offset: 0, |
121 | .encoding: eEncodingUint, |
122 | .format: eFormatHex, |
123 | .kinds: {dwarf_r5, dwarf_r5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
124 | LLDB_INVALID_REGNUM}, |
125 | .value_regs: nullptr, |
126 | .invalidate_regs: nullptr, |
127 | .flags_type: nullptr, |
128 | }, |
129 | {.name: "r6" , |
130 | .alt_name: "" , |
131 | .byte_size: 2, |
132 | .byte_offset: 0, |
133 | .encoding: eEncodingUint, |
134 | .format: eFormatHex, |
135 | .kinds: {dwarf_r6, dwarf_r6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
136 | LLDB_INVALID_REGNUM}, |
137 | .value_regs: nullptr, |
138 | .invalidate_regs: nullptr, |
139 | .flags_type: nullptr, |
140 | }, |
141 | {.name: "r7" , |
142 | .alt_name: "" , |
143 | .byte_size: 2, |
144 | .byte_offset: 0, |
145 | .encoding: eEncodingUint, |
146 | .format: eFormatHex, |
147 | .kinds: {dwarf_r7, dwarf_r7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
148 | LLDB_INVALID_REGNUM}, |
149 | .value_regs: nullptr, |
150 | .invalidate_regs: nullptr, |
151 | .flags_type: nullptr, |
152 | }, |
153 | {.name: "r8" , |
154 | .alt_name: "" , |
155 | .byte_size: 2, |
156 | .byte_offset: 0, |
157 | .encoding: eEncodingUint, |
158 | .format: eFormatHex, |
159 | .kinds: {dwarf_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
160 | LLDB_INVALID_REGNUM}, |
161 | .value_regs: nullptr, |
162 | .invalidate_regs: nullptr, |
163 | .flags_type: nullptr, |
164 | }, |
165 | {.name: "r9" , |
166 | .alt_name: "" , |
167 | .byte_size: 2, |
168 | .byte_offset: 0, |
169 | .encoding: eEncodingUint, |
170 | .format: eFormatHex, |
171 | .kinds: {dwarf_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
172 | LLDB_INVALID_REGNUM}, |
173 | .value_regs: nullptr, |
174 | .invalidate_regs: nullptr, |
175 | .flags_type: nullptr, |
176 | }, |
177 | {.name: "r10" , |
178 | .alt_name: "" , |
179 | .byte_size: 2, |
180 | .byte_offset: 0, |
181 | .encoding: eEncodingUint, |
182 | .format: eFormatHex, |
183 | .kinds: {dwarf_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
184 | LLDB_INVALID_REGNUM}, |
185 | .value_regs: nullptr, |
186 | .invalidate_regs: nullptr, |
187 | .flags_type: nullptr, |
188 | }, |
189 | {.name: "r11" , |
190 | .alt_name: "" , |
191 | .byte_size: 2, |
192 | .byte_offset: 0, |
193 | .encoding: eEncodingUint, |
194 | .format: eFormatHex, |
195 | .kinds: {dwarf_r11, dwarf_r11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
196 | LLDB_INVALID_REGNUM}, |
197 | .value_regs: nullptr, |
198 | .invalidate_regs: nullptr, |
199 | .flags_type: nullptr, |
200 | }, |
201 | {.name: "r12" , |
202 | .alt_name: "" , |
203 | .byte_size: 2, |
204 | .byte_offset: 0, |
205 | .encoding: eEncodingUint, |
206 | .format: eFormatHex, |
207 | .kinds: {dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
208 | LLDB_INVALID_REGNUM}, |
209 | .value_regs: nullptr, |
210 | .invalidate_regs: nullptr, |
211 | .flags_type: nullptr, |
212 | }, |
213 | {.name: "r13" , |
214 | .alt_name: "" , |
215 | .byte_size: 2, |
216 | .byte_offset: 0, |
217 | .encoding: eEncodingUint, |
218 | .format: eFormatHex, |
219 | .kinds: {dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
220 | LLDB_INVALID_REGNUM}, |
221 | .value_regs: nullptr, |
222 | .invalidate_regs: nullptr, |
223 | .flags_type: nullptr, |
224 | }, |
225 | {.name: "r14" , |
226 | .alt_name: "" , |
227 | .byte_size: 2, |
228 | .byte_offset: 0, |
229 | .encoding: eEncodingUint, |
230 | .format: eFormatHex, |
231 | .kinds: {dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
232 | LLDB_INVALID_REGNUM}, |
233 | .value_regs: nullptr, |
234 | .invalidate_regs: nullptr, |
235 | .flags_type: nullptr, |
236 | }, |
237 | {.name: "r15" , |
238 | .alt_name: "" , |
239 | .byte_size: 2, |
240 | .byte_offset: 0, |
241 | .encoding: eEncodingUint, |
242 | .format: eFormatHex, |
243 | .kinds: {dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
244 | LLDB_INVALID_REGNUM}, |
245 | .value_regs: nullptr, |
246 | .invalidate_regs: nullptr, |
247 | .flags_type: nullptr, |
248 | }}; |
249 | |
250 | static const uint32_t k_num_register_infos = |
251 | sizeof(g_register_infos) / sizeof(RegisterInfo); |
252 | |
253 | const lldb_private::RegisterInfo * |
254 | ABISysV_msp430::GetRegisterInfoArray(uint32_t &count) { |
255 | // Make the C-string names and alt_names for the register infos into const |
256 | // C-string values by having the ConstString unique the names in the global |
257 | // constant C-string pool. |
258 | count = k_num_register_infos; |
259 | return g_register_infos; |
260 | } |
261 | |
262 | size_t ABISysV_msp430::GetRedZoneSize() const { return 0; } |
263 | |
264 | //------------------------------------------------------------------ |
265 | // Static Functions |
266 | //------------------------------------------------------------------ |
267 | |
268 | ABISP |
269 | ABISysV_msp430::CreateInstance(lldb::ProcessSP process_sp, |
270 | const ArchSpec &arch) { |
271 | if (arch.GetTriple().getArch() == llvm::Triple::msp430) { |
272 | return ABISP( |
273 | new ABISysV_msp430(std::move(process_sp), MakeMCRegisterInfo(arch))); |
274 | } |
275 | return ABISP(); |
276 | } |
277 | |
278 | bool ABISysV_msp430::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, |
279 | lldb::addr_t pc, lldb::addr_t ra, |
280 | llvm::ArrayRef<addr_t> args) const { |
281 | // we don't use the traditional trivial call specialized for jit |
282 | return false; |
283 | } |
284 | |
285 | bool ABISysV_msp430::GetArgumentValues(Thread &thread, |
286 | ValueList &values) const { |
287 | return false; |
288 | } |
289 | |
290 | Status ABISysV_msp430::SetReturnValueObject(lldb::StackFrameSP &frame_sp, |
291 | lldb::ValueObjectSP &new_value_sp) { |
292 | return Status(); |
293 | } |
294 | |
295 | ValueObjectSP ABISysV_msp430::GetReturnValueObjectSimple( |
296 | Thread &thread, CompilerType &return_compiler_type) const { |
297 | ValueObjectSP return_valobj_sp; |
298 | return return_valobj_sp; |
299 | } |
300 | |
301 | ValueObjectSP ABISysV_msp430::GetReturnValueObjectImpl( |
302 | Thread &thread, CompilerType &return_compiler_type) const { |
303 | ValueObjectSP return_valobj_sp; |
304 | return return_valobj_sp; |
305 | } |
306 | |
307 | // called when we are on the first instruction of a new function |
308 | bool ABISysV_msp430::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { |
309 | unwind_plan.Clear(); |
310 | unwind_plan.SetRegisterKind(eRegisterKindDWARF); |
311 | |
312 | uint32_t sp_reg_num = dwarf_sp; |
313 | uint32_t pc_reg_num = dwarf_pc; |
314 | |
315 | UnwindPlan::RowSP row(new UnwindPlan::Row); |
316 | row->GetCFAValue().SetIsRegisterPlusOffset(reg_num: sp_reg_num, offset: 2); |
317 | row->SetRegisterLocationToAtCFAPlusOffset(reg_num: pc_reg_num, offset: -2, can_replace: true); |
318 | row->SetRegisterLocationToIsCFAPlusOffset(reg_num: sp_reg_num, offset: 0, can_replace: true); |
319 | |
320 | unwind_plan.AppendRow(row_sp: row); |
321 | unwind_plan.SetSourceName("msp430 at-func-entry default" ); |
322 | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
323 | return true; |
324 | } |
325 | |
326 | bool ABISysV_msp430::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { |
327 | unwind_plan.Clear(); |
328 | unwind_plan.SetRegisterKind(eRegisterKindDWARF); |
329 | |
330 | uint32_t fp_reg_num = dwarf_fp; |
331 | uint32_t sp_reg_num = dwarf_sp; |
332 | uint32_t pc_reg_num = dwarf_pc; |
333 | |
334 | UnwindPlan::RowSP row(new UnwindPlan::Row); |
335 | row->GetCFAValue().SetIsRegisterPlusOffset(reg_num: sp_reg_num, offset: 2); |
336 | row->SetRegisterLocationToAtCFAPlusOffset(reg_num: pc_reg_num, offset: -2, can_replace: true); |
337 | row->SetRegisterLocationToIsCFAPlusOffset(reg_num: sp_reg_num, offset: 0, can_replace: true); |
338 | row->SetRegisterLocationToUnspecified(reg_num: fp_reg_num, can_replace: true); |
339 | |
340 | unwind_plan.AppendRow(row_sp: row); |
341 | unwind_plan.SetSourceName("msp430 default unwind plan" ); |
342 | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
343 | unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); |
344 | return true; |
345 | } |
346 | |
347 | bool ABISysV_msp430::RegisterIsVolatile(const RegisterInfo *reg_info) { |
348 | return !RegisterIsCalleeSaved(reg_info); |
349 | } |
350 | |
351 | bool ABISysV_msp430::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { |
352 | int reg = ((reg_info->byte_offset) / 2); |
353 | |
354 | bool save = (reg >= 4) && (reg <= 10); |
355 | return save; |
356 | } |
357 | |
358 | void ABISysV_msp430::Initialize(void) { |
359 | PluginManager::RegisterPlugin( |
360 | name: GetPluginNameStatic(), description: "System V ABI for msp430 targets" , create_callback: CreateInstance); |
361 | } |
362 | |
363 | void ABISysV_msp430::Terminate(void) { |
364 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
365 | } |
366 | |