1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135 |
- /* Target-dependent code for the RISC-V architecture, for GDB.
- Copyright (C) 2018-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "frame.h"
- #include "inferior.h"
- #include "symtab.h"
- #include "value.h"
- #include "gdbcmd.h"
- #include "language.h"
- #include "gdbcore.h"
- #include "symfile.h"
- #include "objfiles.h"
- #include "gdbtypes.h"
- #include "target.h"
- #include "arch-utils.h"
- #include "regcache.h"
- #include "osabi.h"
- #include "riscv-tdep.h"
- #include "block.h"
- #include "reggroups.h"
- #include "opcode/riscv.h"
- #include "elf/riscv.h"
- #include "elf-bfd.h"
- #include "symcat.h"
- #include "dis-asm.h"
- #include "frame-unwind.h"
- #include "frame-base.h"
- #include "trad-frame.h"
- #include "infcall.h"
- #include "floatformat.h"
- #include "remote.h"
- #include "target-descriptions.h"
- #include "dwarf2/frame.h"
- #include "user-regs.h"
- #include "valprint.h"
- #include "gdbsupport/common-defs.h"
- #include "opcode/riscv-opc.h"
- #include "cli/cli-decode.h"
- #include "observable.h"
- #include "prologue-value.h"
- #include "arch/riscv.h"
- #include "riscv-ravenscar-thread.h"
- /* The stack must be 16-byte aligned. */
- #define SP_ALIGNMENT 16
- /* The biggest alignment that the target supports. */
- #define BIGGEST_ALIGNMENT 16
- /* Define a series of is_XXX_insn functions to check if the value INSN
- is an instance of instruction XXX. */
- #define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \
- static inline bool is_ ## INSN_NAME ## _insn (long insn) \
- { \
- return (insn & INSN_MASK) == INSN_MATCH; \
- }
- #include "opcode/riscv-opc.h"
- #undef DECLARE_INSN
- /* When this is set to non-zero debugging information about breakpoint
- kinds will be printed. */
- static unsigned int riscv_debug_breakpoints = 0;
- /* When this is set to non-zero debugging information about inferior calls
- will be printed. */
- static unsigned int riscv_debug_infcall = 0;
- /* When this is set to non-zero debugging information about stack unwinding
- will be printed. */
- static unsigned int riscv_debug_unwinder = 0;
- /* When this is set to non-zero debugging information about gdbarch
- initialisation will be printed. */
- static unsigned int riscv_debug_gdbarch = 0;
- /* The names of the RISC-V target description features. */
- const char *riscv_feature_name_csr = "org.gnu.gdb.riscv.csr";
- static const char *riscv_feature_name_cpu = "org.gnu.gdb.riscv.cpu";
- static const char *riscv_feature_name_fpu = "org.gnu.gdb.riscv.fpu";
- static const char *riscv_feature_name_virtual = "org.gnu.gdb.riscv.virtual";
- static const char *riscv_feature_name_vector = "org.gnu.gdb.riscv.vector";
- /* The current set of options to be passed to the disassembler. */
- static char *riscv_disassembler_options;
- /* Cached information about a frame. */
- struct riscv_unwind_cache
- {
- /* The register from which we can calculate the frame base. This is
- usually $sp or $fp. */
- int frame_base_reg;
- /* The offset from the current value in register FRAME_BASE_REG to the
- actual frame base address. */
- int frame_base_offset;
- /* Information about previous register values. */
- trad_frame_saved_reg *regs;
- /* The id for this frame. */
- struct frame_id this_id;
- /* The base (stack) address for this frame. This is the stack pointer
- value on entry to this frame before any adjustments are made. */
- CORE_ADDR frame_base;
- };
- /* RISC-V specific register group for CSRs. */
- static const reggroup *csr_reggroup = nullptr;
- /* Callback function for user_reg_add. */
- static struct value *
- value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
- {
- const int *reg_p = (const int *) baton;
- return value_of_register (*reg_p, frame);
- }
- /* Information about a register alias that needs to be set up for this
- target. These are collected when the target's XML description is
- analysed, and then processed later, once the gdbarch has been created. */
- class riscv_pending_register_alias
- {
- public:
- /* Constructor. */
- riscv_pending_register_alias (const char *name, const void *baton)
- : m_name (name),
- m_baton (baton)
- { /* Nothing. */ }
- /* Convert this into a user register for GDBARCH. */
- void create (struct gdbarch *gdbarch) const
- {
- user_reg_add (gdbarch, m_name, value_of_riscv_user_reg, m_baton);
- }
- private:
- /* The name for this alias. */
- const char *m_name;
- /* The baton value for passing to user_reg_add. This must point to some
- data that will live for at least as long as the gdbarch object to
- which the user register is attached. */
- const void *m_baton;
- };
- /* A set of registers that we expect to find in a tdesc_feature. These
- are use in RISCV_GDBARCH_INIT when processing the target description. */
- struct riscv_register_feature
- {
- explicit riscv_register_feature (const char *feature_name)
- : m_feature_name (feature_name)
- { /* Delete. */ }
- riscv_register_feature () = delete;
- DISABLE_COPY_AND_ASSIGN (riscv_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 should use when describing this
- register. */
- std::vector<const char *> names;
- /* Look in FEATURE for a register with a name from this classes names
- list. If the register is found then register its number with
- TDESC_DATA and add all its aliases to the ALIASES list.
- PREFER_FIRST_NAME_P is used when deciding which aliases to create. */
- bool check (struct tdesc_arch_data *tdesc_data,
- const struct tdesc_feature *feature,
- bool prefer_first_name_p,
- std::vector<riscv_pending_register_alias> *aliases) const;
- };
- /* Return the name of this feature. */
- const char *name () const
- { return m_feature_name; }
- protected:
- /* Return a target description feature extracted from TDESC for this
- register feature. Will return nullptr if there is no feature in TDESC
- with the name M_FEATURE_NAME. */
- const struct tdesc_feature *tdesc_feature (const struct target_desc *tdesc) const
- {
- return tdesc_find_feature (tdesc, name ());
- }
- /* List of all the registers that we expect that we might find in this
- register set. */
- std::vector<struct register_info> m_registers;
- private:
- /* The name for this feature. This is the name used to find this feature
- within the target description. */
- const char *m_feature_name;
- };
- /* See description in the class declaration above. */
- bool
- riscv_register_feature::register_info::check
- (struct tdesc_arch_data *tdesc_data,
- const struct tdesc_feature *feature,
- bool prefer_first_name_p,
- std::vector<riscv_pending_register_alias> *aliases) const
- {
- for (const char *name : this->names)
- {
- bool found = tdesc_numbered_register (feature, tdesc_data,
- this->regnum, name);
- if (found)
- {
- /* We know that the target description mentions this
- register. In RISCV_REGISTER_NAME we ensure that GDB
- always uses the first name for each register, so here we
- add aliases for all of the remaining names. */
- int start_index = prefer_first_name_p ? 1 : 0;
- for (int i = start_index; i < this->names.size (); ++i)
- {
- const char *alias = this->names[i];
- if (alias == name && !prefer_first_name_p)
- continue;
- aliases->emplace_back (alias, (void *) &this->regnum);
- }
- return true;
- }
- }
- return false;
- }
- /* Class representing the x-registers feature set. */
- struct riscv_xreg_feature : public riscv_register_feature
- {
- riscv_xreg_feature ()
- : riscv_register_feature (riscv_feature_name_cpu)
- {
- m_registers = {
- { RISCV_ZERO_REGNUM + 0, { "zero", "x0" } },
- { RISCV_ZERO_REGNUM + 1, { "ra", "x1" } },
- { RISCV_ZERO_REGNUM + 2, { "sp", "x2" } },
- { RISCV_ZERO_REGNUM + 3, { "gp", "x3" } },
- { RISCV_ZERO_REGNUM + 4, { "tp", "x4" } },
- { RISCV_ZERO_REGNUM + 5, { "t0", "x5" } },
- { RISCV_ZERO_REGNUM + 6, { "t1", "x6" } },
- { RISCV_ZERO_REGNUM + 7, { "t2", "x7" } },
- { RISCV_ZERO_REGNUM + 8, { "fp", "x8", "s0" } },
- { RISCV_ZERO_REGNUM + 9, { "s1", "x9" } },
- { RISCV_ZERO_REGNUM + 10, { "a0", "x10" } },
- { RISCV_ZERO_REGNUM + 11, { "a1", "x11" } },
- { RISCV_ZERO_REGNUM + 12, { "a2", "x12" } },
- { RISCV_ZERO_REGNUM + 13, { "a3", "x13" } },
- { RISCV_ZERO_REGNUM + 14, { "a4", "x14" } },
- { RISCV_ZERO_REGNUM + 15, { "a5", "x15" } },
- { RISCV_ZERO_REGNUM + 16, { "a6", "x16" } },
- { RISCV_ZERO_REGNUM + 17, { "a7", "x17" } },
- { RISCV_ZERO_REGNUM + 18, { "s2", "x18" } },
- { RISCV_ZERO_REGNUM + 19, { "s3", "x19" } },
- { RISCV_ZERO_REGNUM + 20, { "s4", "x20" } },
- { RISCV_ZERO_REGNUM + 21, { "s5", "x21" } },
- { RISCV_ZERO_REGNUM + 22, { "s6", "x22" } },
- { RISCV_ZERO_REGNUM + 23, { "s7", "x23" } },
- { RISCV_ZERO_REGNUM + 24, { "s8", "x24" } },
- { RISCV_ZERO_REGNUM + 25, { "s9", "x25" } },
- { RISCV_ZERO_REGNUM + 26, { "s10", "x26" } },
- { RISCV_ZERO_REGNUM + 27, { "s11", "x27" } },
- { RISCV_ZERO_REGNUM + 28, { "t3", "x28" } },
- { RISCV_ZERO_REGNUM + 29, { "t4", "x29" } },
- { RISCV_ZERO_REGNUM + 30, { "t5", "x30" } },
- { RISCV_ZERO_REGNUM + 31, { "t6", "x31" } },
- { RISCV_ZERO_REGNUM + 32, { "pc" } }
- };
- }
- /* Return the preferred name for the register with gdb register number
- REGNUM, which must be in the inclusive range RISCV_ZERO_REGNUM to
- RISCV_PC_REGNUM. */
- const char *register_name (int regnum) const
- {
- gdb_assert (regnum >= RISCV_ZERO_REGNUM && regnum <= m_registers.size ());
- return m_registers[regnum].names[0];
- }
- /* Check this feature within TDESC, record the registers from this
- feature into TDESC_DATA and update ALIASES and FEATURES. */
- bool check (const struct target_desc *tdesc,
- struct tdesc_arch_data *tdesc_data,
- std::vector<riscv_pending_register_alias> *aliases,
- struct riscv_gdbarch_features *features) const
- {
- const struct tdesc_feature *feature_cpu = tdesc_feature (tdesc);
- if (feature_cpu == nullptr)
- return false;
- bool seen_an_optional_reg_p = false;
- for (const auto ® : m_registers)
- {
- bool found = reg.check (tdesc_data, feature_cpu, true, aliases);
- bool is_optional_reg_p = (reg.regnum >= RISCV_ZERO_REGNUM + 16
- && reg.regnum < RISCV_ZERO_REGNUM + 32);
- if (!found && (!is_optional_reg_p || seen_an_optional_reg_p))
- return false;
- else if (found && is_optional_reg_p)
- seen_an_optional_reg_p = true;
- }
- /* Check that all of the core cpu registers have the same bitsize. */
- int xlen_bitsize = tdesc_register_bitsize (feature_cpu, "pc");
- bool valid_p = true;
- for (auto &tdesc_reg : feature_cpu->registers)
- valid_p &= (tdesc_reg->bitsize == xlen_bitsize);
- features->xlen = (xlen_bitsize / 8);
- features->embedded = !seen_an_optional_reg_p;
- return valid_p;
- }
- };
- /* An instance of the x-register feature set. */
- static const struct riscv_xreg_feature riscv_xreg_feature;
- /* Class representing the f-registers feature set. */
- struct riscv_freg_feature : public riscv_register_feature
- {
- riscv_freg_feature ()
- : riscv_register_feature (riscv_feature_name_fpu)
- {
- m_registers = {
- { RISCV_FIRST_FP_REGNUM + 0, { "ft0", "f0" } },
- { RISCV_FIRST_FP_REGNUM + 1, { "ft1", "f1" } },
- { RISCV_FIRST_FP_REGNUM + 2, { "ft2", "f2" } },
- { RISCV_FIRST_FP_REGNUM + 3, { "ft3", "f3" } },
- { RISCV_FIRST_FP_REGNUM + 4, { "ft4", "f4" } },
- { RISCV_FIRST_FP_REGNUM + 5, { "ft5", "f5" } },
- { RISCV_FIRST_FP_REGNUM + 6, { "ft6", "f6" } },
- { RISCV_FIRST_FP_REGNUM + 7, { "ft7", "f7" } },
- { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8" } },
- { RISCV_FIRST_FP_REGNUM + 9, { "fs1", "f9" } },
- { RISCV_FIRST_FP_REGNUM + 10, { "fa0", "f10" } },
- { RISCV_FIRST_FP_REGNUM + 11, { "fa1", "f11" } },
- { RISCV_FIRST_FP_REGNUM + 12, { "fa2", "f12" } },
- { RISCV_FIRST_FP_REGNUM + 13, { "fa3", "f13" } },
- { RISCV_FIRST_FP_REGNUM + 14, { "fa4", "f14" } },
- { RISCV_FIRST_FP_REGNUM + 15, { "fa5", "f15" } },
- { RISCV_FIRST_FP_REGNUM + 16, { "fa6", "f16" } },
- { RISCV_FIRST_FP_REGNUM + 17, { "fa7", "f17" } },
- { RISCV_FIRST_FP_REGNUM + 18, { "fs2", "f18" } },
- { RISCV_FIRST_FP_REGNUM + 19, { "fs3", "f19" } },
- { RISCV_FIRST_FP_REGNUM + 20, { "fs4", "f20" } },
- { RISCV_FIRST_FP_REGNUM + 21, { "fs5", "f21" } },
- { RISCV_FIRST_FP_REGNUM + 22, { "fs6", "f22" } },
- { RISCV_FIRST_FP_REGNUM + 23, { "fs7", "f23" } },
- { RISCV_FIRST_FP_REGNUM + 24, { "fs8", "f24" } },
- { RISCV_FIRST_FP_REGNUM + 25, { "fs9", "f25" } },
- { RISCV_FIRST_FP_REGNUM + 26, { "fs10", "f26" } },
- { RISCV_FIRST_FP_REGNUM + 27, { "fs11", "f27" } },
- { RISCV_FIRST_FP_REGNUM + 28, { "ft8", "f28" } },
- { RISCV_FIRST_FP_REGNUM + 29, { "ft9", "f29" } },
- { RISCV_FIRST_FP_REGNUM + 30, { "ft10", "f30" } },
- { RISCV_FIRST_FP_REGNUM + 31, { "ft11", "f31" } },
- { RISCV_CSR_FFLAGS_REGNUM, { "fflags", "csr1" } },
- { RISCV_CSR_FRM_REGNUM, { "frm", "csr2" } },
- { RISCV_CSR_FCSR_REGNUM, { "fcsr", "csr3" } },
- };
- }
- /* Return the preferred name for the register with gdb register number
- REGNUM, which must be in the inclusive range RISCV_FIRST_FP_REGNUM to
- RISCV_LAST_FP_REGNUM. */
- const char *register_name (int regnum) const
- {
- gdb_static_assert (RISCV_LAST_FP_REGNUM == RISCV_FIRST_FP_REGNUM + 31);
- gdb_assert (regnum >= RISCV_FIRST_FP_REGNUM
- && regnum <= RISCV_LAST_FP_REGNUM);
- regnum -= RISCV_FIRST_FP_REGNUM;
- return m_registers[regnum].names[0];
- }
- /* Check this feature within TDESC, record the registers from this
- feature into TDESC_DATA and update ALIASES and FEATURES. */
- bool check (const struct target_desc *tdesc,
- struct tdesc_arch_data *tdesc_data,
- std::vector<riscv_pending_register_alias> *aliases,
- struct riscv_gdbarch_features *features) const
- {
- const struct tdesc_feature *feature_fpu = tdesc_feature (tdesc);
- /* It's fine if this feature is missing. Update the architecture
- feature set and return. */
- if (feature_fpu == nullptr)
- {
- features->flen = 0;
- return true;
- }
- /* Check all of the floating pointer registers are present. We also
- check that the floating point CSRs are present too, though if these
- are missing this is not fatal. */
- for (const auto ® : m_registers)
- {
- bool found = reg.check (tdesc_data, feature_fpu, true, aliases);
- bool is_ctrl_reg_p = reg.regnum > RISCV_LAST_FP_REGNUM;
- if (!found && !is_ctrl_reg_p)
- return false;
- }
- /* Look through all of the floating point registers (not the FP CSRs
- though), and check they all have the same bitsize. Use this bitsize
- to update the feature set for this gdbarch. */
- int fp_bitsize = -1;
- for (const auto ® : m_registers)
- {
- /* Stop once we get to the CSRs which are at the end of the
- M_REGISTERS list. */
- if (reg.regnum > RISCV_LAST_FP_REGNUM)
- break;
- int reg_bitsize = -1;
- for (const char *name : reg.names)
- {
- if (tdesc_unnumbered_register (feature_fpu, name))
- {
- reg_bitsize = tdesc_register_bitsize (feature_fpu, name);
- break;
- }
- }
- gdb_assert (reg_bitsize != -1);
- if (fp_bitsize == -1)
- fp_bitsize = reg_bitsize;
- else if (fp_bitsize != reg_bitsize)
- return false;
- }
- features->flen = (fp_bitsize / 8);
- return true;
- }
- };
- /* An instance of the f-register feature set. */
- static const struct riscv_freg_feature riscv_freg_feature;
- /* Class representing the virtual registers. These are not physical
- registers on the hardware, but might be available from the target.
- These are not pseudo registers, reading these really does result in a
- register read from the target, it is just that there might not be a
- physical register backing the result. */
- struct riscv_virtual_feature : public riscv_register_feature
- {
- riscv_virtual_feature ()
- : riscv_register_feature (riscv_feature_name_virtual)
- {
- m_registers = {
- { RISCV_PRIV_REGNUM, { "priv" } }
- };
- }
- bool check (const struct target_desc *tdesc,
- struct tdesc_arch_data *tdesc_data,
- std::vector<riscv_pending_register_alias> *aliases,
- struct riscv_gdbarch_features *features) const
- {
- const struct tdesc_feature *feature_virtual = tdesc_feature (tdesc);
- /* It's fine if this feature is missing. */
- if (feature_virtual == nullptr)
- return true;
- /* We don't check the return value from the call to check here, all the
- registers in this feature are optional. */
- for (const auto ® : m_registers)
- reg.check (tdesc_data, feature_virtual, true, aliases);
- return true;
- }
- };
- /* An instance of the virtual register feature. */
- static const struct riscv_virtual_feature riscv_virtual_feature;
- /* Class representing the CSR feature. */
- struct riscv_csr_feature : public riscv_register_feature
- {
- riscv_csr_feature ()
- : riscv_register_feature (riscv_feature_name_csr)
- {
- m_registers = {
- #define DECLARE_CSR(NAME,VALUE,CLASS,DEFINE_VER,ABORT_VER) \
- { RISCV_ ## VALUE ## _REGNUM, { # NAME } },
- #include "opcode/riscv-opc.h"
- #undef DECLARE_CSR
- };
- riscv_create_csr_aliases ();
- }
- bool check (const struct target_desc *tdesc,
- struct tdesc_arch_data *tdesc_data,
- std::vector<riscv_pending_register_alias> *aliases,
- struct riscv_gdbarch_features *features) const
- {
- const struct tdesc_feature *feature_csr = tdesc_feature (tdesc);
- /* It's fine if this feature is missing. */
- if (feature_csr == nullptr)
- return true;
- /* We don't check the return value from the call to check here, all the
- registers in this feature are optional. */
- for (const auto ® : m_registers)
- reg.check (tdesc_data, feature_csr, true, aliases);
- return true;
- }
- private:
- /* Complete RISCV_CSR_FEATURE, building the CSR alias names and adding them
- to the name list for each register. */
- void
- riscv_create_csr_aliases ()
- {
- for (auto ® : m_registers)
- {
- int csr_num = reg.regnum - RISCV_FIRST_CSR_REGNUM;
- gdb::unique_xmalloc_ptr<char> alias = xstrprintf ("csr%d", csr_num);
- reg.names.push_back (alias.release ());
- }
- }
- };
- /* An instance of the csr register feature. */
- static const struct riscv_csr_feature riscv_csr_feature;
- /* Class representing the v-registers feature set. */
- struct riscv_vector_feature : public riscv_register_feature
- {
- riscv_vector_feature ()
- : riscv_register_feature (riscv_feature_name_vector)
- {
- m_registers = {
- { RISCV_V0_REGNUM + 0, { "v0" } },
- { RISCV_V0_REGNUM + 1, { "v1" } },
- { RISCV_V0_REGNUM + 2, { "v2" } },
- { RISCV_V0_REGNUM + 3, { "v3" } },
- { RISCV_V0_REGNUM + 4, { "v4" } },
- { RISCV_V0_REGNUM + 5, { "v5" } },
- { RISCV_V0_REGNUM + 6, { "v6" } },
- { RISCV_V0_REGNUM + 7, { "v7" } },
- { RISCV_V0_REGNUM + 8, { "v8" } },
- { RISCV_V0_REGNUM + 9, { "v9" } },
- { RISCV_V0_REGNUM + 10, { "v10" } },
- { RISCV_V0_REGNUM + 11, { "v11" } },
- { RISCV_V0_REGNUM + 12, { "v12" } },
- { RISCV_V0_REGNUM + 13, { "v13" } },
- { RISCV_V0_REGNUM + 14, { "v14" } },
- { RISCV_V0_REGNUM + 15, { "v15" } },
- { RISCV_V0_REGNUM + 16, { "v16" } },
- { RISCV_V0_REGNUM + 17, { "v17" } },
- { RISCV_V0_REGNUM + 18, { "v18" } },
- { RISCV_V0_REGNUM + 19, { "v19" } },
- { RISCV_V0_REGNUM + 20, { "v20" } },
- { RISCV_V0_REGNUM + 21, { "v21" } },
- { RISCV_V0_REGNUM + 22, { "v22" } },
- { RISCV_V0_REGNUM + 23, { "v23" } },
- { RISCV_V0_REGNUM + 24, { "v24" } },
- { RISCV_V0_REGNUM + 25, { "v25" } },
- { RISCV_V0_REGNUM + 26, { "v26" } },
- { RISCV_V0_REGNUM + 27, { "v27" } },
- { RISCV_V0_REGNUM + 28, { "v28" } },
- { RISCV_V0_REGNUM + 29, { "v29" } },
- { RISCV_V0_REGNUM + 30, { "v30" } },
- { RISCV_V0_REGNUM + 31, { "v31" } },
- };
- }
- /* Return the preferred name for the register with gdb register number
- REGNUM, which must be in the inclusive range RISCV_V0_REGNUM to
- RISCV_V0_REGNUM + 31. */
- const char *register_name (int regnum) const
- {
- gdb_assert (regnum >= RISCV_V0_REGNUM
- && regnum <= RISCV_V0_REGNUM + 31);
- regnum -= RISCV_V0_REGNUM;
- return m_registers[regnum].names[0];
- }
- /* Check this feature within TDESC, record the registers from this
- feature into TDESC_DATA and update ALIASES and FEATURES. */
- bool check (const struct target_desc *tdesc,
- struct tdesc_arch_data *tdesc_data,
- std::vector<riscv_pending_register_alias> *aliases,
- struct riscv_gdbarch_features *features) const
- {
- const struct tdesc_feature *feature_vector = tdesc_feature (tdesc);
- /* It's fine if this feature is missing. Update the architecture
- feature set and return. */
- if (feature_vector == nullptr)
- {
- features->vlen = 0;
- return true;
- }
- /* Check all of the vector registers are present. */
- for (const auto ® : m_registers)
- {
- if (!reg.check (tdesc_data, feature_vector, true, aliases))
- return false;
- }
- /* Look through all of the vector registers and check they all have the
- same bitsize. Use this bitsize to update the feature set for this
- gdbarch. */
- int vector_bitsize = -1;
- for (const auto ® : m_registers)
- {
- int reg_bitsize = -1;
- for (const char *name : reg.names)
- {
- if (tdesc_unnumbered_register (feature_vector, name))
- {
- reg_bitsize = tdesc_register_bitsize (feature_vector, name);
- break;
- }
- }
- gdb_assert (reg_bitsize != -1);
- if (vector_bitsize == -1)
- vector_bitsize = reg_bitsize;
- else if (vector_bitsize != reg_bitsize)
- return false;
- }
- features->vlen = (vector_bitsize / 8);
- return true;
- }
- };
- /* An instance of the v-register feature set. */
- static const struct riscv_vector_feature riscv_vector_feature;
- /* Controls whether we place compressed breakpoints or not. When in auto
- mode GDB tries to determine if the target supports compressed
- breakpoints, and uses them if it does. */
- static enum auto_boolean use_compressed_breakpoints;
- /* The show callback for 'show riscv use-compressed-breakpoints'. */
- static void
- show_use_compressed_breakpoints (struct ui_file *file, int from_tty,
- struct cmd_list_element *c,
- const char *value)
- {
- gdb_printf (file,
- _("Debugger's use of compressed breakpoints is set "
- "to %s.\n"), value);
- }
- /* The set and show lists for 'set riscv' and 'show riscv' prefixes. */
- static struct cmd_list_element *setriscvcmdlist = NULL;
- static struct cmd_list_element *showriscvcmdlist = NULL;
- /* The set and show lists for 'set riscv' and 'show riscv' prefixes. */
- static struct cmd_list_element *setdebugriscvcmdlist = NULL;
- static struct cmd_list_element *showdebugriscvcmdlist = NULL;
- /* The show callback for all 'show debug riscv VARNAME' variables. */
- static void
- show_riscv_debug_variable (struct ui_file *file, int from_tty,
- struct cmd_list_element *c,
- const char *value)
- {
- gdb_printf (file,
- _("RiscV debug variable `%s' is set to: %s\n"),
- c->name, value);
- }
- /* See riscv-tdep.h. */
- int
- riscv_isa_xlen (struct gdbarch *gdbarch)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- return tdep->isa_features.xlen;
- }
- /* See riscv-tdep.h. */
- int
- riscv_abi_xlen (struct gdbarch *gdbarch)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- return tdep->abi_features.xlen;
- }
- /* See riscv-tdep.h. */
- int
- riscv_isa_flen (struct gdbarch *gdbarch)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- return tdep->isa_features.flen;
- }
- /* See riscv-tdep.h. */
- int
- riscv_abi_flen (struct gdbarch *gdbarch)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- return tdep->abi_features.flen;
- }
- /* See riscv-tdep.h. */
- bool
- riscv_abi_embedded (struct gdbarch *gdbarch)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- return tdep->abi_features.embedded;
- }
- /* Return true if the target for GDBARCH has floating point hardware. */
- static bool
- riscv_has_fp_regs (struct gdbarch *gdbarch)
- {
- return (riscv_isa_flen (gdbarch) > 0);
- }
- /* Return true if GDBARCH is using any of the floating point hardware ABIs. */
- static bool
- riscv_has_fp_abi (struct gdbarch *gdbarch)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- return tdep->abi_features.flen > 0;
- }
- /* Return true if REGNO is a floating pointer register. */
- static bool
- riscv_is_fp_regno_p (int regno)
- {
- return (regno >= RISCV_FIRST_FP_REGNUM
- && regno <= RISCV_LAST_FP_REGNUM);
- }
- /* Implement the breakpoint_kind_from_pc gdbarch method. */
- static int
- riscv_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
- {
- if (use_compressed_breakpoints == AUTO_BOOLEAN_AUTO)
- {
- bool unaligned_p = false;
- gdb_byte buf[1];
- /* Some targets don't support unaligned reads. The address can only
- be unaligned if the C extension is supported. So it is safe to
- use a compressed breakpoint in this case. */
- if (*pcptr & 0x2)
- unaligned_p = true;
- else
- {
- /* Read the opcode byte to determine the instruction length. If
- the read fails this may be because we tried to set the
- breakpoint at an invalid address, in this case we provide a
- fake result which will give a breakpoint length of 4.
- Hopefully when we try to actually insert the breakpoint we
- will see a failure then too which will be reported to the
- user. */
- if (target_read_code (*pcptr, buf, 1) == -1)
- buf[0] = 0;
- }
- if (riscv_debug_breakpoints)
- {
- const char *bp = (unaligned_p || riscv_insn_length (buf[0]) == 2
- ? "C.EBREAK" : "EBREAK");
- gdb_printf (gdb_stdlog, "Using %s for breakpoint at %s ",
- bp, paddress (gdbarch, *pcptr));
- if (unaligned_p)
- gdb_printf (gdb_stdlog, "(unaligned address)\n");
- else
- gdb_printf (gdb_stdlog, "(instruction length %d)\n",
- riscv_insn_length (buf[0]));
- }
- if (unaligned_p || riscv_insn_length (buf[0]) == 2)
- return 2;
- else
- return 4;
- }
- else if (use_compressed_breakpoints == AUTO_BOOLEAN_TRUE)
- return 2;
- else
- return 4;
- }
- /* Implement the sw_breakpoint_from_kind gdbarch method. */
- static const gdb_byte *
- riscv_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
- {
- static const gdb_byte ebreak[] = { 0x73, 0x00, 0x10, 0x00, };
- static const gdb_byte c_ebreak[] = { 0x02, 0x90 };
- *size = kind;
- switch (kind)
- {
- case 2:
- return c_ebreak;
- case 4:
- return ebreak;
- default:
- gdb_assert_not_reached ("unhandled breakpoint kind");
- }
- }
- /* Implement the register_name gdbarch method. This is used instead of
- the function supplied by calling TDESC_USE_REGISTERS so that we can
- ensure the preferred names are offered for x-regs and f-regs. */
- static const char *
- riscv_register_name (struct gdbarch *gdbarch, int regnum)
- {
- /* Lookup the name through the target description. If we get back NULL
- then this is an unknown register. If we do get a name back then we
- look up the registers preferred name below. */
- const char *name = tdesc_register_name (gdbarch, regnum);
- if (name == NULL || name[0] == '\0')
- return NULL;
- /* We want GDB to use the ABI names for registers even if the target
- gives us a target description with the architectural name. For
- example we want to see 'ra' instead of 'x1' whatever the target
- description called it. */
- if (regnum >= RISCV_ZERO_REGNUM && regnum < RISCV_FIRST_FP_REGNUM)
- return riscv_xreg_feature.register_name (regnum);
- /* Like with the x-regs we prefer the abi names for the floating point
- registers. */
- if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
- {
- if (riscv_has_fp_regs (gdbarch))
- return riscv_freg_feature.register_name (regnum);
- else
- return NULL;
- }
- /* Some targets (QEMU) are reporting these three registers twice, once
- in the FPU feature, and once in the CSR feature. Both of these read
- the same underlying state inside the target, but naming the register
- twice in the target description results in GDB having two registers
- with the same name, only one of which can ever be accessed, but both
- will show up in 'info register all'. Unless, we identify the
- duplicate copies of these registers (in riscv_tdesc_unknown_reg) and
- then hide the registers here by giving them no name. */
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->duplicate_fflags_regnum == regnum)
- return NULL;
- if (tdep->duplicate_frm_regnum == regnum)
- return NULL;
- if (tdep->duplicate_fcsr_regnum == regnum)
- return NULL;
- /* The remaining registers are different. For all other registers on the
- machine we prefer to see the names that the target description
- provides. This is particularly important for CSRs which might be
- renamed over time. If GDB keeps track of the "latest" name, but a
- particular target provides an older name then we don't want to force
- users to see the newer name in register output.
- The other case that reaches here are any registers that the target
- provided that GDB is completely unaware of. For these we have no
- choice but to accept the target description name.
- Just accept whatever name TDESC_REGISTER_NAME returned. */
- return name;
- }
- /* Construct a type for 64-bit FP registers. */
- static struct type *
- riscv_fpreg_d_type (struct gdbarch *gdbarch)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->riscv_fpreg_d_type == nullptr)
- {
- const struct builtin_type *bt = builtin_type (gdbarch);
- /* The type we're building is this: */
- #if 0
- union __gdb_builtin_type_fpreg_d
- {
- float f;
- double d;
- };
- #endif
- struct type *t;
- t = arch_composite_type (gdbarch,
- "__gdb_builtin_type_fpreg_d", TYPE_CODE_UNION);
- append_composite_type_field (t, "float", bt->builtin_float);
- append_composite_type_field (t, "double", bt->builtin_double);
- t->set_is_vector (true);
- t->set_name ("builtin_type_fpreg_d");
- tdep->riscv_fpreg_d_type = t;
- }
- return tdep->riscv_fpreg_d_type;
- }
- /* Implement the register_type gdbarch method. This is installed as an
- for the override setup by TDESC_USE_REGISTERS, for most registers we
- delegate the type choice to the target description, but for a few
- registers we try to improve the types if the target description has
- taken a simplistic approach. */
- static struct type *
- riscv_register_type (struct gdbarch *gdbarch, int regnum)
- {
- struct type *type = tdesc_register_type (gdbarch, regnum);
- int xlen = riscv_isa_xlen (gdbarch);
- /* We want to perform some specific type "fixes" in cases where we feel
- that we really can do better than the target description. For all
- other cases we just return what the target description says. */
- if (riscv_is_fp_regno_p (regnum))
- {
- /* This spots the case for RV64 where the double is defined as
- either 'ieee_double' or 'float' (which is the generic name that
- converts to 'double' on 64-bit). In these cases its better to
- present the registers using a union type. */
- int flen = riscv_isa_flen (gdbarch);
- if (flen == 8
- && type->code () == TYPE_CODE_FLT
- && TYPE_LENGTH (type) == flen
- && (strcmp (type->name (), "builtin_type_ieee_double") == 0
- || strcmp (type->name (), "double") == 0))
- type = riscv_fpreg_d_type (gdbarch);
- }
- if ((regnum == gdbarch_pc_regnum (gdbarch)
- || regnum == RISCV_RA_REGNUM
- || regnum == RISCV_FP_REGNUM
- || regnum == RISCV_SP_REGNUM
- || regnum == RISCV_GP_REGNUM
- || regnum == RISCV_TP_REGNUM)
- && type->code () == TYPE_CODE_INT
- && TYPE_LENGTH (type) == xlen)
- {
- /* This spots the case where some interesting registers are defined
- as simple integers of the expected size, we force these registers
- to be pointers as we believe that is more useful. */
- if (regnum == gdbarch_pc_regnum (gdbarch)
- || regnum == RISCV_RA_REGNUM)
- type = builtin_type (gdbarch)->builtin_func_ptr;
- else if (regnum == RISCV_FP_REGNUM
- || regnum == RISCV_SP_REGNUM
- || regnum == RISCV_GP_REGNUM
- || regnum == RISCV_TP_REGNUM)
- type = builtin_type (gdbarch)->builtin_data_ptr;
- }
- return type;
- }
- /* Helper for riscv_print_registers_info, prints info for a single register
- REGNUM. */
- static void
- riscv_print_one_register_info (struct gdbarch *gdbarch,
- struct ui_file *file,
- struct frame_info *frame,
- int regnum)
- {
- const char *name = gdbarch_register_name (gdbarch, regnum);
- struct value *val;
- struct type *regtype;
- int print_raw_format;
- enum tab_stops { value_column_1 = 15 };
- gdb_puts (name, file);
- print_spaces (value_column_1 - strlen (name), file);
- try
- {
- val = value_of_register (regnum, frame);
- regtype = value_type (val);
- }
- catch (const gdb_exception_error &ex)
- {
- /* Handle failure to read a register without interrupting the entire
- 'info registers' flow. */
- gdb_printf (file, "%s\n", ex.what ());
- return;
- }
- print_raw_format = (value_entirely_available (val)
- && !value_optimized_out (val));
- if (regtype->code () == TYPE_CODE_FLT
- || (regtype->code () == TYPE_CODE_UNION
- && regtype->num_fields () == 2
- && regtype->field (0).type ()->code () == TYPE_CODE_FLT
- && regtype->field (1).type ()->code () == TYPE_CODE_FLT)
- || (regtype->code () == TYPE_CODE_UNION
- && regtype->num_fields () == 3
- && regtype->field (0).type ()->code () == TYPE_CODE_FLT
- && regtype->field (1).type ()->code () == TYPE_CODE_FLT
- && regtype->field (2).type ()->code () == TYPE_CODE_FLT))
- {
- struct value_print_options opts;
- const gdb_byte *valaddr = value_contents_for_printing (val).data ();
- enum bfd_endian byte_order = type_byte_order (regtype);
- get_user_print_options (&opts);
- opts.deref_ref = 1;
- common_val_print (val, file, 0, &opts, current_language);
- if (print_raw_format)
- {
- gdb_printf (file, "\t(raw ");
- print_hex_chars (file, valaddr, TYPE_LENGTH (regtype), byte_order,
- true);
- gdb_printf (file, ")");
- }
- }
- else
- {
- struct value_print_options opts;
- /* Print the register in hex. */
- get_formatted_print_options (&opts, 'x');
- opts.deref_ref = 1;
- common_val_print (val, file, 0, &opts, current_language);
- if (print_raw_format)
- {
- if (regnum == RISCV_CSR_MSTATUS_REGNUM)
- {
- LONGEST d;
- int size = register_size (gdbarch, regnum);
- unsigned xlen;
- /* The SD field is always in the upper bit of MSTATUS, regardless
- of the number of bits in MSTATUS. */
- d = value_as_long (val);
- xlen = size * 8;
- gdb_printf (file,
- "\tSD:%X VM:%02X MXR:%X PUM:%X MPRV:%X XS:%X "
- "FS:%X MPP:%x HPP:%X SPP:%X MPIE:%X HPIE:%X "
- "SPIE:%X UPIE:%X MIE:%X HIE:%X SIE:%X UIE:%X",
- (int) ((d >> (xlen - 1)) & 0x1),
- (int) ((d >> 24) & 0x1f),
- (int) ((d >> 19) & 0x1),
- (int) ((d >> 18) & 0x1),
- (int) ((d >> 17) & 0x1),
- (int) ((d >> 15) & 0x3),
- (int) ((d >> 13) & 0x3),
- (int) ((d >> 11) & 0x3),
- (int) ((d >> 9) & 0x3),
- (int) ((d >> 8) & 0x1),
- (int) ((d >> 7) & 0x1),
- (int) ((d >> 6) & 0x1),
- (int) ((d >> 5) & 0x1),
- (int) ((d >> 4) & 0x1),
- (int) ((d >> 3) & 0x1),
- (int) ((d >> 2) & 0x1),
- (int) ((d >> 1) & 0x1),
- (int) ((d >> 0) & 0x1));
- }
- else if (regnum == RISCV_CSR_MISA_REGNUM)
- {
- int base;
- unsigned xlen, i;
- LONGEST d;
- int size = register_size (gdbarch, regnum);
- /* The MXL field is always in the upper two bits of MISA,
- regardless of the number of bits in MISA. Mask out other
- bits to ensure we have a positive value. */
- d = value_as_long (val);
- base = (d >> ((size * 8) - 2)) & 0x3;
- xlen = 16;
- for (; base > 0; base--)
- xlen *= 2;
- gdb_printf (file, "\tRV%d", xlen);
- for (i = 0; i < 26; i++)
- {
- if (d & (1 << i))
- gdb_printf (file, "%c", 'A' + i);
- }
- }
- else if (regnum == RISCV_CSR_FCSR_REGNUM
- || regnum == RISCV_CSR_FFLAGS_REGNUM
- || regnum == RISCV_CSR_FRM_REGNUM)
- {
- LONGEST d;
- d = value_as_long (val);
- gdb_printf (file, "\t");
- if (regnum != RISCV_CSR_FRM_REGNUM)
- gdb_printf (file,
- "RD:%01X NV:%d DZ:%d OF:%d UF:%d NX:%d",
- (int) ((d >> 5) & 0x7),
- (int) ((d >> 4) & 0x1),
- (int) ((d >> 3) & 0x1),
- (int) ((d >> 2) & 0x1),
- (int) ((d >> 1) & 0x1),
- (int) ((d >> 0) & 0x1));
- if (regnum != RISCV_CSR_FFLAGS_REGNUM)
- {
- static const char * const sfrm[] =
- {
- "RNE (round to nearest; ties to even)",
- "RTZ (Round towards zero)",
- "RDN (Round down towards -INF)",
- "RUP (Round up towards +INF)",
- "RMM (Round to nearest; ties to max magnitude)",
- "INVALID[5]",
- "INVALID[6]",
- "dynamic rounding mode",
- };
- int frm = ((regnum == RISCV_CSR_FCSR_REGNUM)
- ? (d >> 5) : d) & 0x3;
- gdb_printf (file, "%sFRM:%i [%s]",
- (regnum == RISCV_CSR_FCSR_REGNUM
- ? " " : ""),
- frm, sfrm[frm]);
- }
- }
- else if (regnum == RISCV_PRIV_REGNUM)
- {
- LONGEST d;
- uint8_t priv;
- d = value_as_long (val);
- priv = d & 0xff;
- if (priv < 4)
- {
- static const char * const sprv[] =
- {
- "User/Application",
- "Supervisor",
- "Hypervisor",
- "Machine"
- };
- gdb_printf (file, "\tprv:%d [%s]",
- priv, sprv[priv]);
- }
- else
- gdb_printf (file, "\tprv:%d [INVALID]", priv);
- }
- else
- {
- /* If not a vector register, print it also according to its
- natural format. */
- if (regtype->is_vector () == 0)
- {
- get_user_print_options (&opts);
- opts.deref_ref = 1;
- gdb_printf (file, "\t");
- common_val_print (val, file, 0, &opts, current_language);
- }
- }
- }
- }
- gdb_printf (file, "\n");
- }
- /* Return true if REGNUM is a valid CSR register. The CSR register space
- is sparsely populated, so not every number is a named CSR. */
- static bool
- riscv_is_regnum_a_named_csr (int regnum)
- {
- gdb_assert (regnum >= RISCV_FIRST_CSR_REGNUM
- && regnum <= RISCV_LAST_CSR_REGNUM);
- switch (regnum)
- {
- #define DECLARE_CSR(name, num, class, define_ver, abort_ver) case RISCV_ ## num ## _REGNUM:
- #include "opcode/riscv-opc.h"
- #undef DECLARE_CSR
- return true;
- default:
- return false;
- }
- }
- /* Return true if REGNUM is an unknown CSR identified in
- riscv_tdesc_unknown_reg for GDBARCH. */
- static bool
- riscv_is_unknown_csr (struct gdbarch *gdbarch, int regnum)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- return (regnum >= tdep->unknown_csrs_first_regnum
- && regnum < (tdep->unknown_csrs_first_regnum
- + tdep->unknown_csrs_count));
- }
- /* Implement the register_reggroup_p gdbarch method. Is REGNUM a member
- of REGGROUP? */
- static int
- riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
- const struct reggroup *reggroup)
- {
- /* Used by 'info registers' and 'info registers <groupname>'. */
- if (gdbarch_register_name (gdbarch, regnum) == NULL
- || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
- return 0;
- if (regnum > RISCV_LAST_REGNUM)
- {
- /* Any extra registers from the CSR tdesc_feature (identified in
- riscv_tdesc_unknown_reg) are removed from the save/restore groups
- as some targets (QEMU) report CSRs which then can't be read and
- having unreadable registers in the save/restore group breaks
- things like inferior calls.
- The unknown CSRs are also removed from the general group, and
- added into both the csr and system group. This is inline with the
- known CSRs (see below). */
- if (riscv_is_unknown_csr (gdbarch, regnum))
- {
- if (reggroup == restore_reggroup || reggroup == save_reggroup
- || reggroup == general_reggroup)
- return 0;
- else if (reggroup == system_reggroup || reggroup == csr_reggroup)
- return 1;
- }
- /* This is some other unknown register from the target description.
- In this case we trust whatever the target description says about
- which groups this register should be in. */
- int ret = tdesc_register_in_reggroup_p (gdbarch, regnum, reggroup);
- if (ret != -1)
- return ret;
- return default_register_reggroup_p (gdbarch, regnum, reggroup);
- }
- if (reggroup == all_reggroup)
- {
- if (regnum < RISCV_FIRST_CSR_REGNUM || regnum >= RISCV_PRIV_REGNUM)
- return 1;
- if (riscv_is_regnum_a_named_csr (regnum))
- return 1;
- return 0;
- }
- else if (reggroup == float_reggroup)
- return (riscv_is_fp_regno_p (regnum)
- || regnum == RISCV_CSR_FCSR_REGNUM
- || regnum == RISCV_CSR_FFLAGS_REGNUM
- || regnum == RISCV_CSR_FRM_REGNUM);
- else if (reggroup == general_reggroup)
- return regnum < RISCV_FIRST_FP_REGNUM;
- else if (reggroup == restore_reggroup || reggroup == save_reggroup)
- {
- if (riscv_has_fp_regs (gdbarch))
- return (regnum <= RISCV_LAST_FP_REGNUM
- || regnum == RISCV_CSR_FCSR_REGNUM
- || regnum == RISCV_CSR_FFLAGS_REGNUM
- || regnum == RISCV_CSR_FRM_REGNUM);
- else
- return regnum < RISCV_FIRST_FP_REGNUM;
- }
- else if (reggroup == system_reggroup || reggroup == csr_reggroup)
- {
- if (regnum == RISCV_PRIV_REGNUM)
- return 1;
- if (regnum < RISCV_FIRST_CSR_REGNUM || regnum > RISCV_LAST_CSR_REGNUM)
- return 0;
- if (riscv_is_regnum_a_named_csr (regnum))
- return 1;
- return 0;
- }
- else if (reggroup == vector_reggroup)
- return (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM);
- else
- return 0;
- }
- /* Implement the print_registers_info gdbarch method. This is used by
- 'info registers' and 'info all-registers'. */
- static void
- riscv_print_registers_info (struct gdbarch *gdbarch,
- struct ui_file *file,
- struct frame_info *frame,
- int regnum, int print_all)
- {
- if (regnum != -1)
- {
- /* Print one specified register. */
- if (gdbarch_register_name (gdbarch, regnum) == NULL
- || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
- error (_("Not a valid register for the current processor type"));
- riscv_print_one_register_info (gdbarch, file, frame, regnum);
- }
- else
- {
- const struct reggroup *reggroup;
- if (print_all)
- reggroup = all_reggroup;
- else
- reggroup = general_reggroup;
- for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); ++regnum)
- {
- /* Zero never changes, so might as well hide by default. */
- if (regnum == RISCV_ZERO_REGNUM && !print_all)
- continue;
- /* Registers with no name are not valid on this ISA. */
- if (gdbarch_register_name (gdbarch, regnum) == NULL
- || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
- continue;
- /* Is the register in the group we're interested in? */
- if (!gdbarch_register_reggroup_p (gdbarch, regnum, reggroup))
- continue;
- riscv_print_one_register_info (gdbarch, file, frame, regnum);
- }
- }
- }
- /* Class that handles one decoded RiscV instruction. */
- class riscv_insn
- {
- public:
- /* Enum of all the opcodes that GDB cares about during the prologue scan. */
- enum opcode
- {
- /* Unknown value is used at initialisation time. */
- UNKNOWN = 0,
- /* These instructions are all the ones we are interested in during the
- prologue scan. */
- ADD,
- ADDI,
- ADDIW,
- ADDW,
- AUIPC,
- LUI,
- SD,
- SW,
- LD,
- LW,
- MV,
- /* These are needed for software breakpoint support. */
- JAL,
- JALR,
- BEQ,
- BNE,
- BLT,
- BGE,
- BLTU,
- BGEU,
- /* These are needed for stepping over atomic sequences. */
- LR,
- SC,
- /* This instruction is used to do a syscall. */
- ECALL,
- /* Other instructions are not interesting during the prologue scan, and
- are ignored. */
- OTHER
- };
- riscv_insn ()
- : m_length (0),
- m_opcode (OTHER),
- m_rd (0),
- m_rs1 (0),
- m_rs2 (0)
- {
- /* Nothing. */
- }
- void decode (struct gdbarch *gdbarch, CORE_ADDR pc);
- /* Get the length of the instruction in bytes. */
- int length () const
- { return m_length; }
- /* Get the opcode for this instruction. */
- enum opcode opcode () const
- { return m_opcode; }
- /* Get destination register field for this instruction. This is only
- valid if the OPCODE implies there is such a field for this
- instruction. */
- int rd () const
- { return m_rd; }
- /* Get the RS1 register field for this instruction. This is only valid
- if the OPCODE implies there is such a field for this instruction. */
- int rs1 () const
- { return m_rs1; }
- /* Get the RS2 register field for this instruction. This is only valid
- if the OPCODE implies there is such a field for this instruction. */
- int rs2 () const
- { return m_rs2; }
- /* Get the immediate for this instruction in signed form. This is only
- valid if the OPCODE implies there is such a field for this
- instruction. */
- int imm_signed () const
- { return m_imm.s; }
- private:
- /* Extract 5 bit register field at OFFSET from instruction OPCODE. */
- int decode_register_index (unsigned long opcode, int offset)
- {
- return (opcode >> offset) & 0x1F;
- }
- /* Extract 5 bit register field at OFFSET from instruction OPCODE. */
- int decode_register_index_short (unsigned long opcode, int offset)
- {
- return ((opcode >> offset) & 0x7) + 8;
- }
- /* Helper for DECODE, decode 32-bit R-type instruction. */
- void decode_r_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rd = decode_register_index (ival, OP_SH_RD);
- m_rs1 = decode_register_index (ival, OP_SH_RS1);
- m_rs2 = decode_register_index (ival, OP_SH_RS2);
- }
- /* Helper for DECODE, decode 16-bit compressed R-type instruction. */
- void decode_cr_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rd = m_rs1 = decode_register_index (ival, OP_SH_CRS1S);
- m_rs2 = decode_register_index (ival, OP_SH_CRS2);
- }
- /* Helper for DECODE, decode 32-bit I-type instruction. */
- void decode_i_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rd = decode_register_index (ival, OP_SH_RD);
- m_rs1 = decode_register_index (ival, OP_SH_RS1);
- m_imm.s = EXTRACT_ITYPE_IMM (ival);
- }
- /* Helper for DECODE, decode 16-bit compressed I-type instruction. */
- void decode_ci_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rd = m_rs1 = decode_register_index (ival, OP_SH_CRS1S);
- m_imm.s = EXTRACT_CITYPE_IMM (ival);
- }
- /* Helper for DECODE, decode 16-bit compressed CL-type instruction. */
- void decode_cl_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rd = decode_register_index_short (ival, OP_SH_CRS2S);
- m_rs1 = decode_register_index_short (ival, OP_SH_CRS1S);
- m_imm.s = EXTRACT_CLTYPE_IMM (ival);
- }
- /* Helper for DECODE, decode 32-bit S-type instruction. */
- void decode_s_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rs1 = decode_register_index (ival, OP_SH_RS1);
- m_rs2 = decode_register_index (ival, OP_SH_RS2);
- m_imm.s = EXTRACT_STYPE_IMM (ival);
- }
- /* Helper for DECODE, decode 16-bit CS-type instruction. The immediate
- encoding is different for each CS format instruction, so extracting
- the immediate is left up to the caller, who should pass the extracted
- immediate value through in IMM. */
- void decode_cs_type_insn (enum opcode opcode, ULONGEST ival, int imm)
- {
- m_opcode = opcode;
- m_imm.s = imm;
- m_rs1 = decode_register_index_short (ival, OP_SH_CRS1S);
- m_rs2 = decode_register_index_short (ival, OP_SH_CRS2S);
- }
- /* Helper for DECODE, decode 16-bit CSS-type instruction. The immediate
- encoding is different for each CSS format instruction, so extracting
- the immediate is left up to the caller, who should pass the extracted
- immediate value through in IMM. */
- void decode_css_type_insn (enum opcode opcode, ULONGEST ival, int imm)
- {
- m_opcode = opcode;
- m_imm.s = imm;
- m_rs1 = RISCV_SP_REGNUM;
- /* Not a compressed register number in this case. */
- m_rs2 = decode_register_index (ival, OP_SH_CRS2);
- }
- /* Helper for DECODE, decode 32-bit U-type instruction. */
- void decode_u_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rd = decode_register_index (ival, OP_SH_RD);
- m_imm.s = EXTRACT_UTYPE_IMM (ival);
- }
- /* Helper for DECODE, decode 32-bit J-type instruction. */
- void decode_j_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rd = decode_register_index (ival, OP_SH_RD);
- m_imm.s = EXTRACT_JTYPE_IMM (ival);
- }
- /* Helper for DECODE, decode 32-bit J-type instruction. */
- void decode_cj_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_imm.s = EXTRACT_CJTYPE_IMM (ival);
- }
- void decode_b_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rs1 = decode_register_index (ival, OP_SH_RS1);
- m_rs2 = decode_register_index (ival, OP_SH_RS2);
- m_imm.s = EXTRACT_BTYPE_IMM (ival);
- }
- void decode_cb_type_insn (enum opcode opcode, ULONGEST ival)
- {
- m_opcode = opcode;
- m_rs1 = decode_register_index_short (ival, OP_SH_CRS1S);
- m_imm.s = EXTRACT_CBTYPE_IMM (ival);
- }
- /* Fetch instruction from target memory at ADDR, return the content of
- the instruction, and update LEN with the instruction length. */
- static ULONGEST fetch_instruction (struct gdbarch *gdbarch,
- CORE_ADDR addr, int *len);
- /* The length of the instruction in bytes. Should be 2 or 4. */
- int m_length;
- /* The instruction opcode. */
- enum opcode m_opcode;
- /* The three possible registers an instruction might reference. Not
- every instruction fills in all of these registers. Which fields are
- valid depends on the opcode. The naming of these fields matches the
- naming in the riscv isa manual. */
- int m_rd;
- int m_rs1;
- int m_rs2;
- /* Possible instruction immediate. This is only valid if the instruction
- format contains an immediate, not all instruction, whether this is
- valid depends on the opcode. Despite only having one format for now
- the immediate is packed into a union, later instructions might require
- an unsigned formatted immediate, having the union in place now will
- reduce the need for code churn later. */
- union riscv_insn_immediate
- {
- riscv_insn_immediate ()
- : s (0)
- {
- /* Nothing. */
- }
- int s;
- } m_imm;
- };
- /* Fetch instruction from target memory at ADDR, return the content of the
- instruction, and update LEN with the instruction length. */
- ULONGEST
- riscv_insn::fetch_instruction (struct gdbarch *gdbarch,
- CORE_ADDR addr, int *len)
- {
- enum bfd_endian byte_order = gdbarch_byte_order_for_code (gdbarch);
- gdb_byte buf[8];
- int instlen, status;
- /* All insns are at least 16 bits. */
- status = target_read_memory (addr, buf, 2);
- if (status)
- memory_error (TARGET_XFER_E_IO, addr);
- /* If we need more, grab it now. */
- instlen = riscv_insn_length (buf[0]);
- gdb_assert (instlen <= sizeof (buf));
- *len = instlen;
- if (instlen > 2)
- {
- status = target_read_memory (addr + 2, buf + 2, instlen - 2);
- if (status)
- memory_error (TARGET_XFER_E_IO, addr + 2);
- }
- return extract_unsigned_integer (buf, instlen, byte_order);
- }
- /* Fetch from target memory an instruction at PC and decode it. This can
- throw an error if the memory access fails, callers are responsible for
- handling this error if that is appropriate. */
- void
- riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- ULONGEST ival;
- /* Fetch the instruction, and the instructions length. */
- ival = fetch_instruction (gdbarch, pc, &m_length);
- if (m_length == 4)
- {
- if (is_add_insn (ival))
- decode_r_type_insn (ADD, ival);
- else if (is_addw_insn (ival))
- decode_r_type_insn (ADDW, ival);
- else if (is_addi_insn (ival))
- decode_i_type_insn (ADDI, ival);
- else if (is_addiw_insn (ival))
- decode_i_type_insn (ADDIW, ival);
- else if (is_auipc_insn (ival))
- decode_u_type_insn (AUIPC, ival);
- else if (is_lui_insn (ival))
- decode_u_type_insn (LUI, ival);
- else if (is_sd_insn (ival))
- decode_s_type_insn (SD, ival);
- else if (is_sw_insn (ival))
- decode_s_type_insn (SW, ival);
- else if (is_jal_insn (ival))
- decode_j_type_insn (JAL, ival);
- else if (is_jalr_insn (ival))
- decode_i_type_insn (JALR, ival);
- else if (is_beq_insn (ival))
- decode_b_type_insn (BEQ, ival);
- else if (is_bne_insn (ival))
- decode_b_type_insn (BNE, ival);
- else if (is_blt_insn (ival))
- decode_b_type_insn (BLT, ival);
- else if (is_bge_insn (ival))
- decode_b_type_insn (BGE, ival);
- else if (is_bltu_insn (ival))
- decode_b_type_insn (BLTU, ival);
- else if (is_bgeu_insn (ival))
- decode_b_type_insn (BGEU, ival);
- else if (is_lr_w_insn (ival))
- decode_r_type_insn (LR, ival);
- else if (is_lr_d_insn (ival))
- decode_r_type_insn (LR, ival);
- else if (is_sc_w_insn (ival))
- decode_r_type_insn (SC, ival);
- else if (is_sc_d_insn (ival))
- decode_r_type_insn (SC, ival);
- else if (is_ecall_insn (ival))
- decode_i_type_insn (ECALL, ival);
- else if (is_ld_insn (ival))
- decode_i_type_insn (LD, ival);
- else if (is_lw_insn (ival))
- decode_i_type_insn (LW, ival);
- else
- /* None of the other fields are valid in this case. */
- m_opcode = OTHER;
- }
- else if (m_length == 2)
- {
- int xlen = riscv_isa_xlen (gdbarch);
- /* C_ADD and C_JALR have the same opcode. If RS2 is 0, then this is a
- C_JALR. So must try to match C_JALR first as it has more bits in
- mask. */
- if (is_c_jalr_insn (ival))
- decode_cr_type_insn (JALR, ival);
- else if (is_c_add_insn (ival))
- decode_cr_type_insn (ADD, ival);
- /* C_ADDW is RV64 and RV128 only. */
- else if (xlen != 4 && is_c_addw_insn (ival))
- decode_cr_type_insn (ADDW, ival);
- else if (is_c_addi_insn (ival))
- decode_ci_type_insn (ADDI, ival);
- /* C_ADDIW and C_JAL have the same opcode. C_ADDIW is RV64 and RV128
- only and C_JAL is RV32 only. */
- else if (xlen != 4 && is_c_addiw_insn (ival))
- decode_ci_type_insn (ADDIW, ival);
- else if (xlen == 4 && is_c_jal_insn (ival))
- decode_cj_type_insn (JAL, ival);
- /* C_ADDI16SP and C_LUI have the same opcode. If RD is 2, then this is a
- C_ADDI16SP. So must try to match C_ADDI16SP first as it has more bits
- in mask. */
- else if (is_c_addi16sp_insn (ival))
- {
- m_opcode = ADDI;
- m_rd = m_rs1 = decode_register_index (ival, OP_SH_RD);
- m_imm.s = EXTRACT_CITYPE_ADDI16SP_IMM (ival);
- }
- else if (is_c_addi4spn_insn (ival))
- {
- m_opcode = ADDI;
- m_rd = decode_register_index_short (ival, OP_SH_CRS2S);
- m_rs1 = RISCV_SP_REGNUM;
- m_imm.s = EXTRACT_CIWTYPE_ADDI4SPN_IMM (ival);
- }
- else if (is_c_lui_insn (ival))
- {
- m_opcode = LUI;
- m_rd = decode_register_index (ival, OP_SH_CRS1S);
- m_imm.s = EXTRACT_CITYPE_LUI_IMM (ival);
- }
- /* C_SD and C_FSW have the same opcode. C_SD is RV64 and RV128 only,
- and C_FSW is RV32 only. */
- else if (xlen != 4 && is_c_sd_insn (ival))
- decode_cs_type_insn (SD, ival, EXTRACT_CLTYPE_LD_IMM (ival));
- else if (is_c_sw_insn (ival))
- decode_cs_type_insn (SW, ival, EXTRACT_CLTYPE_LW_IMM (ival));
- else if (is_c_swsp_insn (ival))
- decode_css_type_insn (SW, ival, EXTRACT_CSSTYPE_SWSP_IMM (ival));
- else if (xlen != 4 && is_c_sdsp_insn (ival))
- decode_css_type_insn (SD, ival, EXTRACT_CSSTYPE_SDSP_IMM (ival));
- /* C_JR and C_MV have the same opcode. If RS2 is 0, then this is a C_JR.
- So must try to match C_JR first as it has more bits in mask. */
- else if (is_c_jr_insn (ival))
- decode_cr_type_insn (JALR, ival);
- else if (is_c_mv_insn (ival))
- decode_cr_type_insn (MV, ival);
- else if (is_c_j_insn (ival))
- decode_cj_type_insn (JAL, ival);
- else if (is_c_beqz_insn (ival))
- decode_cb_type_insn (BEQ, ival);
- else if (is_c_bnez_insn (ival))
- decode_cb_type_insn (BNE, ival);
- else if (is_c_ld_insn (ival))
- decode_cl_type_insn (LD, ival);
- else if (is_c_lw_insn (ival))
- decode_cl_type_insn (LW, ival);
- else
- /* None of the other fields of INSN are valid in this case. */
- m_opcode = OTHER;
- }
- else
- {
- /* This must be a 6 or 8 byte instruction, we don't currently decode
- any of these, so just ignore it. */
- gdb_assert (m_length == 6 || m_length == 8);
- m_opcode = OTHER;
- }
- }
- /* The prologue scanner. This is currently only used for skipping the
- prologue of a function when the DWARF information is not sufficient.
- However, it is written with filling of the frame cache in mind, which
- is why different groups of stack setup instructions are split apart
- during the core of the inner loop. In the future, the intention is to
- extend this function to fully support building up a frame cache that
- can unwind register values when there is no DWARF information. */
- static CORE_ADDR
- riscv_scan_prologue (struct gdbarch *gdbarch,
- CORE_ADDR start_pc, CORE_ADDR end_pc,
- struct riscv_unwind_cache *cache)
- {
- CORE_ADDR cur_pc, next_pc, after_prologue_pc;
- CORE_ADDR end_prologue_addr = 0;
- /* Find an upper limit on the function prologue using the debug
- information. If the debug information could not be used to provide
- that bound, then use an arbitrary large number as the upper bound. */
- after_prologue_pc = skip_prologue_using_sal (gdbarch, start_pc);
- if (after_prologue_pc == 0)
- after_prologue_pc = start_pc + 100; /* Arbitrary large number. */
- if (after_prologue_pc < end_pc)
- end_pc = after_prologue_pc;
- pv_t regs[RISCV_NUM_INTEGER_REGS]; /* Number of GPR. */
- for (int regno = 0; regno < RISCV_NUM_INTEGER_REGS; regno++)
- regs[regno] = pv_register (regno, 0);
- pv_area stack (RISCV_SP_REGNUM, gdbarch_addr_bit (gdbarch));
- if (riscv_debug_unwinder)
- gdb_printf
- (gdb_stdlog,
- "Prologue scan for function starting at %s (limit %s)\n",
- core_addr_to_string (start_pc),
- core_addr_to_string (end_pc));
- for (next_pc = cur_pc = start_pc; cur_pc < end_pc; cur_pc = next_pc)
- {
- struct riscv_insn insn;
- /* Decode the current instruction, and decide where the next
- instruction lives based on the size of this instruction. */
- insn.decode (gdbarch, cur_pc);
- gdb_assert (insn.length () > 0);
- next_pc = cur_pc + insn.length ();
- /* Look for common stack adjustment insns. */
- if ((insn.opcode () == riscv_insn::ADDI
- || insn.opcode () == riscv_insn::ADDIW)
- && insn.rd () == RISCV_SP_REGNUM
- && insn.rs1 () == RISCV_SP_REGNUM)
- {
- /* Handle: addi sp, sp, -i
- or: addiw sp, sp, -i */
- gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
- regs[insn.rd ()]
- = pv_add_constant (regs[insn.rs1 ()], insn.imm_signed ());
- }
- else if ((insn.opcode () == riscv_insn::SW
- || insn.opcode () == riscv_insn::SD)
- && (insn.rs1 () == RISCV_SP_REGNUM
- || insn.rs1 () == RISCV_FP_REGNUM))
- {
- /* Handle: sw reg, offset(sp)
- or: sd reg, offset(sp)
- or: sw reg, offset(s0)
- or: sd reg, offset(s0) */
- /* Instruction storing a register onto the stack. */
- gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS);
- stack.store (pv_add_constant (regs[insn.rs1 ()], insn.imm_signed ()),
- (insn.opcode () == riscv_insn::SW ? 4 : 8),
- regs[insn.rs2 ()]);
- }
- else if (insn.opcode () == riscv_insn::ADDI
- && insn.rd () == RISCV_FP_REGNUM
- && insn.rs1 () == RISCV_SP_REGNUM)
- {
- /* Handle: addi s0, sp, size */
- /* Instructions setting up the frame pointer. */
- gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
- regs[insn.rd ()]
- = pv_add_constant (regs[insn.rs1 ()], insn.imm_signed ());
- }
- else if ((insn.opcode () == riscv_insn::ADD
- || insn.opcode () == riscv_insn::ADDW)
- && insn.rd () == RISCV_FP_REGNUM
- && insn.rs1 () == RISCV_SP_REGNUM
- && insn.rs2 () == RISCV_ZERO_REGNUM)
- {
- /* Handle: add s0, sp, 0
- or: addw s0, sp, 0 */
- /* Instructions setting up the frame pointer. */
- gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
- regs[insn.rd ()] = pv_add_constant (regs[insn.rs1 ()], 0);
- }
- else if ((insn.opcode () == riscv_insn::ADDI
- && insn.rd () == RISCV_ZERO_REGNUM
- && insn.rs1 () == RISCV_ZERO_REGNUM
- && insn.imm_signed () == 0))
- {
- /* Handle: add x0, x0, 0 (NOP) */
- }
- else if (insn.opcode () == riscv_insn::AUIPC)
- {
- gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
- regs[insn.rd ()] = pv_constant (cur_pc + insn.imm_signed ());
- }
- else if (insn.opcode () == riscv_insn::LUI)
- {
- /* Handle: lui REG, n
- Where REG is not gp register. */
- gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
- regs[insn.rd ()] = pv_constant (insn.imm_signed ());
- }
- else if (insn.opcode () == riscv_insn::ADDI)
- {
- /* Handle: addi REG1, REG2, IMM */
- gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
- regs[insn.rd ()]
- = pv_add_constant (regs[insn.rs1 ()], insn.imm_signed ());
- }
- else if (insn.opcode () == riscv_insn::ADD)
- {
- /* Handle: add REG1, REG2, REG3 */
- gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS);
- regs[insn.rd ()] = pv_add (regs[insn.rs1 ()], regs[insn.rs2 ()]);
- }
- else if (insn.opcode () == riscv_insn::LD
- || insn.opcode () == riscv_insn::LW)
- {
- /* Handle: ld reg, offset(rs1)
- or: c.ld reg, offset(rs1)
- or: lw reg, offset(rs1)
- or: c.lw reg, offset(rs1) */
- gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
- regs[insn.rd ()]
- = stack.fetch (pv_add_constant (regs[insn.rs1 ()],
- insn.imm_signed ()),
- (insn.opcode () == riscv_insn::LW ? 4 : 8));
- }
- else if (insn.opcode () == riscv_insn::MV)
- {
- /* Handle: c.mv RD, RS2 */
- gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS);
- gdb_assert (insn.rs2 () > 0);
- regs[insn.rd ()] = regs[insn.rs2 ()];
- }
- else
- {
- end_prologue_addr = cur_pc;
- break;
- }
- }
- if (end_prologue_addr == 0)
- end_prologue_addr = cur_pc;
- if (riscv_debug_unwinder)
- gdb_printf (gdb_stdlog, "End of prologue at %s\n",
- core_addr_to_string (end_prologue_addr));
- if (cache != NULL)
- {
- /* Figure out if it is a frame pointer or just a stack pointer. Also
- the offset held in the pv_t is from the original register value to
- the current value, which for a grows down stack means a negative
- value. The FRAME_BASE_OFFSET is the negation of this, how to get
- from the current value to the original value. */
- if (pv_is_register (regs[RISCV_FP_REGNUM], RISCV_SP_REGNUM))
- {
- cache->frame_base_reg = RISCV_FP_REGNUM;
- cache->frame_base_offset = -regs[RISCV_FP_REGNUM].k;
- }
- else
- {
- cache->frame_base_reg = RISCV_SP_REGNUM;
- cache->frame_base_offset = -regs[RISCV_SP_REGNUM].k;
- }
- /* Assign offset from old SP to all saved registers. As we don't
- have the previous value for the frame base register at this
- point, we store the offset as the address in the trad_frame, and
- then convert this to an actual address later. */
- for (int i = 0; i <= RISCV_NUM_INTEGER_REGS; i++)
- {
- CORE_ADDR offset;
- if (stack.find_reg (gdbarch, i, &offset))
- {
- if (riscv_debug_unwinder)
- {
- /* Display OFFSET as a signed value, the offsets are from
- the frame base address to the registers location on
- the stack, with a descending stack this means the
- offsets are always negative. */
- gdb_printf (gdb_stdlog,
- "Register $%s at stack offset %s\n",
- gdbarch_register_name (gdbarch, i),
- plongest ((LONGEST) offset));
- }
- cache->regs[i].set_addr (offset);
- }
- }
- }
- return end_prologue_addr;
- }
- /* Implement the riscv_skip_prologue gdbarch method. */
- static CORE_ADDR
- riscv_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- CORE_ADDR func_addr;
- /* See if we can determine the end of the prologue via the symbol
- table. If so, then return either PC, or the PC after the
- prologue, whichever is greater. */
- if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
- {
- CORE_ADDR post_prologue_pc
- = skip_prologue_using_sal (gdbarch, func_addr);
- if (post_prologue_pc != 0)
- return std::max (pc, post_prologue_pc);
- }
- /* Can't determine prologue from the symbol table, need to examine
- instructions. Pass -1 for the end address to indicate the prologue
- scanner can scan as far as it needs to find the end of the prologue. */
- return riscv_scan_prologue (gdbarch, pc, ((CORE_ADDR) -1), NULL);
- }
- /* Implement the gdbarch push dummy code callback. */
- static CORE_ADDR
- riscv_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)
- {
- /* A nop instruction is 'add x0, x0, 0'. */
- static const gdb_byte nop_insn[] = { 0x13, 0x00, 0x00, 0x00 };
- /* Allocate space for a breakpoint, and keep the stack correctly
- aligned. The space allocated here must be at least big enough to
- accommodate the NOP_INSN defined above. */
- sp -= 16;
- *bp_addr = sp;
- *real_pc = funaddr;
- /* When we insert a breakpoint we select whether to use a compressed
- breakpoint or not based on the existing contents of the memory.
- If the breakpoint is being placed onto the stack as part of setting up
- for an inferior call from GDB, then the existing stack contents may
- randomly appear to be a compressed instruction, causing GDB to insert
- a compressed breakpoint. If this happens on a target that does not
- support compressed instructions then this could cause problems.
- To prevent this issue we write an uncompressed nop onto the stack at
- the location where the breakpoint will be inserted. In this way we
- ensure that we always use an uncompressed breakpoint, which should
- work on all targets.
- We call TARGET_WRITE_MEMORY here so that if the write fails we don't
- throw an exception. Instead we ignore the error and move on. The
- assumption is that either GDB will error later when actually trying to
- insert a software breakpoint, or GDB will use hardware breakpoints and
- there will be no need to write to memory later. */
- int status = target_write_memory (*bp_addr, nop_insn, sizeof (nop_insn));
- if (riscv_debug_breakpoints || riscv_debug_infcall)
- gdb_printf (gdb_stdlog,
- "Writing %s-byte nop instruction to %s: %s\n",
- plongest (sizeof (nop_insn)),
- paddress (gdbarch, *bp_addr),
- (status == 0 ? "success" : "failed"));
- return sp;
- }
- /* Implement the gdbarch type alignment method, overrides the generic
- alignment algorithm for anything that is RISC-V specific. */
- static ULONGEST
- riscv_type_align (gdbarch *gdbarch, type *type)
- {
- type = check_typedef (type);
- if (type->code () == TYPE_CODE_ARRAY && type->is_vector ())
- return std::min (TYPE_LENGTH (type), (ULONGEST) BIGGEST_ALIGNMENT);
- /* Anything else will be aligned by the generic code. */
- return 0;
- }
- /* Holds information about a single argument either being passed to an
- inferior function, or returned from an inferior function. This includes
- information about the size, type, etc of the argument, and also
- information about how the argument will be passed (or returned). */
- struct riscv_arg_info
- {
- /* Contents of the argument. */
- const gdb_byte *contents;
- /* Length of argument. */
- int length;
- /* Alignment required for an argument of this type. */
- int align;
- /* The type for this argument. */
- struct type *type;
- /* Each argument can have either 1 or 2 locations assigned to it. Each
- location describes where part of the argument will be placed. The
- second location is valid based on the LOC_TYPE and C_LENGTH fields
- of the first location (which is always valid). */
- struct location
- {
- /* What type of location this is. */
- enum location_type
- {
- /* Argument passed in a register. */
- in_reg,
- /* Argument passed as an on stack argument. */
- on_stack,
- /* Argument passed by reference. The second location is always
- valid for a BY_REF argument, and describes where the address
- of the BY_REF argument should be placed. */
- by_ref
- } loc_type;
- /* Information that depends on the location type. */
- union
- {
- /* Which register number to use. */
- int regno;
- /* The offset into the stack region. */
- int offset;
- } loc_data;
- /* The length of contents covered by this location. If this is less
- than the total length of the argument, then the second location
- will be valid, and will describe where the rest of the argument
- will go. */
- int c_length;
- /* The offset within CONTENTS for this part of the argument. This can
- be non-zero even for the first part (the first field of a struct can
- have a non-zero offset due to padding). For the second part of the
- argument, this might be the C_LENGTH value of the first part,
- however, if we are passing a structure in two registers, and there's
- is padding between the first and second field, then this offset
- might be greater than the length of the first argument part. When
- the second argument location is not holding part of the argument
- value, but is instead holding the address of a reference argument,
- then this offset will be set to 0. */
- int c_offset;
- } argloc[2];
- /* TRUE if this is an unnamed argument. */
- bool is_unnamed;
- };
- /* Information about a set of registers being used for passing arguments as
- part of a function call. The register set must be numerically
- sequential from NEXT_REGNUM to LAST_REGNUM. The register set can be
- disabled from use by setting NEXT_REGNUM greater than LAST_REGNUM. */
- struct riscv_arg_reg
- {
- riscv_arg_reg (int first, int last)
- : next_regnum (first),
- last_regnum (last)
- {
- /* Nothing. */
- }
- /* The GDB register number to use in this set. */
- int next_regnum;
- /* The last GDB register number to use in this set. */
- int last_regnum;
- };
- /* Arguments can be passed as on stack arguments, or by reference. The
- on stack arguments must be in a continuous region starting from $sp,
- while the by reference arguments can be anywhere, but we'll put them
- on the stack after (at higher address) the on stack arguments.
- This might not be the right approach to take. The ABI is clear that
- an argument passed by reference can be modified by the callee, which
- us placing the argument (temporarily) onto the stack will not achieve
- (changes will be lost). There's also the possibility that very large
- arguments could overflow the stack.
- This struct is used to track offset into these two areas for where
- arguments are to be placed. */
- struct riscv_memory_offsets
- {
- riscv_memory_offsets ()
- : arg_offset (0),
- ref_offset (0)
- {
- /* Nothing. */
- }
- /* Offset into on stack argument area. */
- int arg_offset;
- /* Offset into the pass by reference area. */
- int ref_offset;
- };
- /* Holds information about where arguments to a call will be placed. This
- is updated as arguments are added onto the call, and can be used to
- figure out where the next argument should be placed. */
- struct riscv_call_info
- {
- riscv_call_info (struct gdbarch *gdbarch)
- : int_regs (RISCV_A0_REGNUM, RISCV_A0_REGNUM + 7),
- float_regs (RISCV_FA0_REGNUM, RISCV_FA0_REGNUM + 7)
- {
- xlen = riscv_abi_xlen (gdbarch);
- flen = riscv_abi_flen (gdbarch);
- /* Reduce the number of integer argument registers when using the
- embedded abi (i.e. rv32e). */
- if (riscv_abi_embedded (gdbarch))
- int_regs.last_regnum = RISCV_A0_REGNUM + 5;
- /* Disable use of floating point registers if needed. */
- if (!riscv_has_fp_abi (gdbarch))
- float_regs.next_regnum = float_regs.last_regnum + 1;
- }
- /* Track the memory areas used for holding in-memory arguments to a
- call. */
- struct riscv_memory_offsets memory;
- /* Holds information about the next integer register to use for passing
- an argument. */
- struct riscv_arg_reg int_regs;
- /* Holds information about the next floating point register to use for
- passing an argument. */
- struct riscv_arg_reg float_regs;
- /* The XLEN and FLEN are copied in to this structure for convenience, and
- are just the results of calling RISCV_ABI_XLEN and RISCV_ABI_FLEN. */
- int xlen;
- int flen;
- };
- /* Return the number of registers available for use as parameters in the
- register set REG. Returned value can be 0 or more. */
- static int
- riscv_arg_regs_available (struct riscv_arg_reg *reg)
- {
- if (reg->next_regnum > reg->last_regnum)
- return 0;
- return (reg->last_regnum - reg->next_regnum + 1);
- }
- /* If there is at least one register available in the register set REG then
- the next register from REG is assigned to LOC and the length field of
- LOC is updated to LENGTH. The register set REG is updated to indicate
- that the assigned register is no longer available and the function
- returns true.
- If there are no registers available in REG then the function returns
- false, and LOC and REG are unchanged. */
- static bool
- riscv_assign_reg_location (struct riscv_arg_info::location *loc,
- struct riscv_arg_reg *reg,
- int length, int offset)
- {
- if (reg->next_regnum <= reg->last_regnum)
- {
- loc->loc_type = riscv_arg_info::location::in_reg;
- loc->loc_data.regno = reg->next_regnum;
- reg->next_regnum++;
- loc->c_length = length;
- loc->c_offset = offset;
- return true;
- }
- return false;
- }
- /* Assign LOC a location as the next stack parameter, and update MEMORY to
- record that an area of stack has been used to hold the parameter
- described by LOC.
- The length field of LOC is updated to LENGTH, the length of the
- parameter being stored, and ALIGN is the alignment required by the
- parameter, which will affect how memory is allocated out of MEMORY. */
- static void
- riscv_assign_stack_location (struct riscv_arg_info::location *loc,
- struct riscv_memory_offsets *memory,
- int length, int align)
- {
- loc->loc_type = riscv_arg_info::location::on_stack;
- memory->arg_offset
- = align_up (memory->arg_offset, align);
- loc->loc_data.offset = memory->arg_offset;
- memory->arg_offset += length;
- loc->c_length = length;
- /* Offset is always 0, either we're the first location part, in which
- case we're reading content from the start of the argument, or we're
- passing the address of a reference argument, so 0. */
- loc->c_offset = 0;
- }
- /* Update AINFO, which describes an argument that should be passed or
- returned using the integer ABI. The argloc fields within AINFO are
- updated to describe the location in which the argument will be passed to
- a function, or returned from a function.
- The CINFO structure contains the ongoing call information, the holds
- information such as which argument registers are remaining to be
- assigned to parameter, and how much memory has been used by parameters
- so far.
- By examining the state of CINFO a suitable location can be selected,
- and assigned to AINFO. */
- static void
- riscv_call_arg_scalar_int (struct riscv_arg_info *ainfo,
- struct riscv_call_info *cinfo)
- {
- if (ainfo->length > (2 * cinfo->xlen))
- {
- /* Argument is going to be passed by reference. */
- ainfo->argloc[0].loc_type
- = riscv_arg_info::location::by_ref;
- cinfo->memory.ref_offset
- = align_up (cinfo->memory.ref_offset, ainfo->align);
- ainfo->argloc[0].loc_data.offset = cinfo->memory.ref_offset;
- cinfo->memory.ref_offset += ainfo->length;
- ainfo->argloc[0].c_length = ainfo->length;
- /* The second location for this argument is given over to holding the
- address of the by-reference data. Pass 0 for the offset as this
- is not part of the actual argument value. */
- if (!riscv_assign_reg_location (&ainfo->argloc[1],
- &cinfo->int_regs,
- cinfo->xlen, 0))
- riscv_assign_stack_location (&ainfo->argloc[1],
- &cinfo->memory, cinfo->xlen,
- cinfo->xlen);
- }
- else
- {
- int len = std::min (ainfo->length, cinfo->xlen);
- int align = std::max (ainfo->align, cinfo->xlen);
- /* Unnamed arguments in registers that require 2*XLEN alignment are
- passed in an aligned register pair. */
- if (ainfo->is_unnamed && (align == cinfo->xlen * 2)
- && cinfo->int_regs.next_regnum & 1)
- cinfo->int_regs.next_regnum++;
- if (!riscv_assign_reg_location (&ainfo->argloc[0],
- &cinfo->int_regs, len, 0))
- riscv_assign_stack_location (&ainfo->argloc[0],
- &cinfo->memory, len, align);
- if (len < ainfo->length)
- {
- len = ainfo->length - len;
- if (!riscv_assign_reg_location (&ainfo->argloc[1],
- &cinfo->int_regs, len,
- cinfo->xlen))
- riscv_assign_stack_location (&ainfo->argloc[1],
- &cinfo->memory, len, cinfo->xlen);
- }
- }
- }
- /* Like RISCV_CALL_ARG_SCALAR_INT, except the argument described by AINFO
- is being passed with the floating point ABI. */
- static void
- riscv_call_arg_scalar_float (struct riscv_arg_info *ainfo,
- struct riscv_call_info *cinfo)
- {
- if (ainfo->length > cinfo->flen || ainfo->is_unnamed)
- return riscv_call_arg_scalar_int (ainfo, cinfo);
- else
- {
- if (!riscv_assign_reg_location (&ainfo->argloc[0],
- &cinfo->float_regs,
- ainfo->length, 0))
- return riscv_call_arg_scalar_int (ainfo, cinfo);
- }
- }
- /* Like RISCV_CALL_ARG_SCALAR_INT, except the argument described by AINFO
- is a complex floating point argument, and is therefore handled
- differently to other argument types. */
- static void
- riscv_call_arg_complex_float (struct riscv_arg_info *ainfo,
- struct riscv_call_info *cinfo)
- {
- if (ainfo->length <= (2 * cinfo->flen)
- && riscv_arg_regs_available (&cinfo->float_regs) >= 2
- && !ainfo->is_unnamed)
- {
- bool result;
- int len = ainfo->length / 2;
- result = riscv_assign_reg_location (&ainfo->argloc[0],
- &cinfo->float_regs, len, 0);
- gdb_assert (result);
- result = riscv_assign_reg_location (&ainfo->argloc[1],
- &cinfo->float_regs, len, len);
- gdb_assert (result);
- }
- else
- return riscv_call_arg_scalar_int (ainfo, cinfo);
- }
- /* A structure used for holding information about a structure type within
- the inferior program. The RiscV ABI has special rules for handling some
- structures with a single field or with two fields. The counting of
- fields here is done after flattening out all nested structures. */
- class riscv_struct_info
- {
- public:
- riscv_struct_info ()
- : m_number_of_fields (0),
- m_types { nullptr, nullptr },
- m_offsets { 0, 0 }
- {
- /* Nothing. */
- }
- /* Analyse TYPE descending into nested structures, count the number of
- scalar fields and record the types of the first two fields found. */
- void analyse (struct type *type)
- {
- analyse_inner (type, 0);
- }
- /* The number of scalar fields found in the analysed type. This is
- currently only accurate if the value returned is 0, 1, or 2 as the
- analysis stops counting when the number of fields is 3. This is
- because the RiscV ABI only has special cases for 1 or 2 fields,
- anything else we just don't care about. */
- int number_of_fields () const
- { return m_number_of_fields; }
- /* Return the type for scalar field INDEX within the analysed type. Will
- return nullptr if there is no field at that index. Only INDEX values
- 0 and 1 can be requested as the RiscV ABI only has special cases for
- structures with 1 or 2 fields. */
- struct type *field_type (int index) const
- {
- gdb_assert (index < (sizeof (m_types) / sizeof (m_types[0])));
- return m_types[index];
- }
- /* Return the offset of scalar field INDEX within the analysed type. Will
- return 0 if there is no field at that index. Only INDEX values 0 and
- 1 can be requested as the RiscV ABI only has special cases for
- structures with 1 or 2 fields. */
- int field_offset (int index) const
- {
- gdb_assert (index < (sizeof (m_offsets) / sizeof (m_offsets[0])));
- return m_offsets[index];
- }
- private:
- /* The number of scalar fields found within the structure after recursing
- into nested structures. */
- int m_number_of_fields;
- /* The types of the first two scalar fields found within the structure
- after recursing into nested structures. */
- struct type *m_types[2];
- /* The offsets of the first two scalar fields found within the structure
- after recursing into nested structures. */
- int m_offsets[2];
- /* Recursive core for ANALYSE, the OFFSET parameter tracks the byte
- offset from the start of the top level structure being analysed. */
- void analyse_inner (struct type *type, int offset);
- };
- /* See description in class declaration. */
- void
- riscv_struct_info::analyse_inner (struct type *type, int offset)
- {
- unsigned int count = type->num_fields ();
- unsigned int i;
- for (i = 0; i < count; ++i)
- {
- if (type->field (i).loc_kind () != FIELD_LOC_KIND_BITPOS)
- continue;
- struct type *field_type = type->field (i).type ();
- field_type = check_typedef (field_type);
- int field_offset
- = offset + type->field (i).loc_bitpos () / TARGET_CHAR_BIT;
- switch (field_type->code ())
- {
- case TYPE_CODE_STRUCT:
- analyse_inner (field_type, field_offset);
- break;
- default:
- /* RiscV only flattens out structures. Anything else does not
- need to be flattened, we just record the type, and when we
- look at the analysis results we'll realise this is not a
- structure we can special case, and pass the structure in
- memory. */
- if (m_number_of_fields < 2)
- {
- m_types[m_number_of_fields] = field_type;
- m_offsets[m_number_of_fields] = field_offset;
- }
- m_number_of_fields++;
- break;
- }
- /* RiscV only has special handling for structures with 1 or 2 scalar
- fields, any more than that and the structure is just passed in
- memory. We can safely drop out early when we find 3 or more
- fields then. */
- if (m_number_of_fields > 2)
- return;
- }
- }
- /* Like RISCV_CALL_ARG_SCALAR_INT, except the argument described by AINFO
- is a structure. Small structures on RiscV have some special case
- handling in order that the structure might be passed in register.
- Larger structures are passed in memory. After assigning location
- information to AINFO, CINFO will have been updated. */
- static void
- riscv_call_arg_struct (struct riscv_arg_info *ainfo,
- struct riscv_call_info *cinfo)
- {
- if (riscv_arg_regs_available (&cinfo->float_regs) >= 1)
- {
- struct riscv_struct_info sinfo;
- sinfo.analyse (ainfo->type);
- if (sinfo.number_of_fields () == 1
- && sinfo.field_type(0)->code () == TYPE_CODE_COMPLEX)
- {
- /* The following is similar to RISCV_CALL_ARG_COMPLEX_FLOAT,
- except we use the type of the complex field instead of the
- type from AINFO, and the first location might be at a non-zero
- offset. */
- if (TYPE_LENGTH (sinfo.field_type (0)) <= (2 * cinfo->flen)
- && riscv_arg_regs_available (&cinfo->float_regs) >= 2
- && !ainfo->is_unnamed)
- {
- bool result;
- int len = TYPE_LENGTH (sinfo.field_type (0)) / 2;
- int offset = sinfo.field_offset (0);
- result = riscv_assign_reg_location (&ainfo->argloc[0],
- &cinfo->float_regs, len,
- offset);
- gdb_assert (result);
- result = riscv_assign_reg_location (&ainfo->argloc[1],
- &cinfo->float_regs, len,
- (offset + len));
- gdb_assert (result);
- }
- else
- riscv_call_arg_scalar_int (ainfo, cinfo);
- return;
- }
- if (sinfo.number_of_fields () == 1
- && sinfo.field_type(0)->code () == TYPE_CODE_FLT)
- {
- /* The following is similar to RISCV_CALL_ARG_SCALAR_FLOAT,
- except we use the type of the first scalar field instead of
- the type from AINFO. Also the location might be at a non-zero
- offset. */
- if (TYPE_LENGTH (sinfo.field_type (0)) > cinfo->flen
- || ainfo->is_unnamed)
- riscv_call_arg_scalar_int (ainfo, cinfo);
- else
- {
- int offset = sinfo.field_offset (0);
- int len = TYPE_LENGTH (sinfo.field_type (0));
- if (!riscv_assign_reg_location (&ainfo->argloc[0],
- &cinfo->float_regs,
- len, offset))
- riscv_call_arg_scalar_int (ainfo, cinfo);
- }
- return;
- }
- if (sinfo.number_of_fields () == 2
- && sinfo.field_type(0)->code () == TYPE_CODE_FLT
- && TYPE_LENGTH (sinfo.field_type (0)) <= cinfo->flen
- && sinfo.field_type(1)->code () == TYPE_CODE_FLT
- && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->flen
- && riscv_arg_regs_available (&cinfo->float_regs) >= 2)
- {
- int len0 = TYPE_LENGTH (sinfo.field_type (0));
- int offset = sinfo.field_offset (0);
- if (!riscv_assign_reg_location (&ainfo->argloc[0],
- &cinfo->float_regs, len0, offset))
- error (_("failed during argument setup"));
- int len1 = TYPE_LENGTH (sinfo.field_type (1));
- offset = sinfo.field_offset (1);
- gdb_assert (len1 <= (TYPE_LENGTH (ainfo->type)
- - TYPE_LENGTH (sinfo.field_type (0))));
- if (!riscv_assign_reg_location (&ainfo->argloc[1],
- &cinfo->float_regs,
- len1, offset))
- error (_("failed during argument setup"));
- return;
- }
- if (sinfo.number_of_fields () == 2
- && riscv_arg_regs_available (&cinfo->int_regs) >= 1
- && (sinfo.field_type(0)->code () == TYPE_CODE_FLT
- && TYPE_LENGTH (sinfo.field_type (0)) <= cinfo->flen
- && is_integral_type (sinfo.field_type (1))
- && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->xlen))
- {
- int len0 = TYPE_LENGTH (sinfo.field_type (0));
- int offset = sinfo.field_offset (0);
- if (!riscv_assign_reg_location (&ainfo->argloc[0],
- &cinfo->float_regs, len0, offset))
- error (_("failed during argument setup"));
- int len1 = TYPE_LENGTH (sinfo.field_type (1));
- offset = sinfo.field_offset (1);
- gdb_assert (len1 <= cinfo->xlen);
- if (!riscv_assign_reg_location (&ainfo->argloc[1],
- &cinfo->int_regs, len1, offset))
- error (_("failed during argument setup"));
- return;
- }
- if (sinfo.number_of_fields () == 2
- && riscv_arg_regs_available (&cinfo->int_regs) >= 1
- && (is_integral_type (sinfo.field_type (0))
- && TYPE_LENGTH (sinfo.field_type (0)) <= cinfo->xlen
- && sinfo.field_type(1)->code () == TYPE_CODE_FLT
- && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->flen))
- {
- int len0 = TYPE_LENGTH (sinfo.field_type (0));
- int len1 = TYPE_LENGTH (sinfo.field_type (1));
- gdb_assert (len0 <= cinfo->xlen);
- gdb_assert (len1 <= cinfo->flen);
- int offset = sinfo.field_offset (0);
- if (!riscv_assign_reg_location (&ainfo->argloc[0],
- &cinfo->int_regs, len0, offset))
- error (_("failed during argument setup"));
- offset = sinfo.field_offset (1);
- if (!riscv_assign_reg_location (&ainfo->argloc[1],
- &cinfo->float_regs,
- len1, offset))
- error (_("failed during argument setup"));
- return;
- }
- }
- /* Non of the structure flattening cases apply, so we just pass using
- the integer ABI. */
- riscv_call_arg_scalar_int (ainfo, cinfo);
- }
- /* Assign a location to call (or return) argument AINFO, the location is
- selected from CINFO which holds information about what call argument
- locations are available for use next. The TYPE is the type of the
- argument being passed, this information is recorded into AINFO (along
- with some additional information derived from the type). IS_UNNAMED
- is true if this is an unnamed (stdarg) argument, this info is also
- recorded into AINFO.
- After assigning a location to AINFO, CINFO will have been updated. */
- static void
- riscv_arg_location (struct gdbarch *gdbarch,
- struct riscv_arg_info *ainfo,
- struct riscv_call_info *cinfo,
- struct type *type, bool is_unnamed)
- {
- ainfo->type = type;
- ainfo->length = TYPE_LENGTH (ainfo->type);
- ainfo->align = type_align (ainfo->type);
- ainfo->is_unnamed = is_unnamed;
- ainfo->contents = nullptr;
- ainfo->argloc[0].c_length = 0;
- ainfo->argloc[1].c_length = 0;
- switch (ainfo->type->code ())
- {
- case TYPE_CODE_INT:
- case TYPE_CODE_BOOL:
- case TYPE_CODE_CHAR:
- case TYPE_CODE_RANGE:
- case TYPE_CODE_ENUM:
- case TYPE_CODE_PTR:
- case TYPE_CODE_FIXED_POINT:
- if (ainfo->length <= cinfo->xlen)
- {
- ainfo->type = builtin_type (gdbarch)->builtin_long;
- ainfo->length = cinfo->xlen;
- }
- else if (ainfo->length <= (2 * cinfo->xlen))
- {
- ainfo->type = builtin_type (gdbarch)->builtin_long_long;
- ainfo->length = 2 * cinfo->xlen;
- }
- /* Recalculate the alignment requirement. */
- ainfo->align = type_align (ainfo->type);
- riscv_call_arg_scalar_int (ainfo, cinfo);
- break;
- case TYPE_CODE_FLT:
- riscv_call_arg_scalar_float (ainfo, cinfo);
- break;
- case TYPE_CODE_COMPLEX:
- riscv_call_arg_complex_float (ainfo, cinfo);
- break;
- case TYPE_CODE_STRUCT:
- riscv_call_arg_struct (ainfo, cinfo);
- break;
- default:
- riscv_call_arg_scalar_int (ainfo, cinfo);
- break;
- }
- }
- /* Used for printing debug information about the call argument location in
- INFO to STREAM. The addresses in SP_REFS and SP_ARGS are the base
- addresses for the location of pass-by-reference and
- arguments-on-the-stack memory areas. */
- static void
- riscv_print_arg_location (ui_file *stream, struct gdbarch *gdbarch,
- struct riscv_arg_info *info,
- CORE_ADDR sp_refs, CORE_ADDR sp_args)
- {
- gdb_printf (stream, "type: '%s', length: 0x%x, alignment: 0x%x",
- TYPE_SAFE_NAME (info->type), info->length, info->align);
- switch (info->argloc[0].loc_type)
- {
- case riscv_arg_info::location::in_reg:
- gdb_printf
- (stream, ", register %s",
- gdbarch_register_name (gdbarch, info->argloc[0].loc_data.regno));
- if (info->argloc[0].c_length < info->length)
- {
- switch (info->argloc[1].loc_type)
- {
- case riscv_arg_info::location::in_reg:
- gdb_printf
- (stream, ", register %s",
- gdbarch_register_name (gdbarch,
- info->argloc[1].loc_data.regno));
- break;
- case riscv_arg_info::location::on_stack:
- gdb_printf (stream, ", on stack at offset 0x%x",
- info->argloc[1].loc_data.offset);
- break;
- case riscv_arg_info::location::by_ref:
- default:
- /* The second location should never be a reference, any
- argument being passed by reference just places its address
- in the first location and is done. */
- error (_("invalid argument location"));
- break;
- }
- if (info->argloc[1].c_offset > info->argloc[0].c_length)
- gdb_printf (stream, " (offset 0x%x)",
- info->argloc[1].c_offset);
- }
- break;
- case riscv_arg_info::location::on_stack:
- gdb_printf (stream, ", on stack at offset 0x%x",
- info->argloc[0].loc_data.offset);
- break;
- case riscv_arg_info::location::by_ref:
- gdb_printf
- (stream, ", by reference, data at offset 0x%x (%s)",
- info->argloc[0].loc_data.offset,
- core_addr_to_string (sp_refs + info->argloc[0].loc_data.offset));
- if (info->argloc[1].loc_type
- == riscv_arg_info::location::in_reg)
- gdb_printf
- (stream, ", address in register %s",
- gdbarch_register_name (gdbarch, info->argloc[1].loc_data.regno));
- else
- {
- gdb_assert (info->argloc[1].loc_type
- == riscv_arg_info::location::on_stack);
- gdb_printf
- (stream, ", address on stack at offset 0x%x (%s)",
- info->argloc[1].loc_data.offset,
- core_addr_to_string (sp_args + info->argloc[1].loc_data.offset));
- }
- break;
- default:
- gdb_assert_not_reached ("unknown argument location type");
- }
- }
- /* Wrapper around REGCACHE->cooked_write. Places the LEN bytes of DATA
- into a buffer that is at least as big as the register REGNUM, padding
- out the DATA with either 0x00, or 0xff. For floating point registers
- 0xff is used, for everyone else 0x00 is used. */
- static void
- riscv_regcache_cooked_write (int regnum, const gdb_byte *data, int len,
- struct regcache *regcache, int flen)
- {
- gdb_byte tmp [sizeof (ULONGEST)];
- /* FP values in FP registers must be NaN-boxed. */
- if (riscv_is_fp_regno_p (regnum) && len < flen)
- memset (tmp, -1, sizeof (tmp));
- else
- memset (tmp, 0, sizeof (tmp));
- memcpy (tmp, data, len);
- regcache->cooked_write (regnum, tmp);
- }
- /* Implement the push dummy call gdbarch callback. */
- static CORE_ADDR
- riscv_push_dummy_call (struct gdbarch *gdbarch,
- struct value *function,
- struct regcache *regcache,
- CORE_ADDR bp_addr,
- int nargs,
- struct value **args,
- CORE_ADDR sp,
- function_call_return_method return_method,
- CORE_ADDR struct_addr)
- {
- int i;
- CORE_ADDR sp_args, sp_refs;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- struct riscv_arg_info *arg_info =
- (struct riscv_arg_info *) alloca (nargs * sizeof (struct riscv_arg_info));
- struct riscv_call_info call_info (gdbarch);
- CORE_ADDR osp = sp;
- struct type *ftype = check_typedef (value_type (function));
- if (ftype->code () == TYPE_CODE_PTR)
- ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
- /* We'll use register $a0 if we're returning a struct. */
- if (return_method == return_method_struct)
- ++call_info.int_regs.next_regnum;
- for (i = 0; i < nargs; ++i)
- {
- struct value *arg_value;
- struct type *arg_type;
- struct riscv_arg_info *info = &arg_info[i];
- arg_value = args[i];
- arg_type = check_typedef (value_type (arg_value));
- riscv_arg_location (gdbarch, info, &call_info, arg_type,
- ftype->has_varargs () && i >= ftype->num_fields ());
- if (info->type != arg_type)
- arg_value = value_cast (info->type, arg_value);
- info->contents = value_contents (arg_value).data ();
- }
- /* Adjust the stack pointer and align it. */
- sp = sp_refs = align_down (sp - call_info.memory.ref_offset, SP_ALIGNMENT);
- sp = sp_args = align_down (sp - call_info.memory.arg_offset, SP_ALIGNMENT);
- if (riscv_debug_infcall > 0)
- {
- gdb_printf (gdb_stdlog, "dummy call args:\n");
- gdb_printf (gdb_stdlog, ": floating point ABI %s in use\n",
- (riscv_has_fp_abi (gdbarch) ? "is" : "is not"));
- gdb_printf (gdb_stdlog, ": xlen: %d\n: flen: %d\n",
- call_info.xlen, call_info.flen);
- if (return_method == return_method_struct)
- gdb_printf (gdb_stdlog,
- "[*] struct return pointer in register $A0\n");
- for (i = 0; i < nargs; ++i)
- {
- struct riscv_arg_info *info = &arg_info [i];
- gdb_printf (gdb_stdlog, "[%2d] ", i);
- riscv_print_arg_location (gdb_stdlog, gdbarch, info, sp_refs, sp_args);
- gdb_printf (gdb_stdlog, "\n");
- }
- if (call_info.memory.arg_offset > 0
- || call_info.memory.ref_offset > 0)
- {
- gdb_printf (gdb_stdlog, " Original sp: %s\n",
- core_addr_to_string (osp));
- gdb_printf (gdb_stdlog, "Stack required (for args): 0x%x\n",
- call_info.memory.arg_offset);
- gdb_printf (gdb_stdlog, "Stack required (for refs): 0x%x\n",
- call_info.memory.ref_offset);
- gdb_printf (gdb_stdlog, " Stack allocated: %s\n",
- core_addr_to_string_nz (osp - sp));
- }
- }
- /* Now load the argument into registers, or onto the stack. */
- if (return_method == return_method_struct)
- {
- gdb_byte buf[sizeof (LONGEST)];
- store_unsigned_integer (buf, call_info.xlen, byte_order, struct_addr);
- regcache->cooked_write (RISCV_A0_REGNUM, buf);
- }
- for (i = 0; i < nargs; ++i)
- {
- CORE_ADDR dst;
- int second_arg_length = 0;
- const gdb_byte *second_arg_data;
- struct riscv_arg_info *info = &arg_info [i];
- gdb_assert (info->length > 0);
- switch (info->argloc[0].loc_type)
- {
- case riscv_arg_info::location::in_reg:
- {
- gdb_assert (info->argloc[0].c_length <= info->length);
- riscv_regcache_cooked_write (info->argloc[0].loc_data.regno,
- (info->contents
- + info->argloc[0].c_offset),
- info->argloc[0].c_length,
- regcache, call_info.flen);
- second_arg_length =
- (((info->argloc[0].c_length + info->argloc[0].c_offset) < info->length)
- ? info->argloc[1].c_length : 0);
- second_arg_data = info->contents + info->argloc[1].c_offset;
- }
- break;
- case riscv_arg_info::location::on_stack:
- dst = sp_args + info->argloc[0].loc_data.offset;
- write_memory (dst, info->contents, info->length);
- second_arg_length = 0;
- break;
- case riscv_arg_info::location::by_ref:
- dst = sp_refs + info->argloc[0].loc_data.offset;
- write_memory (dst, info->contents, info->length);
- second_arg_length = call_info.xlen;
- second_arg_data = (gdb_byte *) &dst;
- break;
- default:
- gdb_assert_not_reached ("unknown argument location type");
- }
- if (second_arg_length > 0)
- {
- switch (info->argloc[1].loc_type)
- {
- case riscv_arg_info::location::in_reg:
- {
- gdb_assert ((riscv_is_fp_regno_p (info->argloc[1].loc_data.regno)
- && second_arg_length <= call_info.flen)
- || second_arg_length <= call_info.xlen);
- riscv_regcache_cooked_write (info->argloc[1].loc_data.regno,
- second_arg_data,
- second_arg_length,
- regcache, call_info.flen);
- }
- break;
- case riscv_arg_info::location::on_stack:
- {
- CORE_ADDR arg_addr;
- arg_addr = sp_args + info->argloc[1].loc_data.offset;
- write_memory (arg_addr, second_arg_data, second_arg_length);
- break;
- }
- case riscv_arg_info::location::by_ref:
- default:
- /* The second location should never be a reference, any
- argument being passed by reference just places its address
- in the first location and is done. */
- error (_("invalid argument location"));
- break;
- }
- }
- }
- /* Set the dummy return value to bp_addr.
- A dummy breakpoint will be setup to execute the call. */
- if (riscv_debug_infcall > 0)
- gdb_printf (gdb_stdlog, ": writing $ra = %s\n",
- core_addr_to_string (bp_addr));
- regcache_cooked_write_unsigned (regcache, RISCV_RA_REGNUM, bp_addr);
- /* Finally, update the stack pointer. */
- if (riscv_debug_infcall > 0)
- gdb_printf (gdb_stdlog, ": writing $sp = %s\n",
- core_addr_to_string (sp));
- regcache_cooked_write_unsigned (regcache, RISCV_SP_REGNUM, sp);
- return sp;
- }
- /* Implement the return_value gdbarch method. */
- static enum return_value_convention
- riscv_return_value (struct gdbarch *gdbarch,
- struct value *function,
- struct type *type,
- struct regcache *regcache,
- gdb_byte *readbuf,
- const gdb_byte *writebuf)
- {
- struct riscv_call_info call_info (gdbarch);
- struct riscv_arg_info info;
- struct type *arg_type;
- arg_type = check_typedef (type);
- riscv_arg_location (gdbarch, &info, &call_info, arg_type, false);
- if (riscv_debug_infcall > 0)
- {
- gdb_printf (gdb_stdlog, "riscv return value:\n");
- gdb_printf (gdb_stdlog, "[R] ");
- riscv_print_arg_location (gdb_stdlog, gdbarch, &info, 0, 0);
- gdb_printf (gdb_stdlog, "\n");
- }
- if (readbuf != nullptr || writebuf != nullptr)
- {
- unsigned int arg_len;
- struct value *abi_val;
- gdb_byte *old_readbuf = nullptr;
- int regnum;
- /* We only do one thing at a time. */
- gdb_assert (readbuf == nullptr || writebuf == nullptr);
- /* In some cases the argument is not returned as the declared type,
- and we need to cast to or from the ABI type in order to
- correctly access the argument. When writing to the machine we
- do the cast here, when reading from the machine the cast occurs
- later, after extracting the value. As the ABI type can be
- larger than the declared type, then the read or write buffers
- passed in might be too small. Here we ensure that we are using
- buffers of sufficient size. */
- if (writebuf != nullptr)
- {
- struct value *arg_val;
- if (is_fixed_point_type (arg_type))
- {
- /* Convert the argument to the type used to pass
- the return value, but being careful to preserve
- the fact that the value needs to be returned
- unscaled. */
- gdb_mpz unscaled;
- unscaled.read (gdb::make_array_view (writebuf,
- TYPE_LENGTH (arg_type)),
- type_byte_order (arg_type),
- arg_type->is_unsigned ());
- abi_val = allocate_value (info.type);
- unscaled.write (value_contents_raw (abi_val),
- type_byte_order (info.type),
- info.type->is_unsigned ());
- }
- else
- {
- arg_val = value_from_contents (arg_type, writebuf);
- abi_val = value_cast (info.type, arg_val);
- }
- writebuf = value_contents_raw (abi_val).data ();
- }
- else
- {
- abi_val = allocate_value (info.type);
- old_readbuf = readbuf;
- readbuf = value_contents_raw (abi_val).data ();
- }
- arg_len = TYPE_LENGTH (info.type);
- switch (info.argloc[0].loc_type)
- {
- /* Return value in register(s). */
- case riscv_arg_info::location::in_reg:
- {
- regnum = info.argloc[0].loc_data.regno;
- gdb_assert (info.argloc[0].c_length <= arg_len);
- gdb_assert (info.argloc[0].c_length
- <= register_size (gdbarch, regnum));
- if (readbuf)
- {
- gdb_byte *ptr = readbuf + info.argloc[0].c_offset;
- regcache->cooked_read_part (regnum, 0,
- info.argloc[0].c_length,
- ptr);
- }
- if (writebuf)
- {
- const gdb_byte *ptr = writebuf + info.argloc[0].c_offset;
- riscv_regcache_cooked_write (regnum, ptr,
- info.argloc[0].c_length,
- regcache, call_info.flen);
- }
- /* A return value in register can have a second part in a
- second register. */
- if (info.argloc[1].c_length > 0)
- {
- switch (info.argloc[1].loc_type)
- {
- case riscv_arg_info::location::in_reg:
- regnum = info.argloc[1].loc_data.regno;
- gdb_assert ((info.argloc[0].c_length
- + info.argloc[1].c_length) <= arg_len);
- gdb_assert (info.argloc[1].c_length
- <= register_size (gdbarch, regnum));
- if (readbuf)
- {
- readbuf += info.argloc[1].c_offset;
- regcache->cooked_read_part (regnum, 0,
- info.argloc[1].c_length,
- readbuf);
- }
- if (writebuf)
- {
- const gdb_byte *ptr
- = writebuf + info.argloc[1].c_offset;
- riscv_regcache_cooked_write
- (regnum, ptr, info.argloc[1].c_length,
- regcache, call_info.flen);
- }
- break;
- case riscv_arg_info::location::by_ref:
- case riscv_arg_info::location::on_stack:
- default:
- error (_("invalid argument location"));
- break;
- }
- }
- }
- break;
- /* Return value by reference will have its address in A0. */
- case riscv_arg_info::location::by_ref:
- {
- ULONGEST addr;
- regcache_cooked_read_unsigned (regcache, RISCV_A0_REGNUM,
- &addr);
- if (readbuf != nullptr)
- read_memory (addr, readbuf, info.length);
- if (writebuf != nullptr)
- write_memory (addr, writebuf, info.length);
- }
- break;
- case riscv_arg_info::location::on_stack:
- default:
- error (_("invalid argument location"));
- break;
- }
- /* This completes the cast from abi type back to the declared type
- in the case that we are reading from the machine. See the
- comment at the head of this block for more details. */
- if (readbuf != nullptr)
- {
- struct value *arg_val;
- if (is_fixed_point_type (arg_type))
- {
- /* Convert abi_val to the actual return type, but
- being careful to preserve the fact that abi_val
- is unscaled. */
- gdb_mpz unscaled;
- unscaled.read (value_contents (abi_val),
- type_byte_order (info.type),
- info.type->is_unsigned ());
- arg_val = allocate_value (arg_type);
- unscaled.write (value_contents_raw (arg_val),
- type_byte_order (arg_type),
- arg_type->is_unsigned ());
- }
- else
- arg_val = value_cast (arg_type, abi_val);
- memcpy (old_readbuf, value_contents_raw (arg_val).data (),
- TYPE_LENGTH (arg_type));
- }
- }
- switch (info.argloc[0].loc_type)
- {
- case riscv_arg_info::location::in_reg:
- return RETURN_VALUE_REGISTER_CONVENTION;
- case riscv_arg_info::location::by_ref:
- return RETURN_VALUE_ABI_PRESERVES_ADDRESS;
- case riscv_arg_info::location::on_stack:
- default:
- error (_("invalid argument location"));
- }
- }
- /* Implement the frame_align gdbarch method. */
- static CORE_ADDR
- riscv_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
- {
- return align_down (addr, 16);
- }
- /* Generate, or return the cached frame cache for the RiscV frame
- unwinder. */
- static struct riscv_unwind_cache *
- riscv_frame_cache (struct frame_info *this_frame, void **this_cache)
- {
- CORE_ADDR pc, start_addr;
- struct riscv_unwind_cache *cache;
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- int numregs, regno;
- if ((*this_cache) != NULL)
- return (struct riscv_unwind_cache *) *this_cache;
- cache = FRAME_OBSTACK_ZALLOC (struct riscv_unwind_cache);
- cache->regs = trad_frame_alloc_saved_regs (this_frame);
- (*this_cache) = cache;
- /* Scan the prologue, filling in the cache. */
- start_addr = get_frame_func (this_frame);
- pc = get_frame_pc (this_frame);
- riscv_scan_prologue (gdbarch, start_addr, pc, cache);
- /* We can now calculate the frame base address. */
- cache->frame_base
- = (get_frame_register_unsigned (this_frame, cache->frame_base_reg)
- + cache->frame_base_offset);
- if (riscv_debug_unwinder)
- gdb_printf (gdb_stdlog, "Frame base is %s ($%s + 0x%x)\n",
- core_addr_to_string (cache->frame_base),
- gdbarch_register_name (gdbarch,
- cache->frame_base_reg),
- cache->frame_base_offset);
- /* The prologue scanner sets the address of registers stored to the stack
- as the offset of that register from the frame base. The prologue
- scanner doesn't know the actual frame base value, and so is unable to
- compute the exact address. We do now know the frame base value, so
- update the address of registers stored to the stack. */
- numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
- for (regno = 0; regno < numregs; ++regno)
- {
- if (cache->regs[regno].is_addr ())
- cache->regs[regno].set_addr (cache->regs[regno].addr ()
- + cache->frame_base);
- }
- /* The previous $pc can be found wherever the $ra value can be found.
- The previous $ra value is gone, this would have been stored be the
- previous frame if required. */
- cache->regs[gdbarch_pc_regnum (gdbarch)] = cache->regs[RISCV_RA_REGNUM];
- cache->regs[RISCV_RA_REGNUM].set_unknown ();
- /* Build the frame id. */
- cache->this_id = frame_id_build (cache->frame_base, start_addr);
- /* The previous $sp value is the frame base value. */
- cache->regs[gdbarch_sp_regnum (gdbarch)].set_value (cache->frame_base);
- return cache;
- }
- /* Implement the this_id callback for RiscV frame unwinder. */
- static void
- riscv_frame_this_id (struct frame_info *this_frame,
- void **prologue_cache,
- struct frame_id *this_id)
- {
- struct riscv_unwind_cache *cache;
- try
- {
- cache = riscv_frame_cache (this_frame, prologue_cache);
- *this_id = cache->this_id;
- }
- catch (const gdb_exception_error &ex)
- {
- /* Ignore errors, this leaves the frame id as the predefined outer
- frame id which terminates the backtrace at this point. */
- }
- }
- /* Implement the prev_register callback for RiscV frame unwinder. */
- static struct value *
- riscv_frame_prev_register (struct frame_info *this_frame,
- void **prologue_cache,
- int regnum)
- {
- struct riscv_unwind_cache *cache;
- cache = riscv_frame_cache (this_frame, prologue_cache);
- return trad_frame_get_prev_register (this_frame, cache->regs, regnum);
- }
- /* Structure defining the RiscV normal frame unwind functions. Since we
- are the fallback unwinder (DWARF unwinder is used first), we use the
- default frame sniffer, which always accepts the frame. */
- static const struct frame_unwind riscv_frame_unwind =
- {
- /*.name =*/ "riscv prologue",
- /*.type =*/ NORMAL_FRAME,
- /*.stop_reason =*/ default_frame_unwind_stop_reason,
- /*.this_id =*/ riscv_frame_this_id,
- /*.prev_register =*/ riscv_frame_prev_register,
- /*.unwind_data =*/ NULL,
- /*.sniffer =*/ default_frame_sniffer,
- /*.dealloc_cache =*/ NULL,
- /*.prev_arch =*/ NULL,
- };
- /* Extract a set of required target features out of ABFD. If ABFD is
- nullptr then a RISCV_GDBARCH_FEATURES is returned in its default state. */
- static struct riscv_gdbarch_features
- riscv_features_from_bfd (const bfd *abfd)
- {
- struct riscv_gdbarch_features features;
- /* Now try to improve on the defaults by looking at the binary we are
- going to execute. We assume the user knows what they are doing and
- that the target will match the binary. Remember, this code path is
- only used at all if the target hasn't given us a description, so this
- is really a last ditched effort to do something sane before giving
- up. */
- if (abfd != nullptr && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
- {
- unsigned char eclass = elf_elfheader (abfd)->e_ident[EI_CLASS];
- int e_flags = elf_elfheader (abfd)->e_flags;
- if (eclass == ELFCLASS32)
- features.xlen = 4;
- else if (eclass == ELFCLASS64)
- features.xlen = 8;
- else
- internal_error (__FILE__, __LINE__,
- _("unknown ELF header class %d"), eclass);
- if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE)
- features.flen = 8;
- else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
- features.flen = 4;
- if (e_flags & EF_RISCV_RVE)
- {
- if (features.xlen == 8)
- {
- warning (_("64-bit ELF with RV32E flag set! Assuming 32-bit"));
- features.xlen = 4;
- }
- features.embedded = true;
- }
- }
- return features;
- }
- /* Find a suitable default target description. Use the contents of INFO,
- specifically the bfd object being executed, to guide the selection of a
- suitable default target description. */
- static const struct target_desc *
- riscv_find_default_target_description (const struct gdbarch_info info)
- {
- /* Extract desired feature set from INFO. */
- struct riscv_gdbarch_features features
- = riscv_features_from_bfd (info.abfd);
- /* If the XLEN field is still 0 then we got nothing useful from INFO.BFD,
- maybe there was no bfd object. In this case we fall back to a minimal
- useful target with no floating point, the x-register size is selected
- based on the architecture from INFO. */
- if (features.xlen == 0)
- features.xlen = info.bfd_arch_info->bits_per_word == 32 ? 4 : 8;
- /* Now build a target description based on the feature set. */
- return riscv_lookup_target_description (features);
- }
- /* Add all the RISC-V specific register groups into GDBARCH. */
- static void
- riscv_add_reggroups (struct gdbarch *gdbarch)
- {
- reggroup_add (gdbarch, csr_reggroup);
- }
- /* Implement the "dwarf2_reg_to_regnum" gdbarch method. */
- static int
- riscv_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
- {
- if (reg < RISCV_DWARF_REGNUM_X31)
- return RISCV_ZERO_REGNUM + (reg - RISCV_DWARF_REGNUM_X0);
- else if (reg < RISCV_DWARF_REGNUM_F31)
- return RISCV_FIRST_FP_REGNUM + (reg - RISCV_DWARF_REGNUM_F0);
- else if (reg >= RISCV_DWARF_FIRST_CSR && reg <= RISCV_DWARF_LAST_CSR)
- return RISCV_FIRST_CSR_REGNUM + (reg - RISCV_DWARF_FIRST_CSR);
- else if (reg >= RISCV_DWARF_REGNUM_V0 && reg <= RISCV_DWARF_REGNUM_V31)
- return RISCV_V0_REGNUM + (reg - RISCV_DWARF_REGNUM_V0);
- return -1;
- }
- /* Implement the gcc_target_options method. We have to select the arch and abi
- from the feature info. We have enough feature info to select the abi, but
- not enough info for the arch given all of the possible architecture
- extensions. So choose reasonable defaults for now. */
- static std::string
- riscv_gcc_target_options (struct gdbarch *gdbarch)
- {
- int isa_xlen = riscv_isa_xlen (gdbarch);
- int isa_flen = riscv_isa_flen (gdbarch);
- int abi_xlen = riscv_abi_xlen (gdbarch);
- int abi_flen = riscv_abi_flen (gdbarch);
- std::string target_options;
- target_options = "-march=rv";
- if (isa_xlen == 8)
- target_options += "64";
- else
- target_options += "32";
- if (isa_flen == 8)
- target_options += "gc";
- else if (isa_flen == 4)
- target_options += "imafc";
- else
- target_options += "imac";
- target_options += " -mabi=";
- if (abi_xlen == 8)
- target_options += "lp64";
- else
- target_options += "ilp32";
- if (abi_flen == 8)
- target_options += "d";
- else if (abi_flen == 4)
- target_options += "f";
- /* The gdb loader doesn't handle link-time relaxation relocations. */
- target_options += " -mno-relax";
- return target_options;
- }
- /* Call back from tdesc_use_registers, called for each unknown register
- found in the target description.
- See target-description.h (typedef tdesc_unknown_register_ftype) for a
- discussion of the arguments and return values. */
- static int
- riscv_tdesc_unknown_reg (struct gdbarch *gdbarch, tdesc_feature *feature,
- const char *reg_name, int possible_regnum)
- {
- /* At one point in time GDB had an incorrect default target description
- that duplicated the fflags, frm, and fcsr registers in both the FPU
- and CSR register sets.
- Some targets (QEMU) copied these target descriptions into their source
- tree, and so we're currently stuck working with some targets that
- declare the same registers twice.
- There's not much we can do about this any more. Assuming the target
- will direct a request for either register number to the correct
- underlying hardware register then it doesn't matter which one GDB
- uses, so long as we (GDB) are consistent (so that we don't end up with
- invalid cache misses).
- As we always scan the FPU registers first, then the CSRs, if the
- target has included the offending registers in both sets then we will
- always see the FPU copies here, as the CSR versions will replace them
- in the register list.
- To prevent these duplicates showing up in any of the register list,
- record their register numbers here. */
- if (strcmp (tdesc_feature_name (feature), riscv_freg_feature.name ()) == 0)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int *regnum_ptr = nullptr;
- if (strcmp (reg_name, "fflags") == 0)
- regnum_ptr = &tdep->duplicate_fflags_regnum;
- else if (strcmp (reg_name, "frm") == 0)
- regnum_ptr = &tdep->duplicate_frm_regnum;
- else if (strcmp (reg_name, "fcsr") == 0)
- regnum_ptr = &tdep->duplicate_fcsr_regnum;
- if (regnum_ptr != nullptr)
- {
- /* This means the register appears more than twice in the target
- description. Just let GDB add this as another register.
- We'll have duplicates in the register name list, but there's
- not much more we can do. */
- if (*regnum_ptr != -1)
- return -1;
- /* Record the number assigned to this register, then return the
- number (so it actually gets assigned to this register). */
- *regnum_ptr = possible_regnum;
- return possible_regnum;
- }
- }
- /* Any unknown registers in the CSR feature are recorded within a single
- block so we can easily identify these registers when making choices
- about register groups in riscv_register_reggroup_p. */
- if (strcmp (tdesc_feature_name (feature), riscv_csr_feature.name ()) == 0)
- {
- riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- if (tdep->unknown_csrs_first_regnum == -1)
- tdep->unknown_csrs_first_regnum = possible_regnum;
- gdb_assert (tdep->unknown_csrs_first_regnum
- + tdep->unknown_csrs_count == possible_regnum);
- tdep->unknown_csrs_count++;
- return possible_regnum;
- }
- /* Some other unknown register. Don't assign this a number now, it will
- be assigned a number automatically later by the target description
- handling code. */
- return -1;
- }
- /* Implement the gnu_triplet_regexp method. A single compiler supports both
- 32-bit and 64-bit code, and may be named riscv32 or riscv64 or (not
- recommended) riscv. */
- static const char *
- riscv_gnu_triplet_regexp (struct gdbarch *gdbarch)
- {
- return "riscv(32|64)?";
- }
- /* Initialize the current architecture based on INFO. If possible,
- re-use an architecture from ARCHES, which is a list of
- architectures already created during this debugging session.
- Called e.g. at program startup, when reading a core file, and when
- reading a binary file. */
- static struct gdbarch *
- riscv_gdbarch_init (struct gdbarch_info info,
- struct gdbarch_list *arches)
- {
- struct gdbarch *gdbarch;
- struct riscv_gdbarch_features features;
- const struct target_desc *tdesc = info.target_desc;
- /* Ensure we always have a target description. */
- if (!tdesc_has_registers (tdesc))
- tdesc = riscv_find_default_target_description (info);
- gdb_assert (tdesc != nullptr);
- if (riscv_debug_gdbarch)
- gdb_printf (gdb_stdlog, "Have got a target description\n");
- tdesc_arch_data_up tdesc_data = tdesc_data_alloc ();
- std::vector<riscv_pending_register_alias> pending_aliases;
- bool valid_p = (riscv_xreg_feature.check (tdesc, tdesc_data.get (),
- &pending_aliases, &features)
- && riscv_freg_feature.check (tdesc, tdesc_data.get (),
- &pending_aliases, &features)
- && riscv_virtual_feature.check (tdesc, tdesc_data.get (),
- &pending_aliases, &features)
- && riscv_csr_feature.check (tdesc, tdesc_data.get (),
- &pending_aliases, &features)
- && riscv_vector_feature.check (tdesc, tdesc_data.get (),
- &pending_aliases, &features));
- if (!valid_p)
- {
- if (riscv_debug_gdbarch)
- gdb_printf (gdb_stdlog, "Target description is not valid\n");
- return NULL;
- }
- /* Have a look at what the supplied (if any) bfd object requires of the
- target, then check that this matches with what the target is
- providing. */
- struct riscv_gdbarch_features abi_features
- = riscv_features_from_bfd (info.abfd);
- /* If the ABI_FEATURES xlen is 0 then this indicates we got no useful abi
- features from the INFO object. In this case we just treat the
- hardware features as defining the abi. */
- if (abi_features.xlen == 0)
- abi_features = features;
- /* In theory a binary compiled for RV32 could run on an RV64 target,
- however, this has not been tested in GDB yet, so for now we require
- that the requested xlen match the targets xlen. */
- if (abi_features.xlen != features.xlen)
- error (_("bfd requires xlen %d, but target has xlen %d"),
- abi_features.xlen, features.xlen);
- /* We do support running binaries compiled for 32-bit float on targets
- with 64-bit float, so we only complain if the binary requires more
- than the target has available. */
- if (abi_features.flen > features.flen)
- error (_("bfd requires flen %d, but target has flen %d"),
- abi_features.flen, features.flen);
- /* Find a candidate among the list of pre-declared architectures. */
- for (arches = gdbarch_list_lookup_by_info (arches, &info);
- arches != NULL;
- arches = gdbarch_list_lookup_by_info (arches->next, &info))
- {
- /* Check that the feature set of the ARCHES matches the feature set
- we are looking for. If it doesn't then we can't reuse this
- gdbarch. */
- riscv_gdbarch_tdep *other_tdep
- = (riscv_gdbarch_tdep *) gdbarch_tdep (arches->gdbarch);
- if (other_tdep->isa_features != features
- || other_tdep->abi_features != abi_features)
- continue;
- break;
- }
- if (arches != NULL)
- return arches->gdbarch;
- /* None found, so create a new architecture from the information provided. */
- riscv_gdbarch_tdep *tdep = new riscv_gdbarch_tdep;
- gdbarch = gdbarch_alloc (&info, tdep);
- tdep->isa_features = features;
- tdep->abi_features = abi_features;
- /* Target data types. */
- set_gdbarch_short_bit (gdbarch, 16);
- set_gdbarch_int_bit (gdbarch, 32);
- set_gdbarch_long_bit (gdbarch, riscv_isa_xlen (gdbarch) * 8);
- set_gdbarch_long_long_bit (gdbarch, 64);
- set_gdbarch_float_bit (gdbarch, 32);
- set_gdbarch_double_bit (gdbarch, 64);
- set_gdbarch_long_double_bit (gdbarch, 128);
- set_gdbarch_long_double_format (gdbarch, floatformats_ieee_quad);
- set_gdbarch_ptr_bit (gdbarch, riscv_isa_xlen (gdbarch) * 8);
- set_gdbarch_char_signed (gdbarch, 0);
- set_gdbarch_type_align (gdbarch, riscv_type_align);
- /* Information about the target architecture. */
- set_gdbarch_return_value (gdbarch, riscv_return_value);
- set_gdbarch_breakpoint_kind_from_pc (gdbarch, riscv_breakpoint_kind_from_pc);
- set_gdbarch_sw_breakpoint_from_kind (gdbarch, riscv_sw_breakpoint_from_kind);
- set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
- /* Functions to analyze frames. */
- set_gdbarch_skip_prologue (gdbarch, riscv_skip_prologue);
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- set_gdbarch_frame_align (gdbarch, riscv_frame_align);
- /* Functions handling dummy frames. */
- set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
- set_gdbarch_push_dummy_code (gdbarch, riscv_push_dummy_code);
- set_gdbarch_push_dummy_call (gdbarch, riscv_push_dummy_call);
- /* Frame unwinders. Use DWARF debug info if available, otherwise use our own
- unwinder. */
- dwarf2_append_unwinders (gdbarch);
- frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
- /* Register architecture. */
- riscv_add_reggroups (gdbarch);
- /* Internal <-> external register number maps. */
- set_gdbarch_dwarf2_reg_to_regnum (gdbarch, riscv_dwarf_reg_to_regnum);
- /* We reserve all possible register numbers for the known registers.
- This means the target description mechanism will add any target
- specific registers after this number. This helps make debugging GDB
- just a little easier. */
- set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
- /* We don't have to provide the count of 0 here (its the default) but
- include this line to make it explicit that, right now, we don't have
- any pseudo registers on RISC-V. */
- set_gdbarch_num_pseudo_regs (gdbarch, 0);
- /* Some specific register numbers GDB likes to know about. */
- set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
- set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
- set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
- /* Finalise the target description registers. */
- tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data),
- riscv_tdesc_unknown_reg);
- /* Override the register type callback setup by the target description
- mechanism. This allows us to provide special type for floating point
- registers. */
- set_gdbarch_register_type (gdbarch, riscv_register_type);
- /* Override the register name callback setup by the target description
- mechanism. This allows us to force our preferred names for the
- registers, no matter what the target description called them. */
- set_gdbarch_register_name (gdbarch, riscv_register_name);
- /* Override the register group callback setup by the target description
- mechanism. This allows us to force registers into the groups we
- want, ignoring what the target tells us. */
- set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p);
- /* Create register aliases for alternative register names. We only
- create aliases for registers which were mentioned in the target
- description. */
- for (const auto &alias : pending_aliases)
- alias.create (gdbarch);
- /* Compile command hooks. */
- set_gdbarch_gcc_target_options (gdbarch, riscv_gcc_target_options);
- set_gdbarch_gnu_triplet_regexp (gdbarch, riscv_gnu_triplet_regexp);
- /* Disassembler options support. */
- set_gdbarch_valid_disassembler_options (gdbarch,
- disassembler_options_riscv ());
- set_gdbarch_disassembler_options (gdbarch, &riscv_disassembler_options);
- /* Hook in OS ABI-specific overrides, if they have been registered. */
- gdbarch_init_osabi (info, gdbarch);
- register_riscv_ravenscar_ops (gdbarch);
- return gdbarch;
- }
- /* This decodes the current instruction and determines the address of the
- next instruction. */
- static CORE_ADDR
- riscv_next_pc (struct regcache *regcache, CORE_ADDR pc)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- const riscv_gdbarch_tdep *tdep
- = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- struct riscv_insn insn;
- CORE_ADDR next_pc;
- insn.decode (gdbarch, pc);
- next_pc = pc + insn.length ();
- if (insn.opcode () == riscv_insn::JAL)
- next_pc = pc + insn.imm_signed ();
- else if (insn.opcode () == riscv_insn::JALR)
- {
- LONGEST source;
- regcache->cooked_read (insn.rs1 (), &source);
- next_pc = (source + insn.imm_signed ()) & ~(CORE_ADDR) 0x1;
- }
- else if (insn.opcode () == riscv_insn::BEQ)
- {
- LONGEST src1, src2;
- regcache->cooked_read (insn.rs1 (), &src1);
- regcache->cooked_read (insn.rs2 (), &src2);
- if (src1 == src2)
- next_pc = pc + insn.imm_signed ();
- }
- else if (insn.opcode () == riscv_insn::BNE)
- {
- LONGEST src1, src2;
- regcache->cooked_read (insn.rs1 (), &src1);
- regcache->cooked_read (insn.rs2 (), &src2);
- if (src1 != src2)
- next_pc = pc + insn.imm_signed ();
- }
- else if (insn.opcode () == riscv_insn::BLT)
- {
- LONGEST src1, src2;
- regcache->cooked_read (insn.rs1 (), &src1);
- regcache->cooked_read (insn.rs2 (), &src2);
- if (src1 < src2)
- next_pc = pc + insn.imm_signed ();
- }
- else if (insn.opcode () == riscv_insn::BGE)
- {
- LONGEST src1, src2;
- regcache->cooked_read (insn.rs1 (), &src1);
- regcache->cooked_read (insn.rs2 (), &src2);
- if (src1 >= src2)
- next_pc = pc + insn.imm_signed ();
- }
- else if (insn.opcode () == riscv_insn::BLTU)
- {
- ULONGEST src1, src2;
- regcache->cooked_read (insn.rs1 (), &src1);
- regcache->cooked_read (insn.rs2 (), &src2);
- if (src1 < src2)
- next_pc = pc + insn.imm_signed ();
- }
- else if (insn.opcode () == riscv_insn::BGEU)
- {
- ULONGEST src1, src2;
- regcache->cooked_read (insn.rs1 (), &src1);
- regcache->cooked_read (insn.rs2 (), &src2);
- if (src1 >= src2)
- next_pc = pc + insn.imm_signed ();
- }
- else if (insn.opcode () == riscv_insn::ECALL)
- {
- if (tdep->syscall_next_pc != nullptr)
- next_pc = tdep->syscall_next_pc (get_current_frame ());
- }
- return next_pc;
- }
- /* We can't put a breakpoint in the middle of a lr/sc atomic sequence, so look
- for the end of the sequence and put the breakpoint there. */
- static bool
- riscv_next_pc_atomic_sequence (struct regcache *regcache, CORE_ADDR pc,
- CORE_ADDR *next_pc)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- struct riscv_insn insn;
- CORE_ADDR cur_step_pc = pc;
- CORE_ADDR last_addr = 0;
- /* First instruction has to be a load reserved. */
- insn.decode (gdbarch, cur_step_pc);
- if (insn.opcode () != riscv_insn::LR)
- return false;
- cur_step_pc = cur_step_pc + insn.length ();
- /* Next instruction should be branch to exit. */
- insn.decode (gdbarch, cur_step_pc);
- if (insn.opcode () != riscv_insn::BNE)
- return false;
- last_addr = cur_step_pc + insn.imm_signed ();
- cur_step_pc = cur_step_pc + insn.length ();
- /* Next instruction should be store conditional. */
- insn.decode (gdbarch, cur_step_pc);
- if (insn.opcode () != riscv_insn::SC)
- return false;
- cur_step_pc = cur_step_pc + insn.length ();
- /* Next instruction should be branch to start. */
- insn.decode (gdbarch, cur_step_pc);
- if (insn.opcode () != riscv_insn::BNE)
- return false;
- if (pc != (cur_step_pc + insn.imm_signed ()))
- return false;
- cur_step_pc = cur_step_pc + insn.length ();
- /* We should now be at the end of the sequence. */
- if (cur_step_pc != last_addr)
- return false;
- *next_pc = cur_step_pc;
- return true;
- }
- /* This is called just before we want to resume the inferior, if we want to
- single-step it but there is no hardware or kernel single-step support. We
- find the target of the coming instruction and breakpoint it. */
- std::vector<CORE_ADDR>
- riscv_software_single_step (struct regcache *regcache)
- {
- CORE_ADDR pc, next_pc;
- pc = regcache_read_pc (regcache);
- if (riscv_next_pc_atomic_sequence (regcache, pc, &next_pc))
- return {next_pc};
- next_pc = riscv_next_pc (regcache, pc);
- return {next_pc};
- }
- /* Create RISC-V specific reggroups. */
- static void
- riscv_init_reggroups ()
- {
- csr_reggroup = reggroup_new ("csr", USER_REGGROUP);
- }
- /* See riscv-tdep.h. */
- void
- riscv_supply_regset (const struct regset *regset,
- struct regcache *regcache, int regnum,
- const void *regs, size_t len)
- {
- regcache->supply_regset (regset, regnum, regs, len);
- if (regnum == -1 || regnum == RISCV_ZERO_REGNUM)
- regcache->raw_supply_zeroed (RISCV_ZERO_REGNUM);
- if (regnum == -1 || regnum == RISCV_CSR_FFLAGS_REGNUM
- || regnum == RISCV_CSR_FRM_REGNUM)
- {
- int fcsr_regnum = RISCV_CSR_FCSR_REGNUM;
- /* Ensure that FCSR has been read into REGCACHE. */
- if (regnum != -1)
- regcache->supply_regset (regset, fcsr_regnum, regs, len);
- /* Grab the FCSR value if it is now in the regcache. We must check
- the status first as, if the register was not supplied by REGSET,
- this call will trigger a recursive attempt to fetch the
- registers. */
- if (regcache->get_register_status (fcsr_regnum) == REG_VALID)
- {
- ULONGEST fcsr_val;
- regcache->raw_read (fcsr_regnum, &fcsr_val);
- /* Extract the fflags and frm values. */
- ULONGEST fflags_val = fcsr_val & 0x1f;
- ULONGEST frm_val = (fcsr_val >> 5) & 0x7;
- /* And supply these if needed. */
- if (regnum == -1 || regnum == RISCV_CSR_FFLAGS_REGNUM)
- regcache->raw_supply_integer (RISCV_CSR_FFLAGS_REGNUM,
- (gdb_byte *) &fflags_val,
- sizeof (fflags_val),
- /* is_signed */ false);
- if (regnum == -1 || regnum == RISCV_CSR_FRM_REGNUM)
- regcache->raw_supply_integer (RISCV_CSR_FRM_REGNUM,
- (gdb_byte *)&frm_val,
- sizeof (fflags_val),
- /* is_signed */ false);
- }
- }
- }
- void _initialize_riscv_tdep ();
- void
- _initialize_riscv_tdep ()
- {
- riscv_init_reggroups ();
- gdbarch_register (bfd_arch_riscv, riscv_gdbarch_init, NULL);
- /* Add root prefix command for all "set debug riscv" and "show debug
- riscv" commands. */
- add_setshow_prefix_cmd ("riscv", no_class,
- _("RISC-V specific debug commands."),
- _("RISC-V specific debug commands."),
- &setdebugriscvcmdlist, &showdebugriscvcmdlist,
- &setdebuglist, &showdebuglist);
- add_setshow_zuinteger_cmd ("breakpoints", class_maintenance,
- &riscv_debug_breakpoints, _("\
- Set riscv breakpoint debugging."), _("\
- Show riscv breakpoint debugging."), _("\
- When non-zero, print debugging information for the riscv specific parts\n\
- of the breakpoint mechanism."),
- NULL,
- show_riscv_debug_variable,
- &setdebugriscvcmdlist, &showdebugriscvcmdlist);
- add_setshow_zuinteger_cmd ("infcall", class_maintenance,
- &riscv_debug_infcall, _("\
- Set riscv inferior call debugging."), _("\
- Show riscv inferior call debugging."), _("\
- When non-zero, print debugging information for the riscv specific parts\n\
- of the inferior call mechanism."),
- NULL,
- show_riscv_debug_variable,
- &setdebugriscvcmdlist, &showdebugriscvcmdlist);
- add_setshow_zuinteger_cmd ("unwinder", class_maintenance,
- &riscv_debug_unwinder, _("\
- Set riscv stack unwinding debugging."), _("\
- Show riscv stack unwinding debugging."), _("\
- When non-zero, print debugging information for the riscv specific parts\n\
- of the stack unwinding mechanism."),
- NULL,
- show_riscv_debug_variable,
- &setdebugriscvcmdlist, &showdebugriscvcmdlist);
- add_setshow_zuinteger_cmd ("gdbarch", class_maintenance,
- &riscv_debug_gdbarch, _("\
- Set riscv gdbarch initialisation debugging."), _("\
- Show riscv gdbarch initialisation debugging."), _("\
- When non-zero, print debugging information for the riscv gdbarch\n\
- initialisation process."),
- NULL,
- show_riscv_debug_variable,
- &setdebugriscvcmdlist, &showdebugriscvcmdlist);
- /* Add root prefix command for all "set riscv" and "show riscv" commands. */
- add_setshow_prefix_cmd ("riscv", no_class,
- _("RISC-V specific commands."),
- _("RISC-V specific commands."),
- &setriscvcmdlist, &showriscvcmdlist,
- &setlist, &showlist);
- use_compressed_breakpoints = AUTO_BOOLEAN_AUTO;
- add_setshow_auto_boolean_cmd ("use-compressed-breakpoints", no_class,
- &use_compressed_breakpoints,
- _("\
- Set debugger's use of compressed breakpoints."), _(" \
- Show debugger's use of compressed breakpoints."), _("\
- Debugging compressed code requires compressed breakpoints to be used. If\n\
- left to 'auto' then gdb will use them if the existing instruction is a\n\
- compressed instruction. If that doesn't give the correct behavior, then\n\
- this option can be used."),
- NULL,
- show_use_compressed_breakpoints,
- &setriscvcmdlist,
- &showriscvcmdlist);
- }
|