12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495 |
- /* Target dependent code for ARC architecture, for GDB.
- Copyright 2005-2022 Free Software Foundation, Inc.
- Contributed by Synopsys 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/>. */
- /* GDB header files. */
- #include "defs.h"
- #include "arch-utils.h"
- #include "elf-bfd.h"
- #include "disasm.h"
- #include "dwarf2/frame.h"
- #include "frame-base.h"
- #include "frame-unwind.h"
- #include "gdbcore.h"
- #include "reggroups.h"
- #include "gdbcmd.h"
- #include "objfiles.h"
- #include "osabi.h"
- #include "prologue-value.h"
- #include "target-descriptions.h"
- #include "trad-frame.h"
- /* ARC header files. */
- #include "opcode/arc.h"
- #include "opcodes/arc-dis.h"
- #include "arc-tdep.h"
- #include "arch/arc.h"
- /* Standard headers. */
- #include <algorithm>
- #include <sstream>
- /* The frame unwind cache for ARC. */
- struct arc_frame_cache
- {
- /* The stack pointer at the time this frame was created; i.e. the caller's
- stack pointer when this function was called. It is used to identify this
- frame. */
- CORE_ADDR prev_sp;
- /* Register that is a base for this frame - FP for normal frame, SP for
- non-FP frames. */
- int frame_base_reg;
- /* Offset from the previous SP to the current frame base. If GCC uses
- `SUB SP,SP,offset` to allocate space for local variables, then it will be
- done after setting up a frame pointer, but it still will be considered
- part of prologue, therefore SP will be lesser than FP at the end of the
- prologue analysis. In this case that would be an offset from old SP to a
- new FP. But in case of non-FP frames, frame base is an SP and thus that
- would be an offset from old SP to new SP. What is important is that this
- is an offset from old SP to a known register, so it can be used to find
- old SP.
- Using FP is preferable, when possible, because SP can change in function
- body after prologue due to alloca, variadic arguments or other shenanigans.
- If that is the case in the caller frame, then PREV_SP will point to SP at
- the moment of function call, but it will be different from SP value at the
- end of the caller prologue. As a result it will not be possible to
- reconstruct caller's frame and go past it in the backtrace. Those things
- are unlikely to happen to FP - FP value at the moment of function call (as
- stored on stack in callee prologue) is also an FP value at the end of the
- caller's prologue. */
- LONGEST frame_base_offset;
- /* Store addresses for registers saved in prologue. During prologue analysis
- GDB stores offsets relatively to "old SP", then after old SP is evaluated,
- offsets are replaced with absolute addresses. */
- trad_frame_saved_reg *saved_regs;
- };
- /* Global debug flag. */
- bool arc_debug;
- /* List of "maintenance print arc" commands. */
- static struct cmd_list_element *maintenance_print_arc_list = NULL;
- /* A set of registers that we expect to find in a tdesc_feature. These
- are used in ARC_TDESC_INIT when processing the target description. */
- struct arc_register_feature
- {
- /* Information for a single register. */
- struct register_info
- {
- /* The GDB register number for this register. */
- int regnum;
- /* List of names for this register. The first name in this list is the
- preferred name, the name GDB will use when describing this register. */
- std::vector<const char *> names;
- /* When true, this register must be present in this feature set. */
- bool required_p;
- };
- /* The name for this feature. This is the name used to find this feature
- within the target description. */
- const char *name;
- /* List of all the registers that we expect to encounter in this register
- set. */
- std::vector<struct register_info> registers;
- };
- /* Obsolete feature names for backward compatibility. */
- static const char *ARC_CORE_V1_OBSOLETE_FEATURE_NAME
- = "org.gnu.gdb.arc.core.arcompact";
- static const char *ARC_CORE_V2_OBSOLETE_FEATURE_NAME
- = "org.gnu.gdb.arc.core.v2";
- static const char *ARC_CORE_V2_REDUCED_OBSOLETE_FEATURE_NAME
- = "org.gnu.gdb.arc.core-reduced.v2";
- static const char *ARC_AUX_OBSOLETE_FEATURE_NAME
- = "org.gnu.gdb.arc.aux-minimal";
- /* Modern feature names. */
- static const char *ARC_CORE_FEATURE_NAME = "org.gnu.gdb.arc.core";
- static const char *ARC_AUX_FEATURE_NAME = "org.gnu.gdb.arc.aux";
- /* ARCv1 (ARC600, ARC601, ARC700) general core registers feature set.
- See also arc_update_acc_reg_names() for "accl/acch" names. */
- static struct arc_register_feature arc_v1_core_reg_feature =
- {
- ARC_CORE_FEATURE_NAME,
- {
- { ARC_R0_REGNUM + 0, { "r0" }, true },
- { ARC_R0_REGNUM + 1, { "r1" }, true },
- { ARC_R0_REGNUM + 2, { "r2" }, true },
- { ARC_R0_REGNUM + 3, { "r3" }, true },
- { ARC_R0_REGNUM + 4, { "r4" }, false },
- { ARC_R0_REGNUM + 5, { "r5" }, false },
- { ARC_R0_REGNUM + 6, { "r6" }, false },
- { ARC_R0_REGNUM + 7, { "r7" }, false },
- { ARC_R0_REGNUM + 8, { "r8" }, false },
- { ARC_R0_REGNUM + 9, { "r9" }, false },
- { ARC_R0_REGNUM + 10, { "r10" }, true },
- { ARC_R0_REGNUM + 11, { "r11" }, true },
- { ARC_R0_REGNUM + 12, { "r12" }, true },
- { ARC_R0_REGNUM + 13, { "r13" }, true },
- { ARC_R0_REGNUM + 14, { "r14" }, true },
- { ARC_R0_REGNUM + 15, { "r15" }, true },
- { ARC_R0_REGNUM + 16, { "r16" }, false },
- { ARC_R0_REGNUM + 17, { "r17" }, false },
- { ARC_R0_REGNUM + 18, { "r18" }, false },
- { ARC_R0_REGNUM + 19, { "r19" }, false },
- { ARC_R0_REGNUM + 20, { "r20" }, false },
- { ARC_R0_REGNUM + 21, { "r21" }, false },
- { ARC_R0_REGNUM + 22, { "r22" }, false },
- { ARC_R0_REGNUM + 23, { "r23" }, false },
- { ARC_R0_REGNUM + 24, { "r24" }, false },
- { ARC_R0_REGNUM + 25, { "r25" }, false },
- { ARC_R0_REGNUM + 26, { "gp" }, true },
- { ARC_R0_REGNUM + 27, { "fp" }, true },
- { ARC_R0_REGNUM + 28, { "sp" }, true },
- { ARC_R0_REGNUM + 29, { "ilink1" }, false },
- { ARC_R0_REGNUM + 30, { "ilink2" }, false },
- { ARC_R0_REGNUM + 31, { "blink" }, true },
- { ARC_R0_REGNUM + 32, { "r32" }, false },
- { ARC_R0_REGNUM + 33, { "r33" }, false },
- { ARC_R0_REGNUM + 34, { "r34" }, false },
- { ARC_R0_REGNUM + 35, { "r35" }, false },
- { ARC_R0_REGNUM + 36, { "r36" }, false },
- { ARC_R0_REGNUM + 37, { "r37" }, false },
- { ARC_R0_REGNUM + 38, { "r38" }, false },
- { ARC_R0_REGNUM + 39, { "r39" }, false },
- { ARC_R0_REGNUM + 40, { "r40" }, false },
- { ARC_R0_REGNUM + 41, { "r41" }, false },
- { ARC_R0_REGNUM + 42, { "r42" }, false },
- { ARC_R0_REGNUM + 43, { "r43" }, false },
- { ARC_R0_REGNUM + 44, { "r44" }, false },
- { ARC_R0_REGNUM + 45, { "r45" }, false },
- { ARC_R0_REGNUM + 46, { "r46" }, false },
- { ARC_R0_REGNUM + 47, { "r47" }, false },
- { ARC_R0_REGNUM + 48, { "r48" }, false },
- { ARC_R0_REGNUM + 49, { "r49" }, false },
- { ARC_R0_REGNUM + 50, { "r50" }, false },
- { ARC_R0_REGNUM + 51, { "r51" }, false },
- { ARC_R0_REGNUM + 52, { "r52" }, false },
- { ARC_R0_REGNUM + 53, { "r53" }, false },
- { ARC_R0_REGNUM + 54, { "r54" }, false },
- { ARC_R0_REGNUM + 55, { "r55" }, false },
- { ARC_R0_REGNUM + 56, { "r56" }, false },
- { ARC_R0_REGNUM + 57, { "r57" }, false },
- { ARC_R0_REGNUM + 58, { "r58", "accl" }, false },
- { ARC_R0_REGNUM + 59, { "r59", "acch" }, false },
- { ARC_R0_REGNUM + 60, { "lp_count" }, false },
- { ARC_R0_REGNUM + 61, { "reserved" }, false },
- { ARC_R0_REGNUM + 62, { "limm" }, false },
- { ARC_R0_REGNUM + 63, { "pcl" }, true }
- }
- };
- /* ARCv2 (ARCHS) general core registers feature set. See also
- arc_update_acc_reg_names() for "accl/acch" names. */
- static struct arc_register_feature arc_v2_core_reg_feature =
- {
- ARC_CORE_FEATURE_NAME,
- {
- { ARC_R0_REGNUM + 0, { "r0" }, true },
- { ARC_R0_REGNUM + 1, { "r1" }, true },
- { ARC_R0_REGNUM + 2, { "r2" }, true },
- { ARC_R0_REGNUM + 3, { "r3" }, true },
- { ARC_R0_REGNUM + 4, { "r4" }, false },
- { ARC_R0_REGNUM + 5, { "r5" }, false },
- { ARC_R0_REGNUM + 6, { "r6" }, false },
- { ARC_R0_REGNUM + 7, { "r7" }, false },
- { ARC_R0_REGNUM + 8, { "r8" }, false },
- { ARC_R0_REGNUM + 9, { "r9" }, false },
- { ARC_R0_REGNUM + 10, { "r10" }, true },
- { ARC_R0_REGNUM + 11, { "r11" }, true },
- { ARC_R0_REGNUM + 12, { "r12" }, true },
- { ARC_R0_REGNUM + 13, { "r13" }, true },
- { ARC_R0_REGNUM + 14, { "r14" }, true },
- { ARC_R0_REGNUM + 15, { "r15" }, true },
- { ARC_R0_REGNUM + 16, { "r16" }, false },
- { ARC_R0_REGNUM + 17, { "r17" }, false },
- { ARC_R0_REGNUM + 18, { "r18" }, false },
- { ARC_R0_REGNUM + 19, { "r19" }, false },
- { ARC_R0_REGNUM + 20, { "r20" }, false },
- { ARC_R0_REGNUM + 21, { "r21" }, false },
- { ARC_R0_REGNUM + 22, { "r22" }, false },
- { ARC_R0_REGNUM + 23, { "r23" }, false },
- { ARC_R0_REGNUM + 24, { "r24" }, false },
- { ARC_R0_REGNUM + 25, { "r25" }, false },
- { ARC_R0_REGNUM + 26, { "gp" }, true },
- { ARC_R0_REGNUM + 27, { "fp" }, true },
- { ARC_R0_REGNUM + 28, { "sp" }, true },
- { ARC_R0_REGNUM + 29, { "ilink" }, false },
- { ARC_R0_REGNUM + 30, { "r30" }, true },
- { ARC_R0_REGNUM + 31, { "blink" }, true },
- { ARC_R0_REGNUM + 32, { "r32" }, false },
- { ARC_R0_REGNUM + 33, { "r33" }, false },
- { ARC_R0_REGNUM + 34, { "r34" }, false },
- { ARC_R0_REGNUM + 35, { "r35" }, false },
- { ARC_R0_REGNUM + 36, { "r36" }, false },
- { ARC_R0_REGNUM + 37, { "r37" }, false },
- { ARC_R0_REGNUM + 38, { "r38" }, false },
- { ARC_R0_REGNUM + 39, { "r39" }, false },
- { ARC_R0_REGNUM + 40, { "r40" }, false },
- { ARC_R0_REGNUM + 41, { "r41" }, false },
- { ARC_R0_REGNUM + 42, { "r42" }, false },
- { ARC_R0_REGNUM + 43, { "r43" }, false },
- { ARC_R0_REGNUM + 44, { "r44" }, false },
- { ARC_R0_REGNUM + 45, { "r45" }, false },
- { ARC_R0_REGNUM + 46, { "r46" }, false },
- { ARC_R0_REGNUM + 47, { "r47" }, false },
- { ARC_R0_REGNUM + 48, { "r48" }, false },
- { ARC_R0_REGNUM + 49, { "r49" }, false },
- { ARC_R0_REGNUM + 50, { "r50" }, false },
- { ARC_R0_REGNUM + 51, { "r51" }, false },
- { ARC_R0_REGNUM + 52, { "r52" }, false },
- { ARC_R0_REGNUM + 53, { "r53" }, false },
- { ARC_R0_REGNUM + 54, { "r54" }, false },
- { ARC_R0_REGNUM + 55, { "r55" }, false },
- { ARC_R0_REGNUM + 56, { "r56" }, false },
- { ARC_R0_REGNUM + 57, { "r57" }, false },
- { ARC_R0_REGNUM + 58, { "r58", "accl" }, false },
- { ARC_R0_REGNUM + 59, { "r59", "acch" }, false },
- { ARC_R0_REGNUM + 60, { "lp_count" }, false },
- { ARC_R0_REGNUM + 61, { "reserved" }, false },
- { ARC_R0_REGNUM + 62, { "limm" }, false },
- { ARC_R0_REGNUM + 63, { "pcl" }, true }
- }
- };
- /* The common auxiliary registers feature set. The REGNUM field
- must match the ARC_REGNUM enum in arc-tdep.h. */
- static const struct arc_register_feature arc_common_aux_reg_feature =
- {
- ARC_AUX_FEATURE_NAME,
- {
- { ARC_FIRST_AUX_REGNUM + 0, { "pc" }, true },
- { ARC_FIRST_AUX_REGNUM + 1, { "status32" }, true },
- { ARC_FIRST_AUX_REGNUM + 2, { "lp_start" }, false },
- { ARC_FIRST_AUX_REGNUM + 3, { "lp_end" }, false },
- { ARC_FIRST_AUX_REGNUM + 4, { "bta" }, false }
- }
- };
- static char *arc_disassembler_options = NULL;
- /* Functions are sorted in the order as they are used in the
- _initialize_arc_tdep (), which uses the same order as gdbarch.h. Static
- functions are defined before the first invocation. */
- /* Returns an unsigned value of OPERAND_NUM in instruction INSN.
- For relative branch instructions returned value is an offset, not an actual
- branch target. */
- static ULONGEST
- arc_insn_get_operand_value (const struct arc_instruction &insn,
- unsigned int operand_num)
- {
- switch (insn.operands[operand_num].kind)
- {
- case ARC_OPERAND_KIND_LIMM:
- gdb_assert (insn.limm_p);
- return insn.limm_value;
- case ARC_OPERAND_KIND_SHIMM:
- return insn.operands[operand_num].value;
- default:
- /* Value in instruction is a register number. */
- struct regcache *regcache = get_current_regcache ();
- ULONGEST value;
- regcache_cooked_read_unsigned (regcache,
- insn.operands[operand_num].value,
- &value);
- return value;
- }
- }
- /* Like arc_insn_get_operand_value, but returns a signed value. */
- static LONGEST
- arc_insn_get_operand_value_signed (const struct arc_instruction &insn,
- unsigned int operand_num)
- {
- switch (insn.operands[operand_num].kind)
- {
- case ARC_OPERAND_KIND_LIMM:
- gdb_assert (insn.limm_p);
- /* Convert unsigned raw value to signed one. This assumes 2's
- complement arithmetic, but so is the LONG_MIN value from generic
- defs.h and that assumption is true for ARC. */
- gdb_static_assert (sizeof (insn.limm_value) == sizeof (int));
- return (((LONGEST) insn.limm_value) ^ INT_MIN) - INT_MIN;
- case ARC_OPERAND_KIND_SHIMM:
- /* Sign conversion has been done by binutils. */
- return insn.operands[operand_num].value;
- default:
- /* Value in instruction is a register number. */
- struct regcache *regcache = get_current_regcache ();
- LONGEST value;
- regcache_cooked_read_signed (regcache,
- insn.operands[operand_num].value,
- &value);
- return value;
- }
- }
- /* Get register with base address of memory operation. */
- static int
- arc_insn_get_memory_base_reg (const struct arc_instruction &insn)
- {
- /* POP_S and PUSH_S have SP as an implicit argument in a disassembler. */
- if (insn.insn_class == PUSH || insn.insn_class == POP)
- return ARC_SP_REGNUM;
- gdb_assert (insn.insn_class == LOAD || insn.insn_class == STORE);
- /* Other instructions all have at least two operands: operand 0 is data,
- operand 1 is address. Operand 2 is offset from address. However, see
- comment to arc_instruction.operands - in some cases, third operand may be
- missing, namely if it is 0. */
- gdb_assert (insn.operands_count >= 2);
- return insn.operands[1].value;
- }
- /* Get offset of a memory operation INSN. */
- static CORE_ADDR
- arc_insn_get_memory_offset (const struct arc_instruction &insn)
- {
- /* POP_S and PUSH_S have offset as an implicit argument in a
- disassembler. */
- if (insn.insn_class == POP)
- return 4;
- else if (insn.insn_class == PUSH)
- return -4;
- gdb_assert (insn.insn_class == LOAD || insn.insn_class == STORE);
- /* Other instructions all have at least two operands: operand 0 is data,
- operand 1 is address. Operand 2 is offset from address. However, see
- comment to arc_instruction.operands - in some cases, third operand may be
- missing, namely if it is 0. */
- if (insn.operands_count < 3)
- return 0;
- CORE_ADDR value = arc_insn_get_operand_value (insn, 2);
- /* Handle scaling. */
- if (insn.writeback_mode == ARC_WRITEBACK_AS)
- {
- /* Byte data size is not valid for AS. Halfword means shift by 1 bit.
- Word and double word means shift by 2 bits. */
- gdb_assert (insn.data_size_mode != ARC_SCALING_B);
- if (insn.data_size_mode == ARC_SCALING_H)
- value <<= 1;
- else
- value <<= 2;
- }
- return value;
- }
- CORE_ADDR
- arc_insn_get_branch_target (const struct arc_instruction &insn)
- {
- gdb_assert (insn.is_control_flow);
- /* BI [c]: PC = nextPC + (c << 2). */
- if (insn.insn_class == BI)
- {
- ULONGEST reg_value = arc_insn_get_operand_value (insn, 0);
- return arc_insn_get_linear_next_pc (insn) + (reg_value << 2);
- }
- /* BIH [c]: PC = nextPC + (c << 1). */
- else if (insn.insn_class == BIH)
- {
- ULONGEST reg_value = arc_insn_get_operand_value (insn, 0);
- return arc_insn_get_linear_next_pc (insn) + (reg_value << 1);
- }
- /* JLI and EI. */
- /* JLI and EI depend on optional AUX registers. Not supported right now. */
- else if (insn.insn_class == JLI)
- {
- gdb_printf (gdb_stderr,
- "JLI_S instruction is not supported by the GDB.");
- return 0;
- }
- else if (insn.insn_class == EI)
- {
- gdb_printf (gdb_stderr,
- "EI_S instruction is not supported by the GDB.");
- return 0;
- }
- /* LEAVE_S: PC = BLINK. */
- else if (insn.insn_class == LEAVE)
- {
- struct regcache *regcache = get_current_regcache ();
- ULONGEST value;
- regcache_cooked_read_unsigned (regcache, ARC_BLINK_REGNUM, &value);
- return value;
- }
- /* BBIT0/1, BRcc: PC = currentPC + operand. */
- else if (insn.insn_class == BBIT0 || insn.insn_class == BBIT1
- || insn.insn_class == BRCC)
- {
- /* Most instructions has branch target as their sole argument. However
- conditional brcc/bbit has it as a third operand. */
- CORE_ADDR pcrel_addr = arc_insn_get_operand_value (insn, 2);
- /* Offset is relative to the 4-byte aligned address of the current
- instruction, hence last two bits should be truncated. */
- return pcrel_addr + align_down (insn.address, 4);
- }
- /* B, Bcc, BL, BLcc, LP, LPcc: PC = currentPC + operand. */
- else if (insn.insn_class == BRANCH || insn.insn_class == LOOP)
- {
- CORE_ADDR pcrel_addr = arc_insn_get_operand_value (insn, 0);
- /* Offset is relative to the 4-byte aligned address of the current
- instruction, hence last two bits should be truncated. */
- return pcrel_addr + align_down (insn.address, 4);
- }
- /* J, Jcc, JL, JLcc: PC = operand. */
- else if (insn.insn_class == JUMP)
- {
- /* All jumps are single-operand. */
- return arc_insn_get_operand_value (insn, 0);
- }
- /* This is some new and unknown instruction. */
- gdb_assert_not_reached ("Unknown branch instruction.");
- }
- /* Dump INSN into gdb_stdlog. */
- static void
- arc_insn_dump (const struct arc_instruction &insn)
- {
- struct gdbarch *gdbarch = target_gdbarch ();
- arc_print ("Dumping arc_instruction at %s\n",
- paddress (gdbarch, insn.address));
- arc_print ("\tlength = %u\n", insn.length);
- if (!insn.valid)
- {
- arc_print ("\tThis is not a valid ARC instruction.\n");
- return;
- }
- arc_print ("\tlength_with_limm = %u\n", insn.length + (insn.limm_p ? 4 : 0));
- arc_print ("\tcc = 0x%x\n", insn.condition_code);
- arc_print ("\tinsn_class = %u\n", insn.insn_class);
- arc_print ("\tis_control_flow = %i\n", insn.is_control_flow);
- arc_print ("\thas_delay_slot = %i\n", insn.has_delay_slot);
- CORE_ADDR next_pc = arc_insn_get_linear_next_pc (insn);
- arc_print ("\tlinear_next_pc = %s\n", paddress (gdbarch, next_pc));
- if (insn.is_control_flow)
- {
- CORE_ADDR t = arc_insn_get_branch_target (insn);
- arc_print ("\tbranch_target = %s\n", paddress (gdbarch, t));
- }
- arc_print ("\tlimm_p = %i\n", insn.limm_p);
- if (insn.limm_p)
- arc_print ("\tlimm_value = 0x%08x\n", insn.limm_value);
- if (insn.insn_class == STORE || insn.insn_class == LOAD
- || insn.insn_class == PUSH || insn.insn_class == POP)
- {
- arc_print ("\twriteback_mode = %u\n", insn.writeback_mode);
- arc_print ("\tdata_size_mode = %u\n", insn.data_size_mode);
- arc_print ("\tmemory_base_register = %s\n",
- gdbarch_register_name (gdbarch,
- arc_insn_get_memory_base_reg (insn)));
- /* get_memory_offset returns an unsigned CORE_ADDR, but treat it as a
- LONGEST for a nicer representation. */
- arc_print ("\taddr_offset = %s\n",
- plongest (arc_insn_get_memory_offset (insn)));
- }
- arc_print ("\toperands_count = %u\n", insn.operands_count);
- for (unsigned int i = 0; i < insn.operands_count; ++i)
- {
- int is_reg = (insn.operands[i].kind == ARC_OPERAND_KIND_REG);
- arc_print ("\toperand[%u] = {\n", i);
- arc_print ("\t\tis_reg = %i\n", is_reg);
- if (is_reg)
- arc_print ("\t\tregister = %s\n",
- gdbarch_register_name (gdbarch, insn.operands[i].value));
- /* Don't know if this value is signed or not, so print both
- representations. This tends to look quite ugly, especially for big
- numbers. */
- arc_print ("\t\tunsigned value = %s\n",
- pulongest (arc_insn_get_operand_value (insn, i)));
- arc_print ("\t\tsigned value = %s\n",
- plongest (arc_insn_get_operand_value_signed (insn, i)));
- arc_print ("\t}\n");
- }
- }
- CORE_ADDR
- arc_insn_get_linear_next_pc (const struct arc_instruction &insn)
- {
- /* In ARC long immediate is always 4 bytes. */
- return (insn.address + insn.length + (insn.limm_p ? 4 : 0));
- }
- /* Implement the "write_pc" gdbarch method.
- In ARC PC register is a normal register so in most cases setting PC value
- is a straightforward process: debugger just writes PC value. However it
- gets trickier in case when current instruction is an instruction in delay
- slot. In this case CPU will execute instruction at current PC value, then
- will set PC to the current value of BTA register; also current instruction
- cannot be branch/jump and some of the other instruction types. Thus if
- debugger would try to just change PC value in this case, this instruction
- will get executed, but then core will "jump" to the original branch target.
- Whether current instruction is a delay-slot instruction or not is indicated
- by DE bit in STATUS32 register indicates if current instruction is a delay
- slot instruction. This bit is writable by debug host, which allows debug
- host to prevent core from jumping after the delay slot instruction. It
- also works in another direction: setting this bit will make core to treat
- any current instructions as a delay slot instruction and to set PC to the
- current value of BTA register.
- To workaround issues with changing PC register while in delay slot
- instruction, debugger should check for the STATUS32.DE bit and reset it if
- it is set. No other change is required in this function. Most common
- case, where this function might be required is calling inferior functions
- from debugger. Generic GDB logic handles this pretty well: current values
- of registers are stored, value of PC is changed (that is the job of this
- function), and after inferior function is executed, GDB restores all
- registers, include BTA and STATUS32, which also means that core is returned
- to its original state of being halted on delay slot instructions.
- This method is useless for ARC 600, because it doesn't have externally
- exposed BTA register. In the case of ARC 600 it is impossible to restore
- core to its state in all occasions thus core should never be halted (from
- the perspective of debugger host) in the delay slot. */
- static void
- arc_write_pc (struct regcache *regcache, CORE_ADDR new_pc)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- arc_debug_printf ("Writing PC, new value=%s",
- paddress (gdbarch, new_pc));
- regcache_cooked_write_unsigned (regcache, gdbarch_pc_regnum (gdbarch),
- new_pc);
- ULONGEST status32;
- regcache_cooked_read_unsigned (regcache, gdbarch_ps_regnum (gdbarch),
- &status32);
- if ((status32 & ARC_STATUS32_DE_MASK) != 0)
- {
- arc_debug_printf ("Changing PC while in delay slot. Will "
- "reset STATUS32.DE bit to zero. Value of STATUS32 "
- "register is 0x%s",
- phex (status32, ARC_REGISTER_SIZE));
- /* Reset bit and write to the cache. */
- status32 &= ~0x40;
- regcache_cooked_write_unsigned (regcache, gdbarch_ps_regnum (gdbarch),
- status32);
- }
- }
- /* Implement the "virtual_frame_pointer" gdbarch method.
- According to ABI the FP (r27) is used to point to the middle of the current
- stack frame, just below the saved FP and before local variables, register
- spill area and outgoing args. However for optimization levels above O2 and
- in any case in leaf functions, the frame pointer is usually not set at all.
- The exception being when handling nested functions.
- We use this function to return a "virtual" frame pointer, marking the start
- of the current stack frame as a register-offset pair. If the FP is not
- being used, then it should return SP, with an offset of the frame size.
- The current implementation doesn't actually know the frame size, nor
- whether the FP is actually being used, so for now we just return SP and an
- offset of zero. This is no worse than other architectures, but is needed
- to avoid assertion failures.
- TODO: Can we determine the frame size to get a correct offset?
- PC is a program counter where we need the virtual FP. REG_PTR is the base
- register used for the virtual FP. OFFSET_PTR is the offset used for the
- virtual FP. */
- static void
- arc_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc,
- int *reg_ptr, LONGEST *offset_ptr)
- {
- *reg_ptr = gdbarch_sp_regnum (gdbarch);
- *offset_ptr = 0;
- }
- /* Implement the "push_dummy_call" gdbarch method.
- Stack Frame Layout
- This shows the layout of the stack frame for the general case of a
- function call; a given function might not have a variable number of
- arguments or local variables, or might not save any registers, so it would
- not have the corresponding frame areas. Additionally, a leaf function
- (i.e. one which calls no other functions) does not need to save the
- contents of the BLINK register (which holds its return address), and a
- function might not have a frame pointer.
- The stack grows downward, so SP points below FP in memory; SP always
- points to the last used word on the stack, not the first one.
- | | |
- | arg word N | | caller's
- | : | | frame
- | arg word 10 | |
- | arg word 9 | |
- old SP ---> +-----------------------+ --+
- | | |
- | callee-saved | |
- | registers | |
- | including fp, blink | |
- | | | callee's
- new FP ---> +-----------------------+ | frame
- | | |
- | local | |
- | variables | |
- | | |
- | register | |
- | spill area | |
- | | |
- | outgoing args | |
- | | |
- new SP ---> +-----------------------+ --+
- | |
- | unused |
- | |
- |
- |
- V
- downwards
- The list of arguments to be passed to a function is considered to be a
- sequence of _N_ words (as though all the parameters were stored in order in
- memory with each parameter occupying an integral number of words). Words
- 1..8 are passed in registers 0..7; if the function has more than 8 words of
- arguments then words 9..@em N are passed on the stack in the caller's frame.
- If the function has a variable number of arguments, e.g. it has a form such
- as `function (p1, p2, ...);' and _P_ words are required to hold the values
- of the named parameters (which are passed in registers 0..@em P -1), then
- the remaining 8 - _P_ words passed in registers _P_..7 are spilled into the
- top of the frame so that the anonymous parameter words occupy a continuous
- region.
- Any arguments are already in target byte order. We just need to store
- them!
- BP_ADDR is the return address where breakpoint must be placed. NARGS is
- the number of arguments to the function. ARGS is the arguments values (in
- target byte order). SP is the Current value of SP register. STRUCT_RETURN
- is TRUE if structures are returned by the function. STRUCT_ADDR is the
- hidden address for returning a struct. Returns SP of a new frame. */
- static CORE_ADDR
- arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
- struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
- struct value **args, CORE_ADDR sp,
- function_call_return_method return_method,
- CORE_ADDR struct_addr)
- {
- arc_debug_printf ("nargs = %d", nargs);
- int arg_reg = ARC_FIRST_ARG_REGNUM;
- /* Push the return address. */
- regcache_cooked_write_unsigned (regcache, ARC_BLINK_REGNUM, bp_addr);
- /* Are we returning a value using a structure return instead of a normal
- value return? If so, struct_addr is the address of the reserved space for
- the return structure to be written on the stack, and that address is
- passed to that function as a hidden first argument. */
- if (return_method == return_method_struct)
- {
- /* Pass the return address in the first argument register. */
- regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
- arc_debug_printf ("struct return address %s passed in R%d",
- print_core_address (gdbarch, struct_addr), arg_reg);
- arg_reg++;
- }
- if (nargs > 0)
- {
- unsigned int total_space = 0;
- /* How much space do the arguments occupy in total? Must round each
- argument's size up to an integral number of words. */
- for (int i = 0; i < nargs; i++)
- {
- unsigned int len = TYPE_LENGTH (value_type (args[i]));
- unsigned int space = align_up (len, 4);
- total_space += space;
- arc_debug_printf ("arg %d: %u bytes -> %u", i, len, space);
- }
- /* Allocate a buffer to hold a memory image of the arguments. */
- gdb_byte *memory_image = XCNEWVEC (gdb_byte, total_space);
- /* Now copy all of the arguments into the buffer, correctly aligned. */
- gdb_byte *data = memory_image;
- for (int i = 0; i < nargs; i++)
- {
- unsigned int len = TYPE_LENGTH (value_type (args[i]));
- unsigned int space = align_up (len, 4);
- memcpy (data, value_contents (args[i]).data (), (size_t) len);
- arc_debug_printf ("copying arg %d, val 0x%08x, len %d to mem",
- i, *((int *) value_contents (args[i]).data ()),
- len);
- data += space;
- }
- /* Now load as much as possible of the memory image into registers. */
- data = memory_image;
- while (arg_reg <= ARC_LAST_ARG_REGNUM)
- {
- arc_debug_printf ("passing 0x%02x%02x%02x%02x in register R%d",
- data[0], data[1], data[2], data[3], arg_reg);
- /* Note we don't use write_unsigned here, since that would convert
- the byte order, but we are already in the correct byte order. */
- regcache->cooked_write (arg_reg, data);
- data += ARC_REGISTER_SIZE;
- total_space -= ARC_REGISTER_SIZE;
- /* All the data is now in registers. */
- if (total_space == 0)
- break;
- arg_reg++;
- }
- /* If there is any data left, push it onto the stack (in a single write
- operation). */
- if (total_space > 0)
- {
- arc_debug_printf ("passing %d bytes on stack\n", total_space);
- sp -= total_space;
- write_memory (sp, data, (int) total_space);
- }
- xfree (memory_image);
- }
- /* Finally, update the SP register. */
- regcache_cooked_write_unsigned (regcache, gdbarch_sp_regnum (gdbarch), sp);
- return sp;
- }
- /* Implement the "push_dummy_code" gdbarch method.
- We don't actually push any code. We just identify where a breakpoint can
- be inserted to which we are can return and the resume address where we
- should be called.
- ARC does not necessarily have an executable stack, so we can't put the
- return breakpoint there. Instead we put it at the entry point of the
- function. This means the SP is unchanged.
- SP is a current stack pointer FUNADDR is an address of the function to be
- called. ARGS is arguments to pass. NARGS is a number of args to pass.
- VALUE_TYPE is a type of value returned. REAL_PC is a resume address when
- the function is called. BP_ADDR is an address where breakpoint should be
- set. Returns the updated stack pointer. */
- static CORE_ADDR
- arc_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
- struct value **args, int nargs, struct type *value_type,
- CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
- struct regcache *regcache)
- {
- *real_pc = funaddr;
- *bp_addr = entry_point_address ();
- return sp;
- }
- /* Implement the "cannot_fetch_register" gdbarch method. */
- static int
- arc_cannot_fetch_register (struct gdbarch *gdbarch, int regnum)
- {
- /* Assume that register is readable if it is unknown. LIMM and RESERVED are
- not real registers, but specific register numbers. They are available as
- regnums to align architectural register numbers with GDB internal regnums,
- but they shouldn't appear in target descriptions generated by
- GDB-servers. */
- switch (regnum)
- {
- case ARC_RESERVED_REGNUM:
- case ARC_LIMM_REGNUM:
- return true;
- default:
- return false;
- }
- }
- /* Implement the "cannot_store_register" gdbarch method. */
- static int
- arc_cannot_store_register (struct gdbarch *gdbarch, int regnum)
- {
- /* Assume that register is writable if it is unknown. See comment in
- arc_cannot_fetch_register about LIMM and RESERVED. */
- switch (regnum)
- {
- case ARC_RESERVED_REGNUM:
- case ARC_LIMM_REGNUM:
- case ARC_PCL_REGNUM:
- return true;
- default:
- return false;
- }
- }
- /* Get the return value of a function from the registers/memory used to
- return it, according to the convention used by the ABI - 4-bytes values are
- in the R0, while 8-byte values are in the R0-R1.
- TODO: This implementation ignores the case of "complex double", where
- according to ABI, value is returned in the R0-R3 registers.
- TYPE is a returned value's type. VALBUF is a buffer for the returned
- value. */
- static void
- arc_extract_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, gdb_byte *valbuf)
- {
- unsigned int len = TYPE_LENGTH (type);
- arc_debug_printf ("called");
- if (len <= ARC_REGISTER_SIZE)
- {
- ULONGEST val;
- /* Get the return value from one register. */
- regcache_cooked_read_unsigned (regcache, ARC_R0_REGNUM, &val);
- store_unsigned_integer (valbuf, (int) len,
- gdbarch_byte_order (gdbarch), val);
- arc_debug_printf ("returning 0x%s", phex (val, ARC_REGISTER_SIZE));
- }
- else if (len <= ARC_REGISTER_SIZE * 2)
- {
- ULONGEST low, high;
- /* Get the return value from two registers. */
- regcache_cooked_read_unsigned (regcache, ARC_R0_REGNUM, &low);
- regcache_cooked_read_unsigned (regcache, ARC_R1_REGNUM, &high);
- store_unsigned_integer (valbuf, ARC_REGISTER_SIZE,
- gdbarch_byte_order (gdbarch), low);
- store_unsigned_integer (valbuf + ARC_REGISTER_SIZE,
- (int) len - ARC_REGISTER_SIZE,
- gdbarch_byte_order (gdbarch), high);
- arc_debug_printf ("returning 0x%s%s",
- phex (high, ARC_REGISTER_SIZE),
- phex (low, ARC_REGISTER_SIZE));
- }
- else
- error (_("arc: extract_return_value: type length %u too large"), len);
- }
- /* Store the return value of a function into the registers/memory used to
- return it, according to the convention used by the ABI.
- TODO: This implementation ignores the case of "complex double", where
- according to ABI, value is returned in the R0-R3 registers.
- TYPE is a returned value's type. VALBUF is a buffer with the value to
- return. */
- static void
- arc_store_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, const gdb_byte *valbuf)
- {
- unsigned int len = TYPE_LENGTH (type);
- arc_debug_printf ("called");
- if (len <= ARC_REGISTER_SIZE)
- {
- ULONGEST val;
- /* Put the return value into one register. */
- val = extract_unsigned_integer (valbuf, (int) len,
- gdbarch_byte_order (gdbarch));
- regcache_cooked_write_unsigned (regcache, ARC_R0_REGNUM, val);
- arc_debug_printf ("storing 0x%s", phex (val, ARC_REGISTER_SIZE));
- }
- else if (len <= ARC_REGISTER_SIZE * 2)
- {
- ULONGEST low, high;
- /* Put the return value into two registers. */
- low = extract_unsigned_integer (valbuf, ARC_REGISTER_SIZE,
- gdbarch_byte_order (gdbarch));
- high = extract_unsigned_integer (valbuf + ARC_REGISTER_SIZE,
- (int) len - ARC_REGISTER_SIZE,
- gdbarch_byte_order (gdbarch));
- regcache_cooked_write_unsigned (regcache, ARC_R0_REGNUM, low);
- regcache_cooked_write_unsigned (regcache, ARC_R1_REGNUM, high);
- arc_debug_printf ("storing 0x%s%s",
- phex (high, ARC_REGISTER_SIZE),
- phex (low, ARC_REGISTER_SIZE));
- }
- else
- error (_("arc_store_return_value: type length too large."));
- }
- /* Implement the "get_longjmp_target" gdbarch method. */
- static int
- arc_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
- {
- arc_debug_printf ("called");
- struct gdbarch *gdbarch = get_frame_arch (frame);
- arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int pc_offset = tdep->jb_pc * ARC_REGISTER_SIZE;
- gdb_byte buf[ARC_REGISTER_SIZE];
- CORE_ADDR jb_addr = get_frame_register_unsigned (frame, ARC_FIRST_ARG_REGNUM);
- if (target_read_memory (jb_addr + pc_offset, buf, ARC_REGISTER_SIZE))
- return 0; /* Failed to read from memory. */
- *pc = extract_unsigned_integer (buf, ARC_REGISTER_SIZE,
- gdbarch_byte_order (gdbarch));
- return 1;
- }
- /* Implement the "return_value" gdbarch method. */
- static enum return_value_convention
- arc_return_value (struct gdbarch *gdbarch, struct value *function,
- struct type *valtype, struct regcache *regcache,
- gdb_byte *readbuf, const gdb_byte *writebuf)
- {
- /* If the return type is a struct, or a union, or would occupy more than two
- registers, the ABI uses the "struct return convention": the calling
- function passes a hidden first parameter to the callee (in R0). That
- parameter is the address at which the value being returned should be
- stored. Otherwise, the result is returned in registers. */
- int is_struct_return = (valtype->code () == TYPE_CODE_STRUCT
- || valtype->code () == TYPE_CODE_UNION
- || TYPE_LENGTH (valtype) > 2 * ARC_REGISTER_SIZE);
- arc_debug_printf ("readbuf = %s, writebuf = %s",
- host_address_to_string (readbuf),
- host_address_to_string (writebuf));
- if (writebuf != NULL)
- {
- /* Case 1. GDB should not ask us to set a struct return value: it
- should know the struct return location and write the value there
- itself. */
- gdb_assert (!is_struct_return);
- arc_store_return_value (gdbarch, valtype, regcache, writebuf);
- }
- else if (readbuf != NULL)
- {
- /* Case 2. GDB should not ask us to get a struct return value: it
- should know the struct return location and read the value from there
- itself. */
- gdb_assert (!is_struct_return);
- arc_extract_return_value (gdbarch, valtype, regcache, readbuf);
- }
- return (is_struct_return
- ? RETURN_VALUE_STRUCT_CONVENTION
- : RETURN_VALUE_REGISTER_CONVENTION);
- }
- /* Return the base address of the frame. For ARC, the base address is the
- frame pointer. */
- static CORE_ADDR
- arc_frame_base_address (struct frame_info *this_frame, void **prologue_cache)
- {
- return (CORE_ADDR) get_frame_register_unsigned (this_frame, ARC_FP_REGNUM);
- }
- /* Helper function that returns valid pv_t for an instruction operand:
- either a register or a constant. */
- static pv_t
- arc_pv_get_operand (pv_t *regs, const struct arc_instruction &insn, int operand)
- {
- if (insn.operands[operand].kind == ARC_OPERAND_KIND_REG)
- return regs[insn.operands[operand].value];
- else
- return pv_constant (arc_insn_get_operand_value (insn, operand));
- }
- /* Determine whether the given disassembled instruction may be part of a
- function prologue. If it is, the information in the frame unwind cache will
- be updated. */
- static bool
- arc_is_in_prologue (struct gdbarch *gdbarch, const struct arc_instruction &insn,
- pv_t *regs, struct pv_area *stack)
- {
- /* It might be that currently analyzed address doesn't contain an
- instruction, hence INSN is not valid. It likely means that address points
- to a data, non-initialized memory, or middle of a 32-bit instruction. In
- practice this may happen if GDB connects to a remote target that has
- non-zeroed memory. GDB would read PC value and would try to analyze
- prologue, but there is no guarantee that memory contents at the address
- specified in PC is address is a valid instruction. There is not much that
- that can be done about that. */
- if (!insn.valid)
- return false;
- /* Branch/jump or a predicated instruction. */
- if (insn.is_control_flow || insn.condition_code != ARC_CC_AL)
- return false;
- /* Store of some register. May or may not update base address register. */
- if (insn.insn_class == STORE || insn.insn_class == PUSH)
- {
- /* There is definitely at least one operand - register/value being
- stored. */
- gdb_assert (insn.operands_count > 0);
- /* Store at some constant address. */
- if (insn.operands_count > 1
- && insn.operands[1].kind != ARC_OPERAND_KIND_REG)
- return false;
- /* Writeback modes:
- Mode Address used Writeback value
- --------------------------------------------------
- No reg + offset no
- A/AW reg + offset reg + offset
- AB reg reg + offset
- AS reg + (offset << scaling) no
- "PUSH reg" is an alias to "ST.AW reg, [SP, -4]" encoding. However
- 16-bit PUSH_S is a distinct instruction encoding, where offset and
- base register are implied through opcode. */
- /* Register with base memory address. */
- int base_reg = arc_insn_get_memory_base_reg (insn);
- /* Address where to write. arc_insn_get_memory_offset returns scaled
- value for ARC_WRITEBACK_AS. */
- pv_t addr;
- if (insn.writeback_mode == ARC_WRITEBACK_AB)
- addr = regs[base_reg];
- else
- addr = pv_add_constant (regs[base_reg],
- arc_insn_get_memory_offset (insn));
- if (stack->store_would_trash (addr))
- return false;
- if (insn.data_size_mode != ARC_SCALING_D)
- {
- /* Find the value being stored. */
- pv_t store_value = arc_pv_get_operand (regs, insn, 0);
- /* What is the size of a the stored value? */
- CORE_ADDR size;
- if (insn.data_size_mode == ARC_SCALING_B)
- size = 1;
- else if (insn.data_size_mode == ARC_SCALING_H)
- size = 2;
- else
- size = ARC_REGISTER_SIZE;
- stack->store (addr, size, store_value);
- }
- else
- {
- if (insn.operands[0].kind == ARC_OPERAND_KIND_REG)
- {
- /* If this is a double store, than write N+1 register as well. */
- pv_t store_value1 = regs[insn.operands[0].value];
- pv_t store_value2 = regs[insn.operands[0].value + 1];
- stack->store (addr, ARC_REGISTER_SIZE, store_value1);
- stack->store (pv_add_constant (addr, ARC_REGISTER_SIZE),
- ARC_REGISTER_SIZE, store_value2);
- }
- else
- {
- pv_t store_value
- = pv_constant (arc_insn_get_operand_value (insn, 0));
- stack->store (addr, ARC_REGISTER_SIZE * 2, store_value);
- }
- }
- /* Is base register updated? */
- if (insn.writeback_mode == ARC_WRITEBACK_A
- || insn.writeback_mode == ARC_WRITEBACK_AB)
- regs[base_reg] = pv_add_constant (regs[base_reg],
- arc_insn_get_memory_offset (insn));
- return true;
- }
- else if (insn.insn_class == MOVE)
- {
- gdb_assert (insn.operands_count == 2);
- /* Destination argument can be "0", so nothing will happen. */
- if (insn.operands[0].kind == ARC_OPERAND_KIND_REG)
- {
- int dst_regnum = insn.operands[0].value;
- regs[dst_regnum] = arc_pv_get_operand (regs, insn, 1);
- }
- return true;
- }
- else if (insn.insn_class == SUB)
- {
- gdb_assert (insn.operands_count == 3);
- /* SUB 0,b,c. */
- if (insn.operands[0].kind != ARC_OPERAND_KIND_REG)
- return true;
- int dst_regnum = insn.operands[0].value;
- regs[dst_regnum] = pv_subtract (arc_pv_get_operand (regs, insn, 1),
- arc_pv_get_operand (regs, insn, 2));
- return true;
- }
- else if (insn.insn_class == ENTER)
- {
- /* ENTER_S is a prologue-in-instruction - it saves all callee-saved
- registers according to given arguments thus greatly reducing code
- size. Which registers will be actually saved depends on arguments.
- ENTER_S {R13-...,FP,BLINK} stores registers in following order:
- new SP ->
- BLINK
- R13
- R14
- R15
- ...
- FP
- old SP ->
- There are up to three arguments for this opcode, as presented by ARC
- disassembler:
- 1) amount of general-purpose registers to be saved - this argument is
- always present even when it is 0;
- 2) FP register number (27) if FP has to be stored, otherwise argument
- is not present;
- 3) BLINK register number (31) if BLINK has to be stored, otherwise
- argument is not present. If both FP and BLINK are stored, then FP
- is present before BLINK in argument list. */
- gdb_assert (insn.operands_count > 0);
- int regs_saved = arc_insn_get_operand_value (insn, 0);
- bool is_fp_saved;
- if (insn.operands_count > 1)
- is_fp_saved = (insn.operands[1].value == ARC_FP_REGNUM);
- else
- is_fp_saved = false;
- bool is_blink_saved;
- if (insn.operands_count > 1)
- is_blink_saved = (insn.operands[insn.operands_count - 1].value
- == ARC_BLINK_REGNUM);
- else
- is_blink_saved = false;
- /* Amount of bytes to be allocated to store specified registers. */
- CORE_ADDR st_size = ((regs_saved + is_fp_saved + is_blink_saved)
- * ARC_REGISTER_SIZE);
- pv_t new_sp = pv_add_constant (regs[ARC_SP_REGNUM], -st_size);
- /* Assume that if the last register (closest to new SP) can be written,
- then it is possible to write all of them. */
- if (stack->store_would_trash (new_sp))
- return false;
- /* Current store address. */
- pv_t addr = regs[ARC_SP_REGNUM];
- if (is_fp_saved)
- {
- addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
- stack->store (addr, ARC_REGISTER_SIZE, regs[ARC_FP_REGNUM]);
- }
- /* Registers are stored in backward order: from GP (R26) to R13. */
- for (int i = ARC_R13_REGNUM + regs_saved - 1; i >= ARC_R13_REGNUM; i--)
- {
- addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
- stack->store (addr, ARC_REGISTER_SIZE, regs[i]);
- }
- if (is_blink_saved)
- {
- addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
- stack->store (addr, ARC_REGISTER_SIZE,
- regs[ARC_BLINK_REGNUM]);
- }
- gdb_assert (pv_is_identical (addr, new_sp));
- regs[ARC_SP_REGNUM] = new_sp;
- if (is_fp_saved)
- regs[ARC_FP_REGNUM] = regs[ARC_SP_REGNUM];
- return true;
- }
- /* Some other architectures, like nds32 or arm, try to continue as far as
- possible when building a prologue cache (as opposed to when skipping
- prologue), so that cache will be as full as possible. However current
- code for ARC doesn't recognize some instructions that may modify SP, like
- ADD, AND, OR, etc, hence there is no way to guarantee that SP wasn't
- clobbered by the skipped instruction. Potential existence of extension
- instruction, which may do anything they want makes this even more complex,
- so it is just better to halt on a first unrecognized instruction. */
- return false;
- }
- /* See arc-tdep.h. */
- struct disassemble_info
- arc_disassemble_info (struct gdbarch *gdbarch)
- {
- struct disassemble_info di;
- init_disassemble_info_for_no_printing (&di);
- di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
- di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
- di.endian = gdbarch_byte_order (gdbarch);
- di.read_memory_func = [](bfd_vma memaddr, gdb_byte *myaddr,
- unsigned int len, struct disassemble_info *info)
- {
- return target_read_code (memaddr, myaddr, len);
- };
- return di;
- }
- /* Analyze the prologue and update the corresponding frame cache for the frame
- unwinder for unwinding frames that doesn't have debug info. In such
- situation GDB attempts to parse instructions in the prologue to understand
- where each register is saved.
- If CACHE is not NULL, then it will be filled with information about saved
- registers.
- There are several variations of prologue which GDB may encounter. "Full"
- prologue looks like this:
- sub sp,sp,<imm> ; Space for variadic arguments.
- push blink ; Store return address.
- push r13 ; Store callee saved registers (up to R26/GP).
- push r14
- push fp ; Store frame pointer.
- mov fp,sp ; Update frame pointer.
- sub sp,sp,<imm> ; Create space for local vars on the stack.
- Depending on compiler options lots of things may change:
- 1) BLINK is not saved in leaf functions.
- 2) Frame pointer is not saved and updated if -fomit-frame-pointer is used.
- 3) 16-bit versions of those instructions may be used.
- 4) Instead of a sequence of several push'es, compiler may instead prefer to
- do one subtract on stack pointer and then store registers using normal
- store, that doesn't update SP. Like this:
- sub sp,sp,8 ; Create space for callee-saved registers.
- st r13,[sp,4] ; Store callee saved registers (up to R26/GP).
- st r14,[sp,0]
- 5) ENTER_S instruction can encode most of prologue sequence in one
- instruction (except for those subtracts for variadic arguments and local
- variables).
- 6) GCC may use "millicode" functions from libgcc to store callee-saved
- registers with minimal code-size requirements. This function currently
- doesn't support this.
- ENTRYPOINT is a function entry point where prologue starts.
- LIMIT_PC is a maximum possible end address of prologue (meaning address
- of first instruction after the prologue). It might also point to the middle
- of prologue if execution has been stopped by the breakpoint at this address
- - in this case debugger should analyze prologue only up to this address,
- because further instructions haven't been executed yet.
- Returns address of the first instruction after the prologue. */
- static CORE_ADDR
- arc_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR entrypoint,
- const CORE_ADDR limit_pc, struct arc_frame_cache *cache)
- {
- arc_debug_printf ("entrypoint=%s, limit_pc=%s",
- paddress (gdbarch, entrypoint),
- paddress (gdbarch, limit_pc));
- /* Prologue values. Only core registers can be stored. */
- pv_t regs[ARC_LAST_CORE_REGNUM + 1];
- for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
- regs[i] = pv_register (i, 0);
- pv_area stack (ARC_SP_REGNUM, gdbarch_addr_bit (gdbarch));
- CORE_ADDR current_prologue_end = entrypoint;
- /* Look at each instruction in the prologue. */
- while (current_prologue_end < limit_pc)
- {
- struct arc_instruction insn;
- struct disassemble_info di = arc_disassemble_info (gdbarch);
- arc_insn_decode (current_prologue_end, &di, arc_delayed_print_insn,
- &insn);
- if (arc_debug)
- arc_insn_dump (insn);
- /* If this instruction is in the prologue, fields in the cache will be
- updated, and the saved registers mask may be updated. */
- if (!arc_is_in_prologue (gdbarch, insn, regs, &stack))
- {
- /* Found an instruction that is not in the prologue. */
- arc_debug_printf ("End of prologue reached at address %s",
- paddress (gdbarch, insn.address));
- break;
- }
- current_prologue_end = arc_insn_get_linear_next_pc (insn);
- }
- if (cache != NULL)
- {
- /* Figure out if it is a frame pointer or just a stack pointer. */
- if (pv_is_register (regs[ARC_FP_REGNUM], ARC_SP_REGNUM))
- {
- cache->frame_base_reg = ARC_FP_REGNUM;
- cache->frame_base_offset = -regs[ARC_FP_REGNUM].k;
- }
- else
- {
- cache->frame_base_reg = ARC_SP_REGNUM;
- cache->frame_base_offset = -regs[ARC_SP_REGNUM].k;
- }
- /* Assign offset from old SP to all saved registers. */
- for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
- {
- CORE_ADDR offset;
- if (stack.find_reg (gdbarch, i, &offset))
- cache->saved_regs[i].set_addr (offset);
- }
- }
- return current_prologue_end;
- }
- /* Estimated maximum prologue length in bytes. This should include:
- 1) Store instruction for each callee-saved register (R25 - R13 + 1)
- 2) Two instructions for FP
- 3) One for BLINK
- 4) Three substract instructions for SP (for variadic args, for
- callee saved regs and for local vars) and assuming that those SUB use
- long-immediate (hence double length).
- 5) Stores of arguments registers are considered part of prologue too
- (R7 - R1 + 1).
- This is quite an extreme case, because even with -O0 GCC will collapse first
- two SUBs into one and long immediate values are quite unlikely to appear in
- this case, but still better to overshoot a bit - prologue analysis will
- anyway stop at the first instruction that doesn't fit prologue, so this
- limit will be rarely reached. */
- const static int MAX_PROLOGUE_LENGTH
- = 4 * (ARC_R25_REGNUM - ARC_R13_REGNUM + 1 + 2 + 1 + 6
- + ARC_LAST_ARG_REGNUM - ARC_FIRST_ARG_REGNUM + 1);
- /* Implement the "skip_prologue" gdbarch method.
- Skip the prologue for the function at PC. This is done by checking from
- the line information read from the DWARF, if possible; otherwise, we scan
- the function prologue to find its end. */
- static CORE_ADDR
- arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- arc_debug_printf ("pc = %s", paddress (gdbarch, pc));
- CORE_ADDR func_addr;
- const char *func_name;
- /* See what the symbol table says. */
- if (find_pc_partial_function (pc, &func_name, &func_addr, NULL))
- {
- /* Found a function. */
- CORE_ADDR postprologue_pc
- = skip_prologue_using_sal (gdbarch, func_addr);
- if (postprologue_pc != 0)
- return std::max (pc, postprologue_pc);
- }
- /* No prologue info in symbol table, have to analyze prologue. */
- /* Find an upper limit on the function prologue using the debug
- information. If there is no debug information about prologue end, then
- skip_prologue_using_sal will return 0. */
- CORE_ADDR limit_pc = skip_prologue_using_sal (gdbarch, pc);
- /* If there is no debug information at all, it is required to give some
- semi-arbitrary hard limit on amount of bytes to scan during prologue
- analysis. */
- if (limit_pc == 0)
- limit_pc = pc + MAX_PROLOGUE_LENGTH;
- /* Find the address of the first instruction after the prologue by scanning
- through it - no other information is needed, so pass NULL as a cache. */
- return arc_analyze_prologue (gdbarch, pc, limit_pc, NULL);
- }
- /* Implement the "print_insn" gdbarch method.
- arc_get_disassembler () may return different functions depending on bfd
- type, so it is not possible to pass print_insn directly to
- set_gdbarch_print_insn (). Instead this wrapper function is used. It also
- may be used by other functions to get disassemble_info for address. It is
- important to note, that those print_insn from opcodes always print
- instruction to the stream specified in the INFO. If this is not desired,
- then either `print_insn` function in INFO should be set to some function
- that will not print, or `stream` should be different from standard
- gdb_stdlog. */
- int
- arc_delayed_print_insn (bfd_vma addr, struct disassemble_info *info)
- {
- /* Standard BFD "machine number" field allows libopcodes disassembler to
- distinguish ARC 600, 700 and v2 cores, however v2 encompasses both ARC EM
- and HS, which have some difference between. There are two ways to specify
- what is the target core:
- 1) via the disassemble_info->disassembler_options;
- 2) otherwise libopcodes will use private (architecture-specific) ELF
- header.
- Using disassembler_options is preferable, because it comes directly from
- GDBserver which scanned an actual ARC core identification info. However,
- not all GDBservers report core architecture, so as a fallback GDB still
- should support analysis of ELF header. The libopcodes disassembly code
- uses the section to find the BFD and the BFD to find the ELF header,
- therefore this function should set disassemble_info->section properly.
- disassembler_options was already set by non-target specific code with
- proper options obtained via gdbarch_disassembler_options ().
- This function might be called multiple times in a sequence, reusing same
- disassemble_info. */
- if ((info->disassembler_options == NULL) && (info->section == NULL))
- {
- struct obj_section *s = find_pc_section (addr);
- if (s != NULL)
- info->section = s->the_bfd_section;
- }
- return default_print_insn (addr, info);
- }
- /* Baremetal breakpoint instructions.
- ARC supports both big- and little-endian. However, instructions for
- little-endian processors are encoded in the middle-endian: half-words are
- in big-endian, while bytes inside the half-words are in little-endian; data
- is represented in the "normal" little-endian. Big-endian processors treat
- data and code identically.
- Assuming the number 0x01020304, it will be presented this way:
- Address : N N+1 N+2 N+3
- little-endian : 0x04 0x03 0x02 0x01
- big-endian : 0x01 0x02 0x03 0x04
- ARC middle-endian : 0x02 0x01 0x04 0x03
- */
- static const gdb_byte arc_brk_s_be[] = { 0x7f, 0xff };
- static const gdb_byte arc_brk_s_le[] = { 0xff, 0x7f };
- static const gdb_byte arc_brk_be[] = { 0x25, 0x6f, 0x00, 0x3f };
- static const gdb_byte arc_brk_le[] = { 0x6f, 0x25, 0x3f, 0x00 };
- /* For ARC ELF, breakpoint uses the 16-bit BRK_S instruction, which is 0x7fff
- (little endian) or 0xff7f (big endian). We used to insert BRK_S even
- instead of 32-bit instructions, which works mostly ok, unless breakpoint is
- inserted into delay slot instruction. In this case if branch is taken
- BLINK value will be set to address of instruction after delay slot, however
- if we replaced 32-bit instruction in delay slot with 16-bit long BRK_S,
- then BLINK value will have an invalid value - it will point to the address
- after the BRK_S (which was there at the moment of branch execution) while
- it should point to the address after the 32-bit long instruction. To avoid
- such issues this function disassembles instruction at target location and
- evaluates it value.
- ARC 600 supports only 16-bit BRK_S.
- NB: Baremetal GDB uses BRK[_S], while user-space GDB uses TRAP_S. BRK[_S]
- is much better because it doesn't commit unlike TRAP_S, so it can be set in
- delay slots; however it cannot be used in user-mode, hence usage of TRAP_S
- in GDB for user-space. */
- /* Implement the "breakpoint_kind_from_pc" gdbarch method. */
- static int
- arc_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
- {
- size_t length_with_limm = gdb_insn_length (gdbarch, *pcptr);
- /* Replace 16-bit instruction with BRK_S, replace 32-bit instructions with
- BRK. LIMM is part of instruction length, so it can be either 4 or 8
- bytes for 32-bit instructions. */
- if ((length_with_limm == 4 || length_with_limm == 8)
- && !arc_mach_is_arc600 (gdbarch))
- return sizeof (arc_brk_le);
- else
- return sizeof (arc_brk_s_le);
- }
- /* Implement the "sw_breakpoint_from_kind" gdbarch method. */
- static const gdb_byte *
- arc_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
- {
- gdb_assert (kind == 2 || kind == 4);
- *size = kind;
- if (kind == sizeof (arc_brk_le))
- {
- return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- ? arc_brk_be
- : arc_brk_le);
- }
- else
- {
- return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- ? arc_brk_s_be
- : arc_brk_s_le);
- }
- }
- /* Implement the "frame_align" gdbarch method. */
- static CORE_ADDR
- arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
- {
- return align_down (sp, 4);
- }
- /* Dump the frame info. Used for internal debugging only. */
- static void
- arc_print_frame_cache (struct gdbarch *gdbarch, const char *message,
- struct arc_frame_cache *cache, int addresses_known)
- {
- arc_debug_printf ("frame_info %s", message);
- arc_debug_printf ("prev_sp = %s", paddress (gdbarch, cache->prev_sp));
- arc_debug_printf ("frame_base_reg = %i", cache->frame_base_reg);
- arc_debug_printf ("frame_base_offset = %s",
- plongest (cache->frame_base_offset));
- for (int i = 0; i <= ARC_BLINK_REGNUM; i++)
- {
- if (cache->saved_regs[i].is_addr ())
- arc_debug_printf ("saved register %s at %s %s",
- gdbarch_register_name (gdbarch, i),
- (addresses_known) ? "address" : "offset",
- paddress (gdbarch, cache->saved_regs[i].addr ()));
- }
- }
- /* Frame unwinder for normal frames. */
- static struct arc_frame_cache *
- arc_make_frame_cache (struct frame_info *this_frame)
- {
- arc_debug_printf ("called");
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
- CORE_ADDR entrypoint, prologue_end;
- if (find_pc_partial_function (block_addr, NULL, &entrypoint, &prologue_end))
- {
- struct symtab_and_line sal = find_pc_line (entrypoint, 0);
- CORE_ADDR prev_pc = get_frame_pc (this_frame);
- if (sal.line == 0)
- /* No line info so use current PC. */
- prologue_end = prev_pc;
- else if (sal.end < prologue_end)
- /* The next line begins after the function end. */
- prologue_end = sal.end;
- prologue_end = std::min (prologue_end, prev_pc);
- }
- else
- {
- /* If find_pc_partial_function returned nothing then there is no symbol
- information at all for this PC. Currently it is assumed in this case
- that current PC is entrypoint to function and try to construct the
- frame from that. This is, probably, suboptimal, for example ARM
- assumes in this case that program is inside the normal frame (with
- frame pointer). ARC, perhaps, should try to do the same. */
- entrypoint = get_frame_register_unsigned (this_frame,
- gdbarch_pc_regnum (gdbarch));
- prologue_end = entrypoint + MAX_PROLOGUE_LENGTH;
- }
- /* Allocate new frame cache instance and space for saved register info.
- FRAME_OBSTACK_ZALLOC will initialize fields to zeroes. */
- struct arc_frame_cache *cache
- = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache);
- cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- arc_analyze_prologue (gdbarch, entrypoint, prologue_end, cache);
- if (arc_debug)
- arc_print_frame_cache (gdbarch, "after prologue", cache, false);
- CORE_ADDR unwound_fb = get_frame_register_unsigned (this_frame,
- cache->frame_base_reg);
- if (unwound_fb == 0)
- return cache;
- cache->prev_sp = unwound_fb + cache->frame_base_offset;
- for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
- {
- if (cache->saved_regs[i].is_addr ())
- cache->saved_regs[i].set_addr (cache->saved_regs[i].addr ()
- + cache->prev_sp);
- }
- if (arc_debug)
- arc_print_frame_cache (gdbarch, "after previous SP found", cache, true);
- return cache;
- }
- /* Implement the "this_id" frame_unwind method. */
- static void
- arc_frame_this_id (struct frame_info *this_frame, void **this_cache,
- struct frame_id *this_id)
- {
- arc_debug_printf ("called");
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- if (*this_cache == NULL)
- *this_cache = arc_make_frame_cache (this_frame);
- struct arc_frame_cache *cache = (struct arc_frame_cache *) (*this_cache);
- CORE_ADDR stack_addr = cache->prev_sp;
- /* There are 4 possible situation which decide how frame_id->code_addr is
- evaluated:
- 1) Function is compiled with option -g. Then frame_id will be created
- in dwarf_* function and not in this function. NB: even if target
- binary is compiled with -g, some std functions like __start and _init
- are not, so they still will follow one of the following choices.
- 2) Function is compiled without -g and binary hasn't been stripped in
- any way. In this case GDB still has enough information to evaluate
- frame code_addr properly. This case is covered by call to
- get_frame_func ().
- 3) Binary has been striped with option -g (strip debug symbols). In
- this case there is still enough symbols for get_frame_func () to work
- properly, so this case is also covered by it.
- 4) Binary has been striped with option -s (strip all symbols). In this
- case GDB cannot get function start address properly, so we return current
- PC value instead.
- */
- CORE_ADDR code_addr = get_frame_func (this_frame);
- if (code_addr == 0)
- code_addr = get_frame_register_unsigned (this_frame,
- gdbarch_pc_regnum (gdbarch));
- *this_id = frame_id_build (stack_addr, code_addr);
- }
- /* Implement the "prev_register" frame_unwind method. */
- static struct value *
- arc_frame_prev_register (struct frame_info *this_frame,
- void **this_cache, int regnum)
- {
- if (*this_cache == NULL)
- *this_cache = arc_make_frame_cache (this_frame);
- struct arc_frame_cache *cache = (struct arc_frame_cache *) (*this_cache);
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- /* If we are asked to unwind the PC, then we need to return BLINK instead:
- the saved value of PC points into this frame's function's prologue, not
- the next frame's function's resume location. */
- if (regnum == gdbarch_pc_regnum (gdbarch))
- regnum = ARC_BLINK_REGNUM;
- /* SP is a special case - we should return prev_sp, because
- trad_frame_get_prev_register will return _current_ SP value.
- Alternatively we could have stored cache->prev_sp in the cache->saved
- regs, but here we follow the lead of AArch64, ARM and Xtensa and will
- leave that logic in this function, instead of prologue analyzers. That I
- think is a bit more clear as `saved_regs` should contain saved regs, not
- computable.
- Because value has been computed, "got_constant" should be used, so that
- returned value will be a "not_lval" - immutable. */
- if (regnum == gdbarch_sp_regnum (gdbarch))
- return frame_unwind_got_constant (this_frame, regnum, cache->prev_sp);
- return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
- }
- /* Implement the "init_reg" dwarf2_frame method. */
- static void
- arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg,
- struct frame_info *info)
- {
- if (regnum == gdbarch_pc_regnum (gdbarch))
- /* The return address column. */
- reg->how = DWARF2_FRAME_REG_RA;
- else if (regnum == gdbarch_sp_regnum (gdbarch))
- /* The call frame address. */
- reg->how = DWARF2_FRAME_REG_CFA;
- }
- /* Signal trampoline frame unwinder. Allows frame unwinding to happen
- from within signal handlers. */
- static struct arc_frame_cache *
- arc_make_sigtramp_frame_cache (struct frame_info *this_frame)
- {
- arc_debug_printf ("called");
- gdbarch *arch = get_frame_arch (this_frame);
- arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (arch);
- /* Allocate new frame cache instance and space for saved register info. */
- struct arc_frame_cache *cache = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache);
- cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- /* Get the stack pointer and use it as the frame base. */
- cache->prev_sp = arc_frame_base_address (this_frame, NULL);
- /* If the ARC-private target-dependent info doesn't have a table of
- offsets of saved register contents within an OS signal context
- structure, then there is nothing to analyze. */
- if (tdep->sc_reg_offset == NULL)
- return cache;
- /* Find the address of the sigcontext structure. */
- CORE_ADDR addr = tdep->sigcontext_addr (this_frame);
- /* For each register, if its contents have been saved within the
- sigcontext structure, determine the address of those contents. */
- gdb_assert (tdep->sc_num_regs <= (ARC_LAST_REGNUM + 1));
- for (int i = 0; i < tdep->sc_num_regs; i++)
- {
- if (tdep->sc_reg_offset[i] != ARC_OFFSET_NO_REGISTER)
- cache->saved_regs[i].set_addr (addr + tdep->sc_reg_offset[i]);
- }
- return cache;
- }
- /* Implement the "this_id" frame_unwind method for signal trampoline
- frames. */
- static void
- arc_sigtramp_frame_this_id (struct frame_info *this_frame,
- void **this_cache, struct frame_id *this_id)
- {
- arc_debug_printf ("called");
- if (*this_cache == NULL)
- *this_cache = arc_make_sigtramp_frame_cache (this_frame);
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
- CORE_ADDR stack_addr = cache->prev_sp;
- CORE_ADDR code_addr
- = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch));
- *this_id = frame_id_build (stack_addr, code_addr);
- }
- /* Get a register from a signal handler frame. */
- static struct value *
- arc_sigtramp_frame_prev_register (struct frame_info *this_frame,
- void **this_cache, int regnum)
- {
- arc_debug_printf ("regnum = %d", regnum);
- /* Make sure we've initialized the cache. */
- if (*this_cache == NULL)
- *this_cache = arc_make_sigtramp_frame_cache (this_frame);
- struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
- return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
- }
- /* Frame sniffer for signal handler frame. Only recognize a frame if we
- have a sigcontext_addr handler in the target dependency. */
- static int
- arc_sigtramp_frame_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame,
- void **this_cache)
- {
- arc_debug_printf ("called");
- gdbarch *arch = get_frame_arch (this_frame);
- arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (arch);
- /* If we have a sigcontext_addr handler, then just return 1 (same as the
- "default_frame_sniffer ()"). */
- return (tdep->sigcontext_addr != NULL && tdep->is_sigtramp != NULL
- && tdep->is_sigtramp (this_frame));
- }
- /* Structure defining the ARC ordinary frame unwind functions. Since we are
- the fallback unwinder, we use the default frame sniffer, which always
- accepts the frame. */
- static const struct frame_unwind arc_frame_unwind = {
- "arc prologue",
- NORMAL_FRAME,
- default_frame_unwind_stop_reason,
- arc_frame_this_id,
- arc_frame_prev_register,
- NULL,
- default_frame_sniffer,
- NULL,
- NULL
- };
- /* Structure defining the ARC signal frame unwind functions. Custom
- sniffer is used, because this frame must be accepted only in the right
- context. */
- static const struct frame_unwind arc_sigtramp_frame_unwind = {
- "arc sigtramp",
- SIGTRAMP_FRAME,
- default_frame_unwind_stop_reason,
- arc_sigtramp_frame_this_id,
- arc_sigtramp_frame_prev_register,
- NULL,
- arc_sigtramp_frame_sniffer,
- NULL,
- NULL
- };
- static const struct frame_base arc_normal_base = {
- &arc_frame_unwind,
- arc_frame_base_address,
- arc_frame_base_address,
- arc_frame_base_address
- };
- static enum arc_isa
- mach_type_to_arc_isa (const unsigned long mach)
- {
- switch (mach)
- {
- case bfd_mach_arc_arc600:
- case bfd_mach_arc_arc601:
- case bfd_mach_arc_arc700:
- return ARC_ISA_ARCV1;
- case bfd_mach_arc_arcv2:
- return ARC_ISA_ARCV2;
- default:
- internal_error (__FILE__, __LINE__,
- _("unknown machine id %lu"), mach);
- }
- }
- /* See arc-tdep.h. */
- arc_arch_features
- arc_arch_features_create (const bfd *abfd, const unsigned long mach)
- {
- /* Use 4 as a fallback value. */
- int reg_size = 4;
- /* Try to guess the features parameters by looking at the binary to be
- executed. If the user is providing a binary that does not match the
- target, then tough luck. This is the last effort to makes sense of
- what's going on. */
- if (abfd != nullptr && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
- {
- unsigned char eclass = elf_elfheader (abfd)->e_ident[EI_CLASS];
- if (eclass == ELFCLASS32)
- reg_size = 4;
- else if (eclass == ELFCLASS64)
- reg_size = 8;
- else
- internal_error (__FILE__, __LINE__,
- _("unknown ELF header class %d"), eclass);
- }
- /* MACH from a bfd_arch_info struct is used here. It should be a safe
- bet, as it looks like the struct is always initialized even when we
- don't pass any elf file to GDB at all (it uses default arch in that
- case). */
- arc_isa isa = mach_type_to_arc_isa (mach);
- return arc_arch_features (reg_size, isa);
- }
- /* Look for obsolete core feature names in TDESC. */
- static const struct tdesc_feature *
- find_obsolete_core_names (const struct target_desc *tdesc)
- {
- const struct tdesc_feature *feat = nullptr;
- feat = tdesc_find_feature (tdesc, ARC_CORE_V1_OBSOLETE_FEATURE_NAME);
- if (feat == nullptr)
- feat = tdesc_find_feature (tdesc, ARC_CORE_V2_OBSOLETE_FEATURE_NAME);
- if (feat == nullptr)
- feat = tdesc_find_feature
- (tdesc, ARC_CORE_V2_REDUCED_OBSOLETE_FEATURE_NAME);
- return feat;
- }
- /* Look for obsolete aux feature names in TDESC. */
- static const struct tdesc_feature *
- find_obsolete_aux_names (const struct target_desc *tdesc)
- {
- return tdesc_find_feature (tdesc, ARC_AUX_OBSOLETE_FEATURE_NAME);
- }
- /* Based on the MACH value, determines which core register features set
- must be used. */
- static arc_register_feature *
- determine_core_reg_feature_set (const unsigned long mach)
- {
- switch (mach_type_to_arc_isa (mach))
- {
- case ARC_ISA_ARCV1:
- return &arc_v1_core_reg_feature;
- case ARC_ISA_ARCV2:
- return &arc_v2_core_reg_feature;
- default:
- gdb_assert_not_reached
- ("Unknown machine type to determine the core feature set.");
- }
- }
- /* At the moment, there is only 1 auxiliary register features set.
- This is a place holder for future extendability. */
- static const arc_register_feature *
- determine_aux_reg_feature_set ()
- {
- return &arc_common_aux_reg_feature;
- }
- /* Update accumulator register names (ACCH/ACCL) for r58 and r59 in the
- register sets. The endianness determines the assignment:
- ,------.------.
- | acch | accl |
- ,----|------+------|
- | LE | r59 | r58 |
- | BE | r58 | r59 |
- `----^------^------' */
- static void
- arc_update_acc_reg_names (const int byte_order)
- {
- const char *r58_alias
- = byte_order == BFD_ENDIAN_LITTLE ? "accl" : "acch";
- const char *r59_alias
- = byte_order == BFD_ENDIAN_LITTLE ? "acch" : "accl";
- /* Subscript 1 must be OK because those registers have 2 names. */
- arc_v1_core_reg_feature.registers[ARC_R58_REGNUM].names[1] = r58_alias;
- arc_v1_core_reg_feature.registers[ARC_R59_REGNUM].names[1] = r59_alias;
- arc_v2_core_reg_feature.registers[ARC_R58_REGNUM].names[1] = r58_alias;
- arc_v2_core_reg_feature.registers[ARC_R59_REGNUM].names[1] = r59_alias;
- }
- /* Go through all the registers in REG_SET and check if they exist
- in FEATURE. The TDESC_DATA is updated with the register number
- in REG_SET if it is found in the feature. If a required register
- is not found, this function returns false. */
- static bool
- arc_check_tdesc_feature (struct tdesc_arch_data *tdesc_data,
- const struct tdesc_feature *feature,
- const struct arc_register_feature *reg_set)
- {
- for (const auto ® : reg_set->registers)
- {
- bool found = false;
- for (const char *name : reg.names)
- {
- found
- = tdesc_numbered_register (feature, tdesc_data, reg.regnum, name);
- if (found)
- break;
- }
- if (!found && reg.required_p)
- {
- std::ostringstream reg_names;
- for (std::size_t i = 0; i < reg.names.size(); ++i)
- {
- if (i == 0)
- reg_names << "'" << reg.names[0] << "'";
- else
- reg_names << " or '" << reg.names[0] << "'";
- }
- arc_print (_("Error: Cannot find required register(s) %s "
- "in feature '%s'.\n"), reg_names.str ().c_str (),
- feature->name.c_str ());
- return false;
- }
- }
- return true;
- }
- /* Check for the existance of "lp_start" and "lp_end" in target description.
- If both are present, assume there is hardware loop support in the target.
- This can be improved by looking into "lpc_size" field of "isa_config"
- auxiliary register. */
- static bool
- arc_check_for_hw_loops (const struct target_desc *tdesc,
- struct tdesc_arch_data *data)
- {
- const auto feature_aux = tdesc_find_feature (tdesc, ARC_AUX_FEATURE_NAME);
- const auto aux_regset = determine_aux_reg_feature_set ();
- if (feature_aux == nullptr)
- return false;
- bool hw_loop_p = false;
- const auto lp_start_name =
- aux_regset->registers[ARC_LP_START_REGNUM - ARC_FIRST_AUX_REGNUM].names[0];
- const auto lp_end_name =
- aux_regset->registers[ARC_LP_END_REGNUM - ARC_FIRST_AUX_REGNUM].names[0];
- hw_loop_p = tdesc_numbered_register (feature_aux, data,
- ARC_LP_START_REGNUM, lp_start_name);
- hw_loop_p &= tdesc_numbered_register (feature_aux, data,
- ARC_LP_END_REGNUM, lp_end_name);
- return hw_loop_p;
- }
- /* Initialize target description for the ARC.
- Returns true if input TDESC was valid and in this case it will assign TDESC
- and TDESC_DATA output parameters. */
- static bool
- arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
- tdesc_arch_data_up *tdesc_data)
- {
- const struct target_desc *tdesc_loc = info.target_desc;
- arc_debug_printf ("Target description initialization.");
- /* If target doesn't provide a description, use the default ones. */
- if (!tdesc_has_registers (tdesc_loc))
- {
- arc_arch_features features
- = arc_arch_features_create (info.abfd,
- info.bfd_arch_info->mach);
- tdesc_loc = arc_lookup_target_description (features);
- }
- gdb_assert (tdesc_loc != nullptr);
- arc_debug_printf ("Have got a target description");
- const struct tdesc_feature *feature_core
- = tdesc_find_feature (tdesc_loc, ARC_CORE_FEATURE_NAME);
- const struct tdesc_feature *feature_aux
- = tdesc_find_feature (tdesc_loc, ARC_AUX_FEATURE_NAME);
- /* Maybe there still is a chance to salvage the input. */
- if (feature_core == nullptr)
- feature_core = find_obsolete_core_names (tdesc_loc);
- if (feature_aux == nullptr)
- feature_aux = find_obsolete_aux_names (tdesc_loc);
- if (feature_core == nullptr)
- {
- arc_print (_("Error: Cannot find required feature '%s' in supplied "
- "target description.\n"), ARC_CORE_FEATURE_NAME);
- return false;
- }
- if (feature_aux == nullptr)
- {
- arc_print (_("Error: Cannot find required feature '%s' in supplied "
- "target description.\n"), ARC_AUX_FEATURE_NAME);
- return false;
- }
- const arc_register_feature *arc_core_reg_feature
- = determine_core_reg_feature_set (info.bfd_arch_info->mach);
- const arc_register_feature *arc_aux_reg_feature
- = determine_aux_reg_feature_set ();
- tdesc_arch_data_up tdesc_data_loc = tdesc_data_alloc ();
- arc_update_acc_reg_names (info.byte_order);
- bool valid_p = arc_check_tdesc_feature (tdesc_data_loc.get (),
- feature_core,
- arc_core_reg_feature);
- valid_p &= arc_check_tdesc_feature (tdesc_data_loc.get (),
- feature_aux,
- arc_aux_reg_feature);
- if (!valid_p)
- {
- arc_debug_printf ("Target description is not valid");
- return false;
- }
- *tdesc = tdesc_loc;
- *tdesc_data = std::move (tdesc_data_loc);
- return true;
- }
- /* Implement the type_align gdbarch function. */
- static ULONGEST
- arc_type_align (struct gdbarch *gdbarch, struct type *type)
- {
- switch (type->code ())
- {
- case TYPE_CODE_PTR:
- case TYPE_CODE_FUNC:
- case TYPE_CODE_FLAGS:
- case TYPE_CODE_INT:
- case TYPE_CODE_RANGE:
- case TYPE_CODE_FLT:
- case TYPE_CODE_ENUM:
- case TYPE_CODE_REF:
- case TYPE_CODE_RVALUE_REF:
- case TYPE_CODE_CHAR:
- case TYPE_CODE_BOOL:
- case TYPE_CODE_DECFLOAT:
- case TYPE_CODE_METHODPTR:
- case TYPE_CODE_MEMBERPTR:
- type = check_typedef (type);
- return std::min<ULONGEST> (4, TYPE_LENGTH (type));
- default:
- return 0;
- }
- }
- /* Implement the "init" gdbarch method. */
- static struct gdbarch *
- arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
- {
- const struct target_desc *tdesc;
- tdesc_arch_data_up tdesc_data;
- arc_debug_printf ("Architecture initialization.");
- if (!arc_tdesc_init (info, &tdesc, &tdesc_data))
- return nullptr;
- /* Allocate the ARC-private target-dependent information structure, and the
- GDB target-independent information structure. */
- std::unique_ptr<arc_gdbarch_tdep> tdep_holder (new arc_gdbarch_tdep);
- arc_gdbarch_tdep *tdep = tdep_holder.get ();
- tdep->jb_pc = -1; /* No longjmp support by default. */
- tdep->has_hw_loops = arc_check_for_hw_loops (tdesc, tdesc_data.get ());
- struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep_holder.release ());
- /* Data types. */
- set_gdbarch_short_bit (gdbarch, 16);
- set_gdbarch_int_bit (gdbarch, 32);
- set_gdbarch_long_bit (gdbarch, 32);
- set_gdbarch_long_long_bit (gdbarch, 64);
- set_gdbarch_type_align (gdbarch, arc_type_align);
- set_gdbarch_float_bit (gdbarch, 32);
- set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
- set_gdbarch_double_bit (gdbarch, 64);
- set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
- set_gdbarch_ptr_bit (gdbarch, 32);
- set_gdbarch_addr_bit (gdbarch, 32);
- set_gdbarch_char_signed (gdbarch, 0);
- set_gdbarch_write_pc (gdbarch, arc_write_pc);
- set_gdbarch_virtual_frame_pointer (gdbarch, arc_virtual_frame_pointer);
- /* tdesc_use_registers expects gdbarch_num_regs to return number of registers
- parsed by gdbarch_init, and then it will add all of the remaining
- registers and will increase number of registers. */
- set_gdbarch_num_regs (gdbarch, ARC_LAST_REGNUM + 1);
- set_gdbarch_num_pseudo_regs (gdbarch, 0);
- set_gdbarch_sp_regnum (gdbarch, ARC_SP_REGNUM);
- set_gdbarch_pc_regnum (gdbarch, ARC_PC_REGNUM);
- set_gdbarch_ps_regnum (gdbarch, ARC_STATUS32_REGNUM);
- set_gdbarch_fp0_regnum (gdbarch, -1); /* No FPU registers. */
- set_gdbarch_push_dummy_call (gdbarch, arc_push_dummy_call);
- set_gdbarch_push_dummy_code (gdbarch, arc_push_dummy_code);
- set_gdbarch_cannot_fetch_register (gdbarch, arc_cannot_fetch_register);
- set_gdbarch_cannot_store_register (gdbarch, arc_cannot_store_register);
- set_gdbarch_believe_pcc_promotion (gdbarch, 1);
- set_gdbarch_return_value (gdbarch, arc_return_value);
- set_gdbarch_skip_prologue (gdbarch, arc_skip_prologue);
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- set_gdbarch_breakpoint_kind_from_pc (gdbarch, arc_breakpoint_kind_from_pc);
- set_gdbarch_sw_breakpoint_from_kind (gdbarch, arc_sw_breakpoint_from_kind);
- /* On ARC 600 BRK_S instruction advances PC, unlike other ARC cores. */
- if (!arc_mach_is_arc600 (gdbarch))
- set_gdbarch_decr_pc_after_break (gdbarch, 0);
- else
- set_gdbarch_decr_pc_after_break (gdbarch, 2);
- set_gdbarch_frame_align (gdbarch, arc_frame_align);
- set_gdbarch_print_insn (gdbarch, arc_delayed_print_insn);
- set_gdbarch_cannot_step_breakpoint (gdbarch, 1);
- /* "nonsteppable" watchpoint means that watchpoint triggers before
- instruction is committed, therefore it is required to remove watchpoint
- to step though instruction that triggers it. ARC watchpoints trigger
- only after instruction is committed, thus there is no need to remove
- them. In fact on ARC watchpoint for memory writes may trigger with more
- significant delay, like one or two instructions, depending on type of
- memory where write is performed (CCM or external) and next instruction
- after the memory write. */
- set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 0);
- /* This doesn't include possible long-immediate value. */
- set_gdbarch_max_insn_length (gdbarch, 4);
- /* Frame unwinders and sniffers. */
- dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg);
- dwarf2_append_unwinders (gdbarch);
- frame_unwind_append_unwinder (gdbarch, &arc_sigtramp_frame_unwind);
- frame_unwind_append_unwinder (gdbarch, &arc_frame_unwind);
- frame_base_set_default (gdbarch, &arc_normal_base);
- /* Setup stuff specific to a particular environment (baremetal or Linux).
- It can override functions set earlier. */
- gdbarch_init_osabi (info, gdbarch);
- if (tdep->jb_pc >= 0)
- set_gdbarch_get_longjmp_target (gdbarch, arc_get_longjmp_target);
- /* Disassembler options. Enforce CPU if it was specified in XML target
- description, otherwise use default method of determining CPU (ELF private
- header). */
- if (info.target_desc != NULL)
- {
- const struct bfd_arch_info *tdesc_arch
- = tdesc_architecture (info.target_desc);
- if (tdesc_arch != NULL)
- {
- xfree (arc_disassembler_options);
- /* FIXME: It is not really good to change disassembler options
- behind the scene, because that might override options
- specified by the user. However as of now ARC doesn't support
- `set disassembler-options' hence this code is the only place
- where options are changed. It also changes options for all
- existing gdbarches, which also can be problematic, if
- arc_gdbarch_init will start reusing existing gdbarch
- instances. */
- /* Target description specifies a BFD architecture, which is
- different from ARC cpu, as accepted by disassembler (and most
- other ARC tools), because cpu values are much more fine grained -
- there can be multiple cpu values per single BFD architecture. As
- a result this code should translate architecture to some cpu
- value. Since there is no info on exact cpu configuration, it is
- best to use the most feature-rich CPU, so that disassembler will
- recognize all instructions available to the specified
- architecture. */
- switch (tdesc_arch->mach)
- {
- case bfd_mach_arc_arc601:
- arc_disassembler_options = xstrdup ("cpu=arc601");
- break;
- case bfd_mach_arc_arc600:
- arc_disassembler_options = xstrdup ("cpu=arc600");
- break;
- case bfd_mach_arc_arc700:
- arc_disassembler_options = xstrdup ("cpu=arc700");
- break;
- case bfd_mach_arc_arcv2:
- /* Machine arcv2 has three arches: ARCv2, EM and HS; where ARCv2
- is treated as EM. */
- if (arc_arch_is_hs (tdesc_arch))
- arc_disassembler_options = xstrdup ("cpu=hs38_linux");
- else
- arc_disassembler_options = xstrdup ("cpu=em4_fpuda");
- break;
- default:
- arc_disassembler_options = NULL;
- break;
- }
- }
- }
- set_gdbarch_disassembler_options (gdbarch, &arc_disassembler_options);
- set_gdbarch_valid_disassembler_options (gdbarch,
- disassembler_options_arc ());
- tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
- return gdbarch;
- }
- /* Implement the "dump_tdep" gdbarch method. */
- static void
- arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
- {
- arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- gdb_printf (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc);
- gdb_printf (file, "arc_dump_tdep: is_sigtramp = <%s>\n",
- host_address_to_string (tdep->is_sigtramp));
- gdb_printf (file, "arc_dump_tdep: sigcontext_addr = <%s>\n",
- host_address_to_string (tdep->sigcontext_addr));
- gdb_printf (file, "arc_dump_tdep: sc_reg_offset = <%s>\n",
- host_address_to_string (tdep->sc_reg_offset));
- gdb_printf (file, "arc_dump_tdep: sc_num_regs = %d\n",
- tdep->sc_num_regs);
- }
- /* This command accepts single argument - address of instruction to
- disassemble. */
- static void
- dump_arc_instruction_command (const char *args, int from_tty)
- {
- struct value *val;
- if (args != NULL && strlen (args) > 0)
- val = evaluate_expression (parse_expression (args).get ());
- else
- val = access_value_history (0);
- record_latest_value (val);
- CORE_ADDR address = value_as_address (val);
- struct arc_instruction insn;
- struct disassemble_info di = arc_disassemble_info (target_gdbarch ());
- arc_insn_decode (address, &di, arc_delayed_print_insn, &insn);
- arc_insn_dump (insn);
- }
- void _initialize_arc_tdep ();
- void
- _initialize_arc_tdep ()
- {
- gdbarch_register (bfd_arch_arc, arc_gdbarch_init, arc_dump_tdep);
- /* Register ARC-specific commands with gdb. */
- /* Add root prefix command for "maintenance print arc" commands. */
- add_show_prefix_cmd ("arc", class_maintenance,
- _("ARC-specific maintenance commands for printing GDB "
- "internal state."),
- &maintenance_print_arc_list,
- 0, &maintenanceprintlist);
- add_cmd ("arc-instruction", class_maintenance,
- dump_arc_instruction_command,
- _("Dump arc_instruction structure for specified address."),
- &maintenance_print_arc_list);
- /* Debug internals for ARC GDB. */
- add_setshow_boolean_cmd ("arc", class_maintenance,
- &arc_debug,
- _("Set ARC specific debugging."),
- _("Show ARC specific debugging."),
- _("When set, ARC specific debugging is enabled."),
- NULL, NULL, &setdebuglist, &showdebuglist);
- }
|