From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7873) id 692DF3858D32; Thu, 7 Jul 2022 09:10:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 692DF3858D32 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Tiezhu Yang To: gdb-cvs@sourceware.org Subject: [binutils-gdb] gdb: LoongArch: Implement the push_dummy_call gdbarch method X-Act-Checkin: binutils-gdb X-Git-Author: Tiezhu Yang X-Git-Refname: refs/heads/master X-Git-Oldrev: 045f385d9a1ee7269d3fa50657c4c7d1d7ba6c0f X-Git-Newrev: 88de583569400f6c81caa6f943d1290d134ea48a Message-Id: <20220707091039.692DF3858D32@sourceware.org> Date: Thu, 7 Jul 2022 09:10:39 +0000 (GMT) X-BeenThere: gdb-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Jul 2022 09:10:39 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D88de58356940= 0f6c81caa6f943d1290d134ea48a commit 88de583569400f6c81caa6f943d1290d134ea48a Author: Tiezhu Yang Date: Thu Jul 7 14:33:19 2022 +0800 gdb: LoongArch: Implement the push_dummy_call gdbarch method =20 According to "Procedure Calling Convention" in "LoongArch ELF ABI specification" [1], implement the push_dummy_call gdbarch method as clear as possible. =20 [1] https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-AB= I-EN.html#_procedure_calling_convention =20 Signed-off-by: Tiezhu Yang Diff: --- gdb/loongarch-tdep.c | 596 +++++++++++++++++++++++++++++++++++++++++++++++= ++++ gdb/loongarch-tdep.h | 2 + 2 files changed, 598 insertions(+) diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c index 76480ce6c94..3add71b2a09 100644 --- a/gdb/loongarch-tdep.c +++ b/gdb/loongarch-tdep.c @@ -452,6 +452,599 @@ static const struct frame_unwind loongarch_frame_unwi= nd =3D { /*.prev_arch =3D*/nullptr, }; =20 +static void +pass_in_gar (struct regcache *regcache, unsigned int gar, const gdb_byte *= val) +{ + unsigned int regnum =3D LOONGARCH_ARG_REGNUM - gar + LOONGARCH_A0_REGNUM; + regcache->cooked_write (regnum, val); +} + +static void +pass_in_far (struct regcache *regcache, unsigned int far, const gdb_byte *= val) +{ + unsigned int regnum =3D LOONGARCH_ARG_REGNUM - far + LOONGARCH_BADV_REGN= UM + 1; + regcache->cooked_write (regnum, val); +} + +static __attribute__((aligned(16))) gdb_byte buf[1024] =3D { 0 }; +static gdb_byte *addr =3D buf; + +static void +pass_on_stack (struct regcache *regcache, const gdb_byte *val, size_t len,= int align) +{ + align =3D align_up (align, 8); + if (align > 16) + align =3D 16; + + CORE_ADDR align_addr =3D (CORE_ADDR) addr; + align_addr =3D align_up (align_addr, align); + addr =3D (gdb_byte *) align_addr; + memcpy (addr, val, len); + addr +=3D len; +} + +static unsigned int fixed_point_members =3D 0; +static unsigned int floating_point_members =3D 0; +static bool first_member_is_fixed_point =3D false; + +static void +compute_struct_member (struct type *type) +{ + for (int i =3D 0; i < type->num_fields (); i++) + { + struct type *field_type =3D check_typedef (type->field (i).type ()); + + if (field_type->code () =3D=3D TYPE_CODE_INT + || field_type->code () =3D=3D TYPE_CODE_BOOL + || field_type->code () =3D=3D TYPE_CODE_CHAR + || field_type->code () =3D=3D TYPE_CODE_RANGE + || field_type->code () =3D=3D TYPE_CODE_ENUM + || field_type->code () =3D=3D TYPE_CODE_PTR) + { + fixed_point_members++; + + if (floating_point_members =3D=3D 0) + first_member_is_fixed_point =3D true; + } + else if (field_type->code () =3D=3D TYPE_CODE_FLT) + floating_point_members++; + else if (field_type->code () =3D=3D TYPE_CODE_STRUCT) + compute_struct_member (field_type); + else if (field_type->code () =3D=3D TYPE_CODE_COMPLEX) + floating_point_members +=3D 2; + } +} + +/* Implement the push_dummy_call gdbarch method. */ + +static CORE_ADDR +loongarch_push_dummy_call (struct gdbarch *gdbarch, + struct value *function, + struct regcache *regcache, + CORE_ADDR bp_addr, + int nargs, + struct value **args, + CORE_ADDR sp, + function_call_return_method return_method, + CORE_ADDR struct_addr) +{ + int regsize =3D register_size (gdbarch, 0); + unsigned int gar =3D LOONGARCH_ARG_REGNUM; + unsigned int far =3D LOONGARCH_ARG_REGNUM; + + if (return_method !=3D return_method_normal) + pass_in_gar (regcache, gar--, (gdb_byte *) &struct_addr); + + addr =3D buf; + for (int i =3D 0; i < nargs; i++) + { + struct value *arg =3D args[i]; + const gdb_byte *val =3D value_contents (arg).data (); + struct type *type =3D check_typedef (value_type (arg)); + size_t len =3D TYPE_LENGTH (type); + int align =3D type_align (type); + enum type_code code =3D type->code (); + + switch (code) + { + case TYPE_CODE_INT: + case TYPE_CODE_BOOL: + case TYPE_CODE_CHAR: + case TYPE_CODE_RANGE: + case TYPE_CODE_ENUM: + case TYPE_CODE_PTR: + { + /* integer or pointer type is passed in GAR. + * If no GAR is available, it=E2=80=99s passed on the stack. + * When passed in registers or on the stack, + * the unsigned integer scalars are zero-extended to GRLEN bits, + * and the signed integer scalars are sign-extended. */ + if (type->is_unsigned ()) + { + ULONGEST data =3D extract_unsigned_integer (val, len, BFD_EN= DIAN_LITTLE); + if (gar > 0) + pass_in_gar (regcache, gar--, (gdb_byte *) &data); + else + pass_on_stack (regcache, (gdb_byte *) &data, len, align); + } + else + { + LONGEST data =3D extract_signed_integer (val, len, BFD_ENDIAN_LITTL= E); + if (gar > 0) + pass_in_gar (regcache, gar--, (gdb_byte *) &data); + else + pass_on_stack (regcache, (gdb_byte *) &data, len, align); + } + } + break; + case TYPE_CODE_FLT: + if (len =3D=3D 2 * regsize) + { + /* long double type is passed in a pair of GAR, + * with the low-order GRLEN bits in the lower-numbered register + * and the high-order GRLEN bits in the higher-numbered register. + * If exactly one register is available, + * the low-order GRLEN bits are passed in the register + * and the high-order GRLEN bits are passed on the stack. + * If no GAR is available, it=E2=80=99s passed on the stack. */ + if (gar >=3D 2) + { + pass_in_gar (regcache, gar--, val); + pass_in_gar (regcache, gar--, val + regsize); + } + else if (gar =3D=3D 1) + { + pass_in_gar (regcache, gar--, val); + pass_on_stack (regcache, val + regsize, len - regsize, align); + } + else + { + pass_on_stack (regcache, val, len, align); + } + } + else + { + /* The other floating-point type is passed in FAR. + * If no FAR is available, it=E2=80=99s passed in GAR. + * If no GAR is available, it=E2=80=99s passed on the stack. */ + if (far > 0) + pass_in_far (regcache, far--, val); + else if (gar > 0) + pass_in_gar (regcache, gar--, val); + else + pass_on_stack (regcache, val, len, align); + } + break; + case TYPE_CODE_STRUCT: + { + fixed_point_members =3D 0; + floating_point_members =3D 0; + first_member_is_fixed_point =3D false; + compute_struct_member (type); + + if (len > 0 && len <=3D regsize) + { + /* The structure has only fixed-point members. */ + if (fixed_point_members > 0 && floating_point_members =3D=3D 0) + { + /* If there is an available GAR, + * the structure is passed through the GAR by value passing; + * If no GAR is available, it=E2=80=99s passed on the stack. */ + if (gar > 0) + pass_in_gar (regcache, gar--, val); + else + pass_on_stack (regcache, val, len, align); + } + /* The structure has only floating-point members. */ + else if (fixed_point_members =3D=3D 0 && floating_point_members > 0) + { + /* One floating-point member. + * The argument is passed in a FAR. + * If no FAR is available, the value is passed in a GAR. + * if no GAR is available, the value is passed on the stack. */ + if (floating_point_members =3D=3D 1) + { + if (far > 0) + pass_in_far (regcache, far--, val); + else if (gar > 0) + pass_in_gar (regcache, gar--, val); + else + pass_on_stack (regcache, val, len, align); + } + /* Two floating-point members. + * The argument is passed in a pair of available FAR, + * with the low-order float member bits in the lower-numbered FAR + * and the high-order float member bits in the higher-numbered FAR. + * If the number of available FAR is less than 2, it=E2=80=99s passe= d in a GAR, + * and passed on the stack if no GAR is available. */ + else if (floating_point_members =3D=3D 2) + { + if (far >=3D 2) + { + pass_in_far (regcache, far--, val); + pass_in_far (regcache, far--, val + align); + } + else if (gar > 0) + { + pass_in_gar (regcache, gar--, val); + } + else + { + pass_on_stack (regcache, val, len, align); + } + } + } + /* The structure has both fixed-point and floating-point members. */ + else if (fixed_point_members > 0 && floating_point_members > 0) + { + /* One float member and multiple fixed-point members. + * If there are available GAR, the structure is passed in a GAR, + * and passed on the stack if no GAR is available. */ + if (floating_point_members =3D=3D 1 && fixed_point_members > 1) + { + if (gar > 0) + pass_in_gar (regcache, gar--, val); + else + pass_on_stack (regcache, val, len, align); + } + /* One float member and only one fixed-point member. + * If one FAR and one GAR are available, + * the floating-point member of the structure is passed in the FAR, + * and the fixed-point member of the structure is passed in the GAR. + * If no floating-point register but one GAR is available, it=E2=80= =99s passed in GAR; + * If no GAR is available, it=E2=80=99s passed on the stack. */ + else if (floating_point_members =3D=3D 1 && fixed_point_members =3D= =3D 1) + { + if (far > 0 && gar > 0) + { + if (first_member_is_fixed_point =3D=3D false) + { + pass_in_far (regcache, far--, val); + pass_in_gar (regcache, gar--, val + align); + } + else + { + pass_in_gar (regcache, gar--, val); + pass_in_far (regcache, far--, val + align); + } + } + else + { + if (gar > 0) + pass_in_gar (regcache, gar--, val); + else + pass_on_stack (regcache, val, len, align); + } + } + } + } + else if (len > regsize && len <=3D 2 * regsize) + { + /* Only fixed-point members. */ + if (fixed_point_members > 0 && floating_point_members =3D=3D 0) + { + /* The argument is passed in a pair of available GAR, + * with the low-order bits in the lower-numbered GAR + * and the high-order bits in the higher-numbered GAR. + * If only one GAR is available, + * the low-order bits are in the GAR + * and the high-order bits are on the stack, + * and passed on the stack if no GAR is available. */ + if (gar >=3D 2) + { + pass_in_gar (regcache, gar--, val); + pass_in_gar (regcache, gar--, val + regsize); + } + else if (gar =3D=3D 1) + { + pass_in_gar (regcache, gar--, val); + pass_on_stack (regcache, val + regsize, len - regsize, align); + } + else + { + pass_on_stack (regcache, val, len, align); + } + } + /* Only floating-point members. */ + else if (fixed_point_members =3D=3D 0 && floating_point_members > 0) + { + /* The structure has one long double member + * or one double member and two adjacent float members + * or 3-4 float members. + * The argument is passed in a pair of available GAR, + * with the low-order bits in the lower-numbered GAR + * and the high-order bits in the higher-numbered GAR. + * If only one GAR is available, + * the low-order bits are in the GAR + * and the high-order bits are on the stack, + * and passed on the stack if no GAR is available. */ + if ((len =3D=3D 16 && floating_point_members =3D=3D 1) + || (len =3D=3D 16 && floating_point_members =3D=3D 3) + || (len =3D=3D 12 && floating_point_members =3D=3D 3) + || (len =3D=3D 16 && floating_point_members =3D=3D 4)) + { + if (gar >=3D 2) + { + pass_in_gar (regcache, gar--, val); + pass_in_gar (regcache, gar--, val + regsize); + } + else if (gar =3D=3D 1) + { + pass_in_gar (regcache, gar--, val); + pass_on_stack (regcache, val + regsize, len - regsize, align); + } + else + { + pass_on_stack (regcache, val, len, align); + } + } + /* The structure with two double members + * is passed in a pair of available FAR, + * with the low-order bits in the lower-numbered FAR + * and the high-order bits in the higher-numbered FAR. + * If no a pair of available FAR, + * it=E2=80=99s passed in a pair of available GAR, + * with the low-order bits in the lower-numbered GAR + * and the high-order bits in the higher-numbered GAR. + * If only one GAR is available, + * the low-order bits are in the GAR + * and the high-order bits are on stack, + * and passed on the stack if no GAR is available. + * A structure with one double member and one float member is same. = */ + else if ((len =3D=3D 16 && floating_point_members =3D=3D 2) + || (len =3D=3D 12 && floating_point_members =3D=3D 2)) + { + if (far >=3D 2) + { + pass_in_far (regcache, far--, val); + pass_in_far (regcache, far--, val + regsize); + } + else if (gar >=3D 2) + { + pass_in_gar (regcache, gar--, val); + pass_in_gar (regcache, gar--, val + regsize); + } + else if (gar =3D=3D 1) + { + pass_in_gar (regcache, gar--, val); + pass_on_stack (regcache, val + regsize, len - regsize, align); + } + else + { + pass_on_stack (regcache, val, len, align); + } + } + } + /* Both fixed-point and floating-point members. */ + else if (fixed_point_members > 0 && floating_point_members > 0) + { + /* The structure has one floating-point member and only one fixed-po= int member. */ + if (floating_point_members =3D=3D 1 && fixed_point_members =3D=3D 1) + { + /* If one FAR and one GAR are available, + * the floating-point member of the structure is passed in the FAR, + * and the fixed-point member of the structure is passed in the GAR; + * If no floating-point registers but two GARs are available, + * it=E2=80=99s passed in the two GARs; + * If only one GAR is available, + * the low-order bits are in the GAR + * and the high-order bits are on the stack; + * And it=E2=80=99s passed on the stack if no GAR is available. */ + if (far > 0 && gar > 0) + { + if (first_member_is_fixed_point =3D=3D false) + { + pass_in_far (regcache, far--, val); + pass_in_gar (regcache, gar--, val + regsize); + } + else + { + pass_in_gar (regcache, gar--, val); + pass_in_far (regcache, far--, val + regsize); + } + } + else if (far =3D=3D 0 && gar >=3D 2) + { + pass_in_gar (regcache, gar--, val); + pass_in_gar (regcache, gar--, val + regsize); + } + else if (far =3D=3D 0 && gar =3D=3D 1) + { + pass_in_gar (regcache, gar--, val); + pass_on_stack (regcache, val + regsize, len - regsize, align); + } + else if (far =3D=3D 0 && gar =3D=3D 0) + { + pass_on_stack (regcache, val, len, align); + } + } + else + { + /* The argument is passed in a pair of available GAR, + * with the low-order bits in the lower-numbered GAR + * and the high-order bits in the higher-numbered GAR. + * If only one GAR is available, + * the low-order bits are in the GAR + * and the high-order bits are on the stack, + * and passed on the stack if no GAR is available. */ + if (gar >=3D 2) + { + pass_in_gar (regcache, gar--, val); + pass_in_gar (regcache, gar--, val + regsize); + } + else if (gar =3D=3D 1) + { + pass_in_gar (regcache, gar--, val); + pass_on_stack (regcache, val + regsize, len - regsize, align); + } + else + { + pass_on_stack (regcache, val, len, align); + } + } + } + } + else if (len > 2 * regsize) + { + /* It=E2=80=99s passed by reference and are replaced in the argum= ent list with the address. + * If there is an available GAR, the reference is passed in the GAR, + * and passed on the stack if no GAR is available. */ + sp =3D align_down (sp - len, 16); + write_memory (sp, val, len); + + if (gar > 0) + pass_in_gar (regcache, gar--, (const gdb_byte *) &sp); + else + pass_on_stack (regcache, (const gdb_byte*) &sp, len, regsize); + } + } + break; + case TYPE_CODE_UNION: + /* Union is passed in GAR or stack. */ + if (len > 0 && len <=3D regsize) + { + /* The argument is passed in a GAR, + * or on the stack by value if no GAR is available. */ + if (gar > 0) + pass_in_gar (regcache, gar--, val); + else + pass_on_stack (regcache, val, len, align); + } + else if (len > regsize && len <=3D 2 * regsize) + { + /* The argument is passed in a pair of available GAR, + * with the low-order bits in the lower-numbered GAR + * and the high-order bits in the higher-numbered GAR. + * If only one GAR is available, + * the low-order bits are in the GAR + * and the high-order bits are on the stack. + * The arguments are passed on the stack when no GAR is available. = */ + if (gar >=3D 2) + { + pass_in_gar (regcache, gar--, val); + pass_in_gar (regcache, gar--, val + regsize); + } + else if (gar =3D=3D 1) + { + pass_in_gar (regcache, gar--, val); + pass_on_stack (regcache, val + regsize, len - regsize, align); + } + else + { + pass_on_stack (regcache, val, len, align); + } + } + else if (len > 2 * regsize) + { + /* It=E2=80=99s passed by reference and are replaced in the argumen= t list with the address. + * If there is an available GAR, the reference is passed in the GAR, + * and passed on the stack if no GAR is available. */ + sp =3D align_down (sp - len, 16); + write_memory (sp, val, len); + + if (gar > 0) + pass_in_gar (regcache, gar--, (const gdb_byte *) &sp); + else + pass_on_stack (regcache, (const gdb_byte*) &sp, len, regsize); + } + break; + case TYPE_CODE_COMPLEX: + { + struct type *target_type =3D check_typedef (TYPE_TARGET_TYPE (type)); + size_t target_len =3D TYPE_LENGTH (target_type); + + if (target_len < regsize) + { + /* The complex with two float members + * is passed in a pair of available FAR, + * with the low-order float member bits in the lower-numbered FAR + * and the high-order float member bits in the higher-numbered FAR. + * If the number of available FAR is less than 2, it=E2=80=99s passed in= a GAR, + * and passed on the stack if no GAR is available. */ + if (far >=3D 2) + { + pass_in_far (regcache, far--, val); + pass_in_far (regcache, far--, val + align); + } + else if (gar > 0) + { + pass_in_gar (regcache, gar--, val); + } + else + { + pass_on_stack (regcache, val, len, align); + } + } + else if (target_len =3D=3D regsize) + { + /* The complex with two double members + * is passed in a pair of available FAR, + * with the low-order bits in the lower-numbered FAR + * and the high-order bits in the higher-numbered FAR. + * If no a pair of available FAR, + * it=E2=80=99s passed in a pair of available GAR, + * with the low-order bits in the lower-numbered GAR + * and the high-order bits in the higher-numbered GAR. + * If only one GAR is available, + * the low-order bits are in the GAR + * and the high-order bits are on stack, + * and passed on the stack if no GAR is available. */ + { + if (far >=3D 2) + { + pass_in_far (regcache, far--, val); + pass_in_far (regcache, far--, val + align); + } + else if (gar >=3D 2) + { + pass_in_gar (regcache, gar--, val); + pass_in_gar (regcache, gar--, val + align); + } + else if (gar =3D=3D 1) + { + pass_in_gar (regcache, gar--, val); + pass_on_stack (regcache, val + align, len - align, align); + } + else + { + pass_on_stack (regcache, val, len, align); + } + } + } + else if (target_len =3D=3D 2 * regsize) + { + /* The complex with two long double members + * is passed by reference and are replaced in the argument list with the= address. + * If there is an available GAR, the reference is passed in the G= AR, + * and passed on the stack if no GAR is available. */ + sp =3D align_down (sp - len, 16); + write_memory (sp, val, len); + + if (gar > 0) + pass_in_gar (regcache, gar--, (const gdb_byte *) &sp); + else + pass_on_stack (regcache, (const gdb_byte*) &sp, regsize, regsize); + } + } + break; + default: + break; + } + } + + if (addr > buf) + { + sp -=3D addr - buf; + sp =3D align_down (sp, 16); + write_memory (sp, buf, addr - buf); + } + + regcache_cooked_write_unsigned (regcache, LOONGARCH_RA_REGNUM, bp_addr); + regcache_cooked_write_unsigned (regcache, LOONGARCH_SP_REGNUM, sp); + + return sp; +} + /* Implement the return_value gdbarch method. */ =20 static enum return_value_convention @@ -644,6 +1237,9 @@ loongarch_gdbarch_init (struct gdbarch_info info, stru= ct gdbarch_list *arches) /* Finalise the target description registers. */ tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data)); =20 + /* Functions handling dummy frames. */ + set_gdbarch_push_dummy_call (gdbarch, loongarch_push_dummy_call); + /* Return value info */ set_gdbarch_return_value (gdbarch, loongarch_return_value); =20 diff --git a/gdb/loongarch-tdep.h b/gdb/loongarch-tdep.h index acf0191fd65..672bc2b80de 100644 --- a/gdb/loongarch-tdep.h +++ b/gdb/loongarch-tdep.h @@ -39,6 +39,8 @@ enum LOONGARCH_PC_REGNUM =3D 33, /* Program Counter. */ LOONGARCH_BADV_REGNUM =3D 34, /* Bad Vaddr for Addressing Exception. */ LOONGARCH_LINUX_NUM_GREGSET =3D 45, /* 32 GPR, ORIG_A0, PC, BADV, RESERV= ED 10. */ + LOONGARCH_ARG_REGNUM =3D 8, /* r4-r11: general-purpose argume= nt registers. + f0-f7: floating-point argument registers. */ }; =20 /* Register set definitions. */