]>
Commit | Line | Data |
---|---|---|
772d1f34 TY |
1 | /* Target-dependent code for the LoongArch architecture, for GDB. |
2 | ||
3 | Copyright (C) 2022 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #include "defs.h" | |
21 | #include "arch-utils.h" | |
22 | #include "dwarf2/frame.h" | |
23 | #include "elf-bfd.h" | |
24 | #include "frame-unwind.h" | |
6e0d24c4 | 25 | #include "gdbcore.h" |
772d1f34 | 26 | #include "loongarch-tdep.h" |
6e0d24c4 | 27 | #include "target.h" |
772d1f34 TY |
28 | #include "target-descriptions.h" |
29 | #include "trad-frame.h" | |
30 | #include "user-regs.h" | |
31 | ||
6e0d24c4 TY |
32 | /* Fetch the instruction at PC. */ |
33 | ||
34 | static insn_t | |
35 | loongarch_fetch_instruction (CORE_ADDR pc) | |
36 | { | |
37 | size_t insn_len = loongarch_insn_length (0); | |
38 | gdb_byte buf[insn_len]; | |
39 | int err; | |
40 | ||
41 | err = target_read_memory (pc, buf, insn_len); | |
42 | if (err) | |
43 | memory_error (TARGET_XFER_E_IO, pc); | |
44 | ||
45 | return extract_unsigned_integer (buf, insn_len, BFD_ENDIAN_LITTLE); | |
46 | } | |
47 | ||
208b57e5 TY |
48 | /* Return TRUE if INSN is a unconditional branch instruction, otherwise return FALSE. */ |
49 | ||
50 | static bool | |
51 | loongarch_insn_is_uncond_branch (insn_t insn) | |
52 | { | |
53 | if ((insn & 0xfc000000) == 0x4c000000 /* jirl */ | |
54 | || (insn & 0xfc000000) == 0x50000000 /* b */ | |
55 | || (insn & 0xfc000000) == 0x54000000) /* bl */ | |
56 | return true; | |
57 | return false; | |
58 | } | |
59 | ||
60 | /* Return TRUE if INSN is a conditional branch instruction, otherwise return FALSE. */ | |
61 | ||
62 | static bool | |
63 | loongarch_insn_is_cond_branch (insn_t insn) | |
64 | { | |
65 | if ((insn & 0xfc000000) == 0x58000000 /* beq */ | |
66 | || (insn & 0xfc000000) == 0x5c000000 /* bne */ | |
67 | || (insn & 0xfc000000) == 0x60000000 /* blt */ | |
68 | || (insn & 0xfc000000) == 0x64000000 /* bge */ | |
69 | || (insn & 0xfc000000) == 0x68000000 /* bltu */ | |
70 | || (insn & 0xfc000000) == 0x6c000000 /* bgeu */ | |
71 | || (insn & 0xfc000000) == 0x40000000 /* beqz */ | |
72 | || (insn & 0xfc000000) == 0x44000000) /* bnez */ | |
73 | return true; | |
74 | return false; | |
75 | } | |
76 | ||
6e0d24c4 TY |
77 | /* Return TRUE if INSN is a branch instruction, otherwise return FALSE. */ |
78 | ||
79 | static bool | |
80 | loongarch_insn_is_branch (insn_t insn) | |
81 | { | |
208b57e5 TY |
82 | bool is_uncond = loongarch_insn_is_uncond_branch (insn); |
83 | bool is_cond = loongarch_insn_is_cond_branch (insn); | |
84 | ||
85 | return (is_uncond || is_cond); | |
86 | } | |
87 | ||
88 | /* Return TRUE if INSN is a Load Linked instruction, otherwise return FALSE. */ | |
89 | ||
90 | static bool | |
91 | loongarch_insn_is_ll (insn_t insn) | |
92 | { | |
93 | if ((insn & 0xff000000) == 0x20000000 /* ll.w */ | |
94 | || (insn & 0xff000000) == 0x22000000) /* ll.d */ | |
95 | return true; | |
96 | return false; | |
97 | } | |
98 | ||
99 | /* Return TRUE if INSN is a Store Conditional instruction, otherwise return FALSE. */ | |
100 | ||
101 | static bool | |
102 | loongarch_insn_is_sc (insn_t insn) | |
103 | { | |
104 | if ((insn & 0xff000000) == 0x21000000 /* sc.w */ | |
105 | || (insn & 0xff000000) == 0x23000000) /* sc.d */ | |
6e0d24c4 TY |
106 | return true; |
107 | return false; | |
108 | } | |
109 | ||
110 | /* Analyze the function prologue from START_PC to LIMIT_PC. | |
111 | Return the address of the first instruction past the prologue. */ | |
112 | ||
113 | static CORE_ADDR | |
114 | loongarch_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc, | |
bd2b40ac | 115 | CORE_ADDR limit_pc, frame_info_ptr this_frame, |
6e0d24c4 TY |
116 | struct trad_frame_cache *this_cache) |
117 | { | |
118 | CORE_ADDR cur_pc = start_pc, prologue_end = 0; | |
0757a503 TY |
119 | int32_t sp = LOONGARCH_SP_REGNUM; |
120 | int32_t fp = LOONGARCH_FP_REGNUM; | |
6e0d24c4 TY |
121 | int32_t reg_value[32] = {0}; |
122 | int32_t reg_used[32] = {1, 0}; | |
123 | ||
124 | while (cur_pc < limit_pc) | |
125 | { | |
126 | insn_t insn = loongarch_fetch_instruction (cur_pc); | |
127 | size_t insn_len = loongarch_insn_length (insn); | |
128 | int32_t rd = loongarch_decode_imm ("0:5", insn, 0); | |
129 | int32_t rj = loongarch_decode_imm ("5:5", insn, 0); | |
130 | int32_t rk = loongarch_decode_imm ("10:5", insn, 0); | |
131 | int32_t si12 = loongarch_decode_imm ("10:12", insn, 1); | |
132 | int32_t si20 = loongarch_decode_imm ("5:20", insn, 1); | |
133 | ||
134 | if ((insn & 0xffc00000) == 0x02c00000 /* addi.d sp,sp,si12 */ | |
135 | && rd == sp && rj == sp && si12 < 0) | |
136 | { | |
137 | prologue_end = cur_pc + insn_len; | |
138 | } | |
139 | else if ((insn & 0xffc00000) == 0x02c00000 /* addi.d fp,sp,si12 */ | |
140 | && rd == fp && rj == sp && si12 > 0) | |
141 | { | |
142 | prologue_end = cur_pc + insn_len; | |
143 | } | |
144 | else if ((insn & 0xffc00000) == 0x29c00000 /* st.d rd,sp,si12 */ | |
145 | && rj == sp) | |
146 | { | |
147 | prologue_end = cur_pc + insn_len; | |
148 | } | |
149 | else if ((insn & 0xff000000) == 0x27000000 /* stptr.d rd,sp,si14 */ | |
150 | && rj == sp) | |
151 | { | |
152 | prologue_end = cur_pc + insn_len; | |
153 | } | |
154 | else if ((insn & 0xfe000000) == 0x14000000) /* lu12i.w rd,si20 */ | |
155 | { | |
156 | reg_value[rd] = si20 << 12; | |
157 | reg_used[rd] = 1; | |
158 | } | |
159 | else if ((insn & 0xffc00000) == 0x03800000) /* ori rd,rj,si12 */ | |
160 | { | |
161 | if (reg_used[rj]) | |
4a75d7c5 TY |
162 | { |
163 | reg_value[rd] = reg_value[rj] | (si12 & 0xfff); | |
164 | reg_used[rd] = 1; | |
165 | } | |
6e0d24c4 TY |
166 | } |
167 | else if ((insn & 0xffff8000) == 0x00108000 /* add.d sp,sp,rk */ | |
168 | && rd == sp && rj == sp) | |
169 | { | |
170 | if (reg_used[rk] == 1 && reg_value[rk] < 0) | |
171 | { | |
172 | prologue_end = cur_pc + insn_len; | |
173 | break; | |
174 | } | |
175 | } | |
176 | else if (loongarch_insn_is_branch (insn)) | |
177 | { | |
178 | break; | |
179 | } | |
180 | ||
181 | cur_pc += insn_len; | |
182 | } | |
183 | ||
184 | if (prologue_end == 0) | |
185 | prologue_end = cur_pc; | |
186 | ||
187 | return prologue_end; | |
188 | } | |
189 | ||
772d1f34 TY |
190 | /* Implement the loongarch_skip_prologue gdbarch method. */ |
191 | ||
192 | static CORE_ADDR | |
193 | loongarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) | |
194 | { | |
195 | CORE_ADDR func_addr; | |
196 | ||
197 | /* See if we can determine the end of the prologue via the symbol table. | |
198 | If so, then return either PC, or the PC after the prologue, whichever | |
199 | is greater. */ | |
200 | if (find_pc_partial_function (pc, nullptr, &func_addr, nullptr)) | |
201 | { | |
202 | CORE_ADDR post_prologue_pc | |
203 | = skip_prologue_using_sal (gdbarch, func_addr); | |
204 | if (post_prologue_pc != 0) | |
205 | return std::max (pc, post_prologue_pc); | |
206 | } | |
207 | ||
6e0d24c4 TY |
208 | /* Can't determine prologue from the symbol table, need to examine |
209 | instructions. */ | |
210 | ||
211 | /* Find an upper limit on the function prologue using the debug | |
212 | information. If the debug information could not be used to provide | |
213 | that bound, then use an arbitrary large number as the upper bound. */ | |
214 | CORE_ADDR limit_pc = skip_prologue_using_sal (gdbarch, pc); | |
215 | if (limit_pc == 0) | |
216 | limit_pc = pc + 100; /* Arbitrary large number. */ | |
217 | ||
218 | return loongarch_scan_prologue (gdbarch, pc, limit_pc, nullptr, nullptr); | |
772d1f34 TY |
219 | } |
220 | ||
2e90d025 TY |
221 | /* Decode the current instruction and determine the address of the |
222 | next instruction. */ | |
223 | ||
224 | static CORE_ADDR | |
208b57e5 | 225 | loongarch_next_pc (struct regcache *regcache, CORE_ADDR cur_pc) |
2e90d025 | 226 | { |
af6e3f77 | 227 | struct gdbarch *gdbarch = regcache->arch (); |
08106042 | 228 | loongarch_gdbarch_tdep *tdep = gdbarch_tdep<loongarch_gdbarch_tdep> (gdbarch); |
208b57e5 | 229 | insn_t insn = loongarch_fetch_instruction (cur_pc); |
2e90d025 TY |
230 | size_t insn_len = loongarch_insn_length (insn); |
231 | CORE_ADDR next_pc = cur_pc + insn_len; | |
232 | ||
233 | if ((insn & 0xfc000000) == 0x4c000000) /* jirl rd, rj, offs16 */ | |
234 | { | |
235 | LONGEST rj = regcache_raw_get_signed (regcache, | |
236 | loongarch_decode_imm ("5:5", insn, 0)); | |
237 | next_pc = rj + loongarch_decode_imm ("10:16<<2", insn, 1); | |
238 | } | |
239 | else if ((insn & 0xfc000000) == 0x50000000 /* b offs26 */ | |
240 | || (insn & 0xfc000000) == 0x54000000) /* bl offs26 */ | |
241 | { | |
242 | next_pc = cur_pc + loongarch_decode_imm ("0:10|10:16<<2", insn, 1); | |
243 | } | |
244 | else if ((insn & 0xfc000000) == 0x58000000) /* beq rj, rd, offs16 */ | |
245 | { | |
246 | LONGEST rj = regcache_raw_get_signed (regcache, | |
247 | loongarch_decode_imm ("5:5", insn, 0)); | |
248 | LONGEST rd = regcache_raw_get_signed (regcache, | |
249 | loongarch_decode_imm ("0:5", insn, 0)); | |
250 | if (rj == rd) | |
251 | next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); | |
252 | } | |
253 | else if ((insn & 0xfc000000) == 0x5c000000) /* bne rj, rd, offs16 */ | |
254 | { | |
255 | LONGEST rj = regcache_raw_get_signed (regcache, | |
256 | loongarch_decode_imm ("5:5", insn, 0)); | |
257 | LONGEST rd = regcache_raw_get_signed (regcache, | |
258 | loongarch_decode_imm ("0:5", insn, 0)); | |
259 | if (rj != rd) | |
260 | next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); | |
261 | } | |
262 | else if ((insn & 0xfc000000) == 0x60000000) /* blt rj, rd, offs16 */ | |
263 | { | |
264 | LONGEST rj = regcache_raw_get_signed (regcache, | |
265 | loongarch_decode_imm ("5:5", insn, 0)); | |
266 | LONGEST rd = regcache_raw_get_signed (regcache, | |
267 | loongarch_decode_imm ("0:5", insn, 0)); | |
268 | if (rj < rd) | |
269 | next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); | |
270 | } | |
271 | else if ((insn & 0xfc000000) == 0x64000000) /* bge rj, rd, offs16 */ | |
272 | { | |
273 | LONGEST rj = regcache_raw_get_signed (regcache, | |
274 | loongarch_decode_imm ("5:5", insn, 0)); | |
275 | LONGEST rd = regcache_raw_get_signed (regcache, | |
276 | loongarch_decode_imm ("0:5", insn, 0)); | |
277 | if (rj >= rd) | |
278 | next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); | |
279 | } | |
280 | else if ((insn & 0xfc000000) == 0x68000000) /* bltu rj, rd, offs16 */ | |
281 | { | |
282 | ULONGEST rj = regcache_raw_get_unsigned (regcache, | |
283 | loongarch_decode_imm ("5:5", insn, 0)); | |
284 | ULONGEST rd = regcache_raw_get_unsigned (regcache, | |
285 | loongarch_decode_imm ("0:5", insn, 0)); | |
286 | if (rj < rd) | |
287 | next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); | |
288 | } | |
289 | else if ((insn & 0xfc000000) == 0x6c000000) /* bgeu rj, rd, offs16 */ | |
290 | { | |
291 | ULONGEST rj = regcache_raw_get_unsigned (regcache, | |
292 | loongarch_decode_imm ("5:5", insn, 0)); | |
293 | ULONGEST rd = regcache_raw_get_unsigned (regcache, | |
294 | loongarch_decode_imm ("0:5", insn, 0)); | |
295 | if (rj >= rd) | |
296 | next_pc = cur_pc + loongarch_decode_imm ("10:16<<2", insn, 1); | |
297 | } | |
298 | else if ((insn & 0xfc000000) == 0x40000000) /* beqz rj, offs21 */ | |
299 | { | |
300 | LONGEST rj = regcache_raw_get_signed (regcache, | |
301 | loongarch_decode_imm ("5:5", insn, 0)); | |
302 | if (rj == 0) | |
303 | next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1); | |
304 | } | |
305 | else if ((insn & 0xfc000000) == 0x44000000) /* bnez rj, offs21 */ | |
306 | { | |
307 | LONGEST rj = regcache_raw_get_signed (regcache, | |
308 | loongarch_decode_imm ("5:5", insn, 0)); | |
309 | if (rj != 0) | |
310 | next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1); | |
311 | } | |
af6e3f77 TY |
312 | else if ((insn & 0xffff8000) == 0x002b0000) /* syscall */ |
313 | { | |
314 | if (tdep->syscall_next_pc != nullptr) | |
315 | next_pc = tdep->syscall_next_pc (get_current_frame ()); | |
316 | } | |
2e90d025 TY |
317 | |
318 | return next_pc; | |
319 | } | |
320 | ||
208b57e5 TY |
321 | /* We can't put a breakpoint in the middle of a ll/sc atomic sequence, |
322 | so look for the end of the sequence and put the breakpoint there. */ | |
323 | ||
324 | static std::vector<CORE_ADDR> | |
325 | loongarch_deal_with_atomic_sequence (struct regcache *regcache, CORE_ADDR cur_pc) | |
326 | { | |
327 | CORE_ADDR next_pc; | |
328 | std::vector<CORE_ADDR> next_pcs; | |
329 | insn_t insn = loongarch_fetch_instruction (cur_pc); | |
330 | size_t insn_len = loongarch_insn_length (insn); | |
331 | const int atomic_sequence_length = 16; | |
332 | bool found_atomic_sequence_endpoint = false; | |
333 | ||
334 | /* Look for a Load Linked instruction which begins the atomic sequence. */ | |
335 | if (!loongarch_insn_is_ll (insn)) | |
336 | return {}; | |
337 | ||
338 | /* Assume that no atomic sequence is longer than "atomic_sequence_length" instructions. */ | |
339 | for (int insn_count = 0; insn_count < atomic_sequence_length; ++insn_count) | |
340 | { | |
341 | cur_pc += insn_len; | |
342 | insn = loongarch_fetch_instruction (cur_pc); | |
343 | ||
344 | /* Look for a unconditional branch instruction, fallback to the standard code. */ | |
345 | if (loongarch_insn_is_uncond_branch (insn)) | |
346 | { | |
347 | return {}; | |
348 | } | |
349 | /* Look for a conditional branch instruction, put a breakpoint in its destination address. */ | |
350 | else if (loongarch_insn_is_cond_branch (insn)) | |
351 | { | |
352 | next_pc = loongarch_next_pc (regcache, cur_pc); | |
353 | next_pcs.push_back (next_pc); | |
354 | } | |
355 | /* Look for a Store Conditional instruction which closes the atomic sequence. */ | |
356 | else if (loongarch_insn_is_sc (insn)) | |
357 | { | |
358 | found_atomic_sequence_endpoint = true; | |
359 | next_pc = cur_pc + insn_len; | |
360 | next_pcs.push_back (next_pc); | |
361 | break; | |
362 | } | |
363 | } | |
364 | ||
365 | /* We didn't find a closing Store Conditional instruction, fallback to the standard code. */ | |
366 | if (!found_atomic_sequence_endpoint) | |
367 | return {}; | |
368 | ||
369 | return next_pcs; | |
370 | } | |
371 | ||
0757a503 | 372 | /* Implement the software_single_step gdbarch method */ |
2e90d025 TY |
373 | |
374 | static std::vector<CORE_ADDR> | |
375 | loongarch_software_single_step (struct regcache *regcache) | |
376 | { | |
377 | CORE_ADDR cur_pc = regcache_read_pc (regcache); | |
208b57e5 TY |
378 | std::vector<CORE_ADDR> next_pcs |
379 | = loongarch_deal_with_atomic_sequence (regcache, cur_pc); | |
380 | ||
381 | if (!next_pcs.empty ()) | |
382 | return next_pcs; | |
383 | ||
384 | CORE_ADDR next_pc = loongarch_next_pc (regcache, cur_pc); | |
2e90d025 TY |
385 | |
386 | return {next_pc}; | |
387 | } | |
388 | ||
0757a503 | 389 | /* Implement the frame_align gdbarch method. */ |
772d1f34 TY |
390 | |
391 | static CORE_ADDR | |
392 | loongarch_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) | |
393 | { | |
394 | return align_down (addr, 16); | |
395 | } | |
396 | ||
0757a503 | 397 | /* Generate, or return the cached frame cache for frame unwinder. */ |
772d1f34 TY |
398 | |
399 | static struct trad_frame_cache * | |
bd2b40ac | 400 | loongarch_frame_cache (frame_info_ptr this_frame, void **this_cache) |
772d1f34 | 401 | { |
772d1f34 TY |
402 | struct trad_frame_cache *cache; |
403 | CORE_ADDR pc; | |
404 | ||
405 | if (*this_cache != nullptr) | |
406 | return (struct trad_frame_cache *) *this_cache; | |
407 | ||
408 | cache = trad_frame_cache_zalloc (this_frame); | |
409 | *this_cache = cache; | |
410 | ||
0757a503 | 411 | trad_frame_set_reg_realreg (cache, LOONGARCH_PC_REGNUM, LOONGARCH_RA_REGNUM); |
772d1f34 TY |
412 | |
413 | pc = get_frame_address_in_block (this_frame); | |
414 | trad_frame_set_id (cache, frame_id_build_unavailable_stack (pc)); | |
415 | ||
416 | return cache; | |
417 | } | |
418 | ||
0757a503 | 419 | /* Implement the this_id callback for frame unwinder. */ |
772d1f34 TY |
420 | |
421 | static void | |
bd2b40ac | 422 | loongarch_frame_this_id (frame_info_ptr this_frame, void **prologue_cache, |
772d1f34 TY |
423 | struct frame_id *this_id) |
424 | { | |
425 | struct trad_frame_cache *info; | |
426 | ||
427 | info = loongarch_frame_cache (this_frame, prologue_cache); | |
428 | trad_frame_get_id (info, this_id); | |
429 | } | |
430 | ||
0757a503 | 431 | /* Implement the prev_register callback for frame unwinder. */ |
772d1f34 TY |
432 | |
433 | static struct value * | |
bd2b40ac | 434 | loongarch_frame_prev_register (frame_info_ptr this_frame, |
772d1f34 TY |
435 | void **prologue_cache, int regnum) |
436 | { | |
437 | struct trad_frame_cache *info; | |
438 | ||
439 | info = loongarch_frame_cache (this_frame, prologue_cache); | |
440 | return trad_frame_get_register (info, this_frame, regnum); | |
441 | } | |
442 | ||
443 | static const struct frame_unwind loongarch_frame_unwind = { | |
444 | "loongarch prologue", | |
445 | /*.type =*/NORMAL_FRAME, | |
446 | /*.stop_reason =*/default_frame_unwind_stop_reason, | |
447 | /*.this_id =*/loongarch_frame_this_id, | |
448 | /*.prev_register =*/loongarch_frame_prev_register, | |
449 | /*.unwind_data =*/nullptr, | |
450 | /*.sniffer =*/default_frame_sniffer, | |
451 | /*.dealloc_cache =*/nullptr, | |
452 | /*.prev_arch =*/nullptr, | |
453 | }; | |
454 | ||
4a75d7c5 TY |
455 | /* Write the contents of buffer VAL into the general-purpose argument |
456 | register defined by GAR in REGCACHE. GAR indicates the available | |
457 | general-purpose argument registers which should be a value in the | |
458 | range 1 to 8 (LOONGARCH_ARG_REGNUM), which correspond to registers | |
459 | a7 and a0 respectively, that is to say, regnum is a7 if GAR is 1, | |
460 | regnum is a6 if GAR is 2, regnum is a5 if GAR is 3, regnum is a4 | |
461 | if GAR is 4, regnum is a3 if GAR is 5, regnum is a2 if GAR is 6, | |
462 | regnum is a1 if GAR is 7, regnum is a0 if GAR is 8. */ | |
463 | ||
88de5835 TY |
464 | static void |
465 | pass_in_gar (struct regcache *regcache, unsigned int gar, const gdb_byte *val) | |
466 | { | |
467 | unsigned int regnum = LOONGARCH_ARG_REGNUM - gar + LOONGARCH_A0_REGNUM; | |
468 | regcache->cooked_write (regnum, val); | |
469 | } | |
470 | ||
4a75d7c5 TY |
471 | /* Write the contents of buffer VAL into the floating-point argument |
472 | register defined by FAR in REGCACHE. FAR indicates the available | |
473 | floating-point argument registers which should be a value in the | |
474 | range 1 to 8 (LOONGARCH_ARG_REGNUM), which correspond to registers | |
475 | f7 and f0 respectively, that is to say, regnum is f7 if FAR is 1, | |
476 | regnum is f6 if FAR is 2, regnum is f5 if FAR is 3, regnum is f4 | |
477 | if FAR is 4, regnum is f3 if FAR is 5, regnum is f2 if FAR is 6, | |
478 | regnum is f1 if FAR is 7, regnum is f0 if FAR is 8. */ | |
479 | ||
88de5835 TY |
480 | static void |
481 | pass_in_far (struct regcache *regcache, unsigned int far, const gdb_byte *val) | |
482 | { | |
657a5022 | 483 | unsigned int regnum = LOONGARCH_ARG_REGNUM - far + LOONGARCH_FIRST_FP_REGNUM; |
88de5835 TY |
484 | regcache->cooked_write (regnum, val); |
485 | } | |
486 | ||
4a75d7c5 | 487 | /* Pass a value on the stack. */ |
88de5835 TY |
488 | |
489 | static void | |
4a75d7c5 TY |
490 | pass_on_stack (struct regcache *regcache, const gdb_byte *val, |
491 | size_t len, int align, gdb_byte **addr) | |
88de5835 TY |
492 | { |
493 | align = align_up (align, 8); | |
494 | if (align > 16) | |
495 | align = 16; | |
496 | ||
4a75d7c5 | 497 | CORE_ADDR align_addr = (CORE_ADDR) (*addr); |
88de5835 | 498 | align_addr = align_up (align_addr, align); |
4a75d7c5 TY |
499 | *addr = (gdb_byte *) align_addr; |
500 | memcpy (*addr, val, len); | |
501 | *addr += len; | |
88de5835 TY |
502 | } |
503 | ||
4a75d7c5 | 504 | /* Compute the numbers of struct member. */ |
88de5835 TY |
505 | |
506 | static void | |
4a75d7c5 TY |
507 | compute_struct_member (struct type *type, |
508 | unsigned int *fixed_point_members, | |
509 | unsigned int *floating_point_members, | |
510 | bool *first_member_is_fixed_point) | |
88de5835 TY |
511 | { |
512 | for (int i = 0; i < type->num_fields (); i++) | |
513 | { | |
514 | struct type *field_type = check_typedef (type->field (i).type ()); | |
515 | ||
516 | if (field_type->code () == TYPE_CODE_INT | |
517 | || field_type->code () == TYPE_CODE_BOOL | |
518 | || field_type->code () == TYPE_CODE_CHAR | |
519 | || field_type->code () == TYPE_CODE_RANGE | |
520 | || field_type->code () == TYPE_CODE_ENUM | |
521 | || field_type->code () == TYPE_CODE_PTR) | |
522 | { | |
4a75d7c5 | 523 | (*fixed_point_members)++; |
88de5835 | 524 | |
4a75d7c5 TY |
525 | if (*floating_point_members == 0) |
526 | *first_member_is_fixed_point = true; | |
88de5835 TY |
527 | } |
528 | else if (field_type->code () == TYPE_CODE_FLT) | |
4a75d7c5 | 529 | (*floating_point_members)++; |
88de5835 | 530 | else if (field_type->code () == TYPE_CODE_STRUCT) |
4a75d7c5 TY |
531 | compute_struct_member (field_type, |
532 | fixed_point_members, | |
533 | floating_point_members, | |
534 | first_member_is_fixed_point); | |
88de5835 | 535 | else if (field_type->code () == TYPE_CODE_COMPLEX) |
4a75d7c5 | 536 | (*floating_point_members) += 2; |
88de5835 TY |
537 | } |
538 | } | |
539 | ||
540 | /* Implement the push_dummy_call gdbarch method. */ | |
541 | ||
542 | static CORE_ADDR | |
543 | loongarch_push_dummy_call (struct gdbarch *gdbarch, | |
544 | struct value *function, | |
545 | struct regcache *regcache, | |
546 | CORE_ADDR bp_addr, | |
547 | int nargs, | |
548 | struct value **args, | |
549 | CORE_ADDR sp, | |
550 | function_call_return_method return_method, | |
551 | CORE_ADDR struct_addr) | |
552 | { | |
553 | int regsize = register_size (gdbarch, 0); | |
554 | unsigned int gar = LOONGARCH_ARG_REGNUM; | |
555 | unsigned int far = LOONGARCH_ARG_REGNUM; | |
4a75d7c5 TY |
556 | unsigned int fixed_point_members; |
557 | unsigned int floating_point_members; | |
558 | bool first_member_is_fixed_point; | |
559 | gdb_byte buf[1024] = { 0 }; | |
560 | gdb_byte *addr = buf; | |
88de5835 TY |
561 | |
562 | if (return_method != return_method_normal) | |
563 | pass_in_gar (regcache, gar--, (gdb_byte *) &struct_addr); | |
564 | ||
88de5835 TY |
565 | for (int i = 0; i < nargs; i++) |
566 | { | |
567 | struct value *arg = args[i]; | |
568 | const gdb_byte *val = value_contents (arg).data (); | |
569 | struct type *type = check_typedef (value_type (arg)); | |
df86565b | 570 | size_t len = type->length (); |
88de5835 TY |
571 | int align = type_align (type); |
572 | enum type_code code = type->code (); | |
84205e65 TY |
573 | struct type *func_type = check_typedef (value_type (function)); |
574 | bool varargs = (func_type->has_varargs () && i >= func_type->num_fields ()); | |
88de5835 TY |
575 | |
576 | switch (code) | |
577 | { | |
578 | case TYPE_CODE_INT: | |
579 | case TYPE_CODE_BOOL: | |
580 | case TYPE_CODE_CHAR: | |
581 | case TYPE_CODE_RANGE: | |
582 | case TYPE_CODE_ENUM: | |
583 | case TYPE_CODE_PTR: | |
584 | { | |
585 | /* integer or pointer type is passed in GAR. | |
4a75d7c5 TY |
586 | If no GAR is available, it's passed on the stack. |
587 | When passed in registers or on the stack, | |
588 | the unsigned integer scalars are zero-extended to GRLEN bits, | |
589 | and the signed integer scalars are sign-extended. */ | |
88de5835 TY |
590 | if (type->is_unsigned ()) |
591 | { | |
592 | ULONGEST data = extract_unsigned_integer (val, len, BFD_ENDIAN_LITTLE); | |
593 | if (gar > 0) | |
594 | pass_in_gar (regcache, gar--, (gdb_byte *) &data); | |
595 | else | |
4a75d7c5 | 596 | pass_on_stack (regcache, (gdb_byte *) &data, len, align, &addr); |
88de5835 TY |
597 | } |
598 | else | |
599 | { | |
600 | LONGEST data = extract_signed_integer (val, len, BFD_ENDIAN_LITTLE); | |
601 | if (gar > 0) | |
602 | pass_in_gar (regcache, gar--, (gdb_byte *) &data); | |
603 | else | |
4a75d7c5 | 604 | pass_on_stack (regcache, (gdb_byte *) &data, len, align, &addr); |
88de5835 TY |
605 | } |
606 | } | |
607 | break; | |
608 | case TYPE_CODE_FLT: | |
609 | if (len == 2 * regsize) | |
610 | { | |
84205e65 | 611 | if (!varargs) |
88de5835 | 612 | { |
84205e65 TY |
613 | /* long double type is passed in a pair of GAR, |
614 | with the low-order GRLEN bits in the lower-numbered register | |
615 | and the high-order GRLEN bits in the higher-numbered register. | |
616 | If exactly one register is available, | |
617 | the low-order GRLEN bits are passed in the register | |
618 | and the high-order GRLEN bits are passed on the stack. | |
619 | If no GAR is available, it's passed on the stack. */ | |
620 | if (gar >= 2) | |
621 | { | |
622 | pass_in_gar (regcache, gar--, val); | |
623 | pass_in_gar (regcache, gar--, val + regsize); | |
624 | } | |
625 | else if (gar == 1) | |
626 | { | |
627 | pass_in_gar (regcache, gar--, val); | |
628 | pass_on_stack (regcache, val + regsize, len - regsize, align, &addr); | |
629 | } | |
630 | else | |
631 | { | |
632 | pass_on_stack (regcache, val, len, align, &addr); | |
633 | } | |
88de5835 TY |
634 | } |
635 | else | |
636 | { | |
84205e65 TY |
637 | /* Variadic arguments are passed in GARs |
638 | in the same manner as named arguments. | |
639 | And after a variadic argument has been passed on the stack, | |
640 | all future arguments will also be passed on the stack, | |
641 | i.e., the last argument register may be left unused | |
642 | due to the aligned register pair rule. | |
643 | long double data tpye is passed in an aligned GAR pair, | |
644 | the first register in the pair is even-numbered. */ | |
645 | if (gar >= 2) | |
646 | { | |
647 | if (gar % 2 == 0) | |
648 | { | |
649 | pass_in_gar (regcache, gar--, val); | |
650 | pass_in_gar (regcache, gar--, val + regsize); | |
651 | } | |
652 | else | |
653 | { | |
654 | gar--; | |
655 | pass_in_gar (regcache, gar--, val); | |
656 | pass_in_gar (regcache, gar--, val + regsize); | |
657 | } | |
658 | } | |
659 | else if (gar == 1) | |
660 | { | |
661 | gar--; | |
662 | pass_on_stack (regcache, val, len, align, &addr); | |
663 | } | |
664 | else | |
665 | { | |
666 | pass_on_stack (regcache, val, len, align, &addr); | |
667 | } | |
88de5835 TY |
668 | } |
669 | } | |
670 | else | |
671 | { | |
672 | /* The other floating-point type is passed in FAR. | |
4a75d7c5 TY |
673 | If no FAR is available, it's passed in GAR. |
674 | If no GAR is available, it's passed on the stack. */ | |
84205e65 | 675 | if (!varargs && far > 0) |
88de5835 TY |
676 | pass_in_far (regcache, far--, val); |
677 | else if (gar > 0) | |
678 | pass_in_gar (regcache, gar--, val); | |
679 | else | |
4a75d7c5 | 680 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
681 | } |
682 | break; | |
683 | case TYPE_CODE_STRUCT: | |
684 | { | |
685 | fixed_point_members = 0; | |
686 | floating_point_members = 0; | |
687 | first_member_is_fixed_point = false; | |
4a75d7c5 TY |
688 | compute_struct_member (type, |
689 | &fixed_point_members, | |
690 | &floating_point_members, | |
691 | &first_member_is_fixed_point); | |
88de5835 TY |
692 | |
693 | if (len > 0 && len <= regsize) | |
694 | { | |
695 | /* The structure has only fixed-point members. */ | |
696 | if (fixed_point_members > 0 && floating_point_members == 0) | |
697 | { | |
698 | /* If there is an available GAR, | |
4a75d7c5 TY |
699 | the structure is passed through the GAR by value passing; |
700 | If no GAR is available, it's passed on the stack. */ | |
88de5835 TY |
701 | if (gar > 0) |
702 | pass_in_gar (regcache, gar--, val); | |
703 | else | |
4a75d7c5 | 704 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
705 | } |
706 | /* The structure has only floating-point members. */ | |
707 | else if (fixed_point_members == 0 && floating_point_members > 0) | |
708 | { | |
4a75d7c5 TY |
709 | /* The structure has one floating-point member. |
710 | The argument is passed in a FAR. | |
711 | If no FAR is available, the value is passed in a GAR. | |
712 | if no GAR is available, the value is passed on the stack. */ | |
88de5835 TY |
713 | if (floating_point_members == 1) |
714 | { | |
84205e65 | 715 | if (!varargs && far > 0) |
88de5835 TY |
716 | pass_in_far (regcache, far--, val); |
717 | else if (gar > 0) | |
718 | pass_in_gar (regcache, gar--, val); | |
719 | else | |
4a75d7c5 | 720 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 | 721 | } |
4a75d7c5 TY |
722 | /* The structure has two floating-point members. |
723 | The argument is passed in a pair of available FAR, | |
724 | with the low-order float member bits in the lower-numbered FAR | |
725 | and the high-order float member bits in the higher-numbered FAR. | |
726 | If the number of available FAR is less than 2, it's passed in a GAR, | |
727 | and passed on the stack if no GAR is available. */ | |
88de5835 TY |
728 | else if (floating_point_members == 2) |
729 | { | |
84205e65 | 730 | if (!varargs && far >= 2) |
88de5835 TY |
731 | { |
732 | pass_in_far (regcache, far--, val); | |
733 | pass_in_far (regcache, far--, val + align); | |
734 | } | |
735 | else if (gar > 0) | |
736 | { | |
737 | pass_in_gar (regcache, gar--, val); | |
738 | } | |
739 | else | |
740 | { | |
4a75d7c5 | 741 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
742 | } |
743 | } | |
744 | } | |
745 | /* The structure has both fixed-point and floating-point members. */ | |
746 | else if (fixed_point_members > 0 && floating_point_members > 0) | |
747 | { | |
4a75d7c5 TY |
748 | /* The structure has one float member and multiple fixed-point members. |
749 | If there are available GAR, the structure is passed in a GAR, | |
750 | and passed on the stack if no GAR is available. */ | |
88de5835 TY |
751 | if (floating_point_members == 1 && fixed_point_members > 1) |
752 | { | |
753 | if (gar > 0) | |
754 | pass_in_gar (regcache, gar--, val); | |
755 | else | |
4a75d7c5 | 756 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 | 757 | } |
4a75d7c5 TY |
758 | /* The structure has one float member and one fixed-point member. |
759 | If one FAR and one GAR are available, | |
760 | the floating-point member of the structure is passed in the FAR, | |
761 | and the fixed-point member of the structure is passed in the GAR. | |
762 | If no floating-point register but one GAR is available, it's passed in GAR; | |
763 | If no GAR is available, it's passed on the stack. */ | |
88de5835 TY |
764 | else if (floating_point_members == 1 && fixed_point_members == 1) |
765 | { | |
84205e65 | 766 | if (!varargs && far > 0 && gar > 0) |
88de5835 TY |
767 | { |
768 | if (first_member_is_fixed_point == false) | |
769 | { | |
770 | pass_in_far (regcache, far--, val); | |
771 | pass_in_gar (regcache, gar--, val + align); | |
772 | } | |
773 | else | |
774 | { | |
775 | pass_in_gar (regcache, gar--, val); | |
776 | pass_in_far (regcache, far--, val + align); | |
777 | } | |
778 | } | |
779 | else | |
780 | { | |
781 | if (gar > 0) | |
782 | pass_in_gar (regcache, gar--, val); | |
783 | else | |
4a75d7c5 | 784 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
785 | } |
786 | } | |
787 | } | |
788 | } | |
789 | else if (len > regsize && len <= 2 * regsize) | |
790 | { | |
4a75d7c5 | 791 | /* The structure has only fixed-point members. */ |
88de5835 TY |
792 | if (fixed_point_members > 0 && floating_point_members == 0) |
793 | { | |
794 | /* The argument is passed in a pair of available GAR, | |
4a75d7c5 TY |
795 | with the low-order bits in the lower-numbered GAR |
796 | and the high-order bits in the higher-numbered GAR. | |
797 | If only one GAR is available, | |
798 | the low-order bits are in the GAR | |
799 | and the high-order bits are on the stack, | |
800 | and passed on the stack if no GAR is available. */ | |
88de5835 TY |
801 | if (gar >= 2) |
802 | { | |
803 | pass_in_gar (regcache, gar--, val); | |
804 | pass_in_gar (regcache, gar--, val + regsize); | |
805 | } | |
806 | else if (gar == 1) | |
807 | { | |
808 | pass_in_gar (regcache, gar--, val); | |
4a75d7c5 | 809 | pass_on_stack (regcache, val + regsize, len - regsize, align, &addr); |
88de5835 TY |
810 | } |
811 | else | |
812 | { | |
4a75d7c5 | 813 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
814 | } |
815 | } | |
4a75d7c5 | 816 | /* The structure has only floating-point members. */ |
88de5835 TY |
817 | else if (fixed_point_members == 0 && floating_point_members > 0) |
818 | { | |
819 | /* The structure has one long double member | |
4a75d7c5 TY |
820 | or one double member and two adjacent float members |
821 | or 3-4 float members. | |
822 | The argument is passed in a pair of available GAR, | |
823 | with the low-order bits in the lower-numbered GAR | |
824 | and the high-order bits in the higher-numbered GAR. | |
825 | If only one GAR is available, | |
826 | the low-order bits are in the GAR | |
827 | and the high-order bits are on the stack, | |
828 | and passed on the stack if no GAR is available. */ | |
88de5835 TY |
829 | if ((len == 16 && floating_point_members == 1) |
830 | || (len == 16 && floating_point_members == 3) | |
831 | || (len == 12 && floating_point_members == 3) | |
832 | || (len == 16 && floating_point_members == 4)) | |
833 | { | |
834 | if (gar >= 2) | |
835 | { | |
836 | pass_in_gar (regcache, gar--, val); | |
837 | pass_in_gar (regcache, gar--, val + regsize); | |
838 | } | |
839 | else if (gar == 1) | |
840 | { | |
84205e65 TY |
841 | if (!varargs) |
842 | { | |
843 | pass_in_gar (regcache, gar--, val); | |
844 | pass_on_stack (regcache, val + regsize, len - regsize, align, &addr); | |
845 | } | |
846 | else | |
847 | { | |
848 | gar--; | |
849 | pass_on_stack (regcache, val, len, align, &addr); | |
850 | } | |
88de5835 TY |
851 | } |
852 | else | |
853 | { | |
4a75d7c5 | 854 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
855 | } |
856 | } | |
4a75d7c5 TY |
857 | /* The structure has two double members |
858 | or one double member and one float member. | |
859 | The argument is passed in a pair of available FAR, | |
860 | with the low-order bits in the lower-numbered FAR | |
861 | and the high-order bits in the higher-numbered FAR. | |
862 | If no a pair of available FAR, | |
863 | it's passed in a pair of available GAR, | |
864 | with the low-order bits in the lower-numbered GAR | |
865 | and the high-order bits in the higher-numbered GAR. | |
866 | If only one GAR is available, | |
867 | the low-order bits are in the GAR | |
868 | and the high-order bits are on stack, | |
869 | and passed on the stack if no GAR is available. */ | |
88de5835 TY |
870 | else if ((len == 16 && floating_point_members == 2) |
871 | || (len == 12 && floating_point_members == 2)) | |
872 | { | |
84205e65 | 873 | if (!varargs && far >= 2) |
88de5835 TY |
874 | { |
875 | pass_in_far (regcache, far--, val); | |
876 | pass_in_far (regcache, far--, val + regsize); | |
877 | } | |
878 | else if (gar >= 2) | |
879 | { | |
880 | pass_in_gar (regcache, gar--, val); | |
881 | pass_in_gar (regcache, gar--, val + regsize); | |
882 | } | |
883 | else if (gar == 1) | |
884 | { | |
885 | pass_in_gar (regcache, gar--, val); | |
4a75d7c5 | 886 | pass_on_stack (regcache, val + regsize, len - regsize, align, &addr); |
88de5835 TY |
887 | } |
888 | else | |
889 | { | |
4a75d7c5 | 890 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
891 | } |
892 | } | |
893 | } | |
4a75d7c5 | 894 | /* The structure has both fixed-point and floating-point members. */ |
88de5835 TY |
895 | else if (fixed_point_members > 0 && floating_point_members > 0) |
896 | { | |
4a75d7c5 | 897 | /* The structure has one floating-point member and one fixed-point member. */ |
88de5835 TY |
898 | if (floating_point_members == 1 && fixed_point_members == 1) |
899 | { | |
900 | /* If one FAR and one GAR are available, | |
4a75d7c5 TY |
901 | the floating-point member of the structure is passed in the FAR, |
902 | and the fixed-point member of the structure is passed in the GAR; | |
903 | If no floating-point registers but two GARs are available, | |
904 | it's passed in the two GARs; | |
905 | If only one GAR is available, | |
906 | the low-order bits are in the GAR | |
907 | and the high-order bits are on the stack; | |
908 | And it's passed on the stack if no GAR is available. */ | |
84205e65 | 909 | if (!varargs && far > 0 && gar > 0) |
88de5835 TY |
910 | { |
911 | if (first_member_is_fixed_point == false) | |
912 | { | |
913 | pass_in_far (regcache, far--, val); | |
914 | pass_in_gar (regcache, gar--, val + regsize); | |
915 | } | |
916 | else | |
917 | { | |
918 | pass_in_gar (regcache, gar--, val); | |
919 | pass_in_far (regcache, far--, val + regsize); | |
920 | } | |
921 | } | |
84205e65 | 922 | else if ((!varargs && far == 0 && gar >= 2) || (varargs && gar >= 2)) |
88de5835 TY |
923 | { |
924 | pass_in_gar (regcache, gar--, val); | |
925 | pass_in_gar (regcache, gar--, val + regsize); | |
926 | } | |
84205e65 | 927 | else if ((!varargs && far == 0 && gar == 1) || (varargs && gar == 1)) |
88de5835 TY |
928 | { |
929 | pass_in_gar (regcache, gar--, val); | |
4a75d7c5 | 930 | pass_on_stack (regcache, val + regsize, len - regsize, align, &addr); |
88de5835 | 931 | } |
84205e65 | 932 | else if ((!varargs && far == 0 && gar == 0) || (varargs && gar == 0)) |
88de5835 | 933 | { |
4a75d7c5 | 934 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
935 | } |
936 | } | |
937 | else | |
938 | { | |
939 | /* The argument is passed in a pair of available GAR, | |
4a75d7c5 TY |
940 | with the low-order bits in the lower-numbered GAR |
941 | and the high-order bits in the higher-numbered GAR. | |
942 | If only one GAR is available, | |
943 | the low-order bits are in the GAR | |
944 | and the high-order bits are on the stack, | |
945 | and passed on the stack if no GAR is available. */ | |
88de5835 TY |
946 | if (gar >= 2) |
947 | { | |
948 | pass_in_gar (regcache, gar--, val); | |
949 | pass_in_gar (regcache, gar--, val + regsize); | |
950 | } | |
951 | else if (gar == 1) | |
952 | { | |
953 | pass_in_gar (regcache, gar--, val); | |
4a75d7c5 | 954 | pass_on_stack (regcache, val + regsize, len - regsize, align, &addr); |
88de5835 TY |
955 | } |
956 | else | |
957 | { | |
4a75d7c5 | 958 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
959 | } |
960 | } | |
961 | } | |
962 | } | |
963 | else if (len > 2 * regsize) | |
964 | { | |
83f477f2 | 965 | /* It's passed by reference and are replaced in the argument list with the address. |
4a75d7c5 TY |
966 | If there is an available GAR, the reference is passed in the GAR, |
967 | and passed on the stack if no GAR is available. */ | |
88de5835 TY |
968 | sp = align_down (sp - len, 16); |
969 | write_memory (sp, val, len); | |
970 | ||
971 | if (gar > 0) | |
972 | pass_in_gar (regcache, gar--, (const gdb_byte *) &sp); | |
973 | else | |
4a75d7c5 | 974 | pass_on_stack (regcache, (const gdb_byte*) &sp, len, regsize, &addr); |
88de5835 TY |
975 | } |
976 | } | |
977 | break; | |
978 | case TYPE_CODE_UNION: | |
979 | /* Union is passed in GAR or stack. */ | |
980 | if (len > 0 && len <= regsize) | |
981 | { | |
982 | /* The argument is passed in a GAR, | |
4a75d7c5 | 983 | or on the stack by value if no GAR is available. */ |
88de5835 TY |
984 | if (gar > 0) |
985 | pass_in_gar (regcache, gar--, val); | |
986 | else | |
4a75d7c5 | 987 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
988 | } |
989 | else if (len > regsize && len <= 2 * regsize) | |
990 | { | |
991 | /* The argument is passed in a pair of available GAR, | |
4a75d7c5 TY |
992 | with the low-order bits in the lower-numbered GAR |
993 | and the high-order bits in the higher-numbered GAR. | |
994 | If only one GAR is available, | |
995 | the low-order bits are in the GAR | |
996 | and the high-order bits are on the stack. | |
997 | The arguments are passed on the stack when no GAR is available. */ | |
88de5835 TY |
998 | if (gar >= 2) |
999 | { | |
1000 | pass_in_gar (regcache, gar--, val); | |
1001 | pass_in_gar (regcache, gar--, val + regsize); | |
1002 | } | |
1003 | else if (gar == 1) | |
1004 | { | |
1005 | pass_in_gar (regcache, gar--, val); | |
4a75d7c5 | 1006 | pass_on_stack (regcache, val + regsize, len - regsize, align, &addr); |
88de5835 TY |
1007 | } |
1008 | else | |
1009 | { | |
4a75d7c5 | 1010 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
1011 | } |
1012 | } | |
1013 | else if (len > 2 * regsize) | |
1014 | { | |
83f477f2 | 1015 | /* It's passed by reference and are replaced in the argument list with the address. |
4a75d7c5 TY |
1016 | If there is an available GAR, the reference is passed in the GAR, |
1017 | and passed on the stack if no GAR is available. */ | |
88de5835 TY |
1018 | sp = align_down (sp - len, 16); |
1019 | write_memory (sp, val, len); | |
1020 | ||
1021 | if (gar > 0) | |
1022 | pass_in_gar (regcache, gar--, (const gdb_byte *) &sp); | |
1023 | else | |
4a75d7c5 | 1024 | pass_on_stack (regcache, (const gdb_byte*) &sp, len, regsize, &addr); |
88de5835 TY |
1025 | } |
1026 | break; | |
1027 | case TYPE_CODE_COMPLEX: | |
1028 | { | |
27710edb | 1029 | struct type *target_type = check_typedef (type->target_type ()); |
df86565b | 1030 | size_t target_len = target_type->length (); |
88de5835 TY |
1031 | |
1032 | if (target_len < regsize) | |
1033 | { | |
1034 | /* The complex with two float members | |
4a75d7c5 TY |
1035 | is passed in a pair of available FAR, |
1036 | with the low-order float member bits in the lower-numbered FAR | |
1037 | and the high-order float member bits in the higher-numbered FAR. | |
1038 | If the number of available FAR is less than 2, it's passed in a GAR, | |
1039 | and passed on the stack if no GAR is available. */ | |
84205e65 | 1040 | if (!varargs && far >= 2) |
88de5835 TY |
1041 | { |
1042 | pass_in_far (regcache, far--, val); | |
1043 | pass_in_far (regcache, far--, val + align); | |
1044 | } | |
1045 | else if (gar > 0) | |
1046 | { | |
1047 | pass_in_gar (regcache, gar--, val); | |
1048 | } | |
1049 | else | |
1050 | { | |
4a75d7c5 | 1051 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
1052 | } |
1053 | } | |
1054 | else if (target_len == regsize) | |
1055 | { | |
1056 | /* The complex with two double members | |
4a75d7c5 TY |
1057 | is passed in a pair of available FAR, |
1058 | with the low-order bits in the lower-numbered FAR | |
1059 | and the high-order bits in the higher-numbered FAR. | |
1060 | If no a pair of available FAR, | |
1061 | it's passed in a pair of available GAR, | |
1062 | with the low-order bits in the lower-numbered GAR | |
1063 | and the high-order bits in the higher-numbered GAR. | |
1064 | If only one GAR is available, | |
1065 | the low-order bits are in the GAR | |
1066 | and the high-order bits are on stack, | |
1067 | and passed on the stack if no GAR is available. */ | |
88de5835 | 1068 | { |
84205e65 | 1069 | if (!varargs && far >= 2) |
88de5835 TY |
1070 | { |
1071 | pass_in_far (regcache, far--, val); | |
1072 | pass_in_far (regcache, far--, val + align); | |
1073 | } | |
1074 | else if (gar >= 2) | |
1075 | { | |
1076 | pass_in_gar (regcache, gar--, val); | |
1077 | pass_in_gar (regcache, gar--, val + align); | |
1078 | } | |
1079 | else if (gar == 1) | |
1080 | { | |
1081 | pass_in_gar (regcache, gar--, val); | |
4a75d7c5 | 1082 | pass_on_stack (regcache, val + align, len - align, align, &addr); |
88de5835 TY |
1083 | } |
1084 | else | |
1085 | { | |
4a75d7c5 | 1086 | pass_on_stack (regcache, val, len, align, &addr); |
88de5835 TY |
1087 | } |
1088 | } | |
1089 | } | |
1090 | else if (target_len == 2 * regsize) | |
1091 | { | |
1092 | /* The complex with two long double members | |
4a75d7c5 TY |
1093 | is passed by reference and are replaced in the argument list with the address. |
1094 | If there is an available GAR, the reference is passed in the GAR, | |
1095 | and passed on the stack if no GAR is available. */ | |
88de5835 TY |
1096 | sp = align_down (sp - len, 16); |
1097 | write_memory (sp, val, len); | |
1098 | ||
1099 | if (gar > 0) | |
1100 | pass_in_gar (regcache, gar--, (const gdb_byte *) &sp); | |
1101 | else | |
4a75d7c5 | 1102 | pass_on_stack (regcache, (const gdb_byte*) &sp, regsize, regsize, &addr); |
88de5835 TY |
1103 | } |
1104 | } | |
1105 | break; | |
1106 | default: | |
1107 | break; | |
1108 | } | |
1109 | } | |
1110 | ||
1111 | if (addr > buf) | |
1112 | { | |
1113 | sp -= addr - buf; | |
1114 | sp = align_down (sp, 16); | |
1115 | write_memory (sp, buf, addr - buf); | |
1116 | } | |
1117 | ||
1118 | regcache_cooked_write_unsigned (regcache, LOONGARCH_RA_REGNUM, bp_addr); | |
1119 | regcache_cooked_write_unsigned (regcache, LOONGARCH_SP_REGNUM, sp); | |
1120 | ||
1121 | return sp; | |
1122 | } | |
1123 | ||
ecbff28a TY |
1124 | /* Partial transfer of a cooked register. */ |
1125 | ||
1126 | static void | |
1127 | loongarch_xfer_reg (struct regcache *regcache, | |
1128 | int regnum, int len, gdb_byte *readbuf, | |
1129 | const gdb_byte *writebuf, size_t offset) | |
1130 | { | |
1131 | if (readbuf) | |
1132 | regcache->cooked_read_part (regnum, 0, len, readbuf + offset); | |
1133 | if (writebuf) | |
1134 | regcache->cooked_write_part (regnum, 0, len, writebuf + offset); | |
1135 | } | |
1136 | ||
0757a503 | 1137 | /* Implement the return_value gdbarch method. */ |
0b8c9557 TY |
1138 | |
1139 | static enum return_value_convention | |
1140 | loongarch_return_value (struct gdbarch *gdbarch, struct value *function, | |
1141 | struct type *type, struct regcache *regcache, | |
1142 | gdb_byte *readbuf, const gdb_byte *writebuf) | |
1143 | { | |
ecbff28a TY |
1144 | int regsize = register_size (gdbarch, 0); |
1145 | enum type_code code = type->code (); | |
df86565b | 1146 | size_t len = type->length (); |
ecbff28a TY |
1147 | unsigned int fixed_point_members; |
1148 | unsigned int floating_point_members; | |
1149 | bool first_member_is_fixed_point; | |
1150 | int a0 = LOONGARCH_A0_REGNUM; | |
1151 | int a1 = LOONGARCH_A0_REGNUM + 1; | |
1152 | int f0 = LOONGARCH_FIRST_FP_REGNUM; | |
1153 | int f1 = LOONGARCH_FIRST_FP_REGNUM + 1; | |
1154 | ||
1155 | if (len > 2 * regsize) | |
1156 | return RETURN_VALUE_STRUCT_CONVENTION; | |
0b8c9557 | 1157 | |
ecbff28a | 1158 | switch (code) |
0b8c9557 | 1159 | { |
ecbff28a TY |
1160 | case TYPE_CODE_INT: |
1161 | case TYPE_CODE_BOOL: | |
1162 | case TYPE_CODE_CHAR: | |
1163 | case TYPE_CODE_RANGE: | |
1164 | case TYPE_CODE_ENUM: | |
1165 | case TYPE_CODE_PTR: | |
1166 | { | |
1167 | /* integer or pointer type. | |
1168 | The return value is passed in a0, | |
1169 | the unsigned integer scalars are zero-extended to GRLEN bits, | |
1170 | and the signed integer scalars are sign-extended. */ | |
1171 | if (writebuf) | |
1172 | { | |
1173 | gdb_byte buf[regsize]; | |
1174 | if (type->is_unsigned ()) | |
1175 | { | |
1176 | ULONGEST data = extract_unsigned_integer (writebuf, len, BFD_ENDIAN_LITTLE); | |
1177 | store_unsigned_integer (buf, regsize, BFD_ENDIAN_LITTLE, data); | |
1178 | } | |
1179 | else | |
1180 | { | |
1181 | LONGEST data = extract_signed_integer (writebuf, len, BFD_ENDIAN_LITTLE); | |
1182 | store_signed_integer (buf, regsize, BFD_ENDIAN_LITTLE, data); | |
1183 | } | |
1184 | loongarch_xfer_reg (regcache, a0, regsize, nullptr, buf, 0); | |
1185 | } | |
1186 | else | |
1187 | loongarch_xfer_reg (regcache, a0, len, readbuf, nullptr, 0); | |
1188 | } | |
1189 | break; | |
1190 | case TYPE_CODE_FLT: | |
1191 | /* long double type. | |
1192 | The return value is passed in a0 and a1. */ | |
1193 | if (len == 2 * regsize) | |
1194 | { | |
1195 | loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); | |
1196 | loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); | |
1197 | } | |
1198 | /* float or double type. | |
1199 | The return value is passed in f0. */ | |
1200 | else | |
1201 | { | |
1202 | loongarch_xfer_reg (regcache, f0, len, readbuf, writebuf, 0); | |
1203 | } | |
1204 | break; | |
1205 | case TYPE_CODE_STRUCT: | |
1206 | { | |
1207 | fixed_point_members = 0; | |
1208 | floating_point_members = 0; | |
1209 | first_member_is_fixed_point = false; | |
1210 | compute_struct_member (type, | |
1211 | &fixed_point_members, | |
1212 | &floating_point_members, | |
1213 | &first_member_is_fixed_point); | |
1214 | ||
1215 | if (len > 0 && len <= regsize) | |
1216 | { | |
1217 | /* The structure has only fixed-point members. */ | |
1218 | if (fixed_point_members > 0 && floating_point_members == 0) | |
1219 | { | |
1220 | /* The return value is passed in a0. */ | |
1221 | loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0); | |
1222 | } | |
1223 | /* The structure has only floating-point members. */ | |
1224 | else if (fixed_point_members == 0 && floating_point_members > 0) | |
1225 | { | |
1226 | /* The structure has one floating-point member. | |
1227 | The return value is passed in f0. */ | |
1228 | if (floating_point_members == 1) | |
1229 | { | |
1230 | loongarch_xfer_reg (regcache, f0, len, readbuf, writebuf, 0); | |
1231 | } | |
1232 | /* The structure has two floating-point members. | |
1233 | The return value is passed in f0 and f1. */ | |
1234 | else if (floating_point_members == 2) | |
1235 | { | |
1236 | loongarch_xfer_reg (regcache, f0, len / 2, readbuf, writebuf, 0); | |
1237 | loongarch_xfer_reg (regcache, f1, len / 2, readbuf, writebuf, len / 2); | |
1238 | } | |
1239 | } | |
1240 | /* The structure has both fixed-point and floating-point members. */ | |
1241 | else if (fixed_point_members > 0 && floating_point_members > 0) | |
1242 | { | |
1243 | /* The structure has one float member and multiple fixed-point members. | |
1244 | The return value is passed in a0. */ | |
1245 | if (floating_point_members == 1 && fixed_point_members > 1) | |
1246 | { | |
1247 | loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0); | |
1248 | } | |
1249 | /* The structure has one float member and one fixed-point member. */ | |
1250 | else if (floating_point_members == 1 && fixed_point_members == 1) | |
1251 | { | |
1252 | /* The return value is passed in f0 and a0 if the first member is floating-point. */ | |
1253 | if (first_member_is_fixed_point == false) | |
1254 | { | |
1255 | loongarch_xfer_reg (regcache, f0, regsize / 2, readbuf, writebuf, 0); | |
1256 | loongarch_xfer_reg (regcache, a0, regsize / 2, readbuf, writebuf, regsize / 2); | |
1257 | } | |
1258 | /* The return value is passed in a0 and f0 if the first member is fixed-point. */ | |
1259 | else | |
1260 | { | |
1261 | loongarch_xfer_reg (regcache, a0, regsize / 2, readbuf, writebuf, 0); | |
1262 | loongarch_xfer_reg (regcache, f0, regsize / 2, readbuf, writebuf, regsize / 2); | |
1263 | } | |
1264 | } | |
1265 | } | |
1266 | } | |
1267 | else if (len > regsize && len <= 2 * regsize) | |
1268 | { | |
1269 | /* The structure has only fixed-point members. */ | |
1270 | if (fixed_point_members > 0 && floating_point_members == 0) | |
1271 | { | |
1272 | /* The return value is passed in a0 and a1. */ | |
1273 | loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); | |
1274 | loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); | |
1275 | } | |
1276 | /* The structure has only floating-point members. */ | |
1277 | else if (fixed_point_members == 0 && floating_point_members > 0) | |
1278 | { | |
1279 | /* The structure has one long double member | |
1280 | or one double member and two adjacent float members | |
1281 | or 3-4 float members. | |
1282 | The return value is passed in a0 and a1. */ | |
1283 | if ((len == 16 && floating_point_members == 1) | |
1284 | || (len == 16 && floating_point_members == 3) | |
1285 | || (len == 12 && floating_point_members == 3) | |
1286 | || (len == 16 && floating_point_members == 4)) | |
1287 | { | |
1288 | loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); | |
1289 | loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); | |
1290 | } | |
1291 | /* The structure has two double members | |
1292 | or one double member and one float member. | |
1293 | The return value is passed in f0 and f1. */ | |
1294 | else if ((len == 16 && floating_point_members == 2) | |
1295 | || (len == 12 && floating_point_members == 2)) | |
1296 | { | |
1297 | loongarch_xfer_reg (regcache, f0, regsize, readbuf, writebuf, 0); | |
1298 | loongarch_xfer_reg (regcache, f1, len - regsize, readbuf, writebuf, regsize); | |
1299 | } | |
1300 | } | |
1301 | /* The structure has both fixed-point and floating-point members. */ | |
1302 | else if (fixed_point_members > 0 && floating_point_members > 0) | |
1303 | { | |
1304 | /* The structure has one floating-point member and one fixed-point member. */ | |
1305 | if (floating_point_members == 1 && fixed_point_members == 1) | |
1306 | { | |
1307 | /* The return value is passed in f0 and a0 if the first member is floating-point. */ | |
1308 | if (first_member_is_fixed_point == false) | |
1309 | { | |
1310 | loongarch_xfer_reg (regcache, f0, regsize, readbuf, writebuf, 0); | |
1311 | loongarch_xfer_reg (regcache, a0, len - regsize, readbuf, writebuf, regsize); | |
1312 | } | |
1313 | /* The return value is passed in a0 and f0 if the first member is fixed-point. */ | |
1314 | else | |
1315 | { | |
1316 | loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); | |
1317 | loongarch_xfer_reg (regcache, f0, len - regsize, readbuf, writebuf, regsize); | |
1318 | } | |
1319 | } | |
1320 | else | |
1321 | { | |
1322 | /* The return value is passed in a0 and a1. */ | |
1323 | loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); | |
1324 | loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); | |
1325 | } | |
1326 | } | |
1327 | } | |
1328 | } | |
1329 | break; | |
1330 | case TYPE_CODE_UNION: | |
1331 | if (len > 0 && len <= regsize) | |
1332 | { | |
1333 | /* The return value is passed in a0. */ | |
1334 | loongarch_xfer_reg (regcache, a0, len, readbuf, writebuf, 0); | |
1335 | } | |
1336 | else if (len > regsize && len <= 2 * regsize) | |
1337 | { | |
1338 | /* The return value is passed in a0 and a1. */ | |
1339 | loongarch_xfer_reg (regcache, a0, regsize, readbuf, writebuf, 0); | |
1340 | loongarch_xfer_reg (regcache, a1, len - regsize, readbuf, writebuf, regsize); | |
1341 | } | |
1342 | break; | |
1343 | case TYPE_CODE_COMPLEX: | |
1344 | { | |
1345 | /* The return value is passed in f0 and f1. */ | |
1346 | loongarch_xfer_reg (regcache, f0, len / 2, readbuf, writebuf, 0); | |
1347 | loongarch_xfer_reg (regcache, f1, len / 2, readbuf, writebuf, len / 2); | |
1348 | } | |
1349 | break; | |
1350 | default: | |
1351 | break; | |
0b8c9557 TY |
1352 | } |
1353 | ||
0b8c9557 TY |
1354 | return RETURN_VALUE_REGISTER_CONVENTION; |
1355 | } | |
1356 | ||
0757a503 | 1357 | /* Implement the dwarf2_reg_to_regnum gdbarch method. */ |
772d1f34 TY |
1358 | |
1359 | static int | |
0757a503 | 1360 | loongarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int regnum) |
772d1f34 | 1361 | { |
0757a503 TY |
1362 | if (regnum >= 0 && regnum < 32) |
1363 | return regnum; | |
657a5022 TY |
1364 | else if (regnum >= 32 && regnum < 66) |
1365 | return LOONGARCH_FIRST_FP_REGNUM + regnum - 32; | |
772d1f34 TY |
1366 | else |
1367 | return -1; | |
1368 | } | |
1369 | ||
1370 | static constexpr gdb_byte loongarch_default_breakpoint[] = {0x05, 0x00, 0x2a, 0x00}; | |
1371 | typedef BP_MANIPULATION (loongarch_default_breakpoint) loongarch_breakpoint; | |
1372 | ||
1373 | /* Extract a set of required target features out of ABFD. If ABFD is nullptr | |
1374 | then a LOONGARCH_GDBARCH_FEATURES is returned in its default state. */ | |
1375 | ||
1376 | static struct loongarch_gdbarch_features | |
1377 | loongarch_features_from_bfd (const bfd *abfd) | |
1378 | { | |
1379 | struct loongarch_gdbarch_features features; | |
1380 | ||
1381 | /* Now try to improve on the defaults by looking at the binary we are | |
1382 | going to execute. We assume the user knows what they are doing and | |
1383 | that the target will match the binary. Remember, this code path is | |
1384 | only used at all if the target hasn't given us a description, so this | |
1385 | is really a last ditched effort to do something sane before giving | |
1386 | up. */ | |
1387 | if (abfd != nullptr && bfd_get_flavour (abfd) == bfd_target_elf_flavour) | |
1388 | { | |
1389 | unsigned char eclass = elf_elfheader (abfd)->e_ident[EI_CLASS]; | |
657a5022 | 1390 | int e_flags = elf_elfheader (abfd)->e_flags; |
772d1f34 TY |
1391 | |
1392 | if (eclass == ELFCLASS32) | |
1393 | features.xlen = 4; | |
1394 | else if (eclass == ELFCLASS64) | |
1395 | features.xlen = 8; | |
1396 | else | |
f34652de | 1397 | internal_error (_("unknown ELF header class %d"), eclass); |
657a5022 TY |
1398 | |
1399 | if (EF_LOONGARCH_IS_SINGLE_FLOAT (e_flags)) | |
1400 | features.fputype = SINGLE_FLOAT; | |
1401 | else if (EF_LOONGARCH_IS_DOUBLE_FLOAT (e_flags)) | |
1402 | features.fputype = DOUBLE_FLOAT; | |
772d1f34 TY |
1403 | } |
1404 | ||
1405 | return features; | |
1406 | } | |
1407 | ||
1408 | /* Find a suitable default target description. Use the contents of INFO, | |
1409 | specifically the bfd object being executed, to guide the selection of a | |
1410 | suitable default target description. */ | |
1411 | ||
1412 | static const struct target_desc * | |
1413 | loongarch_find_default_target_description (const struct gdbarch_info info) | |
1414 | { | |
1415 | /* Extract desired feature set from INFO. */ | |
1416 | struct loongarch_gdbarch_features features | |
1417 | = loongarch_features_from_bfd (info.abfd); | |
1418 | ||
1419 | /* If the XLEN field is still 0 then we got nothing useful from INFO.BFD, | |
1420 | maybe there was no bfd object. In this case we fall back to a minimal | |
657a5022 TY |
1421 | useful target, the x-register size is selected based on the architecture |
1422 | from INFO. */ | |
772d1f34 TY |
1423 | if (features.xlen == 0) |
1424 | features.xlen = info.bfd_arch_info->bits_per_address == 32 ? 4 : 8; | |
1425 | ||
657a5022 TY |
1426 | /* If the FPUTYPE field is still 0 then we got nothing useful from INFO.BFD, |
1427 | maybe there was no bfd object. In this case we fall back to a usual useful | |
1428 | target with double float. */ | |
1429 | if (features.fputype == 0) | |
1430 | features.fputype = DOUBLE_FLOAT; | |
1431 | ||
772d1f34 TY |
1432 | /* Now build a target description based on the feature set. */ |
1433 | return loongarch_lookup_target_description (features); | |
1434 | } | |
1435 | ||
1436 | /* Initialize the current architecture based on INFO */ | |
1437 | ||
1438 | static struct gdbarch * | |
1439 | loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) | |
1440 | { | |
657a5022 TY |
1441 | size_t regnum = 0; |
1442 | struct loongarch_gdbarch_features features; | |
1443 | tdesc_arch_data_up tdesc_data = tdesc_data_alloc (); | |
1444 | loongarch_gdbarch_tdep *tdep = new loongarch_gdbarch_tdep; | |
772d1f34 TY |
1445 | const struct target_desc *tdesc = info.target_desc; |
1446 | ||
1447 | /* Ensure we always have a target description. */ | |
1448 | if (!tdesc_has_registers (tdesc)) | |
1449 | tdesc = loongarch_find_default_target_description (info); | |
1450 | ||
1451 | const struct tdesc_feature *feature_cpu | |
1452 | = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.base"); | |
1453 | if (feature_cpu == nullptr) | |
1454 | return nullptr; | |
1455 | ||
772d1f34 TY |
1456 | |
1457 | /* Validate the description provides the mandatory base registers | |
1458 | and allocate their numbers. */ | |
1459 | bool valid_p = true; | |
1460 | for (int i = 0; i < 32; i++) | |
1461 | valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), regnum++, | |
1462 | loongarch_r_normal_name[i] + 1); | |
73691823 | 1463 | valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), regnum++, "orig_a0"); |
0757a503 TY |
1464 | valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), regnum++, "pc"); |
1465 | valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), regnum++, "badv"); | |
772d1f34 TY |
1466 | if (!valid_p) |
1467 | return nullptr; | |
1468 | ||
657a5022 TY |
1469 | const struct tdesc_feature *feature_fpu |
1470 | = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.fpu"); | |
1471 | if (feature_fpu == nullptr) | |
1472 | return nullptr; | |
1473 | ||
1474 | /* Validate the description provides the fpu registers and | |
1475 | allocate their numbers. */ | |
1476 | regnum = LOONGARCH_FIRST_FP_REGNUM; | |
ea335217 | 1477 | for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++) |
657a5022 TY |
1478 | valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++, |
1479 | loongarch_f_normal_name[i] + 1); | |
ea335217 FC |
1480 | for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++) |
1481 | valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++, | |
1482 | loongarch_c_normal_name[i] + 1); | |
657a5022 TY |
1483 | valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++, "fcsr"); |
1484 | if (!valid_p) | |
1485 | return nullptr; | |
1486 | ||
772d1f34 TY |
1487 | /* LoongArch code is always little-endian. */ |
1488 | info.byte_order_for_code = BFD_ENDIAN_LITTLE; | |
1489 | ||
1490 | /* Have a look at what the supplied (if any) bfd object requires of the | |
1491 | target, then check that this matches with what the target is | |
1492 | providing. */ | |
1493 | struct loongarch_gdbarch_features abi_features | |
1494 | = loongarch_features_from_bfd (info.abfd); | |
1495 | ||
657a5022 TY |
1496 | /* If the ABI_FEATURES xlen or fputype is 0 then this indicates we got |
1497 | no useful abi features from the INFO object. In this case we just | |
1498 | treat the hardware features as defining the abi. */ | |
772d1f34 | 1499 | if (abi_features.xlen == 0) |
657a5022 TY |
1500 | { |
1501 | int xlen_bitsize = tdesc_register_bitsize (feature_cpu, "pc"); | |
1502 | features.xlen = (xlen_bitsize / 8); | |
1503 | features.fputype = abi_features.fputype; | |
1504 | abi_features = features; | |
1505 | } | |
1506 | if (abi_features.fputype == 0) | |
1507 | { | |
1508 | features.xlen = abi_features.xlen; | |
1509 | features.fputype = DOUBLE_FLOAT; | |
1510 | abi_features = features; | |
1511 | } | |
772d1f34 TY |
1512 | |
1513 | /* Find a candidate among the list of pre-declared architectures. */ | |
1514 | for (arches = gdbarch_list_lookup_by_info (arches, &info); | |
1515 | arches != nullptr; | |
1516 | arches = gdbarch_list_lookup_by_info (arches->next, &info)) | |
1517 | { | |
1518 | /* Check that the feature set of the ARCHES matches the feature set | |
1519 | we are looking for. If it doesn't then we can't reuse this | |
1520 | gdbarch. */ | |
1521 | loongarch_gdbarch_tdep *candidate_tdep | |
08106042 | 1522 | = gdbarch_tdep<loongarch_gdbarch_tdep> (arches->gdbarch); |
772d1f34 TY |
1523 | |
1524 | if (candidate_tdep->abi_features != abi_features) | |
1525 | continue; | |
1526 | ||
1527 | break; | |
1528 | } | |
1529 | ||
1530 | if (arches != nullptr) | |
1531 | return arches->gdbarch; | |
1532 | ||
1533 | /* None found, so create a new architecture from the information provided. */ | |
1534 | struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep); | |
1535 | tdep->abi_features = abi_features; | |
1536 | ||
1537 | /* Target data types. */ | |
1538 | set_gdbarch_short_bit (gdbarch, 16); | |
1539 | set_gdbarch_int_bit (gdbarch, 32); | |
1540 | set_gdbarch_long_bit (gdbarch, info.bfd_arch_info->bits_per_address); | |
1541 | set_gdbarch_long_long_bit (gdbarch, 64); | |
e34f44e1 TY |
1542 | set_gdbarch_float_bit (gdbarch, 32); |
1543 | set_gdbarch_double_bit (gdbarch, 64); | |
1544 | set_gdbarch_long_double_bit (gdbarch, 128); | |
552f1157 | 1545 | set_gdbarch_long_double_format (gdbarch, floatformats_ieee_quad); |
772d1f34 TY |
1546 | set_gdbarch_ptr_bit (gdbarch, info.bfd_arch_info->bits_per_address); |
1547 | set_gdbarch_char_signed (gdbarch, 0); | |
1548 | ||
1549 | info.target_desc = tdesc; | |
1550 | info.tdesc_data = tdesc_data.get (); | |
1551 | ||
1552 | /* Information about registers. */ | |
772d1f34 | 1553 | set_gdbarch_num_regs (gdbarch, regnum); |
0757a503 TY |
1554 | set_gdbarch_sp_regnum (gdbarch, LOONGARCH_SP_REGNUM); |
1555 | set_gdbarch_pc_regnum (gdbarch, LOONGARCH_PC_REGNUM); | |
772d1f34 TY |
1556 | |
1557 | /* Finalise the target description registers. */ | |
1558 | tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data)); | |
1559 | ||
88de5835 TY |
1560 | /* Functions handling dummy frames. */ |
1561 | set_gdbarch_push_dummy_call (gdbarch, loongarch_push_dummy_call); | |
1562 | ||
0b8c9557 TY |
1563 | /* Return value info */ |
1564 | set_gdbarch_return_value (gdbarch, loongarch_return_value); | |
1565 | ||
772d1f34 TY |
1566 | /* Advance PC across function entry code. */ |
1567 | set_gdbarch_skip_prologue (gdbarch, loongarch_skip_prologue); | |
1568 | ||
1569 | /* Stack grows downward. */ | |
1570 | set_gdbarch_inner_than (gdbarch, core_addr_lessthan); | |
1571 | ||
1572 | /* Frame info. */ | |
1573 | set_gdbarch_frame_align (gdbarch, loongarch_frame_align); | |
1574 | ||
1575 | /* Breakpoint manipulation. */ | |
2e90d025 | 1576 | set_gdbarch_software_single_step (gdbarch, loongarch_software_single_step); |
772d1f34 TY |
1577 | set_gdbarch_breakpoint_kind_from_pc (gdbarch, loongarch_breakpoint::kind_from_pc); |
1578 | set_gdbarch_sw_breakpoint_from_kind (gdbarch, loongarch_breakpoint::bp_from_kind); | |
1579 | ||
1580 | /* Frame unwinders. Use DWARF debug info if available, otherwise use our own unwinder. */ | |
1581 | set_gdbarch_dwarf2_reg_to_regnum (gdbarch, loongarch_dwarf2_reg_to_regnum); | |
1582 | dwarf2_append_unwinders (gdbarch); | |
1583 | frame_unwind_append_unwinder (gdbarch, &loongarch_frame_unwind); | |
1584 | ||
1585 | /* Hook in OS ABI-specific overrides, if they have been registered. */ | |
1586 | gdbarch_init_osabi (info, gdbarch); | |
1587 | ||
1588 | return gdbarch; | |
1589 | } | |
1590 | ||
1591 | void _initialize_loongarch_tdep (); | |
1592 | void | |
1593 | _initialize_loongarch_tdep () | |
1594 | { | |
1595 | gdbarch_register (bfd_arch_loongarch, loongarch_gdbarch_init, nullptr); | |
1596 | } |