12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655 |
- /* Target-dependent code for GNU/Linux on MIPS processors.
- Copyright (C) 2001-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program 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 a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "gdbcore.h"
- #include "target.h"
- #include "solib-svr4.h"
- #include "osabi.h"
- #include "mips-tdep.h"
- #include "frame.h"
- #include "regcache.h"
- #include "trad-frame.h"
- #include "tramp-frame.h"
- #include "gdbtypes.h"
- #include "objfiles.h"
- #include "solib.h"
- #include "solist.h"
- #include "symtab.h"
- #include "target-descriptions.h"
- #include "regset.h"
- #include "mips-linux-tdep.h"
- #include "glibc-tdep.h"
- #include "linux-tdep.h"
- #include "xml-syscall.h"
- #include "gdbsupport/gdb_signals.h"
- #include "features/mips-linux.c"
- #include "features/mips-dsp-linux.c"
- #include "features/mips64-linux.c"
- #include "features/mips64-dsp-linux.c"
- static struct target_so_ops mips_svr4_so_ops;
- /* This enum represents the signals' numbers on the MIPS
- architecture. It just contains the signal definitions which are
- different from the generic implementation.
- It is derived from the file <arch/mips/include/uapi/asm/signal.h>,
- from the Linux kernel tree. */
- enum
- {
- MIPS_LINUX_SIGEMT = 7,
- MIPS_LINUX_SIGBUS = 10,
- MIPS_LINUX_SIGSYS = 12,
- MIPS_LINUX_SIGUSR1 = 16,
- MIPS_LINUX_SIGUSR2 = 17,
- MIPS_LINUX_SIGCHLD = 18,
- MIPS_LINUX_SIGCLD = MIPS_LINUX_SIGCHLD,
- MIPS_LINUX_SIGPWR = 19,
- MIPS_LINUX_SIGWINCH = 20,
- MIPS_LINUX_SIGURG = 21,
- MIPS_LINUX_SIGIO = 22,
- MIPS_LINUX_SIGPOLL = MIPS_LINUX_SIGIO,
- MIPS_LINUX_SIGSTOP = 23,
- MIPS_LINUX_SIGTSTP = 24,
- MIPS_LINUX_SIGCONT = 25,
- MIPS_LINUX_SIGTTIN = 26,
- MIPS_LINUX_SIGTTOU = 27,
- MIPS_LINUX_SIGVTALRM = 28,
- MIPS_LINUX_SIGPROF = 29,
- MIPS_LINUX_SIGXCPU = 30,
- MIPS_LINUX_SIGXFSZ = 31,
- MIPS_LINUX_SIGRTMIN = 32,
- MIPS_LINUX_SIGRT64 = 64,
- MIPS_LINUX_SIGRTMAX = 127,
- };
- /* Figure out where the longjmp will land.
- We expect the first arg to be a pointer to the jmp_buf structure
- from which we extract the pc (MIPS_LINUX_JB_PC) that we will land
- at. The pc is copied into PC. This routine returns 1 on
- success. */
- #define MIPS_LINUX_JB_ELEMENT_SIZE 4
- #define MIPS_LINUX_JB_PC 0
- static int
- mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
- {
- CORE_ADDR jb_addr;
- struct gdbarch *gdbarch = get_frame_arch (frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- gdb_byte buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT];
- jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
- if (target_read_memory ((jb_addr
- + MIPS_LINUX_JB_PC * MIPS_LINUX_JB_ELEMENT_SIZE),
- buf, gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT))
- return 0;
- *pc = extract_unsigned_integer (buf,
- gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT,
- byte_order);
- return 1;
- }
- /* Transform the bits comprising a 32-bit register to the right size
- for regcache_raw_supply(). This is needed when mips_isa_regsize()
- is 8. */
- static void
- supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr)
- {
- regcache->raw_supply_integer (regnum, (const gdb_byte *) addr, 4, true);
- }
- /* Unpack an elf_gregset_t into GDB's register cache. */
- void
- mips_supply_gregset (struct regcache *regcache,
- const mips_elf_gregset_t *gregsetp)
- {
- int regi;
- const mips_elf_greg_t *regp = *gregsetp;
- struct gdbarch *gdbarch = regcache->arch ();
- for (regi = EF_REG0 + 1; regi <= EF_REG31; regi++)
- supply_32bit_reg (regcache, regi - EF_REG0, regp + regi);
- if (mips_linux_restart_reg_p (gdbarch))
- supply_32bit_reg (regcache, MIPS_RESTART_REGNUM, regp + EF_REG0);
- supply_32bit_reg (regcache, mips_regnum (gdbarch)->lo, regp + EF_LO);
- supply_32bit_reg (regcache, mips_regnum (gdbarch)->hi, regp + EF_HI);
- supply_32bit_reg (regcache, mips_regnum (gdbarch)->pc,
- regp + EF_CP0_EPC);
- supply_32bit_reg (regcache, mips_regnum (gdbarch)->badvaddr,
- regp + EF_CP0_BADVADDR);
- supply_32bit_reg (regcache, MIPS_PS_REGNUM, regp + EF_CP0_STATUS);
- supply_32bit_reg (regcache, mips_regnum (gdbarch)->cause,
- regp + EF_CP0_CAUSE);
- /* Fill the inaccessible zero register with zero. */
- regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM);
- }
- static void
- mips_supply_gregset_wrapper (const struct regset *regset,
- struct regcache *regcache,
- int regnum, const void *gregs, size_t len)
- {
- gdb_assert (len >= sizeof (mips_elf_gregset_t));
- mips_supply_gregset (regcache, (const mips_elf_gregset_t *)gregs);
- }
- /* Pack our registers (or one register) into an elf_gregset_t. */
- void
- mips_fill_gregset (const struct regcache *regcache,
- mips_elf_gregset_t *gregsetp, int regno)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- int regaddr, regi;
- mips_elf_greg_t *regp = *gregsetp;
- void *dst;
- if (regno == -1)
- {
- memset (regp, 0, sizeof (mips_elf_gregset_t));
- for (regi = 1; regi < 32; regi++)
- mips_fill_gregset (regcache, gregsetp, regi);
- mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->lo);
- mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->hi);
- mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->pc);
- mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->badvaddr);
- mips_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM);
- mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->cause);
- mips_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
- return;
- }
- if (regno > 0 && regno < 32)
- {
- dst = regp + regno + EF_REG0;
- regcache->raw_collect (regno, dst);
- return;
- }
- if (regno == mips_regnum (gdbarch)->lo)
- regaddr = EF_LO;
- else if (regno == mips_regnum (gdbarch)->hi)
- regaddr = EF_HI;
- else if (regno == mips_regnum (gdbarch)->pc)
- regaddr = EF_CP0_EPC;
- else if (regno == mips_regnum (gdbarch)->badvaddr)
- regaddr = EF_CP0_BADVADDR;
- else if (regno == MIPS_PS_REGNUM)
- regaddr = EF_CP0_STATUS;
- else if (regno == mips_regnum (gdbarch)->cause)
- regaddr = EF_CP0_CAUSE;
- else if (mips_linux_restart_reg_p (gdbarch)
- && regno == MIPS_RESTART_REGNUM)
- regaddr = EF_REG0;
- else
- regaddr = -1;
- if (regaddr != -1)
- {
- dst = regp + regaddr;
- regcache->raw_collect (regno, dst);
- }
- }
- static void
- mips_fill_gregset_wrapper (const struct regset *regset,
- const struct regcache *regcache,
- int regnum, void *gregs, size_t len)
- {
- gdb_assert (len >= sizeof (mips_elf_gregset_t));
- mips_fill_gregset (regcache, (mips_elf_gregset_t *)gregs, regnum);
- }
- /* Support for 64-bit ABIs. */
- /* Figure out where the longjmp will land.
- We expect the first arg to be a pointer to the jmp_buf structure
- from which we extract the pc (MIPS_LINUX_JB_PC) that we will land
- at. The pc is copied into PC. This routine returns 1 on
- success. */
- /* Details about jmp_buf. */
- #define MIPS64_LINUX_JB_PC 0
- static int
- mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
- {
- CORE_ADDR jb_addr;
- struct gdbarch *gdbarch = get_frame_arch (frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- gdb_byte *buf
- = (gdb_byte *) alloca (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT);
- int element_size = gdbarch_ptr_bit (gdbarch) == 32 ? 4 : 8;
- jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
- if (target_read_memory (jb_addr + MIPS64_LINUX_JB_PC * element_size,
- buf,
- gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT))
- return 0;
- *pc = extract_unsigned_integer (buf,
- gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT,
- byte_order);
- return 1;
- }
- /* Register set support functions. These operate on standard 64-bit
- regsets, but work whether the target is 32-bit or 64-bit. A 32-bit
- target will still use the 64-bit format for PTRACE_GETREGS. */
- /* Supply a 64-bit register. */
- static void
- supply_64bit_reg (struct regcache *regcache, int regnum,
- const gdb_byte *buf)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
- && register_size (gdbarch, regnum) == 4)
- regcache->raw_supply (regnum, buf + 4);
- else
- regcache->raw_supply (regnum, buf);
- }
- /* Unpack a 64-bit elf_gregset_t into GDB's register cache. */
- void
- mips64_supply_gregset (struct regcache *regcache,
- const mips64_elf_gregset_t *gregsetp)
- {
- int regi;
- const mips64_elf_greg_t *regp = *gregsetp;
- struct gdbarch *gdbarch = regcache->arch ();
- for (regi = MIPS64_EF_REG0 + 1; regi <= MIPS64_EF_REG31; regi++)
- supply_64bit_reg (regcache, regi - MIPS64_EF_REG0,
- (const gdb_byte *) (regp + regi));
- if (mips_linux_restart_reg_p (gdbarch))
- supply_64bit_reg (regcache, MIPS_RESTART_REGNUM,
- (const gdb_byte *) (regp + MIPS64_EF_REG0));
- supply_64bit_reg (regcache, mips_regnum (gdbarch)->lo,
- (const gdb_byte *) (regp + MIPS64_EF_LO));
- supply_64bit_reg (regcache, mips_regnum (gdbarch)->hi,
- (const gdb_byte *) (regp + MIPS64_EF_HI));
- supply_64bit_reg (regcache, mips_regnum (gdbarch)->pc,
- (const gdb_byte *) (regp + MIPS64_EF_CP0_EPC));
- supply_64bit_reg (regcache, mips_regnum (gdbarch)->badvaddr,
- (const gdb_byte *) (regp + MIPS64_EF_CP0_BADVADDR));
- supply_64bit_reg (regcache, MIPS_PS_REGNUM,
- (const gdb_byte *) (regp + MIPS64_EF_CP0_STATUS));
- supply_64bit_reg (regcache, mips_regnum (gdbarch)->cause,
- (const gdb_byte *) (regp + MIPS64_EF_CP0_CAUSE));
- /* Fill the inaccessible zero register with zero. */
- regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM);
- }
- static void
- mips64_supply_gregset_wrapper (const struct regset *regset,
- struct regcache *regcache,
- int regnum, const void *gregs, size_t len)
- {
- gdb_assert (len >= sizeof (mips64_elf_gregset_t));
- mips64_supply_gregset (regcache, (const mips64_elf_gregset_t *)gregs);
- }
- /* Pack our registers (or one register) into a 64-bit elf_gregset_t. */
- void
- mips64_fill_gregset (const struct regcache *regcache,
- mips64_elf_gregset_t *gregsetp, int regno)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- int regaddr, regi;
- mips64_elf_greg_t *regp = *gregsetp;
- void *dst;
- if (regno == -1)
- {
- memset (regp, 0, sizeof (mips64_elf_gregset_t));
- for (regi = 1; regi < 32; regi++)
- mips64_fill_gregset (regcache, gregsetp, regi);
- mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->lo);
- mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->hi);
- mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->pc);
- mips64_fill_gregset (regcache, gregsetp,
- mips_regnum (gdbarch)->badvaddr);
- mips64_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM);
- mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->cause);
- mips64_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
- return;
- }
- if (regno > 0 && regno < 32)
- regaddr = regno + MIPS64_EF_REG0;
- else if (regno == mips_regnum (gdbarch)->lo)
- regaddr = MIPS64_EF_LO;
- else if (regno == mips_regnum (gdbarch)->hi)
- regaddr = MIPS64_EF_HI;
- else if (regno == mips_regnum (gdbarch)->pc)
- regaddr = MIPS64_EF_CP0_EPC;
- else if (regno == mips_regnum (gdbarch)->badvaddr)
- regaddr = MIPS64_EF_CP0_BADVADDR;
- else if (regno == MIPS_PS_REGNUM)
- regaddr = MIPS64_EF_CP0_STATUS;
- else if (regno == mips_regnum (gdbarch)->cause)
- regaddr = MIPS64_EF_CP0_CAUSE;
- else if (mips_linux_restart_reg_p (gdbarch)
- && regno == MIPS_RESTART_REGNUM)
- regaddr = MIPS64_EF_REG0;
- else
- regaddr = -1;
- if (regaddr != -1)
- {
- dst = regp + regaddr;
- regcache->raw_collect_integer (regno, (gdb_byte *) dst, 8, true);
- }
- }
- static void
- mips64_fill_gregset_wrapper (const struct regset *regset,
- const struct regcache *regcache,
- int regnum, void *gregs, size_t len)
- {
- gdb_assert (len >= sizeof (mips64_elf_gregset_t));
- mips64_fill_gregset (regcache, (mips64_elf_gregset_t *)gregs, regnum);
- }
- /* Likewise, unpack an elf_fpregset_t. Linux only uses even-numbered
- FPR slots in the Status.FR=0 mode, storing even-odd FPR pairs as the
- SDC1 instruction would. When run on MIPS I architecture processors
- all FPR slots used to be used, unusually, holding the respective FPRs
- in the first 4 bytes, but that was corrected for consistency, with
- `linux-mips.org' (LMO) commit 42533948caac ("Major pile of FP emulator
- changes."), the fix corrected with LMO commit 849fa7a50dff ("R3k FPU
- ptrace() handling fixes."), and then broken and fixed over and over
- again, until last time fixed with commit 80cbfad79096 ("MIPS: Correct
- MIPS I FP context layout"). */
- void
- mips64_supply_fpregset (struct regcache *regcache,
- const mips64_elf_fpregset_t *fpregsetp)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- int regi;
- if (register_size (gdbarch, gdbarch_fp0_regnum (gdbarch)) == 4)
- for (regi = 0; regi < 32; regi++)
- {
- const gdb_byte *reg_ptr
- = (const gdb_byte *) (*fpregsetp + (regi & ~1));
- if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (regi & 1))
- reg_ptr += 4;
- regcache->raw_supply (gdbarch_fp0_regnum (gdbarch) + regi, reg_ptr);
- }
- else
- for (regi = 0; regi < 32; regi++)
- regcache->raw_supply (gdbarch_fp0_regnum (gdbarch) + regi,
- (const char *) (*fpregsetp + regi));
- supply_32bit_reg (regcache, mips_regnum (gdbarch)->fp_control_status,
- (const gdb_byte *) (*fpregsetp + 32));
- /* The ABI doesn't tell us how to supply FCRIR, and core dumps don't
- include it - but the result of PTRACE_GETFPREGS does. The best we
- can do is to assume that its value is present. */
- supply_32bit_reg (regcache,
- mips_regnum (gdbarch)->fp_implementation_revision,
- (const gdb_byte *) (*fpregsetp + 32) + 4);
- }
- static void
- mips64_supply_fpregset_wrapper (const struct regset *regset,
- struct regcache *regcache,
- int regnum, const void *gregs, size_t len)
- {
- gdb_assert (len >= sizeof (mips64_elf_fpregset_t));
- mips64_supply_fpregset (regcache, (const mips64_elf_fpregset_t *)gregs);
- }
- /* Likewise, pack one or all floating point registers into an
- elf_fpregset_t. See `mips_supply_fpregset' for an explanation
- of the layout. */
- void
- mips64_fill_fpregset (const struct regcache *regcache,
- mips64_elf_fpregset_t *fpregsetp, int regno)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- gdb_byte *to;
- if ((regno >= gdbarch_fp0_regnum (gdbarch))
- && (regno < gdbarch_fp0_regnum (gdbarch) + 32))
- {
- if (register_size (gdbarch, regno) == 4)
- {
- int regi = regno - gdbarch_fp0_regnum (gdbarch);
- to = (gdb_byte *) (*fpregsetp + (regi & ~1));
- if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (regi & 1))
- to += 4;
- regcache->raw_collect (regno, to);
- }
- else
- {
- to = (gdb_byte *) (*fpregsetp + regno
- - gdbarch_fp0_regnum (gdbarch));
- regcache->raw_collect (regno, to);
- }
- }
- else if (regno == mips_regnum (gdbarch)->fp_control_status)
- {
- to = (gdb_byte *) (*fpregsetp + 32);
- regcache->raw_collect_integer (regno, to, 4, true);
- }
- else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
- {
- to = (gdb_byte *) (*fpregsetp + 32) + 4;
- regcache->raw_collect_integer (regno, to, 4, true);
- }
- else if (regno == -1)
- {
- int regi;
- for (regi = 0; regi < 32; regi++)
- mips64_fill_fpregset (regcache, fpregsetp,
- gdbarch_fp0_regnum (gdbarch) + regi);
- mips64_fill_fpregset (regcache, fpregsetp,
- mips_regnum (gdbarch)->fp_control_status);
- mips64_fill_fpregset (regcache, fpregsetp,
- mips_regnum (gdbarch)->fp_implementation_revision);
- }
- }
- static void
- mips64_fill_fpregset_wrapper (const struct regset *regset,
- const struct regcache *regcache,
- int regnum, void *gregs, size_t len)
- {
- gdb_assert (len >= sizeof (mips64_elf_fpregset_t));
- mips64_fill_fpregset (regcache, (mips64_elf_fpregset_t *)gregs, regnum);
- }
- static const struct regset mips_linux_gregset =
- {
- NULL, mips_supply_gregset_wrapper, mips_fill_gregset_wrapper
- };
- static const struct regset mips64_linux_gregset =
- {
- NULL, mips64_supply_gregset_wrapper, mips64_fill_gregset_wrapper
- };
- static const struct regset mips64_linux_fpregset =
- {
- NULL, mips64_supply_fpregset_wrapper, mips64_fill_fpregset_wrapper
- };
- static void
- mips_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
- iterate_over_regset_sections_cb *cb,
- void *cb_data,
- const struct regcache *regcache)
- {
- if (register_size (gdbarch, MIPS_ZERO_REGNUM) == 4)
- {
- cb (".reg", sizeof (mips_elf_gregset_t), sizeof (mips_elf_gregset_t),
- &mips_linux_gregset, NULL, cb_data);
- cb (".reg2", sizeof (mips64_elf_fpregset_t),
- sizeof (mips64_elf_fpregset_t), &mips64_linux_fpregset,
- NULL, cb_data);
- }
- else
- {
- cb (".reg", sizeof (mips64_elf_gregset_t), sizeof (mips64_elf_gregset_t),
- &mips64_linux_gregset, NULL, cb_data);
- cb (".reg2", sizeof (mips64_elf_fpregset_t),
- sizeof (mips64_elf_fpregset_t), &mips64_linux_fpregset,
- NULL, cb_data);
- }
- }
- static const struct target_desc *
- mips_linux_core_read_description (struct gdbarch *gdbarch,
- struct target_ops *target,
- bfd *abfd)
- {
- asection *section = bfd_get_section_by_name (abfd, ".reg");
- if (! section)
- return NULL;
- switch (bfd_section_size (section))
- {
- case sizeof (mips_elf_gregset_t):
- return mips_tdesc_gp32;
- case sizeof (mips64_elf_gregset_t):
- return mips_tdesc_gp64;
- default:
- return NULL;
- }
- }
- /* Check the code at PC for a dynamic linker lazy resolution stub.
- GNU ld for MIPS has put lazy resolution stubs into a ".MIPS.stubs"
- section uniformly since version 2.15. If the pc is in that section,
- then we are in such a stub. Before that ".stub" was used in 32-bit
- ELF binaries, however we do not bother checking for that since we
- have never had and that case should be extremely rare these days.
- Instead we pattern-match on the code generated by GNU ld. They look
- like this:
- lw t9,0x8010(gp)
- addu t7,ra
- jalr t9,ra
- addiu t8,zero,INDEX
- (with the appropriate doubleword instructions for N64). As any lazy
- resolution stubs in microMIPS binaries will always be in a
- ".MIPS.stubs" section we only ever verify standard MIPS patterns. */
- static int
- mips_linux_in_dynsym_stub (CORE_ADDR pc)
- {
- gdb_byte buf[28], *p;
- ULONGEST insn, insn1;
- int n64 = (mips_abi (target_gdbarch ()) == MIPS_ABI_N64);
- enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
- if (in_mips_stubs_section (pc))
- return 1;
- read_memory (pc - 12, buf, 28);
- if (n64)
- {
- /* ld t9,0x8010(gp) */
- insn1 = 0xdf998010;
- }
- else
- {
- /* lw t9,0x8010(gp) */
- insn1 = 0x8f998010;
- }
- p = buf + 12;
- while (p >= buf)
- {
- insn = extract_unsigned_integer (p, 4, byte_order);
- if (insn == insn1)
- break;
- p -= 4;
- }
- if (p < buf)
- return 0;
- insn = extract_unsigned_integer (p + 4, 4, byte_order);
- if (n64)
- {
- /* 'daddu t7,ra' or 'or t7, ra, zero'*/
- if (insn != 0x03e0782d && insn != 0x03e07825)
- return 0;
- }
- else
- {
- /* 'addu t7,ra' or 'or t7, ra, zero'*/
- if (insn != 0x03e07821 && insn != 0x03e07825)
- return 0;
- }
- insn = extract_unsigned_integer (p + 8, 4, byte_order);
- /* jalr t9,ra */
- if (insn != 0x0320f809)
- return 0;
- insn = extract_unsigned_integer (p + 12, 4, byte_order);
- if (n64)
- {
- /* daddiu t8,zero,0 */
- if ((insn & 0xffff0000) != 0x64180000)
- return 0;
- }
- else
- {
- /* addiu t8,zero,0 */
- if ((insn & 0xffff0000) != 0x24180000)
- return 0;
- }
- return 1;
- }
- /* Return non-zero iff PC belongs to the dynamic linker resolution
- code, a PLT entry, or a lazy binding stub. */
- static int
- mips_linux_in_dynsym_resolve_code (CORE_ADDR pc)
- {
- /* Check whether PC is in the dynamic linker. This also checks
- whether it is in the .plt section, used by non-PIC executables. */
- if (svr4_in_dynsym_resolve_code (pc))
- return 1;
- /* Likewise for the stubs. They live in the .MIPS.stubs section these
- days, so we check if the PC is within, than fall back to a pattern
- match. */
- if (mips_linux_in_dynsym_stub (pc))
- return 1;
- return 0;
- }
- /* See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c,
- and glibc_skip_solib_resolver in glibc-tdep.c. The normal glibc
- implementation of this triggers at "fixup" from the same objfile as
- "_dl_runtime_resolve"; MIPS GNU/Linux can trigger at
- "__dl_runtime_resolve" directly. An unresolved lazy binding
- stub will point to _dl_runtime_resolve, which will first call
- __dl_runtime_resolve, and then pass control to the resolved
- function. */
- static CORE_ADDR
- mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- struct bound_minimal_symbol resolver;
- resolver = lookup_minimal_symbol ("__dl_runtime_resolve", NULL, NULL);
- if (resolver.minsym && BMSYMBOL_VALUE_ADDRESS (resolver) == pc)
- return frame_unwind_caller_pc (get_current_frame ());
- return glibc_skip_solib_resolver (gdbarch, pc);
- }
- /* Signal trampoline support. There are four supported layouts for a
- signal frame: o32 sigframe, o32 rt_sigframe, n32 rt_sigframe, and
- n64 rt_sigframe. We handle them all independently; not the most
- efficient way, but simplest. First, declare all the unwinders. */
- static void mips_linux_o32_sigframe_init (const struct tramp_frame *self,
- struct frame_info *this_frame,
- struct trad_frame_cache *this_cache,
- CORE_ADDR func);
- static void mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
- struct frame_info *this_frame,
- struct trad_frame_cache *this_cache,
- CORE_ADDR func);
- static int mips_linux_sigframe_validate (const struct tramp_frame *self,
- struct frame_info *this_frame,
- CORE_ADDR *pc);
- static int micromips_linux_sigframe_validate (const struct tramp_frame *self,
- struct frame_info *this_frame,
- CORE_ADDR *pc);
- #define MIPS_NR_LINUX 4000
- #define MIPS_NR_N64_LINUX 5000
- #define MIPS_NR_N32_LINUX 6000
- #define MIPS_NR_sigreturn MIPS_NR_LINUX + 119
- #define MIPS_NR_rt_sigreturn MIPS_NR_LINUX + 193
- #define MIPS_NR_N64_rt_sigreturn MIPS_NR_N64_LINUX + 211
- #define MIPS_NR_N32_rt_sigreturn MIPS_NR_N32_LINUX + 211
- #define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + MIPS_NR_sigreturn
- #define MIPS_INST_LI_V0_RT_SIGRETURN 0x24020000 + MIPS_NR_rt_sigreturn
- #define MIPS_INST_LI_V0_N64_RT_SIGRETURN 0x24020000 + MIPS_NR_N64_rt_sigreturn
- #define MIPS_INST_LI_V0_N32_RT_SIGRETURN 0x24020000 + MIPS_NR_N32_rt_sigreturn
- #define MIPS_INST_SYSCALL 0x0000000c
- #define MICROMIPS_INST_LI_V0 0x3040
- #define MICROMIPS_INST_POOL32A 0x0000
- #define MICROMIPS_INST_SYSCALL 0x8b7c
- static const struct tramp_frame mips_linux_o32_sigframe = {
- SIGTRAMP_FRAME,
- 4,
- {
- { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX },
- { MIPS_INST_SYSCALL, ULONGEST_MAX },
- { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
- },
- mips_linux_o32_sigframe_init,
- mips_linux_sigframe_validate
- };
- static const struct tramp_frame mips_linux_o32_rt_sigframe = {
- SIGTRAMP_FRAME,
- 4,
- {
- { MIPS_INST_LI_V0_RT_SIGRETURN, ULONGEST_MAX },
- { MIPS_INST_SYSCALL, ULONGEST_MAX },
- { TRAMP_SENTINEL_INSN, ULONGEST_MAX } },
- mips_linux_o32_sigframe_init,
- mips_linux_sigframe_validate
- };
- static const struct tramp_frame mips_linux_n32_rt_sigframe = {
- SIGTRAMP_FRAME,
- 4,
- {
- { MIPS_INST_LI_V0_N32_RT_SIGRETURN, ULONGEST_MAX },
- { MIPS_INST_SYSCALL, ULONGEST_MAX },
- { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
- },
- mips_linux_n32n64_sigframe_init,
- mips_linux_sigframe_validate
- };
- static const struct tramp_frame mips_linux_n64_rt_sigframe = {
- SIGTRAMP_FRAME,
- 4,
- {
- { MIPS_INST_LI_V0_N64_RT_SIGRETURN, ULONGEST_MAX },
- { MIPS_INST_SYSCALL, ULONGEST_MAX },
- { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
- },
- mips_linux_n32n64_sigframe_init,
- mips_linux_sigframe_validate
- };
- static const struct tramp_frame micromips_linux_o32_sigframe = {
- SIGTRAMP_FRAME,
- 2,
- {
- { MICROMIPS_INST_LI_V0, ULONGEST_MAX },
- { MIPS_NR_sigreturn, ULONGEST_MAX },
- { MICROMIPS_INST_POOL32A, ULONGEST_MAX },
- { MICROMIPS_INST_SYSCALL, ULONGEST_MAX },
- { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
- },
- mips_linux_o32_sigframe_init,
- micromips_linux_sigframe_validate
- };
- static const struct tramp_frame micromips_linux_o32_rt_sigframe = {
- SIGTRAMP_FRAME,
- 2,
- {
- { MICROMIPS_INST_LI_V0, ULONGEST_MAX },
- { MIPS_NR_rt_sigreturn, ULONGEST_MAX },
- { MICROMIPS_INST_POOL32A, ULONGEST_MAX },
- { MICROMIPS_INST_SYSCALL, ULONGEST_MAX },
- { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
- },
- mips_linux_o32_sigframe_init,
- micromips_linux_sigframe_validate
- };
- static const struct tramp_frame micromips_linux_n32_rt_sigframe = {
- SIGTRAMP_FRAME,
- 2,
- {
- { MICROMIPS_INST_LI_V0, ULONGEST_MAX },
- { MIPS_NR_N32_rt_sigreturn, ULONGEST_MAX },
- { MICROMIPS_INST_POOL32A, ULONGEST_MAX },
- { MICROMIPS_INST_SYSCALL, ULONGEST_MAX },
- { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
- },
- mips_linux_n32n64_sigframe_init,
- micromips_linux_sigframe_validate
- };
- static const struct tramp_frame micromips_linux_n64_rt_sigframe = {
- SIGTRAMP_FRAME,
- 2,
- {
- { MICROMIPS_INST_LI_V0, ULONGEST_MAX },
- { MIPS_NR_N64_rt_sigreturn, ULONGEST_MAX },
- { MICROMIPS_INST_POOL32A, ULONGEST_MAX },
- { MICROMIPS_INST_SYSCALL, ULONGEST_MAX },
- { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
- },
- mips_linux_n32n64_sigframe_init,
- micromips_linux_sigframe_validate
- };
- /* *INDENT-OFF* */
- /* The unwinder for o32 signal frames. The legacy structures look
- like this:
- struct sigframe {
- u32 sf_ass[4]; [argument save space for o32]
- u32 sf_code[2]; [signal trampoline or fill]
- struct sigcontext sf_sc;
- sigset_t sf_mask;
- };
- Pre-2.6.12 sigcontext:
- struct sigcontext {
- unsigned int sc_regmask; [Unused]
- unsigned int sc_status;
- unsigned long long sc_pc;
- unsigned long long sc_regs[32];
- unsigned long long sc_fpregs[32];
- unsigned int sc_ownedfp;
- unsigned int sc_fpc_csr;
- unsigned int sc_fpc_eir; [Unused]
- unsigned int sc_used_math;
- unsigned int sc_ssflags; [Unused]
- [Alignment hole of four bytes]
- unsigned long long sc_mdhi;
- unsigned long long sc_mdlo;
- unsigned int sc_cause; [Unused]
- unsigned int sc_badvaddr; [Unused]
- unsigned long sc_sigset[4]; [kernel's sigset_t]
- };
- Post-2.6.12 sigcontext (SmartMIPS/DSP support added):
- struct sigcontext {
- unsigned int sc_regmask; [Unused]
- unsigned int sc_status; [Unused]
- unsigned long long sc_pc;
- unsigned long long sc_regs[32];
- unsigned long long sc_fpregs[32];
- unsigned int sc_acx;
- unsigned int sc_fpc_csr;
- unsigned int sc_fpc_eir; [Unused]
- unsigned int sc_used_math;
- unsigned int sc_dsp;
- [Alignment hole of four bytes]
- unsigned long long sc_mdhi;
- unsigned long long sc_mdlo;
- unsigned long sc_hi1;
- unsigned long sc_lo1;
- unsigned long sc_hi2;
- unsigned long sc_lo2;
- unsigned long sc_hi3;
- unsigned long sc_lo3;
- };
- The RT signal frames look like this:
- struct rt_sigframe {
- u32 rs_ass[4]; [argument save space for o32]
- u32 rs_code[2] [signal trampoline or fill]
- struct siginfo rs_info;
- struct ucontext rs_uc;
- };
- struct ucontext {
- unsigned long uc_flags;
- struct ucontext *uc_link;
- stack_t uc_stack;
- [Alignment hole of four bytes]
- struct sigcontext uc_mcontext;
- sigset_t uc_sigmask;
- }; */
- /* *INDENT-ON* */
- #define SIGFRAME_SIGCONTEXT_OFFSET (6 * 4)
- #define RTSIGFRAME_SIGINFO_SIZE 128
- #define STACK_T_SIZE (3 * 4)
- #define UCONTEXT_SIGCONTEXT_OFFSET (2 * 4 + STACK_T_SIZE + 4)
- #define RTSIGFRAME_SIGCONTEXT_OFFSET (SIGFRAME_SIGCONTEXT_OFFSET \
- + RTSIGFRAME_SIGINFO_SIZE \
- + UCONTEXT_SIGCONTEXT_OFFSET)
- #define SIGCONTEXT_PC (1 * 8)
- #define SIGCONTEXT_REGS (2 * 8)
- #define SIGCONTEXT_FPREGS (34 * 8)
- #define SIGCONTEXT_FPCSR (66 * 8 + 4)
- #define SIGCONTEXT_DSPCTL (68 * 8 + 0)
- #define SIGCONTEXT_HI (69 * 8)
- #define SIGCONTEXT_LO (70 * 8)
- #define SIGCONTEXT_CAUSE (71 * 8 + 0)
- #define SIGCONTEXT_BADVADDR (71 * 8 + 4)
- #define SIGCONTEXT_HI1 (71 * 8 + 0)
- #define SIGCONTEXT_LO1 (71 * 8 + 4)
- #define SIGCONTEXT_HI2 (72 * 8 + 0)
- #define SIGCONTEXT_LO2 (72 * 8 + 4)
- #define SIGCONTEXT_HI3 (73 * 8 + 0)
- #define SIGCONTEXT_LO3 (73 * 8 + 4)
- #define SIGCONTEXT_REG_SIZE 8
- static void
- mips_linux_o32_sigframe_init (const struct tramp_frame *self,
- struct frame_info *this_frame,
- struct trad_frame_cache *this_cache,
- CORE_ADDR func)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- int ireg;
- CORE_ADDR frame_sp = get_frame_sp (this_frame);
- CORE_ADDR sigcontext_base;
- const struct mips_regnum *regs = mips_regnum (gdbarch);
- CORE_ADDR regs_base;
- if (self == &mips_linux_o32_sigframe
- || self == µmips_linux_o32_sigframe)
- sigcontext_base = frame_sp + SIGFRAME_SIGCONTEXT_OFFSET;
- else
- sigcontext_base = frame_sp + RTSIGFRAME_SIGCONTEXT_OFFSET;
- /* I'm not proud of this hack. Eventually we will have the
- infrastructure to indicate the size of saved registers on a
- per-frame basis, but right now we don't; the kernel saves eight
- bytes but we only want four. Use regs_base to access any
- 64-bit fields. */
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- regs_base = sigcontext_base + 4;
- else
- regs_base = sigcontext_base;
- if (mips_linux_restart_reg_p (gdbarch))
- trad_frame_set_reg_addr (this_cache,
- (MIPS_RESTART_REGNUM
- + gdbarch_num_regs (gdbarch)),
- regs_base + SIGCONTEXT_REGS);
- for (ireg = 1; ireg < 32; ireg++)
- trad_frame_set_reg_addr (this_cache,
- (ireg + MIPS_ZERO_REGNUM
- + gdbarch_num_regs (gdbarch)),
- (regs_base + SIGCONTEXT_REGS
- + ireg * SIGCONTEXT_REG_SIZE));
- for (ireg = 0; ireg < 32; ireg++)
- if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (ireg & 1))
- trad_frame_set_reg_addr (this_cache,
- ireg + regs->fp0 + gdbarch_num_regs (gdbarch),
- (sigcontext_base + SIGCONTEXT_FPREGS + 4
- + (ireg & ~1) * SIGCONTEXT_REG_SIZE));
- else
- trad_frame_set_reg_addr (this_cache,
- ireg + regs->fp0 + gdbarch_num_regs (gdbarch),
- (sigcontext_base + SIGCONTEXT_FPREGS
- + (ireg & ~1) * SIGCONTEXT_REG_SIZE));
- trad_frame_set_reg_addr (this_cache,
- regs->pc + gdbarch_num_regs (gdbarch),
- regs_base + SIGCONTEXT_PC);
- trad_frame_set_reg_addr (this_cache,
- (regs->fp_control_status
- + gdbarch_num_regs (gdbarch)),
- sigcontext_base + SIGCONTEXT_FPCSR);
- if (regs->dspctl != -1)
- trad_frame_set_reg_addr (this_cache,
- regs->dspctl + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_DSPCTL);
- trad_frame_set_reg_addr (this_cache,
- regs->hi + gdbarch_num_regs (gdbarch),
- regs_base + SIGCONTEXT_HI);
- trad_frame_set_reg_addr (this_cache,
- regs->lo + gdbarch_num_regs (gdbarch),
- regs_base + SIGCONTEXT_LO);
- if (regs->dspacc != -1)
- {
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 0 + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_HI1);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 1 + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_LO1);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 2 + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_HI2);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 3 + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_LO2);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 4 + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_HI3);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 5 + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_LO3);
- }
- else
- {
- trad_frame_set_reg_addr (this_cache,
- regs->cause + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_CAUSE);
- trad_frame_set_reg_addr (this_cache,
- regs->badvaddr + gdbarch_num_regs (gdbarch),
- sigcontext_base + SIGCONTEXT_BADVADDR);
- }
- /* Choice of the bottom of the sigframe is somewhat arbitrary. */
- trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
- }
- /* *INDENT-OFF* */
- /* For N32/N64 things look different. There is no non-rt signal frame.
- struct rt_sigframe_n32 {
- u32 rs_ass[4]; [ argument save space for o32 ]
- u32 rs_code[2]; [ signal trampoline or fill ]
- struct siginfo rs_info;
- struct ucontextn32 rs_uc;
- };
- struct ucontextn32 {
- u32 uc_flags;
- s32 uc_link;
- stack32_t uc_stack;
- struct sigcontext uc_mcontext;
- sigset_t uc_sigmask; [ mask last for extensibility ]
- };
- struct rt_sigframe {
- u32 rs_ass[4]; [ argument save space for o32 ]
- u32 rs_code[2]; [ signal trampoline ]
- struct siginfo rs_info;
- struct ucontext rs_uc;
- };
- struct ucontext {
- unsigned long uc_flags;
- struct ucontext *uc_link;
- stack_t uc_stack;
- struct sigcontext uc_mcontext;
- sigset_t uc_sigmask; [ mask last for extensibility ]
- };
- And the sigcontext is different (this is for both n32 and n64):
- struct sigcontext {
- unsigned long long sc_regs[32];
- unsigned long long sc_fpregs[32];
- unsigned long long sc_mdhi;
- unsigned long long sc_hi1;
- unsigned long long sc_hi2;
- unsigned long long sc_hi3;
- unsigned long long sc_mdlo;
- unsigned long long sc_lo1;
- unsigned long long sc_lo2;
- unsigned long long sc_lo3;
- unsigned long long sc_pc;
- unsigned int sc_fpc_csr;
- unsigned int sc_used_math;
- unsigned int sc_dsp;
- unsigned int sc_reserved;
- };
- That is the post-2.6.12 definition of the 64-bit sigcontext; before
- then, there were no hi1-hi3 or lo1-lo3. Cause and badvaddr were
- included too. */
- /* *INDENT-ON* */
- #define N32_STACK_T_SIZE STACK_T_SIZE
- #define N64_STACK_T_SIZE (2 * 8 + 4)
- #define N32_UCONTEXT_SIGCONTEXT_OFFSET (2 * 4 + N32_STACK_T_SIZE + 4)
- #define N64_UCONTEXT_SIGCONTEXT_OFFSET (2 * 8 + N64_STACK_T_SIZE + 4)
- #define N32_SIGFRAME_SIGCONTEXT_OFFSET (SIGFRAME_SIGCONTEXT_OFFSET \
- + RTSIGFRAME_SIGINFO_SIZE \
- + N32_UCONTEXT_SIGCONTEXT_OFFSET)
- #define N64_SIGFRAME_SIGCONTEXT_OFFSET (SIGFRAME_SIGCONTEXT_OFFSET \
- + RTSIGFRAME_SIGINFO_SIZE \
- + N64_UCONTEXT_SIGCONTEXT_OFFSET)
- #define N64_SIGCONTEXT_REGS (0 * 8)
- #define N64_SIGCONTEXT_FPREGS (32 * 8)
- #define N64_SIGCONTEXT_HI (64 * 8)
- #define N64_SIGCONTEXT_HI1 (65 * 8)
- #define N64_SIGCONTEXT_HI2 (66 * 8)
- #define N64_SIGCONTEXT_HI3 (67 * 8)
- #define N64_SIGCONTEXT_LO (68 * 8)
- #define N64_SIGCONTEXT_LO1 (69 * 8)
- #define N64_SIGCONTEXT_LO2 (70 * 8)
- #define N64_SIGCONTEXT_LO3 (71 * 8)
- #define N64_SIGCONTEXT_PC (72 * 8)
- #define N64_SIGCONTEXT_FPCSR (73 * 8 + 0)
- #define N64_SIGCONTEXT_DSPCTL (74 * 8 + 0)
- #define N64_SIGCONTEXT_REG_SIZE 8
- static void
- mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
- struct frame_info *this_frame,
- struct trad_frame_cache *this_cache,
- CORE_ADDR func)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- int ireg;
- CORE_ADDR frame_sp = get_frame_sp (this_frame);
- CORE_ADDR sigcontext_base;
- const struct mips_regnum *regs = mips_regnum (gdbarch);
- if (self == &mips_linux_n32_rt_sigframe
- || self == µmips_linux_n32_rt_sigframe)
- sigcontext_base = frame_sp + N32_SIGFRAME_SIGCONTEXT_OFFSET;
- else
- sigcontext_base = frame_sp + N64_SIGFRAME_SIGCONTEXT_OFFSET;
- if (mips_linux_restart_reg_p (gdbarch))
- trad_frame_set_reg_addr (this_cache,
- (MIPS_RESTART_REGNUM
- + gdbarch_num_regs (gdbarch)),
- sigcontext_base + N64_SIGCONTEXT_REGS);
- for (ireg = 1; ireg < 32; ireg++)
- trad_frame_set_reg_addr (this_cache,
- (ireg + MIPS_ZERO_REGNUM
- + gdbarch_num_regs (gdbarch)),
- (sigcontext_base + N64_SIGCONTEXT_REGS
- + ireg * N64_SIGCONTEXT_REG_SIZE));
- for (ireg = 0; ireg < 32; ireg++)
- trad_frame_set_reg_addr (this_cache,
- ireg + regs->fp0 + gdbarch_num_regs (gdbarch),
- (sigcontext_base + N64_SIGCONTEXT_FPREGS
- + ireg * N64_SIGCONTEXT_REG_SIZE));
- trad_frame_set_reg_addr (this_cache,
- regs->pc + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_PC);
- trad_frame_set_reg_addr (this_cache,
- (regs->fp_control_status
- + gdbarch_num_regs (gdbarch)),
- sigcontext_base + N64_SIGCONTEXT_FPCSR);
- trad_frame_set_reg_addr (this_cache,
- regs->hi + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_HI);
- trad_frame_set_reg_addr (this_cache,
- regs->lo + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_LO);
- if (regs->dspacc != -1)
- {
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 0 + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_HI1);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 1 + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_LO1);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 2 + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_HI2);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 3 + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_LO2);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 4 + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_HI3);
- trad_frame_set_reg_addr (this_cache,
- regs->dspacc + 5 + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_LO3);
- }
- if (regs->dspctl != -1)
- trad_frame_set_reg_addr (this_cache,
- regs->dspctl + gdbarch_num_regs (gdbarch),
- sigcontext_base + N64_SIGCONTEXT_DSPCTL);
- /* Choice of the bottom of the sigframe is somewhat arbitrary. */
- trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
- }
- /* Implement struct tramp_frame's "validate" method for standard MIPS code. */
- static int
- mips_linux_sigframe_validate (const struct tramp_frame *self,
- struct frame_info *this_frame,
- CORE_ADDR *pc)
- {
- return mips_pc_is_mips (*pc);
- }
- /* Implement struct tramp_frame's "validate" method for microMIPS code. */
- static int
- micromips_linux_sigframe_validate (const struct tramp_frame *self,
- struct frame_info *this_frame,
- CORE_ADDR *pc)
- {
- if (mips_pc_is_micromips (get_frame_arch (this_frame), *pc))
- {
- *pc = mips_unmake_compact_addr (*pc);
- return 1;
- }
- else
- return 0;
- }
- /* Implement the "write_pc" gdbarch method. */
- static void
- mips_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- mips_write_pc (regcache, pc);
- /* Clear the syscall restart flag. */
- if (mips_linux_restart_reg_p (gdbarch))
- regcache_cooked_write_unsigned (regcache, MIPS_RESTART_REGNUM, 0);
- }
- /* Return 1 if MIPS_RESTART_REGNUM is usable. */
- int
- mips_linux_restart_reg_p (struct gdbarch *gdbarch)
- {
- /* If we do not have a target description with registers, then
- MIPS_RESTART_REGNUM will not be included in the register set. */
- if (!tdesc_has_registers (gdbarch_target_desc (gdbarch)))
- return 0;
- /* If we do, then MIPS_RESTART_REGNUM is safe to check; it will
- either be GPR-sized or missing. */
- return register_size (gdbarch, MIPS_RESTART_REGNUM) > 0;
- }
- /* When FRAME is at a syscall instruction, return the PC of the next
- instruction to be executed. */
- static CORE_ADDR
- mips_linux_syscall_next_pc (struct frame_info *frame)
- {
- CORE_ADDR pc = get_frame_pc (frame);
- ULONGEST v0 = get_frame_register_unsigned (frame, MIPS_V0_REGNUM);
- /* If we are about to make a sigreturn syscall, use the unwinder to
- decode the signal frame. */
- if (v0 == MIPS_NR_sigreturn
- || v0 == MIPS_NR_rt_sigreturn
- || v0 == MIPS_NR_N64_rt_sigreturn
- || v0 == MIPS_NR_N32_rt_sigreturn)
- return frame_unwind_caller_pc (get_current_frame ());
- return pc + 4;
- }
- /* Return the current system call's number present in the
- v0 register. When the function fails, it returns -1. */
- static LONGEST
- mips_linux_get_syscall_number (struct gdbarch *gdbarch,
- thread_info *thread)
- {
- struct regcache *regcache = get_thread_regcache (thread);
- mips_gdbarch_tdep *tdep = (mips_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- int regsize = register_size (gdbarch, MIPS_V0_REGNUM);
- /* The content of a register */
- gdb_byte buf[8];
- /* The result */
- LONGEST ret;
- /* Make sure we're in a known ABI */
- gdb_assert (tdep->mips_abi == MIPS_ABI_O32
- || tdep->mips_abi == MIPS_ABI_N32
- || tdep->mips_abi == MIPS_ABI_N64);
- gdb_assert (regsize <= sizeof (buf));
- /* Getting the system call number from the register.
- syscall number is in v0 or $2. */
- regcache->cooked_read (MIPS_V0_REGNUM, buf);
- ret = extract_signed_integer (buf, regsize, byte_order);
- return ret;
- }
- /* Implementation of `gdbarch_gdb_signal_to_target', as defined in
- gdbarch.h. */
- static int
- mips_gdb_signal_to_target (struct gdbarch *gdbarch,
- enum gdb_signal signal)
- {
- switch (signal)
- {
- case GDB_SIGNAL_EMT:
- return MIPS_LINUX_SIGEMT;
- case GDB_SIGNAL_BUS:
- return MIPS_LINUX_SIGBUS;
- case GDB_SIGNAL_SYS:
- return MIPS_LINUX_SIGSYS;
- case GDB_SIGNAL_USR1:
- return MIPS_LINUX_SIGUSR1;
- case GDB_SIGNAL_USR2:
- return MIPS_LINUX_SIGUSR2;
- case GDB_SIGNAL_CHLD:
- return MIPS_LINUX_SIGCHLD;
- case GDB_SIGNAL_PWR:
- return MIPS_LINUX_SIGPWR;
- case GDB_SIGNAL_WINCH:
- return MIPS_LINUX_SIGWINCH;
- case GDB_SIGNAL_URG:
- return MIPS_LINUX_SIGURG;
- case GDB_SIGNAL_IO:
- return MIPS_LINUX_SIGIO;
- case GDB_SIGNAL_POLL:
- return MIPS_LINUX_SIGPOLL;
- case GDB_SIGNAL_STOP:
- return MIPS_LINUX_SIGSTOP;
- case GDB_SIGNAL_TSTP:
- return MIPS_LINUX_SIGTSTP;
- case GDB_SIGNAL_CONT:
- return MIPS_LINUX_SIGCONT;
- case GDB_SIGNAL_TTIN:
- return MIPS_LINUX_SIGTTIN;
- case GDB_SIGNAL_TTOU:
- return MIPS_LINUX_SIGTTOU;
- case GDB_SIGNAL_VTALRM:
- return MIPS_LINUX_SIGVTALRM;
- case GDB_SIGNAL_PROF:
- return MIPS_LINUX_SIGPROF;
- case GDB_SIGNAL_XCPU:
- return MIPS_LINUX_SIGXCPU;
- case GDB_SIGNAL_XFSZ:
- return MIPS_LINUX_SIGXFSZ;
- /* GDB_SIGNAL_REALTIME_32 is not continuous in <gdb/signals.def>,
- therefore we have to handle it here. */
- case GDB_SIGNAL_REALTIME_32:
- return MIPS_LINUX_SIGRTMIN;
- }
- if (signal >= GDB_SIGNAL_REALTIME_33
- && signal <= GDB_SIGNAL_REALTIME_63)
- {
- int offset = signal - GDB_SIGNAL_REALTIME_33;
- return MIPS_LINUX_SIGRTMIN + 1 + offset;
- }
- else if (signal >= GDB_SIGNAL_REALTIME_64
- && signal <= GDB_SIGNAL_REALTIME_127)
- {
- int offset = signal - GDB_SIGNAL_REALTIME_64;
- return MIPS_LINUX_SIGRT64 + offset;
- }
- return linux_gdb_signal_to_target (gdbarch, signal);
- }
- /* Translate signals based on MIPS signal values.
- Adapted from gdb/gdbsupport/signals.c. */
- static enum gdb_signal
- mips_gdb_signal_from_target (struct gdbarch *gdbarch, int signal)
- {
- switch (signal)
- {
- case MIPS_LINUX_SIGEMT:
- return GDB_SIGNAL_EMT;
- case MIPS_LINUX_SIGBUS:
- return GDB_SIGNAL_BUS;
- case MIPS_LINUX_SIGSYS:
- return GDB_SIGNAL_SYS;
- case MIPS_LINUX_SIGUSR1:
- return GDB_SIGNAL_USR1;
- case MIPS_LINUX_SIGUSR2:
- return GDB_SIGNAL_USR2;
- case MIPS_LINUX_SIGCHLD:
- return GDB_SIGNAL_CHLD;
- case MIPS_LINUX_SIGPWR:
- return GDB_SIGNAL_PWR;
- case MIPS_LINUX_SIGWINCH:
- return GDB_SIGNAL_WINCH;
- case MIPS_LINUX_SIGURG:
- return GDB_SIGNAL_URG;
- /* No way to differentiate between SIGIO and SIGPOLL.
- Therefore, we just handle the first one. */
- case MIPS_LINUX_SIGIO:
- return GDB_SIGNAL_IO;
- case MIPS_LINUX_SIGSTOP:
- return GDB_SIGNAL_STOP;
- case MIPS_LINUX_SIGTSTP:
- return GDB_SIGNAL_TSTP;
- case MIPS_LINUX_SIGCONT:
- return GDB_SIGNAL_CONT;
- case MIPS_LINUX_SIGTTIN:
- return GDB_SIGNAL_TTIN;
- case MIPS_LINUX_SIGTTOU:
- return GDB_SIGNAL_TTOU;
- case MIPS_LINUX_SIGVTALRM:
- return GDB_SIGNAL_VTALRM;
- case MIPS_LINUX_SIGPROF:
- return GDB_SIGNAL_PROF;
- case MIPS_LINUX_SIGXCPU:
- return GDB_SIGNAL_XCPU;
- case MIPS_LINUX_SIGXFSZ:
- return GDB_SIGNAL_XFSZ;
- }
- if (signal >= MIPS_LINUX_SIGRTMIN && signal <= MIPS_LINUX_SIGRTMAX)
- {
- /* GDB_SIGNAL_REALTIME values are not contiguous, map parts of
- the MIPS block to the respective GDB_SIGNAL_REALTIME blocks. */
- int offset = signal - MIPS_LINUX_SIGRTMIN;
- if (offset == 0)
- return GDB_SIGNAL_REALTIME_32;
- else if (offset < 32)
- return (enum gdb_signal) (offset - 1
- + (int) GDB_SIGNAL_REALTIME_33);
- else
- return (enum gdb_signal) (offset - 32
- + (int) GDB_SIGNAL_REALTIME_64);
- }
- return linux_gdb_signal_from_target (gdbarch, signal);
- }
- /* Initialize one of the GNU/Linux OS ABIs. */
- static void
- mips_linux_init_abi (struct gdbarch_info info,
- struct gdbarch *gdbarch)
- {
- mips_gdbarch_tdep *tdep = (mips_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- enum mips_abi abi = mips_abi (gdbarch);
- struct tdesc_arch_data *tdesc_data = info.tdesc_data;
- linux_init_abi (info, gdbarch, 0);
- /* Get the syscall number from the arch's register. */
- set_gdbarch_get_syscall_number (gdbarch, mips_linux_get_syscall_number);
- switch (abi)
- {
- case MIPS_ABI_O32:
- set_gdbarch_get_longjmp_target (gdbarch,
- mips_linux_get_longjmp_target);
- set_solib_svr4_fetch_link_map_offsets
- (gdbarch, linux_ilp32_fetch_link_map_offsets);
- tramp_frame_prepend_unwinder (gdbarch, µmips_linux_o32_sigframe);
- tramp_frame_prepend_unwinder (gdbarch,
- µmips_linux_o32_rt_sigframe);
- tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_sigframe);
- tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_rt_sigframe);
- set_xml_syscall_file_name (gdbarch, "syscalls/mips-o32-linux.xml");
- break;
- case MIPS_ABI_N32:
- set_gdbarch_get_longjmp_target (gdbarch,
- mips_linux_get_longjmp_target);
- set_solib_svr4_fetch_link_map_offsets
- (gdbarch, linux_ilp32_fetch_link_map_offsets);
- set_gdbarch_long_double_bit (gdbarch, 128);
- set_gdbarch_long_double_format (gdbarch, floatformats_ieee_quad);
- tramp_frame_prepend_unwinder (gdbarch,
- µmips_linux_n32_rt_sigframe);
- tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n32_rt_sigframe);
- set_xml_syscall_file_name (gdbarch, "syscalls/mips-n32-linux.xml");
- break;
- case MIPS_ABI_N64:
- set_gdbarch_get_longjmp_target (gdbarch,
- mips64_linux_get_longjmp_target);
- set_solib_svr4_fetch_link_map_offsets
- (gdbarch, linux_lp64_fetch_link_map_offsets);
- set_gdbarch_long_double_bit (gdbarch, 128);
- set_gdbarch_long_double_format (gdbarch, floatformats_ieee_quad);
- tramp_frame_prepend_unwinder (gdbarch,
- µmips_linux_n64_rt_sigframe);
- tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n64_rt_sigframe);
- set_xml_syscall_file_name (gdbarch, "syscalls/mips-n64-linux.xml");
- break;
- default:
- break;
- }
- set_gdbarch_skip_solib_resolver (gdbarch, mips_linux_skip_resolver);
- set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
- /* Enable TLS support. */
- set_gdbarch_fetch_tls_load_module_address (gdbarch,
- svr4_fetch_objfile_link_map);
- /* Initialize this lazily, to avoid an initialization order
- dependency on solib-svr4.c's _initialize routine. */
- if (mips_svr4_so_ops.in_dynsym_resolve_code == NULL)
- {
- mips_svr4_so_ops = svr4_so_ops;
- mips_svr4_so_ops.in_dynsym_resolve_code
- = mips_linux_in_dynsym_resolve_code;
- }
- set_solib_ops (gdbarch, &mips_svr4_so_ops);
- set_gdbarch_write_pc (gdbarch, mips_linux_write_pc);
- set_gdbarch_core_read_description (gdbarch,
- mips_linux_core_read_description);
- set_gdbarch_iterate_over_regset_sections
- (gdbarch, mips_linux_iterate_over_regset_sections);
- set_gdbarch_gdb_signal_from_target (gdbarch,
- mips_gdb_signal_from_target);
- set_gdbarch_gdb_signal_to_target (gdbarch,
- mips_gdb_signal_to_target);
- tdep->syscall_next_pc = mips_linux_syscall_next_pc;
- if (tdesc_data)
- {
- const struct tdesc_feature *feature;
- /* If we have target-described registers, then we can safely
- reserve a number for MIPS_RESTART_REGNUM (whether it is
- described or not). */
- gdb_assert (gdbarch_num_regs (gdbarch) <= MIPS_RESTART_REGNUM);
- set_gdbarch_num_regs (gdbarch, MIPS_RESTART_REGNUM + 1);
- set_gdbarch_num_pseudo_regs (gdbarch, MIPS_RESTART_REGNUM + 1);
- /* If it's present, then assign it to the reserved number. */
- feature = tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.mips.linux");
- if (feature != NULL)
- tdesc_numbered_register (feature, tdesc_data, MIPS_RESTART_REGNUM,
- "restart");
- }
- }
- void _initialize_mips_linux_tdep ();
- void
- _initialize_mips_linux_tdep ()
- {
- const struct bfd_arch_info *arch_info;
- for (arch_info = bfd_lookup_arch (bfd_arch_mips, 0);
- arch_info != NULL;
- arch_info = arch_info->next)
- {
- gdbarch_register_osabi (bfd_arch_mips, arch_info->mach,
- GDB_OSABI_LINUX,
- mips_linux_init_abi);
- }
- /* Initialize the standard target descriptions. */
- initialize_tdesc_mips_linux ();
- initialize_tdesc_mips_dsp_linux ();
- initialize_tdesc_mips64_linux ();
- initialize_tdesc_mips64_dsp_linux ();
- }
|