tools/elfutils: update MIPS support patches
The original patch series partially added by commit
f97da2c61
("tools/elfutils: add missing MIPS reloc support")
now has a v3 which has half of it's commits accepted.
To prepare for updating to the new release,
use the new series that includes backports.
Manually adjusted patch:
- 010-backport-mips-support-reloc.patch
Add patch:
- 011-backport-mips-support-strip.patch
- 012-backport-mips-support-readelf.patch
- 013-backport-mips-support-elflint.patch
- 014-backport-mips-support-stack.patch
- 015-backport-mips-support-regs.patch
Tested-by: Tony Ambardar <itugrok@yahoo.com>
Signed-off-by: Michael Pratt <mcpratt@pm.me>
Link: https://github.com/openwrt/openwrt/pull/16522
Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
parent
c83941d288
commit
5bb84fb53b
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,230 @@
|
|||
In mips64 little-endian, r_info consists of four byte fields(contains
|
||||
three reloc types) and a 32-bit symbol index. In order to adapt
|
||||
GELF_R_SYM and GELF_R_TYPE, need convert raw data to get correct symbol
|
||||
index and type.
|
||||
|
||||
libelf/elf_getdata.c: Some eu-utils use read-mmap method to map file,
|
||||
so we need to malloc and memcpy raw data to avoid segment fault. After
|
||||
modification, the correct value are saved in the malloced memory not in
|
||||
process address space.
|
||||
libelf/elf_updata.c: Because we converted the relocation info in mips
|
||||
order when we call elf_getdata.c, so we need to convert the modified data
|
||||
in original order bits before writing the data to the file.
|
||||
|
||||
Signed-off-by: Ying Huang <ying.huang@oss.cipunited.com>
|
||||
---
|
||||
libelf/elf_getdata.c | 132 ++++++++++++++++++++++++++++++++++++++++++-
|
||||
libelf/elf_update.c | 53 +++++++++++++++++
|
||||
2 files changed, 183 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/libelf/elf_getdata.c
|
||||
+++ b/libelf/elf_getdata.c
|
||||
@@ -135,6 +135,119 @@ __libelf_data_type (GElf_Ehdr *ehdr, int
|
||||
|
||||
/* Convert the data in the current section. */
|
||||
static void
|
||||
+convert_data_for_mips64el (Elf_Scn *scn, int eclass,
|
||||
+ int data, size_t size, Elf_Type type)
|
||||
+{
|
||||
+ /* Do we need to convert the data and/or adjust for alignment? */
|
||||
+ if (data == MY_ELFDATA || type == ELF_T_BYTE)
|
||||
+ {
|
||||
+ /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need to convert
|
||||
+ relocation info(raw data). Some eu-utils use read-mmap method to map file, so
|
||||
+ we need to malloc and memcpy raw data to avoid segment fault. After modification,
|
||||
+ the correct value are saved in the malloced memory not in process address space. */
|
||||
+ scn->data_base = malloc (size);
|
||||
+ if (scn->data_base == NULL)
|
||||
+ {
|
||||
+ __libelf_seterrno (ELF_E_NOMEM);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* The copy will be appropriately aligned for direct access. */
|
||||
+ memcpy (scn->data_base, scn->rawdata_base, size);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ xfct_t fp;
|
||||
+
|
||||
+ scn->data_base = malloc (size);
|
||||
+ if (scn->data_base == NULL)
|
||||
+ {
|
||||
+ __libelf_seterrno (ELF_E_NOMEM);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Make sure the source is correctly aligned for the conversion
|
||||
+ function to directly access the data elements. */
|
||||
+ char *rawdata_source;
|
||||
+ /* In order to adapt macro GELF_R_SYM and GELF_R_TYPE on mips64, need to convert
|
||||
+ relocation info(raw data). Some eu-utils use read-mmap method to map file, so
|
||||
+ we need to malloc and memcpy raw data to avoid segment fault. After modification,
|
||||
+ the correct value are saved in the malloced memory not in process address space. */
|
||||
+ rawdata_source = malloc (size);
|
||||
+ if (rawdata_source == NULL)
|
||||
+ {
|
||||
+ __libelf_seterrno (ELF_E_NOMEM);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* The copy will be appropriately aligned for direct access. */
|
||||
+ memcpy (rawdata_source, scn->rawdata_base, size);
|
||||
+
|
||||
+ /* Get the conversion function. */
|
||||
+ fp = __elf_xfctstom[eclass - 1][type];
|
||||
+
|
||||
+ fp (scn->data_base, rawdata_source, size, 0);
|
||||
+
|
||||
+ if (rawdata_source != scn->rawdata_base)
|
||||
+ free (rawdata_source);
|
||||
+ }
|
||||
+
|
||||
+ scn->data_list.data.d.d_buf = scn->data_base;
|
||||
+ scn->data_list.data.d.d_size = size;
|
||||
+ scn->data_list.data.d.d_type = type;
|
||||
+ scn->data_list.data.d.d_off = scn->rawdata.d.d_off;
|
||||
+ scn->data_list.data.d.d_align = scn->rawdata.d.d_align;
|
||||
+ scn->data_list.data.d.d_version = scn->rawdata.d.d_version;
|
||||
+
|
||||
+ scn->data_list.data.s = scn;
|
||||
+
|
||||
+ /* In mips64 little-endian, r_info consists of four byte fields(contains
|
||||
+ three reloc types) and a 32-bit symbol index. In order to adapt
|
||||
+ GELF_R_SYM and GELF_R_TYPE, need to convert r_info to get correct symbol
|
||||
+ index and type. */
|
||||
+ /* references:
|
||||
+ https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf
|
||||
+ Page40 && Page41 */
|
||||
+ GElf_Shdr shdr_mem;
|
||||
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
||||
+ if (shdr->sh_type == SHT_REL)
|
||||
+ {
|
||||
+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, EV_CURRENT);
|
||||
+ int nentries = shdr->sh_size / sh_entsize;
|
||||
+ for (int cnt = 0; cnt < nentries; ++cnt)
|
||||
+ {
|
||||
+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d;
|
||||
+ Elf64_Rel *value = &((Elf64_Rel *) data_scn->d.d_buf)[cnt];
|
||||
+ Elf64_Xword info = value->r_info;
|
||||
+ value->r_info = (((info & 0xffffffff) << 32)
|
||||
+ | ((info >> 56) & 0xff)
|
||||
+ | ((info >> 40) & 0xff00)
|
||||
+ | ((info >> 24) & 0xff0000)
|
||||
+ | ((info >> 8) & 0xff000000));
|
||||
+ ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value;
|
||||
+ }
|
||||
+ }
|
||||
+ else if (shdr->sh_type == SHT_RELA)
|
||||
+ {
|
||||
+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, EV_CURRENT);
|
||||
+ int nentries = shdr->sh_size / sh_entsize;
|
||||
+ for (int cnt = 0; cnt < nentries; cnt++)
|
||||
+ {
|
||||
+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) &scn->data_list.data.d;
|
||||
+ Elf64_Rela *value = &((Elf64_Rela *) data_scn->d.d_buf)[cnt];
|
||||
+ Elf64_Xword info = value->r_info;
|
||||
+ value->r_info = (((info & 0xffffffff) << 32)
|
||||
+ | ((info >> 56) & 0xff)
|
||||
+ | ((info >> 40) & 0xff00)
|
||||
+ | ((info >> 24) & 0xff0000)
|
||||
+ | ((info >> 8) & 0xff000000));
|
||||
+ ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Convert the data in the current section. */
|
||||
+static void
|
||||
convert_data (Elf_Scn *scn, int eclass,
|
||||
int data, size_t size, Elf_Type type)
|
||||
{
|
||||
@@ -451,8 +564,23 @@ __libelf_set_data_list_rdlock (Elf_Scn *
|
||||
return;
|
||||
}
|
||||
|
||||
- /* Convert according to the version and the type. */
|
||||
- convert_data (scn, elf->class,
|
||||
+ GElf_Shdr shdr_mem;
|
||||
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
||||
+ GElf_Ehdr ehdr_mem;
|
||||
+ GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem);
|
||||
+ if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) &&
|
||||
+ scn->elf->class == ELFCLASS64 && ehdr != NULL &&
|
||||
+ ehdr->e_machine == EM_MIPS && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||
+ convert_data_for_mips64el (scn, elf->class,
|
||||
+ (elf->class == ELFCLASS32
|
||||
+ || (offsetof (struct Elf, state.elf32.ehdr)
|
||||
+ == offsetof (struct Elf, state.elf64.ehdr))
|
||||
+ ? elf->state.elf32.ehdr->e_ident[EI_DATA]
|
||||
+ : elf->state.elf64.ehdr->e_ident[EI_DATA]),
|
||||
+ scn->rawdata.d.d_size, scn->rawdata.d.d_type);
|
||||
+ else
|
||||
+ /* Convert according to the version and the type. */
|
||||
+ convert_data (scn, elf->class,
|
||||
(elf->class == ELFCLASS32
|
||||
|| (offsetof (struct Elf, state.elf32.ehdr)
|
||||
== offsetof (struct Elf, state.elf64.ehdr))
|
||||
--- a/libelf/elf_update.c
|
||||
+++ b/libelf/elf_update.c
|
||||
@@ -228,7 +228,60 @@ elf_update (Elf *elf, Elf_Cmd cmd)
|
||||
size = -1;
|
||||
}
|
||||
else
|
||||
+ {
|
||||
+ /* Because we converted the relocation info in mips order when we call elf_getdata.c,
|
||||
+ so we need to convert the modified data in original order bits before writing the
|
||||
+ data to the file. */
|
||||
+ Elf_Scn *scn = NULL;
|
||||
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
|
||||
+ {
|
||||
+ GElf_Shdr shdr_mem;
|
||||
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
||||
+ GElf_Ehdr ehdr_mem;
|
||||
+ GElf_Ehdr *ehdr = gelf_getehdr (scn->elf, &ehdr_mem);
|
||||
+ if (shdr != NULL && (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) &&
|
||||
+ scn->elf->class == ELFCLASS64 &&
|
||||
+ ehdr != NULL && ehdr->e_machine == EM_MIPS && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||
+ {
|
||||
+ Elf_Data *d = elf_getdata (scn, NULL);
|
||||
+ if (shdr->sh_type == SHT_REL)
|
||||
+ {
|
||||
+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_REL, 1, EV_CURRENT);
|
||||
+ int nentries = shdr->sh_size / sh_entsize;
|
||||
+ for (int cnt = 0; cnt < nentries; ++cnt)
|
||||
+ {
|
||||
+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d;
|
||||
+ Elf64_Rel *value = &((Elf64_Rel *) data_scn->d.d_buf)[cnt];
|
||||
+ Elf64_Xword info = value->r_info;
|
||||
+ value->r_info = (info >> 32
|
||||
+ | ((info << 56) & 0xff00000000000000)
|
||||
+ | ((info << 40) & 0xff000000000000)
|
||||
+ | ((info << 24) & 0xff0000000000)
|
||||
+ | ((info << 8) & 0xff00000000));
|
||||
+ ((Elf64_Rel *) data_scn->d.d_buf)[cnt] = *value;
|
||||
+ }
|
||||
+ }
|
||||
+ else if (shdr->sh_type == SHT_RELA)
|
||||
+ {
|
||||
+ size_t sh_entsize = gelf_fsize (scn->elf, ELF_T_RELA, 1, EV_CURRENT);
|
||||
+ int nentries = shdr->sh_size / sh_entsize;
|
||||
+ for (int cnt = 0; cnt < nentries; cnt++)
|
||||
+ {
|
||||
+ Elf_Data_Scn *data_scn = (Elf_Data_Scn *) d;
|
||||
+ Elf64_Rela *value = &((Elf64_Rela *) data_scn->d.d_buf)[cnt];
|
||||
+ Elf64_Xword info = value->r_info;
|
||||
+ value->r_info = (info >> 32
|
||||
+ | ((info << 56) & 0xff00000000000000)
|
||||
+ | ((info << 40) & 0xff000000000000)
|
||||
+ | ((info << 24) & 0xff0000000000)
|
||||
+ | ((info << 8) & 0xff00000000));
|
||||
+ ((Elf64_Rela *) data_scn->d.d_buf)[cnt] = *value;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
size = write_file (elf, size, change_bo, shnum);
|
||||
+ }
|
||||
}
|
||||
|
||||
out:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,156 @@
|
|||
The errors were:
|
||||
$ src/elflint --gnu src/nm
|
||||
section [ 2] '.MIPS.options' contains unknown flag(s) 0x8000000
|
||||
section [ 7] '.dynsym': symbol 165 (_DYNAMIC_LINKING): non-local section symbol
|
||||
section [24] '.got' contains invalid processor-specific flag(s) 0x10000000
|
||||
section [25] '.sdata' contains invalid processor-specific flag(s) 0x10000000
|
||||
section [29] '.debug_aranges' has wrong type: expected PROGBITS, is MIPS_DWARF
|
||||
section [30] '.debug_info' has wrong type: expected PROGBITS, is MIPS_DWARF
|
||||
section [31] '.debug_abbrev' has wrong type: expected PROGBITS, is MIPS_DWARF
|
||||
section [32] '.debug_line' has wrong type: expected PROGBITS, is MIPS_DWARF
|
||||
section [33] '.debug_frame' has wrong type: expected PROGBITS, is MIPS_DWARF
|
||||
section [34] '.debug_str' has wrong type: expected PROGBITS, is MIPS_DWARF
|
||||
section [35] '.debug_loc' has wrong type: expected PROGBITS, is MIPS_DWARF
|
||||
section [36] '.debug_ranges' has wrong type: expected PROGBITS, is MIPS_DWARF
|
||||
section [38] '.symtab': symbol 785 (_gp): st_value out of bounds
|
||||
section [38] '.symtab': symbol 910 (_fbss): st_value out of bounds
|
||||
section [38] '.symtab': symbol 1051 (_DYNAMIC_LINKING): non-local section symbol
|
||||
|
||||
After fixing:
|
||||
$ src/elflint --gnu src/nm
|
||||
No errors
|
||||
|
||||
Signed-off-by: Ying Huang <ying.huang@oss.cipunited.com>
|
||||
---
|
||||
backends/mips_init.c | 3 +++
|
||||
backends/mips_symbol.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
src/elflint.c | 26 +++++++++++++++++++++-----
|
||||
3 files changed, 61 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/backends/mips_init.c
|
||||
+++ b/backends/mips_init.c
|
||||
@@ -51,9 +51,12 @@ mips_init (Elf *elf __attribute__ ((unus
|
||||
HOOK (eh, section_type_name);
|
||||
HOOK (eh, machine_flag_check);
|
||||
HOOK (eh, machine_flag_name);
|
||||
+ HOOK (eh, machine_section_flag_check);
|
||||
HOOK (eh, segment_type_name);
|
||||
HOOK (eh, dynamic_tag_check);
|
||||
HOOK (eh, dynamic_tag_name);
|
||||
HOOK (eh, check_object_attribute);
|
||||
+ HOOK (eh, check_special_symbol);
|
||||
+ HOOK (eh, check_reloc_target_type);
|
||||
return eh;
|
||||
}
|
||||
--- a/backends/mips_symbol.c
|
||||
+++ b/backends/mips_symbol.c
|
||||
@@ -158,6 +158,43 @@ mips_section_type_name (int type,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+bool
|
||||
+mips_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), Elf64_Word sh_type)
|
||||
+{
|
||||
+ return (sh_type == SHT_MIPS_DWARF);
|
||||
+}
|
||||
+
|
||||
+/* Check whether given symbol's st_value and st_size are OK despite failing
|
||||
+ normal checks. */
|
||||
+bool
|
||||
+mips_check_special_symbol (Elf *elf,
|
||||
+ const GElf_Sym *sym __attribute__ ((unused)),
|
||||
+ const char *name __attribute__ ((unused)),
|
||||
+ const GElf_Shdr *destshdr)
|
||||
+{
|
||||
+ size_t shstrndx;
|
||||
+ if (elf_getshdrstrndx (elf, &shstrndx) != 0)
|
||||
+ return false;
|
||||
+ const char *sname = elf_strptr (elf, shstrndx, destshdr->sh_name);
|
||||
+ if (sname == NULL)
|
||||
+ return false;
|
||||
+ return (strcmp (sname, ".got") == 0 || strcmp (sname, ".bss") == 0);
|
||||
+}
|
||||
+
|
||||
+/* Check whether SHF_MASKPROC flags are valid. */
|
||||
+bool
|
||||
+mips_machine_section_flag_check (GElf_Xword sh_flags)
|
||||
+{
|
||||
+ return ((sh_flags &~ (SHF_MIPS_GPREL |
|
||||
+ SHF_MIPS_MERGE |
|
||||
+ SHF_MIPS_ADDR |
|
||||
+ SHF_MIPS_STRINGS |
|
||||
+ SHF_MIPS_NOSTRIP |
|
||||
+ SHF_MIPS_LOCAL |
|
||||
+ SHF_MIPS_NAMES |
|
||||
+ SHF_MIPS_NODUPE)) == 0);
|
||||
+}
|
||||
+
|
||||
/* Check whether machine flags are valid. */
|
||||
bool
|
||||
mips_machine_flag_check (GElf_Word flags)
|
||||
--- a/src/elflint.c
|
||||
+++ b/src/elflint.c
|
||||
@@ -936,7 +936,9 @@ section [%2d] '%s': symbol %zu (%s): non
|
||||
}
|
||||
|
||||
if (GELF_ST_TYPE (sym->st_info) == STT_SECTION
|
||||
- && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
|
||||
+ && GELF_ST_BIND (sym->st_info) != STB_LOCAL
|
||||
+ && ehdr->e_machine != EM_MIPS
|
||||
+ && strcmp (name, "_DYNAMIC_LINKING") != 0)
|
||||
ERROR (_("\
|
||||
section [%2d] '%s': symbol %zu (%s): non-local section symbol\n"),
|
||||
idx, section_name (ebl, idx), cnt, name);
|
||||
@@ -3828,6 +3830,10 @@ cannot get section header for section [%
|
||||
&& ebl_bss_plt_p (ebl))
|
||||
good_type = SHT_NOBITS;
|
||||
|
||||
+ if (ehdr->e_machine == EM_MIPS
|
||||
+ && (strstr(special_sections[s].name, ".debug") != NULL))
|
||||
+ good_type = SHT_MIPS_DWARF;
|
||||
+
|
||||
/* In a debuginfo file, any normal section can be SHT_NOBITS.
|
||||
This is only invalid for DWARF sections and .shstrtab. */
|
||||
if (shdr->sh_type != good_type
|
||||
@@ -3988,12 +3994,21 @@ section [%2zu] '%s': size not multiple o
|
||||
ERROR (_("section [%2zu] '%s'"
|
||||
" contains invalid processor-specific flag(s)"
|
||||
" %#" PRIx64 "\n"),
|
||||
- cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC);
|
||||
+ cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC);
|
||||
sh_flags &= ~(GElf_Xword) SHF_MASKPROC;
|
||||
}
|
||||
if (sh_flags & SHF_MASKOS)
|
||||
- if (gnuld)
|
||||
- sh_flags &= ~(GElf_Xword) SHF_GNU_RETAIN;
|
||||
+ {
|
||||
+ if (gnuld)
|
||||
+ sh_flags &= ~(GElf_Xword) SHF_GNU_RETAIN;
|
||||
+ if (!ebl_machine_section_flag_check (ebl,
|
||||
+ sh_flags & SHF_MASKOS))
|
||||
+ ERROR (_("section [%2zu] '%s'"
|
||||
+ " contains invalid os-specific flag(s)"
|
||||
+ " %#" PRIx64 "\n"),
|
||||
+ cnt, section_name (ebl, cnt), sh_flags & SHF_MASKOS);
|
||||
+ sh_flags &= ~(GElf_Xword) SHF_MASKOS;
|
||||
+ }
|
||||
if (sh_flags != 0)
|
||||
ERROR (_("section [%2zu] '%s' contains unknown flag(s)"
|
||||
" %#" PRIx64 "\n"),
|
||||
@@ -4059,6 +4074,7 @@ section [%2zu] '%s': merge flag set but
|
||||
switch (shdr->sh_type)
|
||||
{
|
||||
case SHT_PROGBITS:
|
||||
+ case SHT_MIPS_DWARF:
|
||||
break;
|
||||
|
||||
case SHT_NOBITS:
|
||||
@@ -4716,7 +4732,7 @@ program header offset in ELF header and
|
||||
if (shdr != NULL
|
||||
&& ((is_debuginfo && shdr->sh_type == SHT_NOBITS)
|
||||
|| (! is_debuginfo
|
||||
- && (shdr->sh_type == SHT_PROGBITS
|
||||
+ && (is_debug_section_type(shdr->sh_type)
|
||||
|| shdr->sh_type == SHT_X86_64_UNWIND)))
|
||||
&& elf_strptr (ebl->elf, shstrndx, shdr->sh_name) != NULL
|
||||
&& ! strcmp (".eh_frame_hdr",
|
|
@ -0,0 +1,273 @@
|
|||
From f2acb06970522a9563d82490f2f1b8fc0bb5b720 Mon Sep 17 00:00:00 2001
|
||||
From: Ying Huang <ying.huang@oss.cipunited.com>
|
||||
Date: Tue, 5 Mar 2024 17:51:21 +0800
|
||||
Subject: [PATCH] stack: Fix stack unwind failure on mips
|
||||
|
||||
Add abi_cfi, set_initial_registers_tid, unwind on mips.
|
||||
|
||||
* backends/Makefile.am (mips_SRCS): Add mips_initreg.c,
|
||||
mips_cfi.c and mips_unwind.c.
|
||||
* backends/mips_init.c (mips_init): HOOK abi_cfi, unwind and
|
||||
set_initial_registers_tid. Set frame_nregs to 71.
|
||||
* backends/mips_cfi.c: New file.
|
||||
* backends/mips_initreg.c: Likewise.
|
||||
* backends/mips_unwind.c: Likewise.
|
||||
|
||||
Signed-off-by: Ying Huang <ying.huang@oss.cipunited.com>
|
||||
---
|
||||
backends/Makefile.am | 3 +-
|
||||
backends/mips_cfi.c | 68 +++++++++++++++++++++++++++++++++
|
||||
backends/mips_init.c | 4 ++
|
||||
backends/mips_initreg.c | 61 ++++++++++++++++++++++++++++++
|
||||
backends/mips_unwind.c | 84 +++++++++++++++++++++++++++++++++++++++++
|
||||
5 files changed, 219 insertions(+), 1 deletion(-)
|
||||
create mode 100644 backends/mips_cfi.c
|
||||
create mode 100644 backends/mips_initreg.c
|
||||
create mode 100644 backends/mips_unwind.c
|
||||
|
||||
--- a/backends/Makefile.am
|
||||
+++ b/backends/Makefile.am
|
||||
@@ -102,7 +102,8 @@ loongarch_SRCS = loongarch_init.c loonga
|
||||
|
||||
arc_SRCS = arc_init.c arc_symbol.c
|
||||
|
||||
-mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c
|
||||
+mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c mips_initreg.c \
|
||||
+ mips_cfi.c mips_unwind.c
|
||||
|
||||
libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \
|
||||
$(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \
|
||||
--- /dev/null
|
||||
+++ b/backends/mips_cfi.c
|
||||
@@ -0,0 +1,68 @@
|
||||
+/* MIPS ABI-specified defaults for DWARF CFI.
|
||||
+ Copyright (C) 2009 Red Hat, Inc.
|
||||
+ Copyright (C) 2024 CIP United Inc.
|
||||
+ This file is part of elfutils.
|
||||
+
|
||||
+ This file is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of either
|
||||
+
|
||||
+ * the GNU Lesser General Public License as published by the Free
|
||||
+ Software Foundation; either version 3 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or
|
||||
+
|
||||
+ * the GNU General Public License as published by the Free
|
||||
+ Software Foundation; either version 2 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or both in parallel, as here.
|
||||
+
|
||||
+ elfutils is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ You should have received copies of the GNU General Public License and
|
||||
+ the GNU Lesser General Public License along with this program. If
|
||||
+ not, see <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+# include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#include <dwarf.h>
|
||||
+
|
||||
+#define BACKEND mips_
|
||||
+#include "libebl_CPU.h"
|
||||
+
|
||||
+int
|
||||
+mips_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info)
|
||||
+{
|
||||
+ static const uint8_t abi_cfi[] =
|
||||
+ {
|
||||
+ DW_CFA_def_cfa, ULEB128_7 (31), ULEB128_7 (0),
|
||||
+ /* Callee-saved regs. */
|
||||
+ DW_CFA_same_value, ULEB128_7 (16), /* s0 */
|
||||
+ DW_CFA_same_value, ULEB128_7 (17), /* s1 */
|
||||
+ DW_CFA_same_value, ULEB128_7 (18), /* s2 */
|
||||
+ DW_CFA_same_value, ULEB128_7 (19), /* s3 */
|
||||
+ DW_CFA_same_value, ULEB128_7 (20), /* s4 */
|
||||
+ DW_CFA_same_value, ULEB128_7 (21), /* s5 */
|
||||
+ DW_CFA_same_value, ULEB128_7 (22), /* s6 */
|
||||
+ DW_CFA_same_value, ULEB128_7 (23), /* s7 */
|
||||
+ DW_CFA_same_value, ULEB128_7 (28), /* gp */
|
||||
+ DW_CFA_same_value, ULEB128_7 (29), /* sp */
|
||||
+ DW_CFA_same_value, ULEB128_7 (30), /* fp */
|
||||
+
|
||||
+ DW_CFA_val_offset, ULEB128_7 (29), ULEB128_7 (0),
|
||||
+ };
|
||||
+
|
||||
+ abi_info->initial_instructions = abi_cfi;
|
||||
+ abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi];
|
||||
+ abi_info->data_alignment_factor = 8;
|
||||
+
|
||||
+ abi_info->return_address_register = 31; /* %ra */
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/backends/mips_init.c
|
||||
+++ b/backends/mips_init.c
|
||||
@@ -58,5 +58,9 @@ mips_init (Elf *elf __attribute__ ((unus
|
||||
HOOK (eh, check_object_attribute);
|
||||
HOOK (eh, check_special_symbol);
|
||||
HOOK (eh, check_reloc_target_type);
|
||||
+ HOOK (eh, set_initial_registers_tid);
|
||||
+ HOOK (eh, abi_cfi);
|
||||
+ HOOK (eh, unwind);
|
||||
+ eh->frame_nregs = 71;
|
||||
return eh;
|
||||
}
|
||||
--- /dev/null
|
||||
+++ b/backends/mips_initreg.c
|
||||
@@ -0,0 +1,61 @@
|
||||
+/* Fetch live process registers from TID.
|
||||
+ Copyright (C) 2024 CIP United Inc.
|
||||
+ This file is part of elfutils.
|
||||
+
|
||||
+ This file is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of either
|
||||
+
|
||||
+ * the GNU Lesser General Public License as published by the Free
|
||||
+ Software Foundation; either version 3 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or
|
||||
+
|
||||
+ * the GNU General Public License as published by the Free
|
||||
+ Software Foundation; either version 2 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or both in parallel, as here.
|
||||
+
|
||||
+ elfutils is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ You should have received copies of the GNU General Public License and
|
||||
+ the GNU Lesser General Public License along with this program. If
|
||||
+ not, see <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+# include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#include <stdlib.h>
|
||||
+#if (defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)) && defined(__linux__)
|
||||
+# include <sys/user.h>
|
||||
+# include <sys/ptrace.h>
|
||||
+#include <asm/ptrace.h>
|
||||
+#endif
|
||||
+
|
||||
+#define BACKEND mips_
|
||||
+#include "libebl_CPU.h"
|
||||
+
|
||||
+
|
||||
+bool
|
||||
+mips_set_initial_registers_tid (pid_t tid __attribute__ ((unused)),
|
||||
+ ebl_tid_registers_t *setfunc __attribute__ ((unused)),
|
||||
+ void *arg __attribute__ ((unused)))
|
||||
+{
|
||||
+#if (!defined(mips) && !defined(__mips) && !defined(__mips__) && !defined(MIPS) && !defined(__MIPS__)) || !defined(__linux__)
|
||||
+ return false;
|
||||
+#else /* __mips__ */
|
||||
+/* For PTRACE_GETREGS */
|
||||
+
|
||||
+ struct pt_regs gregs;
|
||||
+ if (ptrace (PTRACE_GETREGS, tid, 0, &gregs) != 0)
|
||||
+ return false;
|
||||
+ if (! setfunc (-1, 1, (Dwarf_Word *) &gregs.cp0_epc, arg))
|
||||
+ return false;
|
||||
+ return setfunc (0, 32, (Dwarf_Word *) &gregs.regs[0], arg);
|
||||
+#endif /* __mips__ */
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ b/backends/mips_unwind.c
|
||||
@@ -0,0 +1,84 @@
|
||||
+/* Get previous frame state for an existing frame state.
|
||||
+ Copyright (C) 2016 The Qt Company Ltd.
|
||||
+ Copyright (C) 2024 CIP United Inc.
|
||||
+ This file is part of elfutils.
|
||||
+
|
||||
+ This file is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of either
|
||||
+
|
||||
+ * the GNU Lesser General Public License as published by the Free
|
||||
+ Software Foundation; either version 3 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or
|
||||
+
|
||||
+ * the GNU General Public License as published by the Free
|
||||
+ Software Foundation; either version 2 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or both in parallel, as here.
|
||||
+
|
||||
+ elfutils is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ You should have received copies of the GNU General Public License and
|
||||
+ the GNU Lesser General Public License along with this program. If
|
||||
+ not, see <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+# include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#define BACKEND mips_
|
||||
+#define SP_REG 29
|
||||
+#define FP_REG 30
|
||||
+#define LR_REG 31
|
||||
+#define FP_OFFSET 0
|
||||
+#define LR_OFFSET 8
|
||||
+#define SP_OFFSET 16
|
||||
+
|
||||
+#include "libebl_CPU.h"
|
||||
+
|
||||
+/* There was no CFI. Maybe we happen to have a frame pointer and can unwind from that? */
|
||||
+
|
||||
+bool
|
||||
+EBLHOOK(unwind) (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr pc __attribute__ ((unused)),
|
||||
+ ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc,
|
||||
+ ebl_pid_memory_read_t *readfunc, void *arg,
|
||||
+ bool *signal_framep __attribute__ ((unused)))
|
||||
+{
|
||||
+ Dwarf_Word fp, lr, sp;
|
||||
+
|
||||
+ if (!getfunc(LR_REG, 1, &lr, arg))
|
||||
+ return false;
|
||||
+
|
||||
+ if (lr == 0 || !setfunc(-1, 1, &lr, arg))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!getfunc(FP_REG, 1, &fp, arg))
|
||||
+ fp = 0;
|
||||
+
|
||||
+ if (!getfunc(SP_REG, 1, &sp, arg))
|
||||
+ sp = 0;
|
||||
+
|
||||
+ Dwarf_Word newLr, newFp, newSp;
|
||||
+
|
||||
+ if (!readfunc(fp + LR_OFFSET, &newLr, arg))
|
||||
+ newLr = 0;
|
||||
+
|
||||
+ if (!readfunc(fp + FP_OFFSET, &newFp, arg))
|
||||
+ newFp = 0;
|
||||
+
|
||||
+ newSp = fp + SP_OFFSET;
|
||||
+
|
||||
+ // These are not fatal if they don't work. They will just prevent unwinding at the next frame.
|
||||
+ setfunc(LR_REG, 1, &newLr, arg);
|
||||
+ setfunc(FP_REG, 1, &newFp, arg);
|
||||
+ setfunc(SP_REG, 1, &newSp, arg);
|
||||
+
|
||||
+ // If the fp is invalid, we might still have a valid lr.
|
||||
+ // But if the fp is valid, then the stack should be moving in the right direction.
|
||||
+ return fp == 0 || newSp > sp;
|
||||
+}
|
|
@ -0,0 +1,475 @@
|
|||
From db33cb0cac3253c34881c0377ada51d9803eaae0 Mon Sep 17 00:00:00 2001
|
||||
From: Ying Huang <ying.huang@oss.cipunited.com>
|
||||
Date: Tue, 5 Mar 2024 17:51:22 +0800
|
||||
Subject: [PATCH] backends: Add register_info, return_value_location, core_note
|
||||
on mips
|
||||
|
||||
* backends/Makefile.am (mips_SRCS): Add mips_regs.c,
|
||||
mips_retval.c and mips_corenote.c.
|
||||
* backends/mips_init.c (mips_init): HOOK register_info,
|
||||
return_value_location and core_note.
|
||||
* backends/mips_corenote.c: New file.
|
||||
* backends/mips_regs.c: Likewise.
|
||||
* backends/mips_retval.c: Likewise.
|
||||
|
||||
Signed-off-by: Ying Huang <ying.huang@oss.cipunited.com>
|
||||
---
|
||||
backends/Makefile.am | 3 +-
|
||||
backends/mips_corenote.c | 85 +++++++++++++++++
|
||||
backends/mips_init.c | 3 +
|
||||
backends/mips_regs.c | 135 +++++++++++++++++++++++++++
|
||||
backends/mips_retval.c | 196 +++++++++++++++++++++++++++++++++++++++
|
||||
5 files changed, 421 insertions(+), 1 deletion(-)
|
||||
create mode 100644 backends/mips_corenote.c
|
||||
create mode 100644 backends/mips_regs.c
|
||||
create mode 100644 backends/mips_retval.c
|
||||
|
||||
--- a/backends/Makefile.am
|
||||
+++ b/backends/Makefile.am
|
||||
@@ -103,7 +103,8 @@ loongarch_SRCS = loongarch_init.c loonga
|
||||
arc_SRCS = arc_init.c arc_symbol.c
|
||||
|
||||
mips_SRCS = mips_init.c mips_symbol.c mips_attrs.c mips_initreg.c \
|
||||
- mips_cfi.c mips_unwind.c
|
||||
+ mips_cfi.c mips_unwind.c mips_regs.c mips_retval.c \
|
||||
+ mips_corenote.c
|
||||
|
||||
libebl_backends_a_SOURCES = $(i386_SRCS) $(sh_SRCS) $(x86_64_SRCS) \
|
||||
$(ia64_SRCS) $(alpha_SRCS) $(arm_SRCS) \
|
||||
--- /dev/null
|
||||
+++ b/backends/mips_corenote.c
|
||||
@@ -0,0 +1,85 @@
|
||||
+/* MIPS specific core note handling.
|
||||
+ Copyright (C) 2024 CIP United Inc.
|
||||
+ This file is part of elfutils.
|
||||
+
|
||||
+ This file is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of either
|
||||
+
|
||||
+ * the GNU Lesser General Public License as published by the Free
|
||||
+ Software Foundation; either version 3 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or
|
||||
+
|
||||
+ * the GNU General Public License as published by the Free
|
||||
+ Software Foundation; either version 2 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or both in parallel, as here.
|
||||
+
|
||||
+ elfutils is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ You should have received copies of the GNU General Public License and
|
||||
+ the GNU Lesser General Public License along with this program. If
|
||||
+ not, see <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+# include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#include <elf.h>
|
||||
+#include <inttypes.h>
|
||||
+#include <stddef.h>
|
||||
+#include <stdio.h>
|
||||
+#include <sys/time.h>
|
||||
+
|
||||
+#define BACKEND mips_
|
||||
+#include "libebl_CPU.h"
|
||||
+
|
||||
+#define BITS 64
|
||||
+#ifndef BITS
|
||||
+# define BITS 32
|
||||
+#else
|
||||
+# define BITS 64
|
||||
+#endif
|
||||
+
|
||||
+#define PRSTATUS_REGS_SIZE (45 * (BITS / 8))
|
||||
+static const Ebl_Register_Location prstatus_regs[] =
|
||||
+ {
|
||||
+ { .offset = 0, .regno = 0, .count = (BITS == 32 ? 40 : 34), .bits = BITS },
|
||||
+ { .offset = BITS/8 * (BITS == 32 ? 41 : 35), .regno = (BITS == 32 ? 41 : 35), .count = (BITS == 32 ? 4 : 10), .bits = BITS },
|
||||
+ };
|
||||
+
|
||||
+#define PRSTATUS_REGSET_ITEMS \
|
||||
+ { \
|
||||
+ .name = "pc", .type = ELF_T_ADDR, .format = 'x', \
|
||||
+ .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + ((BITS/8) * (BITS == 32 ? 40 : 34)), \
|
||||
+ .group = "register", \
|
||||
+ .pc_register = true \
|
||||
+ }
|
||||
+
|
||||
+#if BITS == 32
|
||||
+# define ULONG uint32_t
|
||||
+# define ALIGN_ULONG 4
|
||||
+# define TYPE_ULONG ELF_T_WORD
|
||||
+#define TYPE_LONG ELF_T_SWORD
|
||||
+#else
|
||||
+#define ULONG uint64_t
|
||||
+#define ALIGN_ULONG 8
|
||||
+#define TYPE_ULONG ELF_T_XWORD
|
||||
+#define TYPE_LONG ELF_T_SXWORD
|
||||
+#endif
|
||||
+#define PID_T int32_t
|
||||
+#define UID_T uint32_t
|
||||
+#define GID_T uint32_t
|
||||
+#define ALIGN_PID_T 4
|
||||
+#define ALIGN_UID_T 4
|
||||
+#define ALIGN_GID_T 4
|
||||
+#define TYPE_PID_T ELF_T_SWORD
|
||||
+#define TYPE_UID_T ELF_T_WORD
|
||||
+#define TYPE_GID_T ELF_T_WORD
|
||||
+
|
||||
+#include "linux-core-note.c"
|
||||
--- a/backends/mips_init.c
|
||||
+++ b/backends/mips_init.c
|
||||
@@ -61,6 +61,9 @@ mips_init (Elf *elf __attribute__ ((unus
|
||||
HOOK (eh, set_initial_registers_tid);
|
||||
HOOK (eh, abi_cfi);
|
||||
HOOK (eh, unwind);
|
||||
+ HOOK (eh, register_info);
|
||||
+ HOOK (eh, return_value_location);
|
||||
+ HOOK (eh, core_note);
|
||||
eh->frame_nregs = 71;
|
||||
return eh;
|
||||
}
|
||||
--- /dev/null
|
||||
+++ b/backends/mips_regs.c
|
||||
@@ -0,0 +1,135 @@
|
||||
+/* Register names and numbers for mips DWARF.
|
||||
+ Copyright (C) 2006 Red Hat, Inc.
|
||||
+ Copyright (C) 2024 CIP United Inc.
|
||||
+ This file is part of elfutils.
|
||||
+
|
||||
+ This file is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of either
|
||||
+
|
||||
+ * the GNU Lesser General Public License as published by the Free
|
||||
+ Software Foundation; either version 3 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or
|
||||
+
|
||||
+ * the GNU General Public License as published by the Free
|
||||
+ Software Foundation; either version 2 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or both in parallel, as here.
|
||||
+
|
||||
+ elfutils is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ You should have received copies of the GNU General Public License and
|
||||
+ the GNU Lesser General Public License along with this program. If
|
||||
+ not, see <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+# include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#include <assert.h>
|
||||
+#include <dwarf.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#define BACKEND mips_
|
||||
+#include "libebl_CPU.h"
|
||||
+#include <system.h>
|
||||
+ssize_t
|
||||
+mips_register_info (Ebl *ebl __attribute__ ((unused)),
|
||||
+ int regno, char *name, size_t namelen,
|
||||
+ const char **prefix, const char **setname,
|
||||
+ int *bits, int *type)
|
||||
+{
|
||||
+ if (name == NULL)
|
||||
+ return 72;
|
||||
+
|
||||
+ if (regno < 0 || regno > 71 || namelen < 4)
|
||||
+ return -1;
|
||||
+
|
||||
+ *prefix = "$";
|
||||
+ if (regno < 38)
|
||||
+ {
|
||||
+ *setname = "integer";
|
||||
+ *type = DW_ATE_signed;
|
||||
+ *bits = 32;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ *setname = "FPU";
|
||||
+ *type = DW_ATE_float;
|
||||
+ *bits = 64;
|
||||
+ }
|
||||
+
|
||||
+ if (regno < 32)
|
||||
+ {
|
||||
+ if (regno < 10)
|
||||
+ {
|
||||
+ name[0] = regno + '0';
|
||||
+ namelen = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ name[0] = (regno / 10) + '0';
|
||||
+ name[1] = (regno % 10) + '0';
|
||||
+ namelen = 2;
|
||||
+ }
|
||||
+ if (regno == 28 || regno == 29 || regno == 31)
|
||||
+ *type = DW_ATE_address;
|
||||
+ }
|
||||
+ else if (regno == 32)
|
||||
+ {
|
||||
+ return stpcpy (name, "lo") + 1 - name;
|
||||
+ }
|
||||
+ else if (regno == 33)
|
||||
+ {
|
||||
+ return stpcpy (name, "hi") + 1 - name;
|
||||
+ }
|
||||
+ else if (regno == 34)
|
||||
+ {
|
||||
+ return stpcpy (name, "pc") + 1 - name;
|
||||
+ }
|
||||
+ else if (regno == 35)
|
||||
+ {
|
||||
+ *type = DW_ATE_address;
|
||||
+ return stpcpy (name, "bad") + 1 - name;
|
||||
+ }
|
||||
+ else if (regno == 36)
|
||||
+ {
|
||||
+ return stpcpy (name, "sr") + 1 - name;
|
||||
+ }
|
||||
+ else if (regno == 37)
|
||||
+ {
|
||||
+ *type = DW_ATE_address;
|
||||
+ return stpcpy (name, "cause") + 1 - name;
|
||||
+ }
|
||||
+ else if (regno < 70)
|
||||
+ {
|
||||
+ name[0] = 'f';
|
||||
+ if (regno < 38 + 10)
|
||||
+ {
|
||||
+ name[1] = (regno - 38) + '0';
|
||||
+ namelen = 2;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ name[1] = (regno - 38) / 10 + '0';
|
||||
+ name[2] = (regno - 38) % 10 + '0';
|
||||
+ namelen = 3;
|
||||
+ }
|
||||
+ }
|
||||
+ else if (regno == 70)
|
||||
+ {
|
||||
+ return stpcpy (name, "fsr") + 1 - name;
|
||||
+ }
|
||||
+ else if (regno == 71)
|
||||
+ {
|
||||
+ return stpcpy (name, "fir") + 1 - name;
|
||||
+ }
|
||||
+
|
||||
+ name[namelen++] = '\0';
|
||||
+ return namelen;
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ b/backends/mips_retval.c
|
||||
@@ -0,0 +1,196 @@
|
||||
+/* Function return value location for Linux/mips ABI.
|
||||
+ Copyright (C) 2005 Red Hat, Inc.
|
||||
+ Copyright (C) 2024 CIP United Inc.
|
||||
+ This file is part of elfutils.
|
||||
+
|
||||
+ This file is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of either
|
||||
+
|
||||
+ * the GNU Lesser General Public License as published by the Free
|
||||
+ Software Foundation; either version 3 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or
|
||||
+
|
||||
+ * the GNU General Public License as published by the Free
|
||||
+ Software Foundation; either version 2 of the License, or (at
|
||||
+ your option) any later version
|
||||
+
|
||||
+ or both in parallel, as here.
|
||||
+
|
||||
+ elfutils is distributed in the hope that it will be useful, but
|
||||
+ WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ General Public License for more details.
|
||||
+
|
||||
+ You should have received copies of the GNU General Public License and
|
||||
+ the GNU Lesser General Public License along with this program. If
|
||||
+ not, see <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+# include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#include <assert.h>
|
||||
+#include <dwarf.h>
|
||||
+#include <string.h>
|
||||
+#include <elf.h>
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+#define BACKEND mips_
|
||||
+#include "libebl_CPU.h"
|
||||
+#include "libdwP.h"
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+/* $v0 or pair $v0, $v1 */
|
||||
+static const Dwarf_Op loc_intreg_o32[] =
|
||||
+ {
|
||||
+ { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 },
|
||||
+ { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 },
|
||||
+ };
|
||||
+
|
||||
+static const Dwarf_Op loc_intreg[] =
|
||||
+ {
|
||||
+ { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 8 },
|
||||
+ { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 8 },
|
||||
+ };
|
||||
+#define nloc_intreg 1
|
||||
+#define nloc_intregpair 4
|
||||
+
|
||||
+/* $f0 (float), or pair $f0, $f1 (double).
|
||||
+ * f2/f3 are used for COMPLEX (= 2 doubles) returns in Fortran */
|
||||
+static const Dwarf_Op loc_fpreg_o32[] =
|
||||
+ {
|
||||
+ { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 },
|
||||
+ { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 },
|
||||
+ { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 4 },
|
||||
+ { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 4 },
|
||||
+ };
|
||||
+
|
||||
+/* $f0, or pair $f0, $f2. */
|
||||
+static const Dwarf_Op loc_fpreg[] =
|
||||
+ {
|
||||
+ { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 8 },
|
||||
+ { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 8 },
|
||||
+ };
|
||||
+#define nloc_fpreg 1
|
||||
+#define nloc_fpregpair 4
|
||||
+#define nloc_fpregquad 8
|
||||
+
|
||||
+/* The return value is a structure and is actually stored in stack space
|
||||
+ passed in a hidden argument by the caller. But, the compiler
|
||||
+ helpfully returns the address of that space in $v0. */
|
||||
+static const Dwarf_Op loc_aggregate[] =
|
||||
+ {
|
||||
+ { .atom = DW_OP_breg2, .number = 0 }
|
||||
+ };
|
||||
+#define nloc_aggregate 1
|
||||
+
|
||||
+int
|
||||
+mips_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
|
||||
+{
|
||||
+ unsigned int regsize = (gelf_getclass (functypedie->cu->dbg->elf) == ELFCLASS32 ) ? 4 : 8;
|
||||
+ if (!regsize)
|
||||
+ return -2;
|
||||
+
|
||||
+ /* Start with the function's type, and get the DW_AT_type attribute,
|
||||
+ which is the type of the return value. */
|
||||
+
|
||||
+ Dwarf_Attribute attr_mem;
|
||||
+ Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, &attr_mem);
|
||||
+ if (attr == NULL)
|
||||
+ /* The function has no return value, like a `void' function in C. */
|
||||
+ return 0;
|
||||
+
|
||||
+ Dwarf_Die die_mem;
|
||||
+ Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem);
|
||||
+ int tag = dwarf_tag (typedie);
|
||||
+
|
||||
+ /* Follow typedefs and qualifiers to get to the actual type. */
|
||||
+ while (tag == DW_TAG_typedef
|
||||
+ || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
|
||||
+ || tag == DW_TAG_restrict_type)
|
||||
+ {
|
||||
+ attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
|
||||
+ typedie = dwarf_formref_die (attr, &die_mem);
|
||||
+ tag = dwarf_tag (typedie);
|
||||
+ }
|
||||
+
|
||||
+ switch (tag)
|
||||
+ {
|
||||
+ case -1:
|
||||
+ return -1;
|
||||
+
|
||||
+ case DW_TAG_subrange_type:
|
||||
+ if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
|
||||
+ {
|
||||
+ attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
|
||||
+ typedie = dwarf_formref_die (attr, &die_mem);
|
||||
+ tag = dwarf_tag (typedie);
|
||||
+ }
|
||||
+ /* Fall through. */
|
||||
+ FALLTHROUGH;
|
||||
+
|
||||
+ case DW_TAG_base_type:
|
||||
+ case DW_TAG_enumeration_type:
|
||||
+ CASE_POINTER:
|
||||
+ {
|
||||
+ Dwarf_Word size;
|
||||
+ if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
|
||||
+ &attr_mem), &size) != 0)
|
||||
+ {
|
||||
+ if (dwarf_is_pointer (tag))
|
||||
+ size = regsize;
|
||||
+ else
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if (tag == DW_TAG_base_type)
|
||||
+ {
|
||||
+ Dwarf_Word encoding;
|
||||
+ if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
|
||||
+ &attr_mem), &encoding) != 0)
|
||||
+ return -1;
|
||||
+
|
||||
+#define ARCH_LOC(loc, regsize) ((regsize) == 4 ? (loc ## _o32) : (loc))
|
||||
+
|
||||
+ if (encoding == DW_ATE_float)
|
||||
+ {
|
||||
+ *locp = ARCH_LOC(loc_fpreg, regsize);
|
||||
+ if (size <= regsize)
|
||||
+ return nloc_fpreg;
|
||||
+
|
||||
+ if (size <= 2*regsize)
|
||||
+ return nloc_fpregpair;
|
||||
+
|
||||
+ if (size <= 4*regsize)
|
||||
+ return nloc_fpregquad;
|
||||
+
|
||||
+ goto aggregate;
|
||||
+ }
|
||||
+ }
|
||||
+ *locp = ARCH_LOC(loc_intreg, regsize);
|
||||
+ if (size <= regsize)
|
||||
+ return nloc_intreg;
|
||||
+ if (size <= 2*regsize)
|
||||
+ return nloc_intregpair;
|
||||
+
|
||||
+ /* Else fall through. Shouldn't happen though (at least with gcc) */
|
||||
+ }
|
||||
+ FALLTHROUGH;
|
||||
+
|
||||
+ case DW_TAG_structure_type:
|
||||
+ case DW_TAG_class_type:
|
||||
+ case DW_TAG_union_type:
|
||||
+ case DW_TAG_array_type:
|
||||
+ aggregate:
|
||||
+ *locp = loc_aggregate;
|
||||
+ return nloc_aggregate;
|
||||
+ case DW_TAG_unspecified_type:
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /* XXX We don't have a good way to return specific errors from ebl calls.
|
||||
+ This value means we do not understand the type, but it is well-formed
|
||||
+ DWARF and might be valid. */
|
||||
+ return -2;
|
||||
+}
|
Loading…
Reference in New Issue