12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911 |
- /* Target-struct-independent code to start (run) and stop an inferior
- process.
- Copyright (C) 1986-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 "displaced-stepping.h"
- #include "infrun.h"
- #include <ctype.h>
- #include "symtab.h"
- #include "frame.h"
- #include "inferior.h"
- #include "breakpoint.h"
- #include "gdbcore.h"
- #include "gdbcmd.h"
- #include "target.h"
- #include "target-connection.h"
- #include "gdbthread.h"
- #include "annotate.h"
- #include "symfile.h"
- #include "top.h"
- #include "inf-loop.h"
- #include "regcache.h"
- #include "value.h"
- #include "observable.h"
- #include "language.h"
- #include "solib.h"
- #include "main.h"
- #include "block.h"
- #include "mi/mi-common.h"
- #include "event-top.h"
- #include "record.h"
- #include "record-full.h"
- #include "inline-frame.h"
- #include "jit.h"
- #include "tracepoint.h"
- #include "skip.h"
- #include "probe.h"
- #include "objfiles.h"
- #include "completer.h"
- #include "target-descriptions.h"
- #include "target-dcache.h"
- #include "terminal.h"
- #include "solist.h"
- #include "gdbsupport/event-loop.h"
- #include "thread-fsm.h"
- #include "gdbsupport/enum-flags.h"
- #include "progspace-and-thread.h"
- #include "gdbsupport/gdb_optional.h"
- #include "arch-utils.h"
- #include "gdbsupport/scope-exit.h"
- #include "gdbsupport/forward-scope-exit.h"
- #include "gdbsupport/gdb_select.h"
- #include <unordered_map>
- #include "async-event.h"
- #include "gdbsupport/selftest.h"
- #include "scoped-mock-context.h"
- #include "test-target.h"
- #include "gdbsupport/common-debug.h"
- #include "gdbsupport/buildargv.h"
- /* Prototypes for local functions */
- static void sig_print_info (enum gdb_signal);
- static void sig_print_header (void);
- static void follow_inferior_reset_breakpoints (void);
- static bool currently_stepping (struct thread_info *tp);
- static void insert_hp_step_resume_breakpoint_at_frame (struct frame_info *);
- static void insert_step_resume_breakpoint_at_caller (struct frame_info *);
- static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
- static bool maybe_software_singlestep (struct gdbarch *gdbarch);
- static void resume (gdb_signal sig);
- static void wait_for_inferior (inferior *inf);
- static void restart_threads (struct thread_info *event_thread,
- inferior *inf = nullptr);
- static bool start_step_over (void);
- /* Asynchronous signal handler registered as event loop source for
- when we have pending events ready to be passed to the core. */
- static struct async_event_handler *infrun_async_inferior_event_token;
- /* Stores whether infrun_async was previously enabled or disabled.
- Starts off as -1, indicating "never enabled/disabled". */
- static int infrun_is_async = -1;
- /* See infrun.h. */
- void
- infrun_async (int enable)
- {
- if (infrun_is_async != enable)
- {
- infrun_is_async = enable;
- infrun_debug_printf ("enable=%d", enable);
- if (enable)
- mark_async_event_handler (infrun_async_inferior_event_token);
- else
- clear_async_event_handler (infrun_async_inferior_event_token);
- }
- }
- /* See infrun.h. */
- void
- mark_infrun_async_event_handler (void)
- {
- mark_async_event_handler (infrun_async_inferior_event_token);
- }
- /* When set, stop the 'step' command if we enter a function which has
- no line number information. The normal behavior is that we step
- over such function. */
- bool step_stop_if_no_debug = false;
- static void
- show_step_stop_if_no_debug (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Mode of the step operation is %s.\n"), value);
- }
- /* proceed and normal_stop use this to notify the user when the
- inferior stopped in a different thread than it had been running
- in. */
- static ptid_t previous_inferior_ptid;
- /* If set (default for legacy reasons), when following a fork, GDB
- will detach from one of the fork branches, child or parent.
- Exactly which branch is detached depends on 'set follow-fork-mode'
- setting. */
- static bool detach_fork = true;
- bool debug_infrun = false;
- static void
- show_debug_infrun (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Inferior debugging is %s.\n"), value);
- }
- /* Support for disabling address space randomization. */
- bool disable_randomization = true;
- static void
- show_disable_randomization (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- if (target_supports_disable_randomization ())
- gdb_printf (file,
- _("Disabling randomization of debuggee's "
- "virtual address space is %s.\n"),
- value);
- else
- gdb_puts (_("Disabling randomization of debuggee's "
- "virtual address space is unsupported on\n"
- "this platform.\n"), file);
- }
- static void
- set_disable_randomization (const char *args, int from_tty,
- struct cmd_list_element *c)
- {
- if (!target_supports_disable_randomization ())
- error (_("Disabling randomization of debuggee's "
- "virtual address space is unsupported on\n"
- "this platform."));
- }
- /* User interface for non-stop mode. */
- bool non_stop = false;
- static bool non_stop_1 = false;
- static void
- set_non_stop (const char *args, int from_tty,
- struct cmd_list_element *c)
- {
- if (target_has_execution ())
- {
- non_stop_1 = non_stop;
- error (_("Cannot change this setting while the inferior is running."));
- }
- non_stop = non_stop_1;
- }
- static void
- show_non_stop (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file,
- _("Controlling the inferior in non-stop mode is %s.\n"),
- value);
- }
- /* "Observer mode" is somewhat like a more extreme version of
- non-stop, in which all GDB operations that might affect the
- target's execution have been disabled. */
- static bool observer_mode = false;
- static bool observer_mode_1 = false;
- static void
- set_observer_mode (const char *args, int from_tty,
- struct cmd_list_element *c)
- {
- if (target_has_execution ())
- {
- observer_mode_1 = observer_mode;
- error (_("Cannot change this setting while the inferior is running."));
- }
- observer_mode = observer_mode_1;
- may_write_registers = !observer_mode;
- may_write_memory = !observer_mode;
- may_insert_breakpoints = !observer_mode;
- may_insert_tracepoints = !observer_mode;
- /* We can insert fast tracepoints in or out of observer mode,
- but enable them if we're going into this mode. */
- if (observer_mode)
- may_insert_fast_tracepoints = true;
- may_stop = !observer_mode;
- update_target_permissions ();
- /* Going *into* observer mode we must force non-stop, then
- going out we leave it that way. */
- if (observer_mode)
- {
- pagination_enabled = 0;
- non_stop = non_stop_1 = true;
- }
- if (from_tty)
- gdb_printf (_("Observer mode is now %s.\n"),
- (observer_mode ? "on" : "off"));
- }
- static void
- show_observer_mode (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Observer mode is %s.\n"), value);
- }
- /* This updates the value of observer mode based on changes in
- permissions. Note that we are deliberately ignoring the values of
- may-write-registers and may-write-memory, since the user may have
- reason to enable these during a session, for instance to turn on a
- debugging-related global. */
- void
- update_observer_mode (void)
- {
- bool newval = (!may_insert_breakpoints
- && !may_insert_tracepoints
- && may_insert_fast_tracepoints
- && !may_stop
- && non_stop);
- /* Let the user know if things change. */
- if (newval != observer_mode)
- gdb_printf (_("Observer mode is now %s.\n"),
- (newval ? "on" : "off"));
- observer_mode = observer_mode_1 = newval;
- }
- /* Tables of how to react to signals; the user sets them. */
- static unsigned char signal_stop[GDB_SIGNAL_LAST];
- static unsigned char signal_print[GDB_SIGNAL_LAST];
- static unsigned char signal_program[GDB_SIGNAL_LAST];
- /* Table of signals that are registered with "catch signal". A
- non-zero entry indicates that the signal is caught by some "catch
- signal" command. */
- static unsigned char signal_catch[GDB_SIGNAL_LAST];
- /* Table of signals that the target may silently handle.
- This is automatically determined from the flags above,
- and simply cached here. */
- static unsigned char signal_pass[GDB_SIGNAL_LAST];
- #define SET_SIGS(nsigs,sigs,flags) \
- do { \
- int signum = (nsigs); \
- while (signum-- > 0) \
- if ((sigs)[signum]) \
- (flags)[signum] = 1; \
- } while (0)
- #define UNSET_SIGS(nsigs,sigs,flags) \
- do { \
- int signum = (nsigs); \
- while (signum-- > 0) \
- if ((sigs)[signum]) \
- (flags)[signum] = 0; \
- } while (0)
- /* Update the target's copy of SIGNAL_PROGRAM. The sole purpose of
- this function is to avoid exporting `signal_program'. */
- void
- update_signals_program_target (void)
- {
- target_program_signals (signal_program);
- }
- /* Value to pass to target_resume() to cause all threads to resume. */
- #define RESUME_ALL minus_one_ptid
- /* Command list pointer for the "stop" placeholder. */
- static struct cmd_list_element *stop_command;
- /* Nonzero if we want to give control to the user when we're notified
- of shared library events by the dynamic linker. */
- int stop_on_solib_events;
- /* Enable or disable optional shared library event breakpoints
- as appropriate when the above flag is changed. */
- static void
- set_stop_on_solib_events (const char *args,
- int from_tty, struct cmd_list_element *c)
- {
- update_solib_breakpoints ();
- }
- static void
- show_stop_on_solib_events (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Stopping for shared library events is %s.\n"),
- value);
- }
- /* True after stop if current stack frame should be printed. */
- static bool stop_print_frame;
- /* This is a cached copy of the target/ptid/waitstatus of the last
- event returned by target_wait().
- This information is returned by get_last_target_status(). */
- static process_stratum_target *target_last_proc_target;
- static ptid_t target_last_wait_ptid;
- static struct target_waitstatus target_last_waitstatus;
- void init_thread_stepping_state (struct thread_info *tss);
- static const char follow_fork_mode_child[] = "child";
- static const char follow_fork_mode_parent[] = "parent";
- static const char *const follow_fork_mode_kind_names[] = {
- follow_fork_mode_child,
- follow_fork_mode_parent,
- NULL
- };
- static const char *follow_fork_mode_string = follow_fork_mode_parent;
- static void
- show_follow_fork_mode_string (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file,
- _("Debugger response to a program "
- "call of fork or vfork is \"%s\".\n"),
- value);
- }
- /* Handle changes to the inferior list based on the type of fork,
- which process is being followed, and whether the other process
- should be detached. On entry inferior_ptid must be the ptid of
- the fork parent. At return inferior_ptid is the ptid of the
- followed inferior. */
- static bool
- follow_fork_inferior (bool follow_child, bool detach_fork)
- {
- target_waitkind fork_kind = inferior_thread ()->pending_follow.kind ();
- gdb_assert (fork_kind == TARGET_WAITKIND_FORKED
- || fork_kind == TARGET_WAITKIND_VFORKED);
- bool has_vforked = fork_kind == TARGET_WAITKIND_VFORKED;
- ptid_t parent_ptid = inferior_ptid;
- ptid_t child_ptid = inferior_thread ()->pending_follow.child_ptid ();
- if (has_vforked
- && !non_stop /* Non-stop always resumes both branches. */
- && current_ui->prompt_state == PROMPT_BLOCKED
- && !(follow_child || detach_fork || sched_multi))
- {
- /* The parent stays blocked inside the vfork syscall until the
- child execs or exits. If we don't let the child run, then
- the parent stays blocked. If we're telling the parent to run
- in the foreground, the user will not be able to ctrl-c to get
- back the terminal, effectively hanging the debug session. */
- gdb_printf (gdb_stderr, _("\
- Can not resume the parent process over vfork in the foreground while\n\
- holding the child stopped. Try \"set detach-on-fork\" or \
- \"set schedule-multiple\".\n"));
- return true;
- }
- inferior *parent_inf = current_inferior ();
- inferior *child_inf = nullptr;
- gdb_assert (parent_inf->thread_waiting_for_vfork_done == nullptr);
- if (!follow_child)
- {
- /* Detach new forked process? */
- if (detach_fork)
- {
- /* Before detaching from the child, remove all breakpoints
- from it. If we forked, then this has already been taken
- care of by infrun.c. If we vforked however, any
- breakpoint inserted in the parent is visible in the
- child, even those added while stopped in a vfork
- catchpoint. This will remove the breakpoints from the
- parent also, but they'll be reinserted below. */
- if (has_vforked)
- {
- /* Keep breakpoints list in sync. */
- remove_breakpoints_inf (current_inferior ());
- }
- if (print_inferior_events)
- {
- /* Ensure that we have a process ptid. */
- ptid_t process_ptid = ptid_t (child_ptid.pid ());
- target_terminal::ours_for_output ();
- gdb_printf (_("[Detaching after %s from child %s]\n"),
- has_vforked ? "vfork" : "fork",
- target_pid_to_str (process_ptid).c_str ());
- }
- }
- else
- {
- /* Add process to GDB's tables. */
- child_inf = add_inferior (child_ptid.pid ());
- child_inf->attach_flag = parent_inf->attach_flag;
- copy_terminal_info (child_inf, parent_inf);
- child_inf->gdbarch = parent_inf->gdbarch;
- copy_inferior_target_desc_info (child_inf, parent_inf);
- child_inf->symfile_flags = SYMFILE_NO_READ;
- /* If this is a vfork child, then the address-space is
- shared with the parent. */
- if (has_vforked)
- {
- child_inf->pspace = parent_inf->pspace;
- child_inf->aspace = parent_inf->aspace;
- exec_on_vfork (child_inf);
- /* The parent will be frozen until the child is done
- with the shared region. Keep track of the
- parent. */
- child_inf->vfork_parent = parent_inf;
- child_inf->pending_detach = 0;
- parent_inf->vfork_child = child_inf;
- parent_inf->pending_detach = 0;
- }
- else
- {
- child_inf->aspace = new_address_space ();
- child_inf->pspace = new program_space (child_inf->aspace);
- child_inf->removable = 1;
- clone_program_space (child_inf->pspace, parent_inf->pspace);
- }
- }
- if (has_vforked)
- {
- /* If we detached from the child, then we have to be careful
- to not insert breakpoints in the parent until the child
- is done with the shared memory region. However, if we're
- staying attached to the child, then we can and should
- insert breakpoints, so that we can debug it. A
- subsequent child exec or exit is enough to know when does
- the child stops using the parent's address space. */
- parent_inf->thread_waiting_for_vfork_done
- = detach_fork ? inferior_thread () : nullptr;
- parent_inf->pspace->breakpoints_not_allowed = detach_fork;
- }
- }
- else
- {
- /* Follow the child. */
- if (print_inferior_events)
- {
- std::string parent_pid = target_pid_to_str (parent_ptid);
- std::string child_pid = target_pid_to_str (child_ptid);
- target_terminal::ours_for_output ();
- gdb_printf (_("[Attaching after %s %s to child %s]\n"),
- parent_pid.c_str (),
- has_vforked ? "vfork" : "fork",
- child_pid.c_str ());
- }
- /* Add the new inferior first, so that the target_detach below
- doesn't unpush the target. */
- child_inf = add_inferior (child_ptid.pid ());
- child_inf->attach_flag = parent_inf->attach_flag;
- copy_terminal_info (child_inf, parent_inf);
- child_inf->gdbarch = parent_inf->gdbarch;
- copy_inferior_target_desc_info (child_inf, parent_inf);
- if (has_vforked)
- {
- /* If this is a vfork child, then the address-space is shared
- with the parent. */
- child_inf->aspace = parent_inf->aspace;
- child_inf->pspace = parent_inf->pspace;
- exec_on_vfork (child_inf);
- }
- else if (detach_fork)
- {
- /* We follow the child and detach from the parent: move the parent's
- program space to the child. This simplifies some things, like
- doing "next" over fork() and landing on the expected line in the
- child (note, that is broken with "set detach-on-fork off").
- Before assigning brand new spaces for the parent, remove
- breakpoints from it: because the new pspace won't match
- currently inserted locations, the normal detach procedure
- wouldn't remove them, and we would leave them inserted when
- detaching. */
- remove_breakpoints_inf (parent_inf);
- child_inf->aspace = parent_inf->aspace;
- child_inf->pspace = parent_inf->pspace;
- parent_inf->aspace = new_address_space ();
- parent_inf->pspace = new program_space (parent_inf->aspace);
- clone_program_space (parent_inf->pspace, child_inf->pspace);
- /* The parent inferior is still the current one, so keep things
- in sync. */
- set_current_program_space (parent_inf->pspace);
- }
- else
- {
- child_inf->aspace = new_address_space ();
- child_inf->pspace = new program_space (child_inf->aspace);
- child_inf->removable = 1;
- child_inf->symfile_flags = SYMFILE_NO_READ;
- clone_program_space (child_inf->pspace, parent_inf->pspace);
- }
- }
- gdb_assert (current_inferior () == parent_inf);
- /* If we are setting up an inferior for the child, target_follow_fork is
- responsible for pushing the appropriate targets on the new inferior's
- target stack and adding the initial thread (with ptid CHILD_PTID).
- If we are not setting up an inferior for the child (because following
- the parent and detach_fork is true), it is responsible for detaching
- from CHILD_PTID. */
- target_follow_fork (child_inf, child_ptid, fork_kind, follow_child,
- detach_fork);
- /* target_follow_fork must leave the parent as the current inferior. If we
- want to follow the child, we make it the current one below. */
- gdb_assert (current_inferior () == parent_inf);
- /* If there is a child inferior, target_follow_fork must have created a thread
- for it. */
- if (child_inf != nullptr)
- gdb_assert (!child_inf->thread_list.empty ());
- /* Clear the parent thread's pending follow field. Do this before calling
- target_detach, so that the target can differentiate the two following
- cases:
- - We continue past a fork with "follow-fork-mode == child" &&
- "detach-on-fork on", and therefore detach the parent. In that
- case the target should not detach the fork child.
- - We run to a fork catchpoint and the user types "detach". In that
- case, the target should detach the fork child in addition to the
- parent.
- The former case will have pending_follow cleared, the later will have
- pending_follow set. */
- thread_info *parent_thread = find_thread_ptid (parent_inf, parent_ptid);
- gdb_assert (parent_thread != nullptr);
- parent_thread->pending_follow.set_spurious ();
- /* Detach the parent if needed. */
- if (follow_child)
- {
- /* If we're vforking, we want to hold on to the parent until
- the child exits or execs. At child exec or exit time we
- can remove the old breakpoints from the parent and detach
- or resume debugging it. Otherwise, detach the parent now;
- we'll want to reuse it's program/address spaces, but we
- can't set them to the child before removing breakpoints
- from the parent, otherwise, the breakpoints module could
- decide to remove breakpoints from the wrong process (since
- they'd be assigned to the same address space). */
- if (has_vforked)
- {
- gdb_assert (child_inf->vfork_parent == NULL);
- gdb_assert (parent_inf->vfork_child == NULL);
- child_inf->vfork_parent = parent_inf;
- child_inf->pending_detach = 0;
- parent_inf->vfork_child = child_inf;
- parent_inf->pending_detach = detach_fork;
- }
- else if (detach_fork)
- {
- if (print_inferior_events)
- {
- /* Ensure that we have a process ptid. */
- ptid_t process_ptid = ptid_t (parent_ptid.pid ());
- target_terminal::ours_for_output ();
- gdb_printf (_("[Detaching after fork from "
- "parent %s]\n"),
- target_pid_to_str (process_ptid).c_str ());
- }
- target_detach (parent_inf, 0);
- }
- }
- /* If we ended up creating a new inferior, call post_create_inferior to inform
- the various subcomponents. */
- if (child_inf != nullptr)
- {
- /* If FOLLOW_CHILD, we leave CHILD_INF as the current inferior
- (do not restore the parent as the current inferior). */
- gdb::optional<scoped_restore_current_thread> maybe_restore;
- if (!follow_child)
- maybe_restore.emplace ();
- switch_to_thread (*child_inf->threads ().begin ());
- post_create_inferior (0);
- }
- return false;
- }
- /* Tell the target to follow the fork we're stopped at. Returns true
- if the inferior should be resumed; false, if the target for some
- reason decided it's best not to resume. */
- static bool
- follow_fork ()
- {
- bool follow_child = (follow_fork_mode_string == follow_fork_mode_child);
- bool should_resume = true;
- /* Copy user stepping state to the new inferior thread. FIXME: the
- followed fork child thread should have a copy of most of the
- parent thread structure's run control related fields, not just these.
- Initialized to avoid "may be used uninitialized" warnings from gcc. */
- struct breakpoint *step_resume_breakpoint = NULL;
- struct breakpoint *exception_resume_breakpoint = NULL;
- CORE_ADDR step_range_start = 0;
- CORE_ADDR step_range_end = 0;
- int current_line = 0;
- symtab *current_symtab = NULL;
- struct frame_id step_frame_id = { 0 };
- if (!non_stop)
- {
- process_stratum_target *wait_target;
- ptid_t wait_ptid;
- struct target_waitstatus wait_status;
- /* Get the last target status returned by target_wait(). */
- get_last_target_status (&wait_target, &wait_ptid, &wait_status);
- /* If not stopped at a fork event, then there's nothing else to
- do. */
- if (wait_status.kind () != TARGET_WAITKIND_FORKED
- && wait_status.kind () != TARGET_WAITKIND_VFORKED)
- return 1;
- /* Check if we switched over from WAIT_PTID, since the event was
- reported. */
- if (wait_ptid != minus_one_ptid
- && (current_inferior ()->process_target () != wait_target
- || inferior_ptid != wait_ptid))
- {
- /* We did. Switch back to WAIT_PTID thread, to tell the
- target to follow it (in either direction). We'll
- afterwards refuse to resume, and inform the user what
- happened. */
- thread_info *wait_thread = find_thread_ptid (wait_target, wait_ptid);
- switch_to_thread (wait_thread);
- should_resume = false;
- }
- }
- thread_info *tp = inferior_thread ();
- /* If there were any forks/vforks that were caught and are now to be
- followed, then do so now. */
- switch (tp->pending_follow.kind ())
- {
- case TARGET_WAITKIND_FORKED:
- case TARGET_WAITKIND_VFORKED:
- {
- ptid_t parent, child;
- std::unique_ptr<struct thread_fsm> thread_fsm;
- /* If the user did a next/step, etc, over a fork call,
- preserve the stepping state in the fork child. */
- if (follow_child && should_resume)
- {
- step_resume_breakpoint = clone_momentary_breakpoint
- (tp->control.step_resume_breakpoint);
- step_range_start = tp->control.step_range_start;
- step_range_end = tp->control.step_range_end;
- current_line = tp->current_line;
- current_symtab = tp->current_symtab;
- step_frame_id = tp->control.step_frame_id;
- exception_resume_breakpoint
- = clone_momentary_breakpoint (tp->control.exception_resume_breakpoint);
- thread_fsm = tp->release_thread_fsm ();
- /* For now, delete the parent's sr breakpoint, otherwise,
- parent/child sr breakpoints are considered duplicates,
- and the child version will not be installed. Remove
- this when the breakpoints module becomes aware of
- inferiors and address spaces. */
- delete_step_resume_breakpoint (tp);
- tp->control.step_range_start = 0;
- tp->control.step_range_end = 0;
- tp->control.step_frame_id = null_frame_id;
- delete_exception_resume_breakpoint (tp);
- }
- parent = inferior_ptid;
- child = tp->pending_follow.child_ptid ();
- /* If handling a vfork, stop all the inferior's threads, they will be
- restarted when the vfork shared region is complete. */
- if (tp->pending_follow.kind () == TARGET_WAITKIND_VFORKED
- && target_is_non_stop_p ())
- stop_all_threads ("handling vfork", tp->inf);
- process_stratum_target *parent_targ = tp->inf->process_target ();
- /* Set up inferior(s) as specified by the caller, and tell the
- target to do whatever is necessary to follow either parent
- or child. */
- if (follow_fork_inferior (follow_child, detach_fork))
- {
- /* Target refused to follow, or there's some other reason
- we shouldn't resume. */
- should_resume = 0;
- }
- else
- {
- /* This makes sure we don't try to apply the "Switched
- over from WAIT_PID" logic above. */
- nullify_last_target_wait_ptid ();
- /* If we followed the child, switch to it... */
- if (follow_child)
- {
- thread_info *child_thr = find_thread_ptid (parent_targ, child);
- switch_to_thread (child_thr);
- /* ... and preserve the stepping state, in case the
- user was stepping over the fork call. */
- if (should_resume)
- {
- tp = inferior_thread ();
- tp->control.step_resume_breakpoint
- = step_resume_breakpoint;
- tp->control.step_range_start = step_range_start;
- tp->control.step_range_end = step_range_end;
- tp->current_line = current_line;
- tp->current_symtab = current_symtab;
- tp->control.step_frame_id = step_frame_id;
- tp->control.exception_resume_breakpoint
- = exception_resume_breakpoint;
- tp->set_thread_fsm (std::move (thread_fsm));
- }
- else
- {
- /* If we get here, it was because we're trying to
- resume from a fork catchpoint, but, the user
- has switched threads away from the thread that
- forked. In that case, the resume command
- issued is most likely not applicable to the
- child, so just warn, and refuse to resume. */
- warning (_("Not resuming: switched threads "
- "before following fork child."));
- }
- /* Reset breakpoints in the child as appropriate. */
- follow_inferior_reset_breakpoints ();
- }
- }
- }
- break;
- case TARGET_WAITKIND_SPURIOUS:
- /* Nothing to follow. */
- break;
- default:
- internal_error (__FILE__, __LINE__,
- "Unexpected pending_follow.kind %d\n",
- tp->pending_follow.kind ());
- break;
- }
- return should_resume;
- }
- static void
- follow_inferior_reset_breakpoints (void)
- {
- struct thread_info *tp = inferior_thread ();
- /* Was there a step_resume breakpoint? (There was if the user
- did a "next" at the fork() call.) If so, explicitly reset its
- thread number. Cloned step_resume breakpoints are disabled on
- creation, so enable it here now that it is associated with the
- correct thread.
- step_resumes are a form of bp that are made to be per-thread.
- Since we created the step_resume bp when the parent process
- was being debugged, and now are switching to the child process,
- from the breakpoint package's viewpoint, that's a switch of
- "threads". We must update the bp's notion of which thread
- it is for, or it'll be ignored when it triggers. */
- if (tp->control.step_resume_breakpoint)
- {
- breakpoint_re_set_thread (tp->control.step_resume_breakpoint);
- tp->control.step_resume_breakpoint->loc->enabled = 1;
- }
- /* Treat exception_resume breakpoints like step_resume breakpoints. */
- if (tp->control.exception_resume_breakpoint)
- {
- breakpoint_re_set_thread (tp->control.exception_resume_breakpoint);
- tp->control.exception_resume_breakpoint->loc->enabled = 1;
- }
- /* Reinsert all breakpoints in the child. The user may have set
- breakpoints after catching the fork, in which case those
- were never set in the child, but only in the parent. This makes
- sure the inserted breakpoints match the breakpoint list. */
- breakpoint_re_set ();
- insert_breakpoints ();
- }
- /* The child has exited or execed: resume THREAD, a thread of the parent,
- if it was meant to be executing. */
- static void
- proceed_after_vfork_done (thread_info *thread)
- {
- if (thread->state == THREAD_RUNNING
- && !thread->executing ()
- && !thread->stop_requested
- && thread->stop_signal () == GDB_SIGNAL_0)
- {
- infrun_debug_printf ("resuming vfork parent thread %s",
- thread->ptid.to_string ().c_str ());
- switch_to_thread (thread);
- clear_proceed_status (0);
- proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
- }
- }
- /* Called whenever we notice an exec or exit event, to handle
- detaching or resuming a vfork parent. */
- static void
- handle_vfork_child_exec_or_exit (int exec)
- {
- struct inferior *inf = current_inferior ();
- if (inf->vfork_parent)
- {
- inferior *resume_parent = nullptr;
- /* This exec or exit marks the end of the shared memory region
- between the parent and the child. Break the bonds. */
- inferior *vfork_parent = inf->vfork_parent;
- inf->vfork_parent->vfork_child = NULL;
- inf->vfork_parent = NULL;
- /* If the user wanted to detach from the parent, now is the
- time. */
- if (vfork_parent->pending_detach)
- {
- struct program_space *pspace;
- struct address_space *aspace;
- /* follow-fork child, detach-on-fork on. */
- vfork_parent->pending_detach = 0;
- scoped_restore_current_pspace_and_thread restore_thread;
- /* We're letting loose of the parent. */
- thread_info *tp = any_live_thread_of_inferior (vfork_parent);
- switch_to_thread (tp);
- /* We're about to detach from the parent, which implicitly
- removes breakpoints from its address space. There's a
- catch here: we want to reuse the spaces for the child,
- but, parent/child are still sharing the pspace at this
- point, although the exec in reality makes the kernel give
- the child a fresh set of new pages. The problem here is
- that the breakpoints module being unaware of this, would
- likely chose the child process to write to the parent
- address space. Swapping the child temporarily away from
- the spaces has the desired effect. Yes, this is "sort
- of" a hack. */
- pspace = inf->pspace;
- aspace = inf->aspace;
- inf->aspace = NULL;
- inf->pspace = NULL;
- if (print_inferior_events)
- {
- std::string pidstr
- = target_pid_to_str (ptid_t (vfork_parent->pid));
- target_terminal::ours_for_output ();
- if (exec)
- {
- gdb_printf (_("[Detaching vfork parent %s "
- "after child exec]\n"), pidstr.c_str ());
- }
- else
- {
- gdb_printf (_("[Detaching vfork parent %s "
- "after child exit]\n"), pidstr.c_str ());
- }
- }
- target_detach (vfork_parent, 0);
- /* Put it back. */
- inf->pspace = pspace;
- inf->aspace = aspace;
- }
- else if (exec)
- {
- /* We're staying attached to the parent, so, really give the
- child a new address space. */
- inf->pspace = new program_space (maybe_new_address_space ());
- inf->aspace = inf->pspace->aspace;
- inf->removable = 1;
- set_current_program_space (inf->pspace);
- resume_parent = vfork_parent;
- }
- else
- {
- /* If this is a vfork child exiting, then the pspace and
- aspaces were shared with the parent. Since we're
- reporting the process exit, we'll be mourning all that is
- found in the address space, and switching to null_ptid,
- preparing to start a new inferior. But, since we don't
- want to clobber the parent's address/program spaces, we
- go ahead and create a new one for this exiting
- inferior. */
- /* Switch to no-thread while running clone_program_space, so
- that clone_program_space doesn't want to read the
- selected frame of a dead process. */
- scoped_restore_current_thread restore_thread;
- switch_to_no_thread ();
- inf->pspace = new program_space (maybe_new_address_space ());
- inf->aspace = inf->pspace->aspace;
- set_current_program_space (inf->pspace);
- inf->removable = 1;
- inf->symfile_flags = SYMFILE_NO_READ;
- clone_program_space (inf->pspace, vfork_parent->pspace);
- resume_parent = vfork_parent;
- }
- gdb_assert (current_program_space == inf->pspace);
- if (non_stop && resume_parent != nullptr)
- {
- /* If the user wanted the parent to be running, let it go
- free now. */
- scoped_restore_current_thread restore_thread;
- infrun_debug_printf ("resuming vfork parent process %d",
- resume_parent->pid);
- for (thread_info *thread : resume_parent->threads ())
- proceed_after_vfork_done (thread);
- }
- }
- }
- /* Handle TARGET_WAITKIND_VFORK_DONE. */
- static void
- handle_vfork_done (thread_info *event_thread)
- {
- /* We only care about this event if inferior::thread_waiting_for_vfork_done is
- set, that is if we are waiting for a vfork child not under our control
- (because we detached it) to exec or exit.
- If an inferior has vforked and we are debugging the child, we don't use
- the vfork-done event to get notified about the end of the shared address
- space window. We rely instead on the child's exec or exit event, and the
- inferior::vfork_{parent,child} fields are used instead. See
- handle_vfork_child_exec_or_exit for that. */
- if (event_thread->inf->thread_waiting_for_vfork_done == nullptr)
- {
- infrun_debug_printf ("not waiting for a vfork-done event");
- return;
- }
- INFRUN_SCOPED_DEBUG_ENTER_EXIT;
- /* We stopped all threads (other than the vforking thread) of the inferior in
- follow_fork and kept them stopped until now. It should therefore not be
- possible for another thread to have reported a vfork during that window.
- If THREAD_WAITING_FOR_VFORK_DONE is set, it has to be the same thread whose
- vfork-done we are handling right now. */
- gdb_assert (event_thread->inf->thread_waiting_for_vfork_done == event_thread);
- event_thread->inf->thread_waiting_for_vfork_done = nullptr;
- event_thread->inf->pspace->breakpoints_not_allowed = 0;
- /* On non-stop targets, we stopped all the inferior's threads in follow_fork,
- resume them now. On all-stop targets, everything that needs to be resumed
- will be when we resume the event thread. */
- if (target_is_non_stop_p ())
- {
- /* restart_threads and start_step_over may change the current thread, make
- sure we leave the event thread as the current thread. */
- scoped_restore_current_thread restore_thread;
- insert_breakpoints ();
- restart_threads (event_thread, event_thread->inf);
- start_step_over ();
- }
- }
- /* Enum strings for "set|show follow-exec-mode". */
- static const char follow_exec_mode_new[] = "new";
- static const char follow_exec_mode_same[] = "same";
- static const char *const follow_exec_mode_names[] =
- {
- follow_exec_mode_new,
- follow_exec_mode_same,
- NULL,
- };
- static const char *follow_exec_mode_string = follow_exec_mode_same;
- static void
- show_follow_exec_mode_string (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Follow exec mode is \"%s\".\n"), value);
- }
- /* EXEC_FILE_TARGET is assumed to be non-NULL. */
- static void
- follow_exec (ptid_t ptid, const char *exec_file_target)
- {
- int pid = ptid.pid ();
- ptid_t process_ptid;
- /* Switch terminal for any messages produced e.g. by
- breakpoint_re_set. */
- target_terminal::ours_for_output ();
- /* This is an exec event that we actually wish to pay attention to.
- Refresh our symbol table to the newly exec'd program, remove any
- momentary bp's, etc.
- If there are breakpoints, they aren't really inserted now,
- since the exec() transformed our inferior into a fresh set
- of instructions.
- We want to preserve symbolic breakpoints on the list, since
- we have hopes that they can be reset after the new a.out's
- symbol table is read.
- However, any "raw" breakpoints must be removed from the list
- (e.g., the solib bp's), since their address is probably invalid
- now.
- And, we DON'T want to call delete_breakpoints() here, since
- that may write the bp's "shadow contents" (the instruction
- value that was overwritten with a TRAP instruction). Since
- we now have a new a.out, those shadow contents aren't valid. */
- mark_breakpoints_out ();
- /* The target reports the exec event to the main thread, even if
- some other thread does the exec, and even if the main thread was
- stopped or already gone. We may still have non-leader threads of
- the process on our list. E.g., on targets that don't have thread
- exit events (like remote); or on native Linux in non-stop mode if
- there were only two threads in the inferior and the non-leader
- one is the one that execs (and nothing forces an update of the
- thread list up to here). When debugging remotely, it's best to
- avoid extra traffic, when possible, so avoid syncing the thread
- list with the target, and instead go ahead and delete all threads
- of the process but one that reported the event. Note this must
- be done before calling update_breakpoints_after_exec, as
- otherwise clearing the threads' resources would reference stale
- thread breakpoints -- it may have been one of these threads that
- stepped across the exec. We could just clear their stepping
- states, but as long as we're iterating, might as well delete
- them. Deleting them now rather than at the next user-visible
- stop provides a nicer sequence of events for user and MI
- notifications. */
- for (thread_info *th : all_threads_safe ())
- if (th->ptid.pid () == pid && th->ptid != ptid)
- delete_thread (th);
- /* We also need to clear any left over stale state for the
- leader/event thread. E.g., if there was any step-resume
- breakpoint or similar, it's gone now. We cannot truly
- step-to-next statement through an exec(). */
- thread_info *th = inferior_thread ();
- th->control.step_resume_breakpoint = NULL;
- th->control.exception_resume_breakpoint = NULL;
- th->control.single_step_breakpoints = NULL;
- th->control.step_range_start = 0;
- th->control.step_range_end = 0;
- /* The user may have had the main thread held stopped in the
- previous image (e.g., schedlock on, or non-stop). Release
- it now. */
- th->stop_requested = 0;
- update_breakpoints_after_exec ();
- /* What is this a.out's name? */
- process_ptid = ptid_t (pid);
- gdb_printf (_("%s is executing new program: %s\n"),
- target_pid_to_str (process_ptid).c_str (),
- exec_file_target);
- /* We've followed the inferior through an exec. Therefore, the
- inferior has essentially been killed & reborn. */
- breakpoint_init_inferior (inf_execd);
- gdb::unique_xmalloc_ptr<char> exec_file_host
- = exec_file_find (exec_file_target, NULL);
- /* If we were unable to map the executable target pathname onto a host
- pathname, tell the user that. Otherwise GDB's subsequent behavior
- is confusing. Maybe it would even be better to stop at this point
- so that the user can specify a file manually before continuing. */
- if (exec_file_host == NULL)
- warning (_("Could not load symbols for executable %s.\n"
- "Do you need \"set sysroot\"?"),
- exec_file_target);
- /* Reset the shared library package. This ensures that we get a
- shlib event when the child reaches "_start", at which point the
- dld will have had a chance to initialize the child. */
- /* Also, loading a symbol file below may trigger symbol lookups, and
- we don't want those to be satisfied by the libraries of the
- previous incarnation of this process. */
- no_shared_libraries (NULL, 0);
- struct inferior *inf = current_inferior ();
- if (follow_exec_mode_string == follow_exec_mode_new)
- {
- /* The user wants to keep the old inferior and program spaces
- around. Create a new fresh one, and switch to it. */
- /* Do exit processing for the original inferior before setting the new
- inferior's pid. Having two inferiors with the same pid would confuse
- find_inferior_p(t)id. Transfer the terminal state and info from the
- old to the new inferior. */
- inferior *new_inferior = add_inferior_with_spaces ();
- swap_terminal_info (new_inferior, inf);
- exit_inferior_silent (inf);
- new_inferior->pid = pid;
- target_follow_exec (new_inferior, ptid, exec_file_target);
- /* We continue with the new inferior. */
- inf = new_inferior;
- }
- else
- {
- /* The old description may no longer be fit for the new image.
- E.g, a 64-bit process exec'ed a 32-bit process. Clear the
- old description; we'll read a new one below. No need to do
- this on "follow-exec-mode new", as the old inferior stays
- around (its description is later cleared/refetched on
- restart). */
- target_clear_description ();
- target_follow_exec (inf, ptid, exec_file_target);
- }
- gdb_assert (current_inferior () == inf);
- gdb_assert (current_program_space == inf->pspace);
- /* Attempt to open the exec file. SYMFILE_DEFER_BP_RESET is used
- because the proper displacement for a PIE (Position Independent
- Executable) main symbol file will only be computed by
- solib_create_inferior_hook below. breakpoint_re_set would fail
- to insert the breakpoints with the zero displacement. */
- try_open_exec_file (exec_file_host.get (), inf, SYMFILE_DEFER_BP_RESET);
- /* If the target can specify a description, read it. Must do this
- after flipping to the new executable (because the target supplied
- description must be compatible with the executable's
- architecture, and the old executable may e.g., be 32-bit, while
- the new one 64-bit), and before anything involving memory or
- registers. */
- target_find_description ();
- gdb::observers::inferior_execd.notify (inf);
- breakpoint_re_set ();
- /* Reinsert all breakpoints. (Those which were symbolic have
- been reset to the proper address in the new a.out, thanks
- to symbol_file_command...). */
- insert_breakpoints ();
- /* The next resume of this inferior should bring it to the shlib
- startup breakpoints. (If the user had also set bp's on
- "main" from the old (parent) process, then they'll auto-
- matically get reset there in the new process.). */
- }
- /* The chain of threads that need to do a step-over operation to get
- past e.g., a breakpoint. What technique is used to step over the
- breakpoint/watchpoint does not matter -- all threads end up in the
- same queue, to maintain rough temporal order of execution, in order
- to avoid starvation, otherwise, we could e.g., find ourselves
- constantly stepping the same couple threads past their breakpoints
- over and over, if the single-step finish fast enough. */
- thread_step_over_list global_thread_step_over_list;
- /* Bit flags indicating what the thread needs to step over. */
- enum step_over_what_flag
- {
- /* Step over a breakpoint. */
- STEP_OVER_BREAKPOINT = 1,
- /* Step past a non-continuable watchpoint, in order to let the
- instruction execute so we can evaluate the watchpoint
- expression. */
- STEP_OVER_WATCHPOINT = 2
- };
- DEF_ENUM_FLAGS_TYPE (enum step_over_what_flag, step_over_what);
- /* Info about an instruction that is being stepped over. */
- struct step_over_info
- {
- /* If we're stepping past a breakpoint, this is the address space
- and address of the instruction the breakpoint is set at. We'll
- skip inserting all breakpoints here. Valid iff ASPACE is
- non-NULL. */
- const address_space *aspace = nullptr;
- CORE_ADDR address = 0;
- /* The instruction being stepped over triggers a nonsteppable
- watchpoint. If true, we'll skip inserting watchpoints. */
- int nonsteppable_watchpoint_p = 0;
- /* The thread's global number. */
- int thread = -1;
- };
- /* The step-over info of the location that is being stepped over.
- Note that with async/breakpoint always-inserted mode, a user might
- set a new breakpoint/watchpoint/etc. exactly while a breakpoint is
- being stepped over. As setting a new breakpoint inserts all
- breakpoints, we need to make sure the breakpoint being stepped over
- isn't inserted then. We do that by only clearing the step-over
- info when the step-over is actually finished (or aborted).
- Presently GDB can only step over one breakpoint at any given time.
- Given threads that can't run code in the same address space as the
- breakpoint's can't really miss the breakpoint, GDB could be taught
- to step-over at most one breakpoint per address space (so this info
- could move to the address space object if/when GDB is extended).
- The set of breakpoints being stepped over will normally be much
- smaller than the set of all breakpoints, so a flag in the
- breakpoint location structure would be wasteful. A separate list
- also saves complexity and run-time, as otherwise we'd have to go
- through all breakpoint locations clearing their flag whenever we
- start a new sequence. Similar considerations weigh against storing
- this info in the thread object. Plus, not all step overs actually
- have breakpoint locations -- e.g., stepping past a single-step
- breakpoint, or stepping to complete a non-continuable
- watchpoint. */
- static struct step_over_info step_over_info;
- /* Record the address of the breakpoint/instruction we're currently
- stepping over.
- N.B. We record the aspace and address now, instead of say just the thread,
- because when we need the info later the thread may be running. */
- static void
- set_step_over_info (const address_space *aspace, CORE_ADDR address,
- int nonsteppable_watchpoint_p,
- int thread)
- {
- step_over_info.aspace = aspace;
- step_over_info.address = address;
- step_over_info.nonsteppable_watchpoint_p = nonsteppable_watchpoint_p;
- step_over_info.thread = thread;
- }
- /* Called when we're not longer stepping over a breakpoint / an
- instruction, so all breakpoints are free to be (re)inserted. */
- static void
- clear_step_over_info (void)
- {
- infrun_debug_printf ("clearing step over info");
- step_over_info.aspace = NULL;
- step_over_info.address = 0;
- step_over_info.nonsteppable_watchpoint_p = 0;
- step_over_info.thread = -1;
- }
- /* See infrun.h. */
- int
- stepping_past_instruction_at (struct address_space *aspace,
- CORE_ADDR address)
- {
- return (step_over_info.aspace != NULL
- && breakpoint_address_match (aspace, address,
- step_over_info.aspace,
- step_over_info.address));
- }
- /* See infrun.h. */
- int
- thread_is_stepping_over_breakpoint (int thread)
- {
- return (step_over_info.thread != -1
- && thread == step_over_info.thread);
- }
- /* See infrun.h. */
- int
- stepping_past_nonsteppable_watchpoint (void)
- {
- return step_over_info.nonsteppable_watchpoint_p;
- }
- /* Returns true if step-over info is valid. */
- static bool
- step_over_info_valid_p (void)
- {
- return (step_over_info.aspace != NULL
- || stepping_past_nonsteppable_watchpoint ());
- }
- /* Displaced stepping. */
- /* In non-stop debugging mode, we must take special care to manage
- breakpoints properly; in particular, the traditional strategy for
- stepping a thread past a breakpoint it has hit is unsuitable.
- 'Displaced stepping' is a tactic for stepping one thread past a
- breakpoint it has hit while ensuring that other threads running
- concurrently will hit the breakpoint as they should.
- The traditional way to step a thread T off a breakpoint in a
- multi-threaded program in all-stop mode is as follows:
- a0) Initially, all threads are stopped, and breakpoints are not
- inserted.
- a1) We single-step T, leaving breakpoints uninserted.
- a2) We insert breakpoints, and resume all threads.
- In non-stop debugging, however, this strategy is unsuitable: we
- don't want to have to stop all threads in the system in order to
- continue or step T past a breakpoint. Instead, we use displaced
- stepping:
- n0) Initially, T is stopped, other threads are running, and
- breakpoints are inserted.
- n1) We copy the instruction "under" the breakpoint to a separate
- location, outside the main code stream, making any adjustments
- to the instruction, register, and memory state as directed by
- T's architecture.
- n2) We single-step T over the instruction at its new location.
- n3) We adjust the resulting register and memory state as directed
- by T's architecture. This includes resetting T's PC to point
- back into the main instruction stream.
- n4) We resume T.
- This approach depends on the following gdbarch methods:
- - gdbarch_max_insn_length and gdbarch_displaced_step_location
- indicate where to copy the instruction, and how much space must
- be reserved there. We use these in step n1.
- - gdbarch_displaced_step_copy_insn copies a instruction to a new
- address, and makes any necessary adjustments to the instruction,
- register contents, and memory. We use this in step n1.
- - gdbarch_displaced_step_fixup adjusts registers and memory after
- we have successfully single-stepped the instruction, to yield the
- same effect the instruction would have had if we had executed it
- at its original address. We use this in step n3.
- The gdbarch_displaced_step_copy_insn and
- gdbarch_displaced_step_fixup functions must be written so that
- copying an instruction with gdbarch_displaced_step_copy_insn,
- single-stepping across the copied instruction, and then applying
- gdbarch_displaced_insn_fixup should have the same effects on the
- thread's memory and registers as stepping the instruction in place
- would have. Exactly which responsibilities fall to the copy and
- which fall to the fixup is up to the author of those functions.
- See the comments in gdbarch.sh for details.
- Note that displaced stepping and software single-step cannot
- currently be used in combination, although with some care I think
- they could be made to. Software single-step works by placing
- breakpoints on all possible subsequent instructions; if the
- displaced instruction is a PC-relative jump, those breakpoints
- could fall in very strange places --- on pages that aren't
- executable, or at addresses that are not proper instruction
- boundaries. (We do generally let other threads run while we wait
- to hit the software single-step breakpoint, and they might
- encounter such a corrupted instruction.) One way to work around
- this would be to have gdbarch_displaced_step_copy_insn fully
- simulate the effect of PC-relative instructions (and return NULL)
- on architectures that use software single-stepping.
- In non-stop mode, we can have independent and simultaneous step
- requests, so more than one thread may need to simultaneously step
- over a breakpoint. The current implementation assumes there is
- only one scratch space per process. In this case, we have to
- serialize access to the scratch space. If thread A wants to step
- over a breakpoint, but we are currently waiting for some other
- thread to complete a displaced step, we leave thread A stopped and
- place it in the displaced_step_request_queue. Whenever a displaced
- step finishes, we pick the next thread in the queue and start a new
- displaced step operation on it. See displaced_step_prepare and
- displaced_step_finish for details. */
- /* Return true if THREAD is doing a displaced step. */
- static bool
- displaced_step_in_progress_thread (thread_info *thread)
- {
- gdb_assert (thread != NULL);
- return thread->displaced_step_state.in_progress ();
- }
- /* Return true if INF has a thread doing a displaced step. */
- static bool
- displaced_step_in_progress (inferior *inf)
- {
- return inf->displaced_step_state.in_progress_count > 0;
- }
- /* Return true if any thread is doing a displaced step. */
- static bool
- displaced_step_in_progress_any_thread ()
- {
- for (inferior *inf : all_non_exited_inferiors ())
- {
- if (displaced_step_in_progress (inf))
- return true;
- }
- return false;
- }
- static void
- infrun_inferior_exit (struct inferior *inf)
- {
- inf->displaced_step_state.reset ();
- inf->thread_waiting_for_vfork_done = nullptr;
- }
- static void
- infrun_inferior_execd (inferior *inf)
- {
- /* If some threads where was doing a displaced step in this inferior at the
- moment of the exec, they no longer exist. Even if the exec'ing thread
- doing a displaced step, we don't want to to any fixup nor restore displaced
- stepping buffer bytes. */
- inf->displaced_step_state.reset ();
- for (thread_info *thread : inf->threads ())
- thread->displaced_step_state.reset ();
- /* Since an in-line step is done with everything else stopped, if there was
- one in progress at the time of the exec, it must have been the exec'ing
- thread. */
- clear_step_over_info ();
- inf->thread_waiting_for_vfork_done = nullptr;
- }
- /* If ON, and the architecture supports it, GDB will use displaced
- stepping to step over breakpoints. If OFF, or if the architecture
- doesn't support it, GDB will instead use the traditional
- hold-and-step approach. If AUTO (which is the default), GDB will
- decide which technique to use to step over breakpoints depending on
- whether the target works in a non-stop way (see use_displaced_stepping). */
- static enum auto_boolean can_use_displaced_stepping = AUTO_BOOLEAN_AUTO;
- static void
- show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
- struct cmd_list_element *c,
- const char *value)
- {
- if (can_use_displaced_stepping == AUTO_BOOLEAN_AUTO)
- gdb_printf (file,
- _("Debugger's willingness to use displaced stepping "
- "to step over breakpoints is %s (currently %s).\n"),
- value, target_is_non_stop_p () ? "on" : "off");
- else
- gdb_printf (file,
- _("Debugger's willingness to use displaced stepping "
- "to step over breakpoints is %s.\n"), value);
- }
- /* Return true if the gdbarch implements the required methods to use
- displaced stepping. */
- static bool
- gdbarch_supports_displaced_stepping (gdbarch *arch)
- {
- /* Only check for the presence of `prepare`. The gdbarch verification ensures
- that if `prepare` is provided, so is `finish`. */
- return gdbarch_displaced_step_prepare_p (arch);
- }
- /* Return non-zero if displaced stepping can/should be used to step
- over breakpoints of thread TP. */
- static bool
- use_displaced_stepping (thread_info *tp)
- {
- /* If the user disabled it explicitly, don't use displaced stepping. */
- if (can_use_displaced_stepping == AUTO_BOOLEAN_FALSE)
- return false;
- /* If "auto", only use displaced stepping if the target operates in a non-stop
- way. */
- if (can_use_displaced_stepping == AUTO_BOOLEAN_AUTO
- && !target_is_non_stop_p ())
- return false;
- gdbarch *gdbarch = get_thread_regcache (tp)->arch ();
- /* If the architecture doesn't implement displaced stepping, don't use
- it. */
- if (!gdbarch_supports_displaced_stepping (gdbarch))
- return false;
- /* If recording, don't use displaced stepping. */
- if (find_record_target () != nullptr)
- return false;
- /* If displaced stepping failed before for this inferior, don't bother trying
- again. */
- if (tp->inf->displaced_step_state.failed_before)
- return false;
- return true;
- }
- /* Simple function wrapper around displaced_step_thread_state::reset. */
- static void
- displaced_step_reset (displaced_step_thread_state *displaced)
- {
- displaced->reset ();
- }
- /* A cleanup that wraps displaced_step_reset. We use this instead of, say,
- SCOPE_EXIT, because it needs to be discardable with "cleanup.release ()". */
- using displaced_step_reset_cleanup = FORWARD_SCOPE_EXIT (displaced_step_reset);
- /* See infrun.h. */
- std::string
- displaced_step_dump_bytes (const gdb_byte *buf, size_t len)
- {
- std::string ret;
- for (size_t i = 0; i < len; i++)
- {
- if (i == 0)
- ret += string_printf ("%02x", buf[i]);
- else
- ret += string_printf (" %02x", buf[i]);
- }
- return ret;
- }
- /* Prepare to single-step, using displaced stepping.
- Note that we cannot use displaced stepping when we have a signal to
- deliver. If we have a signal to deliver and an instruction to step
- over, then after the step, there will be no indication from the
- target whether the thread entered a signal handler or ignored the
- signal and stepped over the instruction successfully --- both cases
- result in a simple SIGTRAP. In the first case we mustn't do a
- fixup, and in the second case we must --- but we can't tell which.
- Comments in the code for 'random signals' in handle_inferior_event
- explain how we handle this case instead.
- Returns DISPLACED_STEP_PREPARE_STATUS_OK if preparing was successful -- this
- thread is going to be stepped now; DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE
- if displaced stepping this thread got queued; or
- DISPLACED_STEP_PREPARE_STATUS_CANT if this instruction can't be displaced
- stepped. */
- static displaced_step_prepare_status
- displaced_step_prepare_throw (thread_info *tp)
- {
- regcache *regcache = get_thread_regcache (tp);
- struct gdbarch *gdbarch = regcache->arch ();
- displaced_step_thread_state &disp_step_thread_state
- = tp->displaced_step_state;
- /* We should never reach this function if the architecture does not
- support displaced stepping. */
- gdb_assert (gdbarch_supports_displaced_stepping (gdbarch));
- /* Nor if the thread isn't meant to step over a breakpoint. */
- gdb_assert (tp->control.trap_expected);
- /* Disable range stepping while executing in the scratch pad. We
- want a single-step even if executing the displaced instruction in
- the scratch buffer lands within the stepping range (e.g., a
- jump/branch). */
- tp->control.may_range_step = 0;
- /* We are about to start a displaced step for this thread. If one is already
- in progress, something's wrong. */
- gdb_assert (!disp_step_thread_state.in_progress ());
- if (tp->inf->displaced_step_state.unavailable)
- {
- /* The gdbarch tells us it's not worth asking to try a prepare because
- it is likely that it will return unavailable, so don't bother asking. */
- displaced_debug_printf ("deferring step of %s",
- tp->ptid.to_string ().c_str ());
- global_thread_step_over_chain_enqueue (tp);
- return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
- }
- displaced_debug_printf ("displaced-stepping %s now",
- tp->ptid.to_string ().c_str ());
- scoped_restore_current_thread restore_thread;
- switch_to_thread (tp);
- CORE_ADDR original_pc = regcache_read_pc (regcache);
- CORE_ADDR displaced_pc;
- displaced_step_prepare_status status
- = gdbarch_displaced_step_prepare (gdbarch, tp, displaced_pc);
- if (status == DISPLACED_STEP_PREPARE_STATUS_CANT)
- {
- displaced_debug_printf ("failed to prepare (%s)",
- tp->ptid.to_string ().c_str ());
- return DISPLACED_STEP_PREPARE_STATUS_CANT;
- }
- else if (status == DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE)
- {
- /* Not enough displaced stepping resources available, defer this
- request by placing it the queue. */
- displaced_debug_printf ("not enough resources available, "
- "deferring step of %s",
- tp->ptid.to_string ().c_str ());
- global_thread_step_over_chain_enqueue (tp);
- return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
- }
- gdb_assert (status == DISPLACED_STEP_PREPARE_STATUS_OK);
- /* Save the information we need to fix things up if the step
- succeeds. */
- disp_step_thread_state.set (gdbarch);
- tp->inf->displaced_step_state.in_progress_count++;
- displaced_debug_printf ("prepared successfully thread=%s, "
- "original_pc=%s, displaced_pc=%s",
- tp->ptid.to_string ().c_str (),
- paddress (gdbarch, original_pc),
- paddress (gdbarch, displaced_pc));
- return DISPLACED_STEP_PREPARE_STATUS_OK;
- }
- /* Wrapper for displaced_step_prepare_throw that disabled further
- attempts at displaced stepping if we get a memory error. */
- static displaced_step_prepare_status
- displaced_step_prepare (thread_info *thread)
- {
- displaced_step_prepare_status status
- = DISPLACED_STEP_PREPARE_STATUS_CANT;
- try
- {
- status = displaced_step_prepare_throw (thread);
- }
- catch (const gdb_exception_error &ex)
- {
- if (ex.error != MEMORY_ERROR
- && ex.error != NOT_SUPPORTED_ERROR)
- throw;
- infrun_debug_printf ("caught exception, disabling displaced stepping: %s",
- ex.what ());
- /* Be verbose if "set displaced-stepping" is "on", silent if
- "auto". */
- if (can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
- {
- warning (_("disabling displaced stepping: %s"),
- ex.what ());
- }
- /* Disable further displaced stepping attempts. */
- thread->inf->displaced_step_state.failed_before = 1;
- }
- return status;
- }
- /* If we displaced stepped an instruction successfully, adjust registers and
- memory to yield the same effect the instruction would have had if we had
- executed it at its original address, and return
- DISPLACED_STEP_FINISH_STATUS_OK. If the instruction didn't complete,
- relocate the PC and return DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED.
- If the thread wasn't displaced stepping, return
- DISPLACED_STEP_FINISH_STATUS_OK as well. */
- static displaced_step_finish_status
- displaced_step_finish (thread_info *event_thread, enum gdb_signal signal)
- {
- displaced_step_thread_state *displaced = &event_thread->displaced_step_state;
- /* Was this thread performing a displaced step? */
- if (!displaced->in_progress ())
- return DISPLACED_STEP_FINISH_STATUS_OK;
- gdb_assert (event_thread->inf->displaced_step_state.in_progress_count > 0);
- event_thread->inf->displaced_step_state.in_progress_count--;
- /* Fixup may need to read memory/registers. Switch to the thread
- that we're fixing up. Also, target_stopped_by_watchpoint checks
- the current thread, and displaced_step_restore performs ptid-dependent
- memory accesses using current_inferior(). */
- switch_to_thread (event_thread);
- displaced_step_reset_cleanup cleanup (displaced);
- /* Do the fixup, and release the resources acquired to do the displaced
- step. */
- return gdbarch_displaced_step_finish (displaced->get_original_gdbarch (),
- event_thread, signal);
- }
- /* Data to be passed around while handling an event. This data is
- discarded between events. */
- struct execution_control_state
- {
- execution_control_state ()
- {
- this->reset ();
- }
- void reset ()
- {
- this->target = nullptr;
- this->ptid = null_ptid;
- this->event_thread = nullptr;
- ws = target_waitstatus ();
- stop_func_filled_in = 0;
- stop_func_start = 0;
- stop_func_end = 0;
- stop_func_name = nullptr;
- wait_some_more = 0;
- hit_singlestep_breakpoint = 0;
- }
- process_stratum_target *target;
- ptid_t ptid;
- /* The thread that got the event, if this was a thread event; NULL
- otherwise. */
- struct thread_info *event_thread;
- struct target_waitstatus ws;
- int stop_func_filled_in;
- CORE_ADDR stop_func_start;
- CORE_ADDR stop_func_end;
- const char *stop_func_name;
- int wait_some_more;
- /* True if the event thread hit the single-step breakpoint of
- another thread. Thus the event doesn't cause a stop, the thread
- needs to be single-stepped past the single-step breakpoint before
- we can switch back to the original stepping thread. */
- int hit_singlestep_breakpoint;
- };
- /* Clear ECS and set it to point at TP. */
- static void
- reset_ecs (struct execution_control_state *ecs, struct thread_info *tp)
- {
- ecs->reset ();
- ecs->event_thread = tp;
- ecs->ptid = tp->ptid;
- }
- static void keep_going_pass_signal (struct execution_control_state *ecs);
- static void prepare_to_wait (struct execution_control_state *ecs);
- static bool keep_going_stepped_thread (struct thread_info *tp);
- static step_over_what thread_still_needs_step_over (struct thread_info *tp);
- /* Are there any pending step-over requests? If so, run all we can
- now and return true. Otherwise, return false. */
- static bool
- start_step_over (void)
- {
- INFRUN_SCOPED_DEBUG_ENTER_EXIT;
- /* Don't start a new step-over if we already have an in-line
- step-over operation ongoing. */
- if (step_over_info_valid_p ())
- return false;
- /* Steal the global thread step over chain. As we try to initiate displaced
- steps, threads will be enqueued in the global chain if no buffers are
- available. If we iterated on the global chain directly, we might iterate
- indefinitely. */
- thread_step_over_list threads_to_step
- = std::move (global_thread_step_over_list);
- infrun_debug_printf ("stealing global queue of threads to step, length = %d",
- thread_step_over_chain_length (threads_to_step));
- bool started = false;
- /* On scope exit (whatever the reason, return or exception), if there are
- threads left in the THREADS_TO_STEP chain, put back these threads in the
- global list. */
- SCOPE_EXIT
- {
- if (threads_to_step.empty ())
- infrun_debug_printf ("step-over queue now empty");
- else
- {
- infrun_debug_printf ("putting back %d threads to step in global queue",
- thread_step_over_chain_length (threads_to_step));
- global_thread_step_over_chain_enqueue_chain
- (std::move (threads_to_step));
- }
- };
- thread_step_over_list_safe_range range
- = make_thread_step_over_list_safe_range (threads_to_step);
- for (thread_info *tp : range)
- {
- struct execution_control_state ecss;
- struct execution_control_state *ecs = &ecss;
- step_over_what step_what;
- int must_be_in_line;
- gdb_assert (!tp->stop_requested);
- if (tp->inf->displaced_step_state.unavailable)
- {
- /* The arch told us to not even try preparing another displaced step
- for this inferior. Just leave the thread in THREADS_TO_STEP, it
- will get moved to the global chain on scope exit. */
- continue;
- }
- if (tp->inf->thread_waiting_for_vfork_done != nullptr)
- {
- /* When we stop all threads, handling a vfork, any thread in the step
- over chain remains there. A user could also try to continue a
- thread stopped at a breakpoint while another thread is waiting for
- a vfork-done event. In any case, we don't want to start a step
- over right now. */
- continue;
- }
- /* Remove thread from the THREADS_TO_STEP chain. If anything goes wrong
- while we try to prepare the displaced step, we don't add it back to
- the global step over chain. This is to avoid a thread staying in the
- step over chain indefinitely if something goes wrong when resuming it
- If the error is intermittent and it still needs a step over, it will
- get enqueued again when we try to resume it normally. */
- threads_to_step.erase (threads_to_step.iterator_to (*tp));
- step_what = thread_still_needs_step_over (tp);
- must_be_in_line = ((step_what & STEP_OVER_WATCHPOINT)
- || ((step_what & STEP_OVER_BREAKPOINT)
- && !use_displaced_stepping (tp)));
- /* We currently stop all threads of all processes to step-over
- in-line. If we need to start a new in-line step-over, let
- any pending displaced steps finish first. */
- if (must_be_in_line && displaced_step_in_progress_any_thread ())
- {
- global_thread_step_over_chain_enqueue (tp);
- continue;
- }
- if (tp->control.trap_expected
- || tp->resumed ()
- || tp->executing ())
- {
- internal_error (__FILE__, __LINE__,
- "[%s] has inconsistent state: "
- "trap_expected=%d, resumed=%d, executing=%d\n",
- tp->ptid.to_string ().c_str (),
- tp->control.trap_expected,
- tp->resumed (),
- tp->executing ());
- }
- infrun_debug_printf ("resuming [%s] for step-over",
- tp->ptid.to_string ().c_str ());
- /* keep_going_pass_signal skips the step-over if the breakpoint
- is no longer inserted. In all-stop, we want to keep looking
- for a thread that needs a step-over instead of resuming TP,
- because we wouldn't be able to resume anything else until the
- target stops again. In non-stop, the resume always resumes
- only TP, so it's OK to let the thread resume freely. */
- if (!target_is_non_stop_p () && !step_what)
- continue;
- switch_to_thread (tp);
- reset_ecs (ecs, tp);
- keep_going_pass_signal (ecs);
- if (!ecs->wait_some_more)
- error (_("Command aborted."));
- /* If the thread's step over could not be initiated because no buffers
- were available, it was re-added to the global step over chain. */
- if (tp->resumed ())
- {
- infrun_debug_printf ("[%s] was resumed.",
- tp->ptid.to_string ().c_str ());
- gdb_assert (!thread_is_in_step_over_chain (tp));
- }
- else
- {
- infrun_debug_printf ("[%s] was NOT resumed.",
- tp->ptid.to_string ().c_str ());
- gdb_assert (thread_is_in_step_over_chain (tp));
- }
- /* If we started a new in-line step-over, we're done. */
- if (step_over_info_valid_p ())
- {
- gdb_assert (tp->control.trap_expected);
- started = true;
- break;
- }
- if (!target_is_non_stop_p ())
- {
- /* On all-stop, shouldn't have resumed unless we needed a
- step over. */
- gdb_assert (tp->control.trap_expected
- || tp->step_after_step_resume_breakpoint);
- /* With remote targets (at least), in all-stop, we can't
- issue any further remote commands until the program stops
- again. */
- started = true;
- break;
- }
- /* Either the thread no longer needed a step-over, or a new
- displaced stepping sequence started. Even in the latter
- case, continue looking. Maybe we can also start another
- displaced step on a thread of other process. */
- }
- return started;
- }
- /* Update global variables holding ptids to hold NEW_PTID if they were
- holding OLD_PTID. */
- static void
- infrun_thread_ptid_changed (process_stratum_target *target,
- ptid_t old_ptid, ptid_t new_ptid)
- {
- if (inferior_ptid == old_ptid
- && current_inferior ()->process_target () == target)
- inferior_ptid = new_ptid;
- }
- static const char schedlock_off[] = "off";
- static const char schedlock_on[] = "on";
- static const char schedlock_step[] = "step";
- static const char schedlock_replay[] = "replay";
- static const char *const scheduler_enums[] = {
- schedlock_off,
- schedlock_on,
- schedlock_step,
- schedlock_replay,
- NULL
- };
- static const char *scheduler_mode = schedlock_replay;
- static void
- show_scheduler_mode (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file,
- _("Mode for locking scheduler "
- "during execution is \"%s\".\n"),
- value);
- }
- static void
- set_schedlock_func (const char *args, int from_tty, struct cmd_list_element *c)
- {
- if (!target_can_lock_scheduler ())
- {
- scheduler_mode = schedlock_off;
- error (_("Target '%s' cannot support this command."),
- target_shortname ());
- }
- }
- /* True if execution commands resume all threads of all processes by
- default; otherwise, resume only threads of the current inferior
- process. */
- bool sched_multi = false;
- /* Try to setup for software single stepping. Return true if target_resume()
- should use hardware single step.
- GDBARCH the current gdbarch. */
- static bool
- maybe_software_singlestep (struct gdbarch *gdbarch)
- {
- bool hw_step = true;
- if (execution_direction == EXEC_FORWARD
- && gdbarch_software_single_step_p (gdbarch))
- hw_step = !insert_single_step_breakpoints (gdbarch);
- return hw_step;
- }
- /* See infrun.h. */
- ptid_t
- user_visible_resume_ptid (int step)
- {
- ptid_t resume_ptid;
- if (non_stop)
- {
- /* With non-stop mode on, threads are always handled
- individually. */
- resume_ptid = inferior_ptid;
- }
- else if ((scheduler_mode == schedlock_on)
- || (scheduler_mode == schedlock_step && step))
- {
- /* User-settable 'scheduler' mode requires solo thread
- resume. */
- resume_ptid = inferior_ptid;
- }
- else if ((scheduler_mode == schedlock_replay)
- && target_record_will_replay (minus_one_ptid, execution_direction))
- {
- /* User-settable 'scheduler' mode requires solo thread resume in replay
- mode. */
- resume_ptid = inferior_ptid;
- }
- else if (!sched_multi && target_supports_multi_process ())
- {
- /* Resume all threads of the current process (and none of other
- processes). */
- resume_ptid = ptid_t (inferior_ptid.pid ());
- }
- else
- {
- /* Resume all threads of all processes. */
- resume_ptid = RESUME_ALL;
- }
- return resume_ptid;
- }
- /* See infrun.h. */
- process_stratum_target *
- user_visible_resume_target (ptid_t resume_ptid)
- {
- return (resume_ptid == minus_one_ptid && sched_multi
- ? NULL
- : current_inferior ()->process_target ());
- }
- /* Return a ptid representing the set of threads that we will resume,
- in the perspective of the target, assuming run control handling
- does not require leaving some threads stopped (e.g., stepping past
- breakpoint). USER_STEP indicates whether we're about to start the
- target for a stepping command. */
- static ptid_t
- internal_resume_ptid (int user_step)
- {
- /* In non-stop, we always control threads individually. Note that
- the target may always work in non-stop mode even with "set
- non-stop off", in which case user_visible_resume_ptid could
- return a wildcard ptid. */
- if (target_is_non_stop_p ())
- return inferior_ptid;
- /* The rest of the function assumes non-stop==off and
- target-non-stop==off.
- If a thread is waiting for a vfork-done event, it means breakpoints are out
- for this inferior (well, program space in fact). We don't want to resume
- any thread other than the one waiting for vfork done, otherwise these other
- threads could miss breakpoints. So if a thread in the resumption set is
- waiting for a vfork-done event, resume only that thread.
- The resumption set width depends on whether schedule-multiple is on or off.
- Note that if the target_resume interface was more flexible, we could be
- smarter here when schedule-multiple is on. For example, imagine 3
- inferiors with 2 threads each (1.1, 1.2, 2.1, 2.2, 3.1 and 3.2). Threads
- 2.1 and 3.2 are both waiting for a vfork-done event. Then we could ask the
- target(s) to resume:
- - All threads of inferior 1
- - Thread 2.1
- - Thread 3.2
- Since we don't have that flexibility (we can only pass one ptid), just
- resume the first thread waiting for a vfork-done event we find (e.g. thread
- 2.1). */
- if (sched_multi)
- {
- for (inferior *inf : all_non_exited_inferiors ())
- if (inf->thread_waiting_for_vfork_done != nullptr)
- return inf->thread_waiting_for_vfork_done->ptid;
- }
- else if (current_inferior ()->thread_waiting_for_vfork_done != nullptr)
- return current_inferior ()->thread_waiting_for_vfork_done->ptid;
- return user_visible_resume_ptid (user_step);
- }
- /* Wrapper for target_resume, that handles infrun-specific
- bookkeeping. */
- static void
- do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
- {
- struct thread_info *tp = inferior_thread ();
- gdb_assert (!tp->stop_requested);
- /* Install inferior's terminal modes. */
- target_terminal::inferior ();
- /* Avoid confusing the next resume, if the next stop/resume
- happens to apply to another thread. */
- tp->set_stop_signal (GDB_SIGNAL_0);
- /* Advise target which signals may be handled silently.
- If we have removed breakpoints because we are stepping over one
- in-line (in any thread), we need to receive all signals to avoid
- accidentally skipping a breakpoint during execution of a signal
- handler.
- Likewise if we're displaced stepping, otherwise a trap for a
- breakpoint in a signal handler might be confused with the
- displaced step finishing. We don't make the displaced_step_finish
- step distinguish the cases instead, because:
- - a backtrace while stopped in the signal handler would show the
- scratch pad as frame older than the signal handler, instead of
- the real mainline code.
- - when the thread is later resumed, the signal handler would
- return to the scratch pad area, which would no longer be
- valid. */
- if (step_over_info_valid_p ()
- || displaced_step_in_progress (tp->inf))
- target_pass_signals ({});
- else
- target_pass_signals (signal_pass);
- infrun_debug_printf ("resume_ptid=%s, step=%d, sig=%s",
- resume_ptid.to_string ().c_str (),
- step, gdb_signal_to_symbol_string (sig));
- target_resume (resume_ptid, step, sig);
- }
- /* Resume the inferior. SIG is the signal to give the inferior
- (GDB_SIGNAL_0 for none). Note: don't call this directly; instead
- call 'resume', which handles exceptions. */
- static void
- resume_1 (enum gdb_signal sig)
- {
- struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = regcache->arch ();
- struct thread_info *tp = inferior_thread ();
- const address_space *aspace = regcache->aspace ();
- ptid_t resume_ptid;
- /* This represents the user's step vs continue request. When
- deciding whether "set scheduler-locking step" applies, it's the
- user's intention that counts. */
- const int user_step = tp->control.stepping_command;
- /* This represents what we'll actually request the target to do.
- This can decay from a step to a continue, if e.g., we need to
- implement single-stepping with breakpoints (software
- single-step). */
- bool step;
- gdb_assert (!tp->stop_requested);
- gdb_assert (!thread_is_in_step_over_chain (tp));
- if (tp->has_pending_waitstatus ())
- {
- infrun_debug_printf
- ("thread %s has pending wait "
- "status %s (currently_stepping=%d).",
- tp->ptid.to_string ().c_str (),
- tp->pending_waitstatus ().to_string ().c_str (),
- currently_stepping (tp));
- tp->inf->process_target ()->threads_executing = true;
- tp->set_resumed (true);
- /* FIXME: What should we do if we are supposed to resume this
- thread with a signal? Maybe we should maintain a queue of
- pending signals to deliver. */
- if (sig != GDB_SIGNAL_0)
- {
- warning (_("Couldn't deliver signal %s to %s."),
- gdb_signal_to_name (sig),
- tp->ptid.to_string ().c_str ());
- }
- tp->set_stop_signal (GDB_SIGNAL_0);
- if (target_can_async_p ())
- {
- target_async (1);
- /* Tell the event loop we have an event to process. */
- mark_async_event_handler (infrun_async_inferior_event_token);
- }
- return;
- }
- tp->stepped_breakpoint = 0;
- /* Depends on stepped_breakpoint. */
- step = currently_stepping (tp);
- if (current_inferior ()->thread_waiting_for_vfork_done != nullptr)
- {
- /* Don't try to single-step a vfork parent that is waiting for
- the child to get out of the shared memory region (by exec'ing
- or exiting). This is particularly important on software
- single-step archs, as the child process would trip on the
- software single step breakpoint inserted for the parent
- process. Since the parent will not actually execute any
- instruction until the child is out of the shared region (such
- are vfork's semantics), it is safe to simply continue it.
- Eventually, we'll see a TARGET_WAITKIND_VFORK_DONE event for
- the parent, and tell it to `keep_going', which automatically
- re-sets it stepping. */
- infrun_debug_printf ("resume : clear step");
- step = false;
- }
- CORE_ADDR pc = regcache_read_pc (regcache);
- infrun_debug_printf ("step=%d, signal=%s, trap_expected=%d, "
- "current thread [%s] at %s",
- step, gdb_signal_to_symbol_string (sig),
- tp->control.trap_expected,
- inferior_ptid.to_string ().c_str (),
- paddress (gdbarch, pc));
- /* Normally, by the time we reach `resume', the breakpoints are either
- removed or inserted, as appropriate. The exception is if we're sitting
- at a permanent breakpoint; we need to step over it, but permanent
- breakpoints can't be removed. So we have to test for it here. */
- if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here)
- {
- if (sig != GDB_SIGNAL_0)
- {
- /* We have a signal to pass to the inferior. The resume
- may, or may not take us to the signal handler. If this
- is a step, we'll need to stop in the signal handler, if
- there's one, (if the target supports stepping into
- handlers), or in the next mainline instruction, if
- there's no handler. If this is a continue, we need to be
- sure to run the handler with all breakpoints inserted.
- In all cases, set a breakpoint at the current address
- (where the handler returns to), and once that breakpoint
- is hit, resume skipping the permanent breakpoint. If
- that breakpoint isn't hit, then we've stepped into the
- signal handler (or hit some other event). We'll delete
- the step-resume breakpoint then. */
- infrun_debug_printf ("resume: skipping permanent breakpoint, "
- "deliver signal first");
- clear_step_over_info ();
- tp->control.trap_expected = 0;
- if (tp->control.step_resume_breakpoint == NULL)
- {
- /* Set a "high-priority" step-resume, as we don't want
- user breakpoints at PC to trigger (again) when this
- hits. */
- insert_hp_step_resume_breakpoint_at_frame (get_current_frame ());
- gdb_assert (tp->control.step_resume_breakpoint->loc->permanent);
- tp->step_after_step_resume_breakpoint = step;
- }
- insert_breakpoints ();
- }
- else
- {
- /* There's no signal to pass, we can go ahead and skip the
- permanent breakpoint manually. */
- infrun_debug_printf ("skipping permanent breakpoint");
- gdbarch_skip_permanent_breakpoint (gdbarch, regcache);
- /* Update pc to reflect the new address from which we will
- execute instructions. */
- pc = regcache_read_pc (regcache);
- if (step)
- {
- /* We've already advanced the PC, so the stepping part
- is done. Now we need to arrange for a trap to be
- reported to handle_inferior_event. Set a breakpoint
- at the current PC, and run to it. Don't update
- prev_pc, because if we end in
- switch_back_to_stepped_thread, we want the "expected
- thread advanced also" branch to be taken. IOW, we
- don't want this thread to step further from PC
- (overstep). */
- gdb_assert (!step_over_info_valid_p ());
- insert_single_step_breakpoint (gdbarch, aspace, pc);
- insert_breakpoints ();
- resume_ptid = internal_resume_ptid (user_step);
- do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
- tp->set_resumed (true);
- return;
- }
- }
- }
- /* If we have a breakpoint to step over, make sure to do a single
- step only. Same if we have software watchpoints. */
- if (tp->control.trap_expected || bpstat_should_step ())
- tp->control.may_range_step = 0;
- /* If displaced stepping is enabled, step over breakpoints by executing a
- copy of the instruction at a different address.
- We can't use displaced stepping when we have a signal to deliver;
- the comments for displaced_step_prepare explain why. The
- comments in the handle_inferior event for dealing with 'random
- signals' explain what we do instead.
- We can't use displaced stepping when we are waiting for vfork_done
- event, displaced stepping breaks the vfork child similarly as single
- step software breakpoint. */
- if (tp->control.trap_expected
- && use_displaced_stepping (tp)
- && !step_over_info_valid_p ()
- && sig == GDB_SIGNAL_0
- && current_inferior ()->thread_waiting_for_vfork_done == nullptr)
- {
- displaced_step_prepare_status prepare_status
- = displaced_step_prepare (tp);
- if (prepare_status == DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE)
- {
- infrun_debug_printf ("Got placed in step-over queue");
- tp->control.trap_expected = 0;
- return;
- }
- else if (prepare_status == DISPLACED_STEP_PREPARE_STATUS_CANT)
- {
- /* Fallback to stepping over the breakpoint in-line. */
- if (target_is_non_stop_p ())
- stop_all_threads ("displaced stepping falling back on inline stepping");
- set_step_over_info (regcache->aspace (),
- regcache_read_pc (regcache), 0, tp->global_num);
- step = maybe_software_singlestep (gdbarch);
- insert_breakpoints ();
- }
- else if (prepare_status == DISPLACED_STEP_PREPARE_STATUS_OK)
- {
- /* Update pc to reflect the new address from which we will
- execute instructions due to displaced stepping. */
- pc = regcache_read_pc (get_thread_regcache (tp));
- step = gdbarch_displaced_step_hw_singlestep (gdbarch);
- }
- else
- gdb_assert_not_reached ("Invalid displaced_step_prepare_status "
- "value.");
- }
- /* Do we need to do it the hard way, w/temp breakpoints? */
- else if (step)
- step = maybe_software_singlestep (gdbarch);
- /* Currently, our software single-step implementation leads to different
- results than hardware single-stepping in one situation: when stepping
- into delivering a signal which has an associated signal handler,
- hardware single-step will stop at the first instruction of the handler,
- while software single-step will simply skip execution of the handler.
- For now, this difference in behavior is accepted since there is no
- easy way to actually implement single-stepping into a signal handler
- without kernel support.
- However, there is one scenario where this difference leads to follow-on
- problems: if we're stepping off a breakpoint by removing all breakpoints
- and then single-stepping. In this case, the software single-step
- behavior means that even if there is a *breakpoint* in the signal
- handler, GDB still would not stop.
- Fortunately, we can at least fix this particular issue. We detect
- here the case where we are about to deliver a signal while software
- single-stepping with breakpoints removed. In this situation, we
- revert the decisions to remove all breakpoints and insert single-
- step breakpoints, and instead we install a step-resume breakpoint
- at the current address, deliver the signal without stepping, and
- once we arrive back at the step-resume breakpoint, actually step
- over the breakpoint we originally wanted to step over. */
- if (thread_has_single_step_breakpoints_set (tp)
- && sig != GDB_SIGNAL_0
- && step_over_info_valid_p ())
- {
- /* If we have nested signals or a pending signal is delivered
- immediately after a handler returns, might already have
- a step-resume breakpoint set on the earlier handler. We cannot
- set another step-resume breakpoint; just continue on until the
- original breakpoint is hit. */
- if (tp->control.step_resume_breakpoint == NULL)
- {
- insert_hp_step_resume_breakpoint_at_frame (get_current_frame ());
- tp->step_after_step_resume_breakpoint = 1;
- }
- delete_single_step_breakpoints (tp);
- clear_step_over_info ();
- tp->control.trap_expected = 0;
- insert_breakpoints ();
- }
- /* If STEP is set, it's a request to use hardware stepping
- facilities. But in that case, we should never
- use singlestep breakpoint. */
- gdb_assert (!(thread_has_single_step_breakpoints_set (tp) && step));
- /* Decide the set of threads to ask the target to resume. */
- if (tp->control.trap_expected)
- {
- /* We're allowing a thread to run past a breakpoint it has
- hit, either by single-stepping the thread with the breakpoint
- removed, or by displaced stepping, with the breakpoint inserted.
- In the former case, we need to single-step only this thread,
- and keep others stopped, as they can miss this breakpoint if
- allowed to run. That's not really a problem for displaced
- stepping, but, we still keep other threads stopped, in case
- another thread is also stopped for a breakpoint waiting for
- its turn in the displaced stepping queue. */
- resume_ptid = inferior_ptid;
- }
- else
- resume_ptid = internal_resume_ptid (user_step);
- if (execution_direction != EXEC_REVERSE
- && step && breakpoint_inserted_here_p (aspace, pc))
- {
- /* There are two cases where we currently need to step a
- breakpoint instruction when we have a signal to deliver:
- - See handle_signal_stop where we handle random signals that
- could take out us out of the stepping range. Normally, in
- that case we end up continuing (instead of stepping) over the
- signal handler with a breakpoint at PC, but there are cases
- where we should _always_ single-step, even if we have a
- step-resume breakpoint, like when a software watchpoint is
- set. Assuming single-stepping and delivering a signal at the
- same time would takes us to the signal handler, then we could
- have removed the breakpoint at PC to step over it. However,
- some hardware step targets (like e.g., Mac OS) can't step
- into signal handlers, and for those, we need to leave the
- breakpoint at PC inserted, as otherwise if the handler
- recurses and executes PC again, it'll miss the breakpoint.
- So we leave the breakpoint inserted anyway, but we need to
- record that we tried to step a breakpoint instruction, so
- that adjust_pc_after_break doesn't end up confused.
- - In non-stop if we insert a breakpoint (e.g., a step-resume)
- in one thread after another thread that was stepping had been
- momentarily paused for a step-over. When we re-resume the
- stepping thread, it may be resumed from that address with a
- breakpoint that hasn't trapped yet. Seen with
- gdb.threads/non-stop-fair-events.exp, on targets that don't
- do displaced stepping. */
- infrun_debug_printf ("resume: [%s] stepped breakpoint",
- tp->ptid.to_string ().c_str ());
- tp->stepped_breakpoint = 1;
- /* Most targets can step a breakpoint instruction, thus
- executing it normally. But if this one cannot, just
- continue and we will hit it anyway. */
- if (gdbarch_cannot_step_breakpoint (gdbarch))
- step = false;
- }
- if (debug_displaced
- && tp->control.trap_expected
- && use_displaced_stepping (tp)
- && !step_over_info_valid_p ())
- {
- struct regcache *resume_regcache = get_thread_regcache (tp);
- struct gdbarch *resume_gdbarch = resume_regcache->arch ();
- CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
- gdb_byte buf[4];
- read_memory (actual_pc, buf, sizeof (buf));
- displaced_debug_printf ("run %s: %s",
- paddress (resume_gdbarch, actual_pc),
- displaced_step_dump_bytes
- (buf, sizeof (buf)).c_str ());
- }
- if (tp->control.may_range_step)
- {
- /* If we're resuming a thread with the PC out of the step
- range, then we're doing some nested/finer run control
- operation, like stepping the thread out of the dynamic
- linker or the displaced stepping scratch pad. We
- shouldn't have allowed a range step then. */
- gdb_assert (pc_in_thread_step_range (pc, tp));
- }
- do_target_resume (resume_ptid, step, sig);
- tp->set_resumed (true);
- }
- /* Resume the inferior. SIG is the signal to give the inferior
- (GDB_SIGNAL_0 for none). This is a wrapper around 'resume_1' that
- rolls back state on error. */
- static void
- resume (gdb_signal sig)
- {
- try
- {
- resume_1 (sig);
- }
- catch (const gdb_exception &ex)
- {
- /* If resuming is being aborted for any reason, delete any
- single-step breakpoint resume_1 may have created, to avoid
- confusing the following resumption, and to avoid leaving
- single-step breakpoints perturbing other threads, in case
- we're running in non-stop mode. */
- if (inferior_ptid != null_ptid)
- delete_single_step_breakpoints (inferior_thread ());
- throw;
- }
- }
- /* Proceeding. */
- /* See infrun.h. */
- /* Counter that tracks number of user visible stops. This can be used
- to tell whether a command has proceeded the inferior past the
- current location. This allows e.g., inferior function calls in
- breakpoint commands to not interrupt the command list. When the
- call finishes successfully, the inferior is standing at the same
- breakpoint as if nothing happened (and so we don't call
- normal_stop). */
- static ULONGEST current_stop_id;
- /* See infrun.h. */
- ULONGEST
- get_stop_id (void)
- {
- return current_stop_id;
- }
- /* Called when we report a user visible stop. */
- static void
- new_stop_id (void)
- {
- current_stop_id++;
- }
- /* Clear out all variables saying what to do when inferior is continued.
- First do this, then set the ones you want, then call `proceed'. */
- static void
- clear_proceed_status_thread (struct thread_info *tp)
- {
- infrun_debug_printf ("%s", tp->ptid.to_string ().c_str ());
- /* If we're starting a new sequence, then the previous finished
- single-step is no longer relevant. */
- if (tp->has_pending_waitstatus ())
- {
- if (tp->stop_reason () == TARGET_STOPPED_BY_SINGLE_STEP)
- {
- infrun_debug_printf ("pending event of %s was a finished step. "
- "Discarding.",
- tp->ptid.to_string ().c_str ());
- tp->clear_pending_waitstatus ();
- tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON);
- }
- else
- {
- infrun_debug_printf
- ("thread %s has pending wait status %s (currently_stepping=%d).",
- tp->ptid.to_string ().c_str (),
- tp->pending_waitstatus ().to_string ().c_str (),
- currently_stepping (tp));
- }
- }
- /* If this signal should not be seen by program, give it zero.
- Used for debugging signals. */
- if (!signal_pass_state (tp->stop_signal ()))
- tp->set_stop_signal (GDB_SIGNAL_0);
- tp->release_thread_fsm ();
- tp->control.trap_expected = 0;
- tp->control.step_range_start = 0;
- tp->control.step_range_end = 0;
- tp->control.may_range_step = 0;
- tp->control.step_frame_id = null_frame_id;
- tp->control.step_stack_frame_id = null_frame_id;
- tp->control.step_over_calls = STEP_OVER_UNDEBUGGABLE;
- tp->control.step_start_function = NULL;
- tp->stop_requested = 0;
- tp->control.stop_step = 0;
- tp->control.proceed_to_finish = 0;
- tp->control.stepping_command = 0;
- /* Discard any remaining commands or status from previous stop. */
- bpstat_clear (&tp->control.stop_bpstat);
- }
- void
- clear_proceed_status (int step)
- {
- /* With scheduler-locking replay, stop replaying other threads if we're
- not replaying the user-visible resume ptid.
- This is a convenience feature to not require the user to explicitly
- stop replaying the other threads. We're assuming that the user's
- intent is to resume tracing the recorded process. */
- if (!non_stop && scheduler_mode == schedlock_replay
- && target_record_is_replaying (minus_one_ptid)
- && !target_record_will_replay (user_visible_resume_ptid (step),
- execution_direction))
- target_record_stop_replaying ();
- if (!non_stop && inferior_ptid != null_ptid)
- {
- ptid_t resume_ptid = user_visible_resume_ptid (step);
- process_stratum_target *resume_target
- = user_visible_resume_target (resume_ptid);
- /* In all-stop mode, delete the per-thread status of all threads
- we're about to resume, implicitly and explicitly. */
- for (thread_info *tp : all_non_exited_threads (resume_target, resume_ptid))
- clear_proceed_status_thread (tp);
- }
- if (inferior_ptid != null_ptid)
- {
- struct inferior *inferior;
- if (non_stop)
- {
- /* If in non-stop mode, only delete the per-thread status of
- the current thread. */
- clear_proceed_status_thread (inferior_thread ());
- }
- inferior = current_inferior ();
- inferior->control.stop_soon = NO_STOP_QUIETLY;
- }
- gdb::observers::about_to_proceed.notify ();
- }
- /* Returns true if TP is still stopped at a breakpoint that needs
- stepping-over in order to make progress. If the breakpoint is gone
- meanwhile, we can skip the whole step-over dance. */
- static bool
- thread_still_needs_step_over_bp (struct thread_info *tp)
- {
- if (tp->stepping_over_breakpoint)
- {
- struct regcache *regcache = get_thread_regcache (tp);
- if (breakpoint_here_p (regcache->aspace (),
- regcache_read_pc (regcache))
- == ordinary_breakpoint_here)
- return true;
- tp->stepping_over_breakpoint = 0;
- }
- return false;
- }
- /* Check whether thread TP still needs to start a step-over in order
- to make progress when resumed. Returns an bitwise or of enum
- step_over_what bits, indicating what needs to be stepped over. */
- static step_over_what
- thread_still_needs_step_over (struct thread_info *tp)
- {
- step_over_what what = 0;
- if (thread_still_needs_step_over_bp (tp))
- what |= STEP_OVER_BREAKPOINT;
- if (tp->stepping_over_watchpoint
- && !target_have_steppable_watchpoint ())
- what |= STEP_OVER_WATCHPOINT;
- return what;
- }
- /* Returns true if scheduler locking applies. STEP indicates whether
- we're about to do a step/next-like command to a thread. */
- static bool
- schedlock_applies (struct thread_info *tp)
- {
- return (scheduler_mode == schedlock_on
- || (scheduler_mode == schedlock_step
- && tp->control.stepping_command)
- || (scheduler_mode == schedlock_replay
- && target_record_will_replay (minus_one_ptid,
- execution_direction)));
- }
- /* Set process_stratum_target::COMMIT_RESUMED_STATE in all target
- stacks that have threads executing and don't have threads with
- pending events. */
- static void
- maybe_set_commit_resumed_all_targets ()
- {
- scoped_restore_current_thread restore_thread;
- for (inferior *inf : all_non_exited_inferiors ())
- {
- process_stratum_target *proc_target = inf->process_target ();
- if (proc_target->commit_resumed_state)
- {
- /* We already set this in a previous iteration, via another
- inferior sharing the process_stratum target. */
- continue;
- }
- /* If the target has no resumed threads, it would be useless to
- ask it to commit the resumed threads. */
- if (!proc_target->threads_executing)
- {
- infrun_debug_printf ("not requesting commit-resumed for target "
- "%s, no resumed threads",
- proc_target->shortname ());
- continue;
- }
- /* As an optimization, if a thread from this target has some
- status to report, handle it before requiring the target to
- commit its resumed threads: handling the status might lead to
- resuming more threads. */
- if (proc_target->has_resumed_with_pending_wait_status ())
- {
- infrun_debug_printf ("not requesting commit-resumed for target %s, a"
- " thread has a pending waitstatus",
- proc_target->shortname ());
- continue;
- }
- switch_to_inferior_no_thread (inf);
- if (target_has_pending_events ())
- {
- infrun_debug_printf ("not requesting commit-resumed for target %s, "
- "target has pending events",
- proc_target->shortname ());
- continue;
- }
- infrun_debug_printf ("enabling commit-resumed for target %s",
- proc_target->shortname ());
- proc_target->commit_resumed_state = true;
- }
- }
- /* See infrun.h. */
- void
- maybe_call_commit_resumed_all_targets ()
- {
- scoped_restore_current_thread restore_thread;
- for (inferior *inf : all_non_exited_inferiors ())
- {
- process_stratum_target *proc_target = inf->process_target ();
- if (!proc_target->commit_resumed_state)
- continue;
- switch_to_inferior_no_thread (inf);
- infrun_debug_printf ("calling commit_resumed for target %s",
- proc_target->shortname());
- target_commit_resumed ();
- }
- }
- /* To track nesting of scoped_disable_commit_resumed objects, ensuring
- that only the outermost one attempts to re-enable
- commit-resumed. */
- static bool enable_commit_resumed = true;
- /* See infrun.h. */
- scoped_disable_commit_resumed::scoped_disable_commit_resumed
- (const char *reason)
- : m_reason (reason),
- m_prev_enable_commit_resumed (enable_commit_resumed)
- {
- infrun_debug_printf ("reason=%s", m_reason);
- enable_commit_resumed = false;
- for (inferior *inf : all_non_exited_inferiors ())
- {
- process_stratum_target *proc_target = inf->process_target ();
- if (m_prev_enable_commit_resumed)
- {
- /* This is the outermost instance: force all
- COMMIT_RESUMED_STATE to false. */
- proc_target->commit_resumed_state = false;
- }
- else
- {
- /* This is not the outermost instance, we expect
- COMMIT_RESUMED_STATE to have been cleared by the
- outermost instance. */
- gdb_assert (!proc_target->commit_resumed_state);
- }
- }
- }
- /* See infrun.h. */
- void
- scoped_disable_commit_resumed::reset ()
- {
- if (m_reset)
- return;
- m_reset = true;
- infrun_debug_printf ("reason=%s", m_reason);
- gdb_assert (!enable_commit_resumed);
- enable_commit_resumed = m_prev_enable_commit_resumed;
- if (m_prev_enable_commit_resumed)
- {
- /* This is the outermost instance, re-enable
- COMMIT_RESUMED_STATE on the targets where it's possible. */
- maybe_set_commit_resumed_all_targets ();
- }
- else
- {
- /* This is not the outermost instance, we expect
- COMMIT_RESUMED_STATE to still be false. */
- for (inferior *inf : all_non_exited_inferiors ())
- {
- process_stratum_target *proc_target = inf->process_target ();
- gdb_assert (!proc_target->commit_resumed_state);
- }
- }
- }
- /* See infrun.h. */
- scoped_disable_commit_resumed::~scoped_disable_commit_resumed ()
- {
- reset ();
- }
- /* See infrun.h. */
- void
- scoped_disable_commit_resumed::reset_and_commit ()
- {
- reset ();
- maybe_call_commit_resumed_all_targets ();
- }
- /* See infrun.h. */
- scoped_enable_commit_resumed::scoped_enable_commit_resumed
- (const char *reason)
- : m_reason (reason),
- m_prev_enable_commit_resumed (enable_commit_resumed)
- {
- infrun_debug_printf ("reason=%s", m_reason);
- if (!enable_commit_resumed)
- {
- enable_commit_resumed = true;
- /* Re-enable COMMIT_RESUMED_STATE on the targets where it's
- possible. */
- maybe_set_commit_resumed_all_targets ();
- maybe_call_commit_resumed_all_targets ();
- }
- }
- /* See infrun.h. */
- scoped_enable_commit_resumed::~scoped_enable_commit_resumed ()
- {
- infrun_debug_printf ("reason=%s", m_reason);
- gdb_assert (enable_commit_resumed);
- enable_commit_resumed = m_prev_enable_commit_resumed;
- if (!enable_commit_resumed)
- {
- /* Force all COMMIT_RESUMED_STATE back to false. */
- for (inferior *inf : all_non_exited_inferiors ())
- {
- process_stratum_target *proc_target = inf->process_target ();
- proc_target->commit_resumed_state = false;
- }
- }
- }
- /* Check that all the targets we're about to resume are in non-stop
- mode. Ideally, we'd only care whether all targets support
- target-async, but we're not there yet. E.g., stop_all_threads
- doesn't know how to handle all-stop targets. Also, the remote
- protocol in all-stop mode is synchronous, irrespective of
- target-async, which means that things like a breakpoint re-set
- triggered by one target would try to read memory from all targets
- and fail. */
- static void
- check_multi_target_resumption (process_stratum_target *resume_target)
- {
- if (!non_stop && resume_target == nullptr)
- {
- scoped_restore_current_thread restore_thread;
- /* This is used to track whether we're resuming more than one
- target. */
- process_stratum_target *first_connection = nullptr;
- /* The first inferior we see with a target that does not work in
- always-non-stop mode. */
- inferior *first_not_non_stop = nullptr;
- for (inferior *inf : all_non_exited_inferiors ())
- {
- switch_to_inferior_no_thread (inf);
- if (!target_has_execution ())
- continue;
- process_stratum_target *proc_target
- = current_inferior ()->process_target();
- if (!target_is_non_stop_p ())
- first_not_non_stop = inf;
- if (first_connection == nullptr)
- first_connection = proc_target;
- else if (first_connection != proc_target
- && first_not_non_stop != nullptr)
- {
- switch_to_inferior_no_thread (first_not_non_stop);
- proc_target = current_inferior ()->process_target();
- error (_("Connection %d (%s) does not support "
- "multi-target resumption."),
- proc_target->connection_number,
- make_target_connection_string (proc_target).c_str ());
- }
- }
- }
- }
- /* Basic routine for continuing the program in various fashions.
- ADDR is the address to resume at, or -1 for resume where stopped.
- SIGGNAL is the signal to give it, or GDB_SIGNAL_0 for none,
- or GDB_SIGNAL_DEFAULT for act according to how it stopped.
- You should call clear_proceed_status before calling proceed. */
- void
- proceed (CORE_ADDR addr, enum gdb_signal siggnal)
- {
- INFRUN_SCOPED_DEBUG_ENTER_EXIT;
- struct regcache *regcache;
- struct gdbarch *gdbarch;
- CORE_ADDR pc;
- struct execution_control_state ecss;
- struct execution_control_state *ecs = &ecss;
- /* If we're stopped at a fork/vfork, follow the branch set by the
- "set follow-fork-mode" command; otherwise, we'll just proceed
- resuming the current thread. */
- if (!follow_fork ())
- {
- /* The target for some reason decided not to resume. */
- normal_stop ();
- if (target_can_async_p ())
- inferior_event_handler (INF_EXEC_COMPLETE);
- return;
- }
- /* We'll update this if & when we switch to a new thread. */
- previous_inferior_ptid = inferior_ptid;
- regcache = get_current_regcache ();
- gdbarch = regcache->arch ();
- const address_space *aspace = regcache->aspace ();
- pc = regcache_read_pc_protected (regcache);
- thread_info *cur_thr = inferior_thread ();
- /* Fill in with reasonable starting values. */
- init_thread_stepping_state (cur_thr);
- gdb_assert (!thread_is_in_step_over_chain (cur_thr));
- ptid_t resume_ptid
- = user_visible_resume_ptid (cur_thr->control.stepping_command);
- process_stratum_target *resume_target
- = user_visible_resume_target (resume_ptid);
- check_multi_target_resumption (resume_target);
- if (addr == (CORE_ADDR) -1)
- {
- if (cur_thr->stop_pc_p ()
- && pc == cur_thr->stop_pc ()
- && breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here
- && execution_direction != EXEC_REVERSE)
- /* There is a breakpoint at the address we will resume at,
- step one instruction before inserting breakpoints so that
- we do not stop right away (and report a second hit at this
- breakpoint).
- Note, we don't do this in reverse, because we won't
- actually be executing the breakpoint insn anyway.
- We'll be (un-)executing the previous instruction. */
- cur_thr->stepping_over_breakpoint = 1;
- else if (gdbarch_single_step_through_delay_p (gdbarch)
- && gdbarch_single_step_through_delay (gdbarch,
- get_current_frame ()))
- /* We stepped onto an instruction that needs to be stepped
- again before re-inserting the breakpoint, do so. */
- cur_thr->stepping_over_breakpoint = 1;
- }
- else
- {
- regcache_write_pc (regcache, addr);
- }
- if (siggnal != GDB_SIGNAL_DEFAULT)
- cur_thr->set_stop_signal (siggnal);
- /* If an exception is thrown from this point on, make sure to
- propagate GDB's knowledge of the executing state to the
- frontend/user running state. */
- scoped_finish_thread_state finish_state (resume_target, resume_ptid);
- /* Even if RESUME_PTID is a wildcard, and we end up resuming fewer
- threads (e.g., we might need to set threads stepping over
- breakpoints first), from the user/frontend's point of view, all
- threads in RESUME_PTID are now running. Unless we're calling an
- inferior function, as in that case we pretend the inferior
- doesn't run at all. */
- if (!cur_thr->control.in_infcall)
- set_running (resume_target, resume_ptid, true);
- infrun_debug_printf ("addr=%s, signal=%s", paddress (gdbarch, addr),
- gdb_signal_to_symbol_string (siggnal));
- annotate_starting ();
- /* Make sure that output from GDB appears before output from the
- inferior. */
- gdb_flush (gdb_stdout);
- /* Since we've marked the inferior running, give it the terminal. A
- QUIT/Ctrl-C from here on is forwarded to the target (which can
- still detect attempts to unblock a stuck connection with repeated
- Ctrl-C from within target_pass_ctrlc). */
- target_terminal::inferior ();
- /* In a multi-threaded task we may select another thread and
- then continue or step.
- But if a thread that we're resuming had stopped at a breakpoint,
- it will immediately cause another breakpoint stop without any
- execution (i.e. it will report a breakpoint hit incorrectly). So
- we must step over it first.
- Look for threads other than the current (TP) that reported a
- breakpoint hit and haven't been resumed yet since. */
- /* If scheduler locking applies, we can avoid iterating over all
- threads. */
- if (!non_stop && !schedlock_applies (cur_thr))
- {
- for (thread_info *tp : all_non_exited_threads (resume_target,
- resume_ptid))
- {
- switch_to_thread_no_regs (tp);
- /* Ignore the current thread here. It's handled
- afterwards. */
- if (tp == cur_thr)
- continue;
- if (!thread_still_needs_step_over (tp))
- continue;
- gdb_assert (!thread_is_in_step_over_chain (tp));
- infrun_debug_printf ("need to step-over [%s] first",
- tp->ptid.to_string ().c_str ());
- global_thread_step_over_chain_enqueue (tp);
- }
- switch_to_thread (cur_thr);
- }
- /* Enqueue the current thread last, so that we move all other
- threads over their breakpoints first. */
- if (cur_thr->stepping_over_breakpoint)
- global_thread_step_over_chain_enqueue (cur_thr);
- /* If the thread isn't started, we'll still need to set its prev_pc,
- so that switch_back_to_stepped_thread knows the thread hasn't
- advanced. Must do this before resuming any thread, as in
- all-stop/remote, once we resume we can't send any other packet
- until the target stops again. */
- cur_thr->prev_pc = regcache_read_pc_protected (regcache);
- {
- scoped_disable_commit_resumed disable_commit_resumed ("proceeding");
- bool step_over_started = start_step_over ();
- if (step_over_info_valid_p ())
- {
- /* Either this thread started a new in-line step over, or some
- other thread was already doing one. In either case, don't
- resume anything else until the step-over is finished. */
- }
- else if (step_over_started && !target_is_non_stop_p ())
- {
- /* A new displaced stepping sequence was started. In all-stop,
- we can't talk to the target anymore until it next stops. */
- }
- else if (!non_stop && target_is_non_stop_p ())
- {
- INFRUN_SCOPED_DEBUG_START_END
- ("resuming threads, all-stop-on-top-of-non-stop");
- /* In all-stop, but the target is always in non-stop mode.
- Start all other threads that are implicitly resumed too. */
- for (thread_info *tp : all_non_exited_threads (resume_target,
- resume_ptid))
- {
- switch_to_thread_no_regs (tp);
- if (!tp->inf->has_execution ())
- {
- infrun_debug_printf ("[%s] target has no execution",
- tp->ptid.to_string ().c_str ());
- continue;
- }
- if (tp->resumed ())
- {
- infrun_debug_printf ("[%s] resumed",
- tp->ptid.to_string ().c_str ());
- gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
- continue;
- }
- if (thread_is_in_step_over_chain (tp))
- {
- infrun_debug_printf ("[%s] needs step-over",
- tp->ptid.to_string ().c_str ());
- continue;
- }
- /* If a thread of that inferior is waiting for a vfork-done
- (for a detached vfork child to exec or exit), breakpoints are
- removed. We must not resume any thread of that inferior, other
- than the one waiting for the vfork-done. */
- if (tp->inf->thread_waiting_for_vfork_done != nullptr
- && tp != tp->inf->thread_waiting_for_vfork_done)
- {
- infrun_debug_printf ("[%s] another thread of this inferior is "
- "waiting for vfork-done",
- tp->ptid.to_string ().c_str ());
- continue;
- }
- infrun_debug_printf ("resuming %s",
- tp->ptid.to_string ().c_str ());
- reset_ecs (ecs, tp);
- switch_to_thread (tp);
- keep_going_pass_signal (ecs);
- if (!ecs->wait_some_more)
- error (_("Command aborted."));
- }
- }
- else if (!cur_thr->resumed ()
- && !thread_is_in_step_over_chain (cur_thr)
- /* In non-stop, forbid resuming a thread if some other thread of
- that inferior is waiting for a vfork-done event (this means
- breakpoints are out for this inferior). */
- && !(non_stop
- && cur_thr->inf->thread_waiting_for_vfork_done != nullptr))
- {
- /* The thread wasn't started, and isn't queued, run it now. */
- reset_ecs (ecs, cur_thr);
- switch_to_thread (cur_thr);
- keep_going_pass_signal (ecs);
- if (!ecs->wait_some_more)
- error (_("Command aborted."));
- }
- disable_commit_resumed.reset_and_commit ();
- }
- finish_state.release ();
- /* If we've switched threads above, switch back to the previously
- current thread. We don't want the user to see a different
- selected thread. */
- switch_to_thread (cur_thr);
- /* Tell the event loop to wait for it to stop. If the target
- supports asynchronous execution, it'll do this from within
- target_resume. */
- if (!target_can_async_p ())
- mark_async_event_handler (infrun_async_inferior_event_token);
- }
- /* Start remote-debugging of a machine over a serial link. */
- void
- start_remote (int from_tty)
- {
- inferior *inf = current_inferior ();
- inf->control.stop_soon = STOP_QUIETLY_REMOTE;
- /* Always go on waiting for the target, regardless of the mode. */
- /* FIXME: cagney/1999-09-23: At present it isn't possible to
- indicate to wait_for_inferior that a target should timeout if
- nothing is returned (instead of just blocking). Because of this,
- targets expecting an immediate response need to, internally, set
- things up so that the target_wait() is forced to eventually
- timeout. */
- /* FIXME: cagney/1999-09-24: It isn't possible for target_open() to
- differentiate to its caller what the state of the target is after
- the initial open has been performed. Here we're assuming that
- the target has stopped. It should be possible to eventually have
- target_open() return to the caller an indication that the target
- is currently running and GDB state should be set to the same as
- for an async run. */
- wait_for_inferior (inf);
- /* Now that the inferior has stopped, do any bookkeeping like
- loading shared libraries. We want to do this before normal_stop,
- so that the displayed frame is up to date. */
- post_create_inferior (from_tty);
- normal_stop ();
- }
- /* Initialize static vars when a new inferior begins. */
- void
- init_wait_for_inferior (void)
- {
- /* These are meaningless until the first time through wait_for_inferior. */
- breakpoint_init_inferior (inf_starting);
- clear_proceed_status (0);
- nullify_last_target_wait_ptid ();
- previous_inferior_ptid = inferior_ptid;
- }
- static void handle_inferior_event (struct execution_control_state *ecs);
- static void handle_step_into_function (struct gdbarch *gdbarch,
- struct execution_control_state *ecs);
- static void handle_step_into_function_backward (struct gdbarch *gdbarch,
- struct execution_control_state *ecs);
- static void handle_signal_stop (struct execution_control_state *ecs);
- static void check_exception_resume (struct execution_control_state *,
- struct frame_info *);
- static void end_stepping_range (struct execution_control_state *ecs);
- static void stop_waiting (struct execution_control_state *ecs);
- static void keep_going (struct execution_control_state *ecs);
- static void process_event_stop_test (struct execution_control_state *ecs);
- static bool switch_back_to_stepped_thread (struct execution_control_state *ecs);
- /* This function is attached as a "thread_stop_requested" observer.
- Cleanup local state that assumed the PTID was to be resumed, and
- report the stop to the frontend. */
- static void
- infrun_thread_stop_requested (ptid_t ptid)
- {
- process_stratum_target *curr_target = current_inferior ()->process_target ();
- /* PTID was requested to stop. If the thread was already stopped,
- but the user/frontend doesn't know about that yet (e.g., the
- thread had been temporarily paused for some step-over), set up
- for reporting the stop now. */
- for (thread_info *tp : all_threads (curr_target, ptid))
- {
- if (tp->state != THREAD_RUNNING)
- continue;
- if (tp->executing ())
- continue;
- /* Remove matching threads from the step-over queue, so
- start_step_over doesn't try to resume them
- automatically. */
- if (thread_is_in_step_over_chain (tp))
- global_thread_step_over_chain_remove (tp);
- /* If the thread is stopped, but the user/frontend doesn't
- know about that yet, queue a pending event, as if the
- thread had just stopped now. Unless the thread already had
- a pending event. */
- if (!tp->has_pending_waitstatus ())
- {
- target_waitstatus ws;
- ws.set_stopped (GDB_SIGNAL_0);
- tp->set_pending_waitstatus (ws);
- }
- /* Clear the inline-frame state, since we're re-processing the
- stop. */
- clear_inline_frame_state (tp);
- /* If this thread was paused because some other thread was
- doing an inline-step over, let that finish first. Once
- that happens, we'll restart all threads and consume pending
- stop events then. */
- if (step_over_info_valid_p ())
- continue;
- /* Otherwise we can process the (new) pending event now. Set
- it so this pending event is considered by
- do_target_wait. */
- tp->set_resumed (true);
- }
- }
- static void
- infrun_thread_thread_exit (struct thread_info *tp, int silent)
- {
- if (target_last_proc_target == tp->inf->process_target ()
- && target_last_wait_ptid == tp->ptid)
- nullify_last_target_wait_ptid ();
- }
- /* Delete the step resume, single-step and longjmp/exception resume
- breakpoints of TP. */
- static void
- delete_thread_infrun_breakpoints (struct thread_info *tp)
- {
- delete_step_resume_breakpoint (tp);
- delete_exception_resume_breakpoint (tp);
- delete_single_step_breakpoints (tp);
- }
- /* If the target still has execution, call FUNC for each thread that
- just stopped. In all-stop, that's all the non-exited threads; in
- non-stop, that's the current thread, only. */
- typedef void (*for_each_just_stopped_thread_callback_func)
- (struct thread_info *tp);
- static void
- for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func)
- {
- if (!target_has_execution () || inferior_ptid == null_ptid)
- return;
- if (target_is_non_stop_p ())
- {
- /* If in non-stop mode, only the current thread stopped. */
- func (inferior_thread ());
- }
- else
- {
- /* In all-stop mode, all threads have stopped. */
- for (thread_info *tp : all_non_exited_threads ())
- func (tp);
- }
- }
- /* Delete the step resume and longjmp/exception resume breakpoints of
- the threads that just stopped. */
- static void
- delete_just_stopped_threads_infrun_breakpoints (void)
- {
- for_each_just_stopped_thread (delete_thread_infrun_breakpoints);
- }
- /* Delete the single-step breakpoints of the threads that just
- stopped. */
- static void
- delete_just_stopped_threads_single_step_breakpoints (void)
- {
- for_each_just_stopped_thread (delete_single_step_breakpoints);
- }
- /* See infrun.h. */
- void
- print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
- const struct target_waitstatus &ws)
- {
- infrun_debug_printf ("target_wait (%s [%s], status) =",
- waiton_ptid.to_string ().c_str (),
- target_pid_to_str (waiton_ptid).c_str ());
- infrun_debug_printf (" %s [%s],",
- result_ptid.to_string ().c_str (),
- target_pid_to_str (result_ptid).c_str ());
- infrun_debug_printf (" %s", ws.to_string ().c_str ());
- }
- /* Select a thread at random, out of those which are resumed and have
- had events. */
- static struct thread_info *
- random_pending_event_thread (inferior *inf, ptid_t waiton_ptid)
- {
- process_stratum_target *proc_target = inf->process_target ();
- thread_info *thread
- = proc_target->random_resumed_with_pending_wait_status (inf, waiton_ptid);
- if (thread == nullptr)
- {
- infrun_debug_printf ("None found.");
- return nullptr;
- }
- infrun_debug_printf ("Found %s.", thread->ptid.to_string ().c_str ());
- gdb_assert (thread->resumed ());
- gdb_assert (thread->has_pending_waitstatus ());
- return thread;
- }
- /* Wrapper for target_wait that first checks whether threads have
- pending statuses to report before actually asking the target for
- more events. INF is the inferior we're using to call target_wait
- on. */
- static ptid_t
- do_target_wait_1 (inferior *inf, ptid_t ptid,
- target_waitstatus *status, target_wait_flags options)
- {
- struct thread_info *tp;
- /* We know that we are looking for an event in the target of inferior
- INF, but we don't know which thread the event might come from. As
- such we want to make sure that INFERIOR_PTID is reset so that none of
- the wait code relies on it - doing so is always a mistake. */
- switch_to_inferior_no_thread (inf);
- /* First check if there is a resumed thread with a wait status
- pending. */
- if (ptid == minus_one_ptid || ptid.is_pid ())
- {
- tp = random_pending_event_thread (inf, ptid);
- }
- else
- {
- infrun_debug_printf ("Waiting for specific thread %s.",
- ptid.to_string ().c_str ());
- /* We have a specific thread to check. */
- tp = find_thread_ptid (inf, ptid);
- gdb_assert (tp != NULL);
- if (!tp->has_pending_waitstatus ())
- tp = NULL;
- }
- if (tp != NULL
- && (tp->stop_reason () == TARGET_STOPPED_BY_SW_BREAKPOINT
- || tp->stop_reason () == TARGET_STOPPED_BY_HW_BREAKPOINT))
- {
- struct regcache *regcache = get_thread_regcache (tp);
- struct gdbarch *gdbarch = regcache->arch ();
- CORE_ADDR pc;
- int discard = 0;
- pc = regcache_read_pc (regcache);
- if (pc != tp->stop_pc ())
- {
- infrun_debug_printf ("PC of %s changed. was=%s, now=%s",
- tp->ptid.to_string ().c_str (),
- paddress (gdbarch, tp->stop_pc ()),
- paddress (gdbarch, pc));
- discard = 1;
- }
- else if (!breakpoint_inserted_here_p (regcache->aspace (), pc))
- {
- infrun_debug_printf ("previous breakpoint of %s, at %s gone",
- tp->ptid.to_string ().c_str (),
- paddress (gdbarch, pc));
- discard = 1;
- }
- if (discard)
- {
- infrun_debug_printf ("pending event of %s cancelled.",
- tp->ptid.to_string ().c_str ());
- tp->clear_pending_waitstatus ();
- target_waitstatus ws;
- ws.set_spurious ();
- tp->set_pending_waitstatus (ws);
- tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON);
- }
- }
- if (tp != NULL)
- {
- infrun_debug_printf ("Using pending wait status %s for %s.",
- tp->pending_waitstatus ().to_string ().c_str (),
- tp->ptid.to_string ().c_str ());
- /* Now that we've selected our final event LWP, un-adjust its PC
- if it was a software breakpoint (and the target doesn't
- always adjust the PC itself). */
- if (tp->stop_reason () == TARGET_STOPPED_BY_SW_BREAKPOINT
- && !target_supports_stopped_by_sw_breakpoint ())
- {
- struct regcache *regcache;
- struct gdbarch *gdbarch;
- int decr_pc;
- regcache = get_thread_regcache (tp);
- gdbarch = regcache->arch ();
- decr_pc = gdbarch_decr_pc_after_break (gdbarch);
- if (decr_pc != 0)
- {
- CORE_ADDR pc;
- pc = regcache_read_pc (regcache);
- regcache_write_pc (regcache, pc + decr_pc);
- }
- }
- tp->set_stop_reason (TARGET_STOPPED_BY_NO_REASON);
- *status = tp->pending_waitstatus ();
- tp->clear_pending_waitstatus ();
- /* Wake up the event loop again, until all pending events are
- processed. */
- if (target_is_async_p ())
- mark_async_event_handler (infrun_async_inferior_event_token);
- return tp->ptid;
- }
- /* But if we don't find one, we'll have to wait. */
- /* We can't ask a non-async target to do a non-blocking wait, so this will be
- a blocking wait. */
- if (!target_can_async_p ())
- options &= ~TARGET_WNOHANG;
- return target_wait (ptid, status, options);
- }
- /* Wrapper for target_wait that first checks whether threads have
- pending statuses to report before actually asking the target for
- more events. Polls for events from all inferiors/targets. */
- static bool
- do_target_wait (execution_control_state *ecs, target_wait_flags options)
- {
- int num_inferiors = 0;
- int random_selector;
- /* For fairness, we pick the first inferior/target to poll at random
- out of all inferiors that may report events, and then continue
- polling the rest of the inferior list starting from that one in a
- circular fashion until the whole list is polled once. */
- auto inferior_matches = [] (inferior *inf)
- {
- return inf->process_target () != nullptr;
- };
- /* First see how many matching inferiors we have. */
- for (inferior *inf : all_inferiors ())
- if (inferior_matches (inf))
- num_inferiors++;
- if (num_inferiors == 0)
- {
- ecs->ws.set_ignore ();
- return false;
- }
- /* Now randomly pick an inferior out of those that matched. */
- random_selector = (int)
- ((num_inferiors * (double) rand ()) / (RAND_MAX + 1.0));
- if (num_inferiors > 1)
- infrun_debug_printf ("Found %d inferiors, starting at #%d",
- num_inferiors, random_selector);
- /* Select the Nth inferior that matched. */
- inferior *selected = nullptr;
- for (inferior *inf : all_inferiors ())
- if (inferior_matches (inf))
- if (random_selector-- == 0)
- {
- selected = inf;
- break;
- }
- /* Now poll for events out of each of the matching inferior's
- targets, starting from the selected one. */
- auto do_wait = [&] (inferior *inf)
- {
- ecs->ptid = do_target_wait_1 (inf, minus_one_ptid, &ecs->ws, options);
- ecs->target = inf->process_target ();
- return (ecs->ws.kind () != TARGET_WAITKIND_IGNORE);
- };
- /* Needed in 'all-stop + target-non-stop' mode, because we end up
- here spuriously after the target is all stopped and we've already
- reported the stop to the user, polling for events. */
- scoped_restore_current_thread restore_thread;
- intrusive_list_iterator<inferior> start
- = inferior_list.iterator_to (*selected);
- for (intrusive_list_iterator<inferior> it = start;
- it != inferior_list.end ();
- ++it)
- {
- inferior *inf = &*it;
- if (inferior_matches (inf) && do_wait (inf))
- return true;
- }
- for (intrusive_list_iterator<inferior> it = inferior_list.begin ();
- it != start;
- ++it)
- {
- inferior *inf = &*it;
- if (inferior_matches (inf) && do_wait (inf))
- return true;
- }
- ecs->ws.set_ignore ();
- return false;
- }
- /* An event reported by wait_one. */
- struct wait_one_event
- {
- /* The target the event came out of. */
- process_stratum_target *target;
- /* The PTID the event was for. */
- ptid_t ptid;
- /* The waitstatus. */
- target_waitstatus ws;
- };
- static bool handle_one (const wait_one_event &event);
- /* Prepare and stabilize the inferior for detaching it. E.g.,
- detaching while a thread is displaced stepping is a recipe for
- crashing it, as nothing would readjust the PC out of the scratch
- pad. */
- void
- prepare_for_detach (void)
- {
- struct inferior *inf = current_inferior ();
- ptid_t pid_ptid = ptid_t (inf->pid);
- scoped_restore_current_thread restore_thread;
- scoped_restore restore_detaching = make_scoped_restore (&inf->detaching, true);
- /* Remove all threads of INF from the global step-over chain. We
- want to stop any ongoing step-over, not start any new one. */
- thread_step_over_list_safe_range range
- = make_thread_step_over_list_safe_range (global_thread_step_over_list);
- for (thread_info *tp : range)
- if (tp->inf == inf)
- {
- infrun_debug_printf ("removing thread %s from global step over chain",
- tp->ptid.to_string ().c_str ());
- global_thread_step_over_chain_remove (tp);
- }
- /* If we were already in the middle of an inline step-over, and the
- thread stepping belongs to the inferior we're detaching, we need
- to restart the threads of other inferiors. */
- if (step_over_info.thread != -1)
- {
- infrun_debug_printf ("inline step-over in-process while detaching");
- thread_info *thr = find_thread_global_id (step_over_info.thread);
- if (thr->inf == inf)
- {
- /* Since we removed threads of INF from the step-over chain,
- we know this won't start a step-over for INF. */
- clear_step_over_info ();
- if (target_is_non_stop_p ())
- {
- /* Start a new step-over in another thread if there's
- one that needs it. */
- start_step_over ();
- /* Restart all other threads (except the
- previously-stepping thread, since that one is still
- running). */
- if (!step_over_info_valid_p ())
- restart_threads (thr);
- }
- }
- }
- if (displaced_step_in_progress (inf))
- {
- infrun_debug_printf ("displaced-stepping in-process while detaching");
- /* Stop threads currently displaced stepping, aborting it. */
- for (thread_info *thr : inf->non_exited_threads ())
- {
- if (thr->displaced_step_state.in_progress ())
- {
- if (thr->executing ())
- {
- if (!thr->stop_requested)
- {
- target_stop (thr->ptid);
- thr->stop_requested = true;
- }
- }
- else
- thr->set_resumed (false);
- }
- }
- while (displaced_step_in_progress (inf))
- {
- wait_one_event event;
- event.target = inf->process_target ();
- event.ptid = do_target_wait_1 (inf, pid_ptid, &event.ws, 0);
- if (debug_infrun)
- print_target_wait_results (pid_ptid, event.ptid, event.ws);
- handle_one (event);
- }
- /* It's OK to leave some of the threads of INF stopped, since
- they'll be detached shortly. */
- }
- }
- /* Wait for control to return from inferior to debugger.
- If inferior gets a signal, we may decide to start it up again
- instead of returning. That is why there is a loop in this function.
- When this function actually returns it means the inferior
- should be left stopped and GDB should read more commands. */
- static void
- wait_for_inferior (inferior *inf)
- {
- infrun_debug_printf ("wait_for_inferior ()");
- SCOPE_EXIT { delete_just_stopped_threads_infrun_breakpoints (); };
- /* If an error happens while handling the event, propagate GDB's
- knowledge of the executing state to the frontend/user running
- state. */
- scoped_finish_thread_state finish_state
- (inf->process_target (), minus_one_ptid);
- while (1)
- {
- struct execution_control_state ecss;
- struct execution_control_state *ecs = &ecss;
- overlay_cache_invalid = 1;
- /* Flush target cache before starting to handle each event.
- Target was running and cache could be stale. This is just a
- heuristic. Running threads may modify target memory, but we
- don't get any event. */
- target_dcache_invalidate ();
- ecs->ptid = do_target_wait_1 (inf, minus_one_ptid, &ecs->ws, 0);
- ecs->target = inf->process_target ();
- if (debug_infrun)
- print_target_wait_results (minus_one_ptid, ecs->ptid, ecs->ws);
- /* Now figure out what to do with the result of the result. */
- handle_inferior_event (ecs);
- if (!ecs->wait_some_more)
- break;
- }
- /* No error, don't finish the state yet. */
- finish_state.release ();
- }
- /* Cleanup that reinstalls the readline callback handler, if the
- target is running in the background. If while handling the target
- event something triggered a secondary prompt, like e.g., a
- pagination prompt, we'll have removed the callback handler (see
- gdb_readline_wrapper_line). Need to do this as we go back to the
- event loop, ready to process further input. Note this has no
- effect if the handler hasn't actually been removed, because calling
- rl_callback_handler_install resets the line buffer, thus losing
- input. */
- static void
- reinstall_readline_callback_handler_cleanup ()
- {
- struct ui *ui = current_ui;
- if (!ui->async)
- {
- /* We're not going back to the top level event loop yet. Don't
- install the readline callback, as it'd prep the terminal,
- readline-style (raw, noecho) (e.g., --batch). We'll install
- it the next time the prompt is displayed, when we're ready
- for input. */
- return;
- }
- if (ui->command_editing && ui->prompt_state != PROMPT_BLOCKED)
- gdb_rl_callback_handler_reinstall ();
- }
- /* Clean up the FSMs of threads that are now stopped. In non-stop,
- that's just the event thread. In all-stop, that's all threads. */
- static void
- clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
- {
- if (ecs->event_thread != nullptr
- && ecs->event_thread->thread_fsm () != nullptr)
- ecs->event_thread->thread_fsm ()->clean_up (ecs->event_thread);
- if (!non_stop)
- {
- for (thread_info *thr : all_non_exited_threads ())
- {
- if (thr->thread_fsm () == nullptr)
- continue;
- if (thr == ecs->event_thread)
- continue;
- switch_to_thread (thr);
- thr->thread_fsm ()->clean_up (thr);
- }
- if (ecs->event_thread != nullptr)
- switch_to_thread (ecs->event_thread);
- }
- }
- /* Helper for all_uis_check_sync_execution_done that works on the
- current UI. */
- static void
- check_curr_ui_sync_execution_done (void)
- {
- struct ui *ui = current_ui;
- if (ui->prompt_state == PROMPT_NEEDED
- && ui->async
- && !gdb_in_secondary_prompt_p (ui))
- {
- target_terminal::ours ();
- gdb::observers::sync_execution_done.notify ();
- ui_register_input_event_handler (ui);
- }
- }
- /* See infrun.h. */
- void
- all_uis_check_sync_execution_done (void)
- {
- SWITCH_THRU_ALL_UIS ()
- {
- check_curr_ui_sync_execution_done ();
- }
- }
- /* See infrun.h. */
- void
- all_uis_on_sync_execution_starting (void)
- {
- SWITCH_THRU_ALL_UIS ()
- {
- if (current_ui->prompt_state == PROMPT_NEEDED)
- async_disable_stdin ();
- }
- }
- /* Asynchronous version of wait_for_inferior. It is called by the
- event loop whenever a change of state is detected on the file
- descriptor corresponding to the target. It can be called more than
- once to complete a single execution command. In such cases we need
- to keep the state in a global variable ECSS. If it is the last time
- that this function is called for a single execution command, then
- report to the user that the inferior has stopped, and do the
- necessary cleanups. */
- void
- fetch_inferior_event ()
- {
- INFRUN_SCOPED_DEBUG_ENTER_EXIT;
- struct execution_control_state ecss;
- struct execution_control_state *ecs = &ecss;
- int cmd_done = 0;
- /* Events are always processed with the main UI as current UI. This
- way, warnings, debug output, etc. are always consistently sent to
- the main console. */
- scoped_restore save_ui = make_scoped_restore (¤t_ui, main_ui);
- /* Temporarily disable pagination. Otherwise, the user would be
- given an option to press 'q' to quit, which would cause an early
- exit and could leave GDB in a half-baked state. */
- scoped_restore save_pagination
- = make_scoped_restore (&pagination_enabled, false);
- /* End up with readline processing input, if necessary. */
- {
- SCOPE_EXIT { reinstall_readline_callback_handler_cleanup (); };
- /* We're handling a live event, so make sure we're doing live
- debugging. If we're looking at traceframes while the target is
- running, we're going to need to get back to that mode after
- handling the event. */
- gdb::optional<scoped_restore_current_traceframe> maybe_restore_traceframe;
- if (non_stop)
- {
- maybe_restore_traceframe.emplace ();
- set_current_traceframe (-1);
- }
- /* The user/frontend should not notice a thread switch due to
- internal events. Make sure we revert to the user selected
- thread and frame after handling the event and running any
- breakpoint commands. */
- scoped_restore_current_thread restore_thread;
- overlay_cache_invalid = 1;
- /* Flush target cache before starting to handle each event. Target
- was running and cache could be stale. This is just a heuristic.
- Running threads may modify target memory, but we don't get any
- event. */
- target_dcache_invalidate ();
- scoped_restore save_exec_dir
- = make_scoped_restore (&execution_direction,
- target_execution_direction ());
- /* Allow targets to pause their resumed threads while we handle
- the event. */
- scoped_disable_commit_resumed disable_commit_resumed ("handling event");
- if (!do_target_wait (ecs, TARGET_WNOHANG))
- {
- infrun_debug_printf ("do_target_wait returned no event");
- disable_commit_resumed.reset_and_commit ();
- return;
- }
- gdb_assert (ecs->ws.kind () != TARGET_WAITKIND_IGNORE);
- /* Switch to the target that generated the event, so we can do
- target calls. */
- switch_to_target_no_thread (ecs->target);
- if (debug_infrun)
- print_target_wait_results (minus_one_ptid, ecs->ptid, ecs->ws);
- /* If an error happens while handling the event, propagate GDB's
- knowledge of the executing state to the frontend/user running
- state. */
- ptid_t finish_ptid = !target_is_non_stop_p () ? minus_one_ptid : ecs->ptid;
- scoped_finish_thread_state finish_state (ecs->target, finish_ptid);
- /* Get executed before scoped_restore_current_thread above to apply
- still for the thread which has thrown the exception. */
- auto defer_bpstat_clear
- = make_scope_exit (bpstat_clear_actions);
- auto defer_delete_threads
- = make_scope_exit (delete_just_stopped_threads_infrun_breakpoints);
- /* Now figure out what to do with the result of the result. */
- handle_inferior_event (ecs);
- if (!ecs->wait_some_more)
- {
- struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
- bool should_stop = true;
- struct thread_info *thr = ecs->event_thread;
- delete_just_stopped_threads_infrun_breakpoints ();
- if (thr != nullptr && thr->thread_fsm () != nullptr)
- should_stop = thr->thread_fsm ()->should_stop (thr);
- if (!should_stop)
- {
- keep_going (ecs);
- }
- else
- {
- bool should_notify_stop = true;
- int proceeded = 0;
- clean_up_just_stopped_threads_fsms (ecs);
- if (thr != nullptr && thr->thread_fsm () != nullptr)
- should_notify_stop
- = thr->thread_fsm ()->should_notify_stop ();
- if (should_notify_stop)
- {
- /* We may not find an inferior if this was a process exit. */
- if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY)
- proceeded = normal_stop ();
- }
- if (!proceeded)
- {
- inferior_event_handler (INF_EXEC_COMPLETE);
- cmd_done = 1;
- }
- /* If we got a TARGET_WAITKIND_NO_RESUMED event, then the
- previously selected thread is gone. We have two
- choices - switch to no thread selected, or restore the
- previously selected thread (now exited). We chose the
- later, just because that's what GDB used to do. After
- this, "info threads" says "The current thread <Thread
- ID 2> has terminated." instead of "No thread
- selected.". */
- if (!non_stop
- && cmd_done
- && ecs->ws.kind () != TARGET_WAITKIND_NO_RESUMED)
- restore_thread.dont_restore ();
- }
- }
- defer_delete_threads.release ();
- defer_bpstat_clear.release ();
- /* No error, don't finish the thread states yet. */
- finish_state.release ();
- disable_commit_resumed.reset_and_commit ();
- /* This scope is used to ensure that readline callbacks are
- reinstalled here. */
- }
- /* If a UI was in sync execution mode, and now isn't, restore its
- prompt (a synchronous execution command has finished, and we're
- ready for input). */
- all_uis_check_sync_execution_done ();
- if (cmd_done
- && exec_done_display_p
- && (inferior_ptid == null_ptid
- || inferior_thread ()->state != THREAD_RUNNING))
- gdb_printf (_("completed.\n"));
- }
- /* See infrun.h. */
- void
- set_step_info (thread_info *tp, struct frame_info *frame,
- struct symtab_and_line sal)
- {
- /* This can be removed once this function no longer implicitly relies on the
- inferior_ptid value. */
- gdb_assert (inferior_ptid == tp->ptid);
- tp->control.step_frame_id = get_frame_id (frame);
- tp->control.step_stack_frame_id = get_stack_frame_id (frame);
- tp->current_symtab = sal.symtab;
- tp->current_line = sal.line;
- infrun_debug_printf
- ("symtab = %s, line = %d, step_frame_id = %s, step_stack_frame_id = %s",
- tp->current_symtab != nullptr ? tp->current_symtab->filename : "<null>",
- tp->current_line,
- tp->control.step_frame_id.to_string ().c_str (),
- tp->control.step_stack_frame_id.to_string ().c_str ());
- }
- /* Clear context switchable stepping state. */
- void
- init_thread_stepping_state (struct thread_info *tss)
- {
- tss->stepped_breakpoint = 0;
- tss->stepping_over_breakpoint = 0;
- tss->stepping_over_watchpoint = 0;
- tss->step_after_step_resume_breakpoint = 0;
- }
- /* See infrun.h. */
- void
- set_last_target_status (process_stratum_target *target, ptid_t ptid,
- const target_waitstatus &status)
- {
- target_last_proc_target = target;
- target_last_wait_ptid = ptid;
- target_last_waitstatus = status;
- }
- /* See infrun.h. */
- void
- get_last_target_status (process_stratum_target **target, ptid_t *ptid,
- target_waitstatus *status)
- {
- if (target != nullptr)
- *target = target_last_proc_target;
- if (ptid != nullptr)
- *ptid = target_last_wait_ptid;
- if (status != nullptr)
- *status = target_last_waitstatus;
- }
- /* See infrun.h. */
- void
- nullify_last_target_wait_ptid (void)
- {
- target_last_proc_target = nullptr;
- target_last_wait_ptid = minus_one_ptid;
- target_last_waitstatus = {};
- }
- /* Switch thread contexts. */
- static void
- context_switch (execution_control_state *ecs)
- {
- if (ecs->ptid != inferior_ptid
- && (inferior_ptid == null_ptid
- || ecs->event_thread != inferior_thread ()))
- {
- infrun_debug_printf ("Switching context from %s to %s",
- inferior_ptid.to_string ().c_str (),
- ecs->ptid.to_string ().c_str ());
- }
- switch_to_thread (ecs->event_thread);
- }
- /* If the target can't tell whether we've hit breakpoints
- (target_supports_stopped_by_sw_breakpoint), and we got a SIGTRAP,
- check whether that could have been caused by a breakpoint. If so,
- adjust the PC, per gdbarch_decr_pc_after_break. */
- static void
- adjust_pc_after_break (struct thread_info *thread,
- const target_waitstatus &ws)
- {
- struct regcache *regcache;
- struct gdbarch *gdbarch;
- CORE_ADDR breakpoint_pc, decr_pc;
- /* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
- we aren't, just return.
- We assume that waitkinds other than TARGET_WAITKIND_STOPPED are not
- affected by gdbarch_decr_pc_after_break. Other waitkinds which are
- implemented by software breakpoints should be handled through the normal
- breakpoint layer.
- NOTE drow/2004-01-31: On some targets, breakpoints may generate
- different signals (SIGILL or SIGEMT for instance), but it is less
- clear where the PC is pointing afterwards. It may not match
- gdbarch_decr_pc_after_break. I don't know any specific target that
- generates these signals at breakpoints (the code has been in GDB since at
- least 1992) so I can not guess how to handle them here.
- In earlier versions of GDB, a target with
- gdbarch_have_nonsteppable_watchpoint would have the PC after hitting a
- watchpoint affected by gdbarch_decr_pc_after_break. I haven't found any
- target with both of these set in GDB history, and it seems unlikely to be
- correct, so gdbarch_have_nonsteppable_watchpoint is not checked here. */
- if (ws.kind () != TARGET_WAITKIND_STOPPED)
- return;
- if (ws.sig () != GDB_SIGNAL_TRAP)
- return;
- /* In reverse execution, when a breakpoint is hit, the instruction
- under it has already been de-executed. The reported PC always
- points at the breakpoint address, so adjusting it further would
- be wrong. E.g., consider this case on a decr_pc_after_break == 1
- architecture:
- B1 0x08000000 : INSN1
- B2 0x08000001 : INSN2
- 0x08000002 : INSN3
- PC -> 0x08000003 : INSN4
- Say you're stopped at 0x08000003 as above. Reverse continuing
- from that point should hit B2 as below. Reading the PC when the
- SIGTRAP is reported should read 0x08000001 and INSN2 should have
- been de-executed already.
- B1 0x08000000 : INSN1
- B2 PC -> 0x08000001 : INSN2
- 0x08000002 : INSN3
- 0x08000003 : INSN4
- We can't apply the same logic as for forward execution, because
- we would wrongly adjust the PC to 0x08000000, since there's a
- breakpoint at PC - 1. We'd then report a hit on B1, although
- INSN1 hadn't been de-executed yet. Doing nothing is the correct
- behaviour. */
- if (execution_direction == EXEC_REVERSE)
- return;
- /* If the target can tell whether the thread hit a SW breakpoint,
- trust it. Targets that can tell also adjust the PC
- themselves. */
- if (target_supports_stopped_by_sw_breakpoint ())
- return;
- /* Note that relying on whether a breakpoint is planted in memory to
- determine this can fail. E.g,. the breakpoint could have been
- removed since. Or the thread could have been told to step an
- instruction the size of a breakpoint instruction, and only
- _after_ was a breakpoint inserted at its address. */
- /* If this target does not decrement the PC after breakpoints, then
- we have nothing to do. */
- regcache = get_thread_regcache (thread);
- gdbarch = regcache->arch ();
- decr_pc = gdbarch_decr_pc_after_break (gdbarch);
- if (decr_pc == 0)
- return;
- const address_space *aspace = regcache->aspace ();
- /* Find the location where (if we've hit a breakpoint) the
- breakpoint would be. */
- breakpoint_pc = regcache_read_pc (regcache) - decr_pc;
- /* If the target can't tell whether a software breakpoint triggered,
- fallback to figuring it out based on breakpoints we think were
- inserted in the target, and on whether the thread was stepped or
- continued. */
- /* Check whether there actually is a software breakpoint inserted at
- that location.
- If in non-stop mode, a race condition is possible where we've
- removed a breakpoint, but stop events for that breakpoint were
- already queued and arrive later. To suppress those spurious
- SIGTRAPs, we keep a list of such breakpoint locations for a bit,
- and retire them after a number of stop events are reported. Note
- this is an heuristic and can thus get confused. The real fix is
- to get the "stopped by SW BP and needs adjustment" info out of
- the target/kernel (and thus never reach here; see above). */
- if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
- || (target_is_non_stop_p ()
- && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
- {
- gdb::optional<scoped_restore_tmpl<int>> restore_operation_disable;
- if (record_full_is_used ())
- restore_operation_disable.emplace
- (record_full_gdb_operation_disable_set ());
- /* When using hardware single-step, a SIGTRAP is reported for both
- a completed single-step and a software breakpoint. Need to
- differentiate between the two, as the latter needs adjusting
- but the former does not.
- The SIGTRAP can be due to a completed hardware single-step only if
- - we didn't insert software single-step breakpoints
- - this thread is currently being stepped
- If any of these events did not occur, we must have stopped due
- to hitting a software breakpoint, and have to back up to the
- breakpoint address.
- As a special case, we could have hardware single-stepped a
- software breakpoint. In this case (prev_pc == breakpoint_pc),
- we also need to back up to the breakpoint address. */
- if (thread_has_single_step_breakpoints_set (thread)
- || !currently_stepping (thread)
- || (thread->stepped_breakpoint
- && thread->prev_pc == breakpoint_pc))
- regcache_write_pc (regcache, breakpoint_pc);
- }
- }
- static bool
- stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id)
- {
- for (frame = get_prev_frame (frame);
- frame != NULL;
- frame = get_prev_frame (frame))
- {
- if (frame_id_eq (get_frame_id (frame), step_frame_id))
- return true;
- if (get_frame_type (frame) != INLINE_FRAME)
- break;
- }
- return false;
- }
- /* Look for an inline frame that is marked for skip.
- If PREV_FRAME is TRUE start at the previous frame,
- otherwise start at the current frame. Stop at the
- first non-inline frame, or at the frame where the
- step started. */
- static bool
- inline_frame_is_marked_for_skip (bool prev_frame, struct thread_info *tp)
- {
- struct frame_info *frame = get_current_frame ();
- if (prev_frame)
- frame = get_prev_frame (frame);
- for (; frame != NULL; frame = get_prev_frame (frame))
- {
- const char *fn = NULL;
- symtab_and_line sal;
- struct symbol *sym;
- if (frame_id_eq (get_frame_id (frame), tp->control.step_frame_id))
- break;
- if (get_frame_type (frame) != INLINE_FRAME)
- break;
- sal = find_frame_sal (frame);
- sym = get_frame_function (frame);
- if (sym != NULL)
- fn = sym->print_name ();
- if (sal.line != 0
- && function_name_is_marked_for_skip (fn, sal))
- return true;
- }
- return false;
- }
- /* If the event thread has the stop requested flag set, pretend it
- stopped for a GDB_SIGNAL_0 (i.e., as if it stopped due to
- target_stop). */
- static bool
- handle_stop_requested (struct execution_control_state *ecs)
- {
- if (ecs->event_thread->stop_requested)
- {
- ecs->ws.set_stopped (GDB_SIGNAL_0);
- handle_signal_stop (ecs);
- return true;
- }
- return false;
- }
- /* Auxiliary function that handles syscall entry/return events.
- It returns true if the inferior should keep going (and GDB
- should ignore the event), or false if the event deserves to be
- processed. */
- static bool
- handle_syscall_event (struct execution_control_state *ecs)
- {
- struct regcache *regcache;
- int syscall_number;
- context_switch (ecs);
- regcache = get_thread_regcache (ecs->event_thread);
- syscall_number = ecs->ws.syscall_number ();
- ecs->event_thread->set_stop_pc (regcache_read_pc (regcache));
- if (catch_syscall_enabled () > 0
- && catching_syscall_number (syscall_number))
- {
- infrun_debug_printf ("syscall number=%d", syscall_number);
- ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status_nowatch (regcache->aspace (),
- ecs->event_thread->stop_pc (),
- ecs->event_thread, ecs->ws);
- if (handle_stop_requested (ecs))
- return false;
- if (bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
- {
- /* Catchpoint hit. */
- return false;
- }
- }
- if (handle_stop_requested (ecs))
- return false;
- /* If no catchpoint triggered for this, then keep going. */
- keep_going (ecs);
- return true;
- }
- /* Lazily fill in the execution_control_state's stop_func_* fields. */
- static void
- fill_in_stop_func (struct gdbarch *gdbarch,
- struct execution_control_state *ecs)
- {
- if (!ecs->stop_func_filled_in)
- {
- const block *block;
- const general_symbol_info *gsi;
- /* Don't care about return value; stop_func_start and stop_func_name
- will both be 0 if it doesn't work. */
- find_pc_partial_function_sym (ecs->event_thread->stop_pc (),
- &gsi,
- &ecs->stop_func_start,
- &ecs->stop_func_end,
- &block);
- ecs->stop_func_name = gsi == nullptr ? nullptr : gsi->print_name ();
- /* The call to find_pc_partial_function, above, will set
- stop_func_start and stop_func_end to the start and end
- of the range containing the stop pc. If this range
- contains the entry pc for the block (which is always the
- case for contiguous blocks), advance stop_func_start past
- the function's start offset and entrypoint. Note that
- stop_func_start is NOT advanced when in a range of a
- non-contiguous block that does not contain the entry pc. */
- if (block != nullptr
- && ecs->stop_func_start <= BLOCK_ENTRY_PC (block)
- && BLOCK_ENTRY_PC (block) < ecs->stop_func_end)
- {
- ecs->stop_func_start
- += gdbarch_deprecated_function_start_offset (gdbarch);
- if (gdbarch_skip_entrypoint_p (gdbarch))
- ecs->stop_func_start
- = gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
- }
- ecs->stop_func_filled_in = 1;
- }
- }
- /* Return the STOP_SOON field of the inferior pointed at by ECS. */
- static enum stop_kind
- get_inferior_stop_soon (execution_control_state *ecs)
- {
- struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
- gdb_assert (inf != NULL);
- return inf->control.stop_soon;
- }
- /* Poll for one event out of the current target. Store the resulting
- waitstatus in WS, and return the event ptid. Does not block. */
- static ptid_t
- poll_one_curr_target (struct target_waitstatus *ws)
- {
- ptid_t event_ptid;
- overlay_cache_invalid = 1;
- /* Flush target cache before starting to handle each event.
- Target was running and cache could be stale. This is just a
- heuristic. Running threads may modify target memory, but we
- don't get any event. */
- target_dcache_invalidate ();
- event_ptid = target_wait (minus_one_ptid, ws, TARGET_WNOHANG);
- if (debug_infrun)
- print_target_wait_results (minus_one_ptid, event_ptid, *ws);
- return event_ptid;
- }
- /* Wait for one event out of any target. */
- static wait_one_event
- wait_one ()
- {
- while (1)
- {
- for (inferior *inf : all_inferiors ())
- {
- process_stratum_target *target = inf->process_target ();
- if (target == NULL
- || !target->is_async_p ()
- || !target->threads_executing)
- continue;
- switch_to_inferior_no_thread (inf);
- wait_one_event event;
- event.target = target;
- event.ptid = poll_one_curr_target (&event.ws);
- if (event.ws.kind () == TARGET_WAITKIND_NO_RESUMED)
- {
- /* If nothing is resumed, remove the target from the
- event loop. */
- target_async (0);
- }
- else if (event.ws.kind () != TARGET_WAITKIND_IGNORE)
- return event;
- }
- /* Block waiting for some event. */
- fd_set readfds;
- int nfds = 0;
- FD_ZERO (&readfds);
- for (inferior *inf : all_inferiors ())
- {
- process_stratum_target *target = inf->process_target ();
- if (target == NULL
- || !target->is_async_p ()
- || !target->threads_executing)
- continue;
- int fd = target->async_wait_fd ();
- FD_SET (fd, &readfds);
- if (nfds <= fd)
- nfds = fd + 1;
- }
- if (nfds == 0)
- {
- /* No waitable targets left. All must be stopped. */
- target_waitstatus ws;
- ws.set_no_resumed ();
- return {NULL, minus_one_ptid, std::move (ws)};
- }
- QUIT;
- int numfds = interruptible_select (nfds, &readfds, 0, NULL, 0);
- if (numfds < 0)
- {
- if (errno == EINTR)
- continue;
- else
- perror_with_name ("interruptible_select");
- }
- }
- }
- /* Save the thread's event and stop reason to process it later. */
- static void
- save_waitstatus (struct thread_info *tp, const target_waitstatus &ws)
- {
- infrun_debug_printf ("saving status %s for %s",
- ws.to_string ().c_str (),
- tp->ptid.to_string ().c_str ());
- /* Record for later. */
- tp->set_pending_waitstatus (ws);
- if (ws.kind () == TARGET_WAITKIND_STOPPED
- && ws.sig () == GDB_SIGNAL_TRAP)
- {
- struct regcache *regcache = get_thread_regcache (tp);
- const address_space *aspace = regcache->aspace ();
- CORE_ADDR pc = regcache_read_pc (regcache);
- adjust_pc_after_break (tp, tp->pending_waitstatus ());
- scoped_restore_current_thread restore_thread;
- switch_to_thread (tp);
- if (target_stopped_by_watchpoint ())
- tp->set_stop_reason (TARGET_STOPPED_BY_WATCHPOINT);
- else if (target_supports_stopped_by_sw_breakpoint ()
- && target_stopped_by_sw_breakpoint ())
- tp->set_stop_reason (TARGET_STOPPED_BY_SW_BREAKPOINT);
- else if (target_supports_stopped_by_hw_breakpoint ()
- && target_stopped_by_hw_breakpoint ())
- tp->set_stop_reason (TARGET_STOPPED_BY_HW_BREAKPOINT);
- else if (!target_supports_stopped_by_hw_breakpoint ()
- && hardware_breakpoint_inserted_here_p (aspace, pc))
- tp->set_stop_reason (TARGET_STOPPED_BY_HW_BREAKPOINT);
- else if (!target_supports_stopped_by_sw_breakpoint ()
- && software_breakpoint_inserted_here_p (aspace, pc))
- tp->set_stop_reason (TARGET_STOPPED_BY_SW_BREAKPOINT);
- else if (!thread_has_single_step_breakpoints_set (tp)
- && currently_stepping (tp))
- tp->set_stop_reason (TARGET_STOPPED_BY_SINGLE_STEP);
- }
- }
- /* Mark the non-executing threads accordingly. In all-stop, all
- threads of all processes are stopped when we get any event
- reported. In non-stop mode, only the event thread stops. */
- static void
- mark_non_executing_threads (process_stratum_target *target,
- ptid_t event_ptid,
- const target_waitstatus &ws)
- {
- ptid_t mark_ptid;
- if (!target_is_non_stop_p ())
- mark_ptid = minus_one_ptid;
- else if (ws.kind () == TARGET_WAITKIND_SIGNALLED
- || ws.kind () == TARGET_WAITKIND_EXITED)
- {
- /* If we're handling a process exit in non-stop mode, even
- though threads haven't been deleted yet, one would think
- that there is nothing to do, as threads of the dead process
- will be soon deleted, and threads of any other process were
- left running. However, on some targets, threads survive a
- process exit event. E.g., for the "checkpoint" command,
- when the current checkpoint/fork exits, linux-fork.c
- automatically switches to another fork from within
- target_mourn_inferior, by associating the same
- inferior/thread to another fork. We haven't mourned yet at
- this point, but we must mark any threads left in the
- process as not-executing so that finish_thread_state marks
- them stopped (in the user's perspective) if/when we present
- the stop to the user. */
- mark_ptid = ptid_t (event_ptid.pid ());
- }
- else
- mark_ptid = event_ptid;
- set_executing (target, mark_ptid, false);
- /* Likewise the resumed flag. */
- set_resumed (target, mark_ptid, false);
- }
- /* Handle one event after stopping threads. If the eventing thread
- reports back any interesting event, we leave it pending. If the
- eventing thread was in the middle of a displaced step, we
- cancel/finish it, and unless the thread's inferior is being
- detached, put the thread back in the step-over chain. Returns true
- if there are no resumed threads left in the target (thus there's no
- point in waiting further), false otherwise. */
- static bool
- handle_one (const wait_one_event &event)
- {
- infrun_debug_printf
- ("%s %s", event.ws.to_string ().c_str (),
- event.ptid.to_string ().c_str ());
- if (event.ws.kind () == TARGET_WAITKIND_NO_RESUMED)
- {
- /* All resumed threads exited. */
- return true;
- }
- else if (event.ws.kind () == TARGET_WAITKIND_THREAD_EXITED
- || event.ws.kind () == TARGET_WAITKIND_EXITED
- || event.ws.kind () == TARGET_WAITKIND_SIGNALLED)
- {
- /* One thread/process exited/signalled. */
- thread_info *t = nullptr;
- /* The target may have reported just a pid. If so, try
- the first non-exited thread. */
- if (event.ptid.is_pid ())
- {
- int pid = event.ptid.pid ();
- inferior *inf = find_inferior_pid (event.target, pid);
- for (thread_info *tp : inf->non_exited_threads ())
- {
- t = tp;
- break;
- }
- /* If there is no available thread, the event would
- have to be appended to a per-inferior event list,
- which does not exist (and if it did, we'd have
- to adjust run control command to be able to
- resume such an inferior). We assert here instead
- of going into an infinite loop. */
- gdb_assert (t != nullptr);
- infrun_debug_printf
- ("using %s", t->ptid.to_string ().c_str ());
- }
- else
- {
- t = find_thread_ptid (event.target, event.ptid);
- /* Check if this is the first time we see this thread.
- Don't bother adding if it individually exited. */
- if (t == nullptr
- && event.ws.kind () != TARGET_WAITKIND_THREAD_EXITED)
- t = add_thread (event.target, event.ptid);
- }
- if (t != nullptr)
- {
- /* Set the threads as non-executing to avoid
- another stop attempt on them. */
- switch_to_thread_no_regs (t);
- mark_non_executing_threads (event.target, event.ptid,
- event.ws);
- save_waitstatus (t, event.ws);
- t->stop_requested = false;
- }
- }
- else
- {
- thread_info *t = find_thread_ptid (event.target, event.ptid);
- if (t == NULL)
- t = add_thread (event.target, event.ptid);
- t->stop_requested = 0;
- t->set_executing (false);
- t->set_resumed (false);
- t->control.may_range_step = 0;
- /* This may be the first time we see the inferior report
- a stop. */
- if (t->inf->needs_setup)
- {
- switch_to_thread_no_regs (t);
- setup_inferior (0);
- }
- if (event.ws.kind () == TARGET_WAITKIND_STOPPED
- && event.ws.sig () == GDB_SIGNAL_0)
- {
- /* We caught the event that we intended to catch, so
- there's no event to save as pending. */
- if (displaced_step_finish (t, GDB_SIGNAL_0)
- == DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED)
- {
- /* Add it back to the step-over queue. */
- infrun_debug_printf
- ("displaced-step of %s canceled",
- t->ptid.to_string ().c_str ());
- t->control.trap_expected = 0;
- if (!t->inf->detaching)
- global_thread_step_over_chain_enqueue (t);
- }
- }
- else
- {
- enum gdb_signal sig;
- struct regcache *regcache;
- infrun_debug_printf
- ("target_wait %s, saving status for %s",
- event.ws.to_string ().c_str (),
- t->ptid.to_string ().c_str ());
- /* Record for later. */
- save_waitstatus (t, event.ws);
- sig = (event.ws.kind () == TARGET_WAITKIND_STOPPED
- ? event.ws.sig () : GDB_SIGNAL_0);
- if (displaced_step_finish (t, sig)
- == DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED)
- {
- /* Add it back to the step-over queue. */
- t->control.trap_expected = 0;
- if (!t->inf->detaching)
- global_thread_step_over_chain_enqueue (t);
- }
- regcache = get_thread_regcache (t);
- t->set_stop_pc (regcache_read_pc (regcache));
- infrun_debug_printf ("saved stop_pc=%s for %s "
- "(currently_stepping=%d)",
- paddress (target_gdbarch (), t->stop_pc ()),
- t->ptid.to_string ().c_str (),
- currently_stepping (t));
- }
- }
- return false;
- }
- /* See infrun.h. */
- void
- stop_all_threads (const char *reason, inferior *inf)
- {
- /* We may need multiple passes to discover all threads. */
- int pass;
- int iterations = 0;
- gdb_assert (exists_non_stop_target ());
- INFRUN_SCOPED_DEBUG_START_END ("reason=%s, inf=%d", reason,
- inf != nullptr ? inf->num : -1);
- scoped_restore_current_thread restore_thread;
- /* Enable thread events on relevant targets. */
- for (auto *target : all_non_exited_process_targets ())
- {
- if (inf != nullptr && inf->process_target () != target)
- continue;
- switch_to_target_no_thread (target);
- target_thread_events (true);
- }
- SCOPE_EXIT
- {
- /* Disable thread events on relevant targets. */
- for (auto *target : all_non_exited_process_targets ())
- {
- if (inf != nullptr && inf->process_target () != target)
- continue;
- switch_to_target_no_thread (target);
- target_thread_events (false);
- }
- /* Use debug_prefixed_printf directly to get a meaningful function
- name. */
- if (debug_infrun)
- debug_prefixed_printf ("infrun", "stop_all_threads", "done");
- };
- /* Request threads to stop, and then wait for the stops. Because
- threads we already know about can spawn more threads while we're
- trying to stop them, and we only learn about new threads when we
- update the thread list, do this in a loop, and keep iterating
- until two passes find no threads that need to be stopped. */
- for (pass = 0; pass < 2; pass++, iterations++)
- {
- infrun_debug_printf ("pass=%d, iterations=%d", pass, iterations);
- while (1)
- {
- int waits_needed = 0;
- for (auto *target : all_non_exited_process_targets ())
- {
- if (inf != nullptr && inf->process_target () != target)
- continue;
- switch_to_target_no_thread (target);
- update_thread_list ();
- }
- /* Go through all threads looking for threads that we need
- to tell the target to stop. */
- for (thread_info *t : all_non_exited_threads ())
- {
- if (inf != nullptr && t->inf != inf)
- continue;
- /* For a single-target setting with an all-stop target,
- we would not even arrive here. For a multi-target
- setting, until GDB is able to handle a mixture of
- all-stop and non-stop targets, simply skip all-stop
- targets' threads. This should be fine due to the
- protection of 'check_multi_target_resumption'. */
- switch_to_thread_no_regs (t);
- if (!target_is_non_stop_p ())
- continue;
- if (t->executing ())
- {
- /* If already stopping, don't request a stop again.
- We just haven't seen the notification yet. */
- if (!t->stop_requested)
- {
- infrun_debug_printf (" %s executing, need stop",
- t->ptid.to_string ().c_str ());
- target_stop (t->ptid);
- t->stop_requested = 1;
- }
- else
- {
- infrun_debug_printf (" %s executing, already stopping",
- t->ptid.to_string ().c_str ());
- }
- if (t->stop_requested)
- waits_needed++;
- }
- else
- {
- infrun_debug_printf (" %s not executing",
- t->ptid.to_string ().c_str ());
- /* The thread may be not executing, but still be
- resumed with a pending status to process. */
- t->set_resumed (false);
- }
- }
- if (waits_needed == 0)
- break;
- /* If we find new threads on the second iteration, restart
- over. We want to see two iterations in a row with all
- threads stopped. */
- if (pass > 0)
- pass = -1;
- for (int i = 0; i < waits_needed; i++)
- {
- wait_one_event event = wait_one ();
- if (handle_one (event))
- break;
- }
- }
- }
- }
- /* Handle a TARGET_WAITKIND_NO_RESUMED event. */
- static bool
- handle_no_resumed (struct execution_control_state *ecs)
- {
- if (target_can_async_p ())
- {
- bool any_sync = false;
- for (ui *ui : all_uis ())
- {
- if (ui->prompt_state == PROMPT_BLOCKED)
- {
- any_sync = true;
- break;
- }
- }
- if (!any_sync)
- {
- /* There were no unwaited-for children left in the target, but,
- we're not synchronously waiting for events either. Just
- ignore. */
- infrun_debug_printf ("TARGET_WAITKIND_NO_RESUMED (ignoring: bg)");
- prepare_to_wait (ecs);
- return true;
- }
- }
- /* Otherwise, if we were running a synchronous execution command, we
- may need to cancel it and give the user back the terminal.
- In non-stop mode, the target can't tell whether we've already
- consumed previous stop events, so it can end up sending us a
- no-resumed event like so:
- #0 - thread 1 is left stopped
- #1 - thread 2 is resumed and hits breakpoint
- -> TARGET_WAITKIND_STOPPED
- #2 - thread 3 is resumed and exits
- this is the last resumed thread, so
- -> TARGET_WAITKIND_NO_RESUMED
- #3 - gdb processes stop for thread 2 and decides to re-resume
- it.
- #4 - gdb processes the TARGET_WAITKIND_NO_RESUMED event.
- thread 2 is now resumed, so the event should be ignored.
- IOW, if the stop for thread 2 doesn't end a foreground command,
- then we need to ignore the following TARGET_WAITKIND_NO_RESUMED
- event. But it could be that the event meant that thread 2 itself
- (or whatever other thread was the last resumed thread) exited.
- To address this we refresh the thread list and check whether we
- have resumed threads _now_. In the example above, this removes
- thread 3 from the thread list. If thread 2 was re-resumed, we
- ignore this event. If we find no thread resumed, then we cancel
- the synchronous command and show "no unwaited-for " to the
- user. */
- inferior *curr_inf = current_inferior ();
- scoped_restore_current_thread restore_thread;
- for (auto *target : all_non_exited_process_targets ())
- {
- switch_to_target_no_thread (target);
- update_thread_list ();
- }
- /* If:
- - the current target has no thread executing, and
- - the current inferior is native, and
- - the current inferior is the one which has the terminal, and
- - we did nothing,
- then a Ctrl-C from this point on would remain stuck in the
- kernel, until a thread resumes and dequeues it. That would
- result in the GDB CLI not reacting to Ctrl-C, not able to
- interrupt the program. To address this, if the current inferior
- no longer has any thread executing, we give the terminal to some
- other inferior that has at least one thread executing. */
- bool swap_terminal = true;
- /* Whether to ignore this TARGET_WAITKIND_NO_RESUMED event, or
- whether to report it to the user. */
- bool ignore_event = false;
- for (thread_info *thread : all_non_exited_threads ())
- {
- if (swap_terminal && thread->executing ())
- {
- if (thread->inf != curr_inf)
- {
- target_terminal::ours ();
- switch_to_thread (thread);
- target_terminal::inferior ();
- }
- swap_terminal = false;
- }
- if (!ignore_event && thread->resumed ())
- {
- /* Either there were no unwaited-for children left in the
- target at some point, but there are now, or some target
- other than the eventing one has unwaited-for children
- left. Just ignore. */
- infrun_debug_printf ("TARGET_WAITKIND_NO_RESUMED "
- "(ignoring: found resumed)");
- ignore_event = true;
- }
- if (ignore_event && !swap_terminal)
- break;
- }
- if (ignore_event)
- {
- switch_to_inferior_no_thread (curr_inf);
- prepare_to_wait (ecs);
- return true;
- }
- /* Go ahead and report the event. */
- return false;
- }
- /* Given an execution control state that has been freshly filled in by
- an event from the inferior, figure out what it means and take
- appropriate action.
- The alternatives are:
- 1) stop_waiting and return; to really stop and return to the
- debugger.
- 2) keep_going and return; to wait for the next event (set
- ecs->event_thread->stepping_over_breakpoint to 1 to single step
- once). */
- static void
- handle_inferior_event (struct execution_control_state *ecs)
- {
- /* Make sure that all temporary struct value objects that were
- created during the handling of the event get deleted at the
- end. */
- scoped_value_mark free_values;
- infrun_debug_printf ("%s", ecs->ws.to_string ().c_str ());
- if (ecs->ws.kind () == TARGET_WAITKIND_IGNORE)
- {
- /* We had an event in the inferior, but we are not interested in
- handling it at this level. The lower layers have already
- done what needs to be done, if anything.
- One of the possible circumstances for this is when the
- inferior produces output for the console. The inferior has
- not stopped, and we are ignoring the event. Another possible
- circumstance is any event which the lower level knows will be
- reported multiple times without an intervening resume. */
- prepare_to_wait (ecs);
- return;
- }
- if (ecs->ws.kind () == TARGET_WAITKIND_THREAD_EXITED)
- {
- prepare_to_wait (ecs);
- return;
- }
- if (ecs->ws.kind () == TARGET_WAITKIND_NO_RESUMED
- && handle_no_resumed (ecs))
- return;
- /* Cache the last target/ptid/waitstatus. */
- set_last_target_status (ecs->target, ecs->ptid, ecs->ws);
- /* Always clear state belonging to the previous time we stopped. */
- stop_stack_dummy = STOP_NONE;
- if (ecs->ws.kind () == TARGET_WAITKIND_NO_RESUMED)
- {
- /* No unwaited-for children left. IOW, all resumed children
- have exited. */
- stop_print_frame = false;
- stop_waiting (ecs);
- return;
- }
- if (ecs->ws.kind () != TARGET_WAITKIND_EXITED
- && ecs->ws.kind () != TARGET_WAITKIND_SIGNALLED)
- {
- ecs->event_thread = find_thread_ptid (ecs->target, ecs->ptid);
- /* If it's a new thread, add it to the thread database. */
- if (ecs->event_thread == NULL)
- ecs->event_thread = add_thread (ecs->target, ecs->ptid);
- /* Disable range stepping. If the next step request could use a
- range, this will be end up re-enabled then. */
- ecs->event_thread->control.may_range_step = 0;
- }
- /* Dependent on valid ECS->EVENT_THREAD. */
- adjust_pc_after_break (ecs->event_thread, ecs->ws);
- /* Dependent on the current PC value modified by adjust_pc_after_break. */
- reinit_frame_cache ();
- breakpoint_retire_moribund ();
- /* First, distinguish signals caused by the debugger from signals
- that have to do with the program's own actions. Note that
- breakpoint insns may cause SIGTRAP or SIGILL or SIGEMT, depending
- on the operating system version. Here we detect when a SIGILL or
- SIGEMT is really a breakpoint and change it to SIGTRAP. We do
- something similar for SIGSEGV, since a SIGSEGV will be generated
- when we're trying to execute a breakpoint instruction on a
- non-executable stack. This happens for call dummy breakpoints
- for architectures like SPARC that place call dummies on the
- stack. */
- if (ecs->ws.kind () == TARGET_WAITKIND_STOPPED
- && (ecs->ws.sig () == GDB_SIGNAL_ILL
- || ecs->ws.sig () == GDB_SIGNAL_SEGV
- || ecs->ws.sig () == GDB_SIGNAL_EMT))
- {
- struct regcache *regcache = get_thread_regcache (ecs->event_thread);
- if (breakpoint_inserted_here_p (regcache->aspace (),
- regcache_read_pc (regcache)))
- {
- infrun_debug_printf ("Treating signal as SIGTRAP");
- ecs->ws.set_stopped (GDB_SIGNAL_TRAP);
- }
- }
- mark_non_executing_threads (ecs->target, ecs->ptid, ecs->ws);
- switch (ecs->ws.kind ())
- {
- case TARGET_WAITKIND_LOADED:
- {
- context_switch (ecs);
- /* Ignore gracefully during startup of the inferior, as it might
- be the shell which has just loaded some objects, otherwise
- add the symbols for the newly loaded objects. Also ignore at
- the beginning of an attach or remote session; we will query
- the full list of libraries once the connection is
- established. */
- stop_kind stop_soon = get_inferior_stop_soon (ecs);
- if (stop_soon == NO_STOP_QUIETLY)
- {
- struct regcache *regcache;
- regcache = get_thread_regcache (ecs->event_thread);
- handle_solib_event ();
- ecs->event_thread->set_stop_pc (regcache_read_pc (regcache));
- ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status_nowatch (regcache->aspace (),
- ecs->event_thread->stop_pc (),
- ecs->event_thread, ecs->ws);
- if (handle_stop_requested (ecs))
- return;
- if (bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
- {
- /* A catchpoint triggered. */
- process_event_stop_test (ecs);
- return;
- }
- /* If requested, stop when the dynamic linker notifies
- gdb of events. This allows the user to get control
- and place breakpoints in initializer routines for
- dynamically loaded objects (among other things). */
- ecs->event_thread->set_stop_signal (GDB_SIGNAL_0);
- if (stop_on_solib_events)
- {
- /* Make sure we print "Stopped due to solib-event" in
- normal_stop. */
- stop_print_frame = true;
- stop_waiting (ecs);
- return;
- }
- }
- /* If we are skipping through a shell, or through shared library
- loading that we aren't interested in, resume the program. If
- we're running the program normally, also resume. */
- if (stop_soon == STOP_QUIETLY || stop_soon == NO_STOP_QUIETLY)
- {
- /* Loading of shared libraries might have changed breakpoint
- addresses. Make sure new breakpoints are inserted. */
- if (stop_soon == NO_STOP_QUIETLY)
- insert_breakpoints ();
- resume (GDB_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
- }
- /* But stop if we're attaching or setting up a remote
- connection. */
- if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
- || stop_soon == STOP_QUIETLY_REMOTE)
- {
- infrun_debug_printf ("quietly stopped");
- stop_waiting (ecs);
- return;
- }
- internal_error (__FILE__, __LINE__,
- _("unhandled stop_soon: %d"), (int) stop_soon);
- }
- case TARGET_WAITKIND_SPURIOUS:
- if (handle_stop_requested (ecs))
- return;
- context_switch (ecs);
- resume (GDB_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
- case TARGET_WAITKIND_THREAD_CREATED:
- if (handle_stop_requested (ecs))
- return;
- context_switch (ecs);
- if (!switch_back_to_stepped_thread (ecs))
- keep_going (ecs);
- return;
- case TARGET_WAITKIND_EXITED:
- case TARGET_WAITKIND_SIGNALLED:
- {
- /* Depending on the system, ecs->ptid may point to a thread or
- to a process. On some targets, target_mourn_inferior may
- need to have access to the just-exited thread. That is the
- case of GNU/Linux's "checkpoint" support, for example.
- Call the switch_to_xxx routine as appropriate. */
- thread_info *thr = find_thread_ptid (ecs->target, ecs->ptid);
- if (thr != nullptr)
- switch_to_thread (thr);
- else
- {
- inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
- switch_to_inferior_no_thread (inf);
- }
- }
- handle_vfork_child_exec_or_exit (0);
- target_terminal::ours (); /* Must do this before mourn anyway. */
- /* Clearing any previous state of convenience variables. */
- clear_exit_convenience_vars ();
- if (ecs->ws.kind () == TARGET_WAITKIND_EXITED)
- {
- /* Record the exit code in the convenience variable $_exitcode, so
- that the user can inspect this again later. */
- set_internalvar_integer (lookup_internalvar ("_exitcode"),
- (LONGEST) ecs->ws.exit_status ());
- /* Also record this in the inferior itself. */
- current_inferior ()->has_exit_code = 1;
- current_inferior ()->exit_code = (LONGEST) ecs->ws.exit_status ();
- /* Support the --return-child-result option. */
- return_child_result_value = ecs->ws.exit_status ();
- gdb::observers::exited.notify (ecs->ws.exit_status ());
- }
- else
- {
- struct gdbarch *gdbarch = current_inferior ()->gdbarch;
- if (gdbarch_gdb_signal_to_target_p (gdbarch))
- {
- /* Set the value of the internal variable $_exitsignal,
- which holds the signal uncaught by the inferior. */
- set_internalvar_integer (lookup_internalvar ("_exitsignal"),
- gdbarch_gdb_signal_to_target (gdbarch,
- ecs->ws.sig ()));
- }
- else
- {
- /* We don't have access to the target's method used for
- converting between signal numbers (GDB's internal
- representation <-> target's representation).
- Therefore, we cannot do a good job at displaying this
- information to the user. It's better to just warn
- her about it (if infrun debugging is enabled), and
- give up. */
- infrun_debug_printf ("Cannot fill $_exitsignal with the correct "
- "signal number.");
- }
- gdb::observers::signal_exited.notify (ecs->ws.sig ());
- }
- gdb_flush (gdb_stdout);
- target_mourn_inferior (inferior_ptid);
- stop_print_frame = false;
- stop_waiting (ecs);
- return;
- case TARGET_WAITKIND_FORKED:
- case TARGET_WAITKIND_VFORKED:
- /* Check whether the inferior is displaced stepping. */
- {
- struct regcache *regcache = get_thread_regcache (ecs->event_thread);
- struct gdbarch *gdbarch = regcache->arch ();
- inferior *parent_inf = find_inferior_ptid (ecs->target, ecs->ptid);
- /* If this is a fork (child gets its own address space copy)
- and some displaced step buffers were in use at the time of
- the fork, restore the displaced step buffer bytes in the
- child process.
- Architectures which support displaced stepping and fork
- events must supply an implementation of
- gdbarch_displaced_step_restore_all_in_ptid. This is not
- enforced during gdbarch validation to support architectures
- which support displaced stepping but not forks. */
- if (ecs->ws.kind () == TARGET_WAITKIND_FORKED
- && gdbarch_supports_displaced_stepping (gdbarch))
- gdbarch_displaced_step_restore_all_in_ptid
- (gdbarch, parent_inf, ecs->ws.child_ptid ());
- /* If displaced stepping is supported, and thread ecs->ptid is
- displaced stepping. */
- if (displaced_step_in_progress_thread (ecs->event_thread))
- {
- struct regcache *child_regcache;
- CORE_ADDR parent_pc;
- /* GDB has got TARGET_WAITKIND_FORKED or TARGET_WAITKIND_VFORKED,
- indicating that the displaced stepping of syscall instruction
- has been done. Perform cleanup for parent process here. Note
- that this operation also cleans up the child process for vfork,
- because their pages are shared. */
- displaced_step_finish (ecs->event_thread, GDB_SIGNAL_TRAP);
- /* Start a new step-over in another thread if there's one
- that needs it. */
- start_step_over ();
- /* Since the vfork/fork syscall instruction was executed in the scratchpad,
- the child's PC is also within the scratchpad. Set the child's PC
- to the parent's PC value, which has already been fixed up.
- FIXME: we use the parent's aspace here, although we're touching
- the child, because the child hasn't been added to the inferior
- list yet at this point. */
- child_regcache
- = get_thread_arch_aspace_regcache (parent_inf->process_target (),
- ecs->ws.child_ptid (),
- gdbarch,
- parent_inf->aspace);
- /* Read PC value of parent process. */
- parent_pc = regcache_read_pc (regcache);
- displaced_debug_printf ("write child pc from %s to %s",
- paddress (gdbarch,
- regcache_read_pc (child_regcache)),
- paddress (gdbarch, parent_pc));
- regcache_write_pc (child_regcache, parent_pc);
- }
- }
- context_switch (ecs);
- /* Immediately detach breakpoints from the child before there's
- any chance of letting the user delete breakpoints from the
- breakpoint lists. If we don't do this early, it's easy to
- leave left over traps in the child, vis: "break foo; catch
- fork; c; <fork>; del; c; <child calls foo>". We only follow
- the fork on the last `continue', and by that time the
- breakpoint at "foo" is long gone from the breakpoint table.
- If we vforked, then we don't need to unpatch here, since both
- parent and child are sharing the same memory pages; we'll
- need to unpatch at follow/detach time instead to be certain
- that new breakpoints added between catchpoint hit time and
- vfork follow are detached. */
- if (ecs->ws.kind () != TARGET_WAITKIND_VFORKED)
- {
- /* This won't actually modify the breakpoint list, but will
- physically remove the breakpoints from the child. */
- detach_breakpoints (ecs->ws.child_ptid ());
- }
- delete_just_stopped_threads_single_step_breakpoints ();
- /* In case the event is caught by a catchpoint, remember that
- the event is to be followed at the next resume of the thread,
- and not immediately. */
- ecs->event_thread->pending_follow = ecs->ws;
- ecs->event_thread->set_stop_pc
- (regcache_read_pc (get_thread_regcache (ecs->event_thread)));
- ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status_nowatch (get_current_regcache ()->aspace (),
- ecs->event_thread->stop_pc (),
- ecs->event_thread, ecs->ws);
- if (handle_stop_requested (ecs))
- return;
- /* If no catchpoint triggered for this, then keep going. Note
- that we're interested in knowing the bpstat actually causes a
- stop, not just if it may explain the signal. Software
- watchpoints, for example, always appear in the bpstat. */
- if (!bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
- {
- bool follow_child
- = (follow_fork_mode_string == follow_fork_mode_child);
- ecs->event_thread->set_stop_signal (GDB_SIGNAL_0);
- process_stratum_target *targ
- = ecs->event_thread->inf->process_target ();
- bool should_resume = follow_fork ();
- /* Note that one of these may be an invalid pointer,
- depending on detach_fork. */
- thread_info *parent = ecs->event_thread;
- thread_info *child = find_thread_ptid (targ, ecs->ws.child_ptid ());
- /* At this point, the parent is marked running, and the
- child is marked stopped. */
- /* If not resuming the parent, mark it stopped. */
- if (follow_child && !detach_fork && !non_stop && !sched_multi)
- parent->set_running (false);
- /* If resuming the child, mark it running. */
- if (follow_child || (!detach_fork && (non_stop || sched_multi)))
- child->set_running (true);
- /* In non-stop mode, also resume the other branch. */
- if (!detach_fork && (non_stop
- || (sched_multi && target_is_non_stop_p ())))
- {
- if (follow_child)
- switch_to_thread (parent);
- else
- switch_to_thread (child);
- ecs->event_thread = inferior_thread ();
- ecs->ptid = inferior_ptid;
- keep_going (ecs);
- }
- if (follow_child)
- switch_to_thread (child);
- else
- switch_to_thread (parent);
- ecs->event_thread = inferior_thread ();
- ecs->ptid = inferior_ptid;
- if (should_resume)
- {
- /* Never call switch_back_to_stepped_thread if we are waiting for
- vfork-done (waiting for an external vfork child to exec or
- exit). We will resume only the vforking thread for the purpose
- of collecting the vfork-done event, and we will restart any
- step once the critical shared address space window is done. */
- if ((!follow_child
- && detach_fork
- && parent->inf->thread_waiting_for_vfork_done != nullptr)
- || !switch_back_to_stepped_thread (ecs))
- keep_going (ecs);
- }
- else
- stop_waiting (ecs);
- return;
- }
- process_event_stop_test (ecs);
- return;
- case TARGET_WAITKIND_VFORK_DONE:
- /* Done with the shared memory region. Re-insert breakpoints in
- the parent, and keep going. */
- context_switch (ecs);
- handle_vfork_done (ecs->event_thread);
- gdb_assert (inferior_thread () == ecs->event_thread);
- if (handle_stop_requested (ecs))
- return;
- if (!switch_back_to_stepped_thread (ecs))
- {
- gdb_assert (inferior_thread () == ecs->event_thread);
- /* This also takes care of reinserting breakpoints in the
- previously locked inferior. */
- keep_going (ecs);
- }
- return;
- case TARGET_WAITKIND_EXECD:
- /* Note we can't read registers yet (the stop_pc), because we
- don't yet know the inferior's post-exec architecture.
- 'stop_pc' is explicitly read below instead. */
- switch_to_thread_no_regs (ecs->event_thread);
- /* Do whatever is necessary to the parent branch of the vfork. */
- handle_vfork_child_exec_or_exit (1);
- /* This causes the eventpoints and symbol table to be reset.
- Must do this now, before trying to determine whether to
- stop. */
- follow_exec (inferior_ptid, ecs->ws.execd_pathname ());
- /* In follow_exec we may have deleted the original thread and
- created a new one. Make sure that the event thread is the
- execd thread for that case (this is a nop otherwise). */
- ecs->event_thread = inferior_thread ();
- ecs->event_thread->set_stop_pc
- (regcache_read_pc (get_thread_regcache (ecs->event_thread)));
- ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status_nowatch (get_current_regcache ()->aspace (),
- ecs->event_thread->stop_pc (),
- ecs->event_thread, ecs->ws);
- if (handle_stop_requested (ecs))
- return;
- /* If no catchpoint triggered for this, then keep going. */
- if (!bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
- {
- ecs->event_thread->set_stop_signal (GDB_SIGNAL_0);
- keep_going (ecs);
- return;
- }
- process_event_stop_test (ecs);
- return;
- /* Be careful not to try to gather much state about a thread
- that's in a syscall. It's frequently a losing proposition. */
- case TARGET_WAITKIND_SYSCALL_ENTRY:
- /* Getting the current syscall number. */
- if (handle_syscall_event (ecs) == 0)
- process_event_stop_test (ecs);
- return;
- /* Before examining the threads further, step this thread to
- get it entirely out of the syscall. (We get notice of the
- event when the thread is just on the verge of exiting a
- syscall. Stepping one instruction seems to get it back
- into user code.) */
- case TARGET_WAITKIND_SYSCALL_RETURN:
- if (handle_syscall_event (ecs) == 0)
- process_event_stop_test (ecs);
- return;
- case TARGET_WAITKIND_STOPPED:
- handle_signal_stop (ecs);
- return;
- case TARGET_WAITKIND_NO_HISTORY:
- /* Reverse execution: target ran out of history info. */
- /* Switch to the stopped thread. */
- context_switch (ecs);
- infrun_debug_printf ("stopped");
- delete_just_stopped_threads_single_step_breakpoints ();
- ecs->event_thread->set_stop_pc
- (regcache_read_pc (get_thread_regcache (inferior_thread ())));
- if (handle_stop_requested (ecs))
- return;
- gdb::observers::no_history.notify ();
- stop_waiting (ecs);
- return;
- }
- }
- /* Restart threads back to what they were trying to do back when we
- paused them (because of an in-line step-over or vfork, for example).
- The EVENT_THREAD thread is ignored (not restarted).
- If INF is non-nullptr, only resume threads from INF. */
- static void
- restart_threads (struct thread_info *event_thread, inferior *inf)
- {
- INFRUN_SCOPED_DEBUG_START_END ("event_thread=%s, inf=%d",
- event_thread->ptid.to_string ().c_str (),
- inf != nullptr ? inf->num : -1);
- /* In case the instruction just stepped spawned a new thread. */
- update_thread_list ();
- for (thread_info *tp : all_non_exited_threads ())
- {
- if (inf != nullptr && tp->inf != inf)
- continue;
- if (tp->inf->detaching)
- {
- infrun_debug_printf ("restart threads: [%s] inferior detaching",
- tp->ptid.to_string ().c_str ());
- continue;
- }
- switch_to_thread_no_regs (tp);
- if (tp == event_thread)
- {
- infrun_debug_printf ("restart threads: [%s] is event thread",
- tp->ptid.to_string ().c_str ());
- continue;
- }
- if (!(tp->state == THREAD_RUNNING || tp->control.in_infcall))
- {
- infrun_debug_printf ("restart threads: [%s] not meant to be running",
- tp->ptid.to_string ().c_str ());
- continue;
- }
- if (tp->resumed ())
- {
- infrun_debug_printf ("restart threads: [%s] resumed",
- tp->ptid.to_string ().c_str ());
- gdb_assert (tp->executing () || tp->has_pending_waitstatus ());
- continue;
- }
- if (thread_is_in_step_over_chain (tp))
- {
- infrun_debug_printf ("restart threads: [%s] needs step-over",
- tp->ptid.to_string ().c_str ());
- gdb_assert (!tp->resumed ());
- continue;
- }
- if (tp->has_pending_waitstatus ())
- {
- infrun_debug_printf ("restart threads: [%s] has pending status",
- tp->ptid.to_string ().c_str ());
- tp->set_resumed (true);
- continue;
- }
- gdb_assert (!tp->stop_requested);
- /* If some thread needs to start a step-over at this point, it
- should still be in the step-over queue, and thus skipped
- above. */
- if (thread_still_needs_step_over (tp))
- {
- internal_error (__FILE__, __LINE__,
- "thread [%s] needs a step-over, but not in "
- "step-over queue\n",
- tp->ptid.to_string ().c_str ());
- }
- if (currently_stepping (tp))
- {
- infrun_debug_printf ("restart threads: [%s] was stepping",
- tp->ptid.to_string ().c_str ());
- keep_going_stepped_thread (tp);
- }
- else
- {
- struct execution_control_state ecss;
- struct execution_control_state *ecs = &ecss;
- infrun_debug_printf ("restart threads: [%s] continuing",
- tp->ptid.to_string ().c_str ());
- reset_ecs (ecs, tp);
- switch_to_thread (tp);
- keep_going_pass_signal (ecs);
- }
- }
- }
- /* Callback for iterate_over_threads. Find a resumed thread that has
- a pending waitstatus. */
- static int
- resumed_thread_with_pending_status (struct thread_info *tp,
- void *arg)
- {
- return tp->resumed () && tp->has_pending_waitstatus ();
- }
- /* Called when we get an event that may finish an in-line or
- out-of-line (displaced stepping) step-over started previously.
- Return true if the event is processed and we should go back to the
- event loop; false if the caller should continue processing the
- event. */
- static int
- finish_step_over (struct execution_control_state *ecs)
- {
- displaced_step_finish (ecs->event_thread, ecs->event_thread->stop_signal ());
- bool had_step_over_info = step_over_info_valid_p ();
- if (had_step_over_info)
- {
- /* If we're stepping over a breakpoint with all threads locked,
- then only the thread that was stepped should be reporting
- back an event. */
- gdb_assert (ecs->event_thread->control.trap_expected);
- clear_step_over_info ();
- }
- if (!target_is_non_stop_p ())
- return 0;
- /* Start a new step-over in another thread if there's one that
- needs it. */
- start_step_over ();
- /* If we were stepping over a breakpoint before, and haven't started
- a new in-line step-over sequence, then restart all other threads
- (except the event thread). We can't do this in all-stop, as then
- e.g., we wouldn't be able to issue any other remote packet until
- these other threads stop. */
- if (had_step_over_info && !step_over_info_valid_p ())
- {
- struct thread_info *pending;
- /* If we only have threads with pending statuses, the restart
- below won't restart any thread and so nothing re-inserts the
- breakpoint we just stepped over. But we need it inserted
- when we later process the pending events, otherwise if
- another thread has a pending event for this breakpoint too,
- we'd discard its event (because the breakpoint that
- originally caused the event was no longer inserted). */
- context_switch (ecs);
- insert_breakpoints ();
- restart_threads (ecs->event_thread);
- /* If we have events pending, go through handle_inferior_event
- again, picking up a pending event at random. This avoids
- thread starvation. */
- /* But not if we just stepped over a watchpoint in order to let
- the instruction execute so we can evaluate its expression.
- The set of watchpoints that triggered is recorded in the
- breakpoint objects themselves (see bp->watchpoint_triggered).
- If we processed another event first, that other event could
- clobber this info. */
- if (ecs->event_thread->stepping_over_watchpoint)
- return 0;
- pending = iterate_over_threads (resumed_thread_with_pending_status,
- NULL);
- if (pending != NULL)
- {
- struct thread_info *tp = ecs->event_thread;
- struct regcache *regcache;
- infrun_debug_printf ("found resumed threads with "
- "pending events, saving status");
- gdb_assert (pending != tp);
- /* Record the event thread's event for later. */
- save_waitstatus (tp, ecs->ws);
- /* This was cleared early, by handle_inferior_event. Set it
- so this pending event is considered by
- do_target_wait. */
- tp->set_resumed (true);
- gdb_assert (!tp->executing ());
- regcache = get_thread_regcache (tp);
- tp->set_stop_pc (regcache_read_pc (regcache));
- infrun_debug_printf ("saved stop_pc=%s for %s "
- "(currently_stepping=%d)",
- paddress (target_gdbarch (), tp->stop_pc ()),
- tp->ptid.to_string ().c_str (),
- currently_stepping (tp));
- /* This in-line step-over finished; clear this so we won't
- start a new one. This is what handle_signal_stop would
- do, if we returned false. */
- tp->stepping_over_breakpoint = 0;
- /* Wake up the event loop again. */
- mark_async_event_handler (infrun_async_inferior_event_token);
- prepare_to_wait (ecs);
- return 1;
- }
- }
- return 0;
- }
- /* Come here when the program has stopped with a signal. */
- static void
- handle_signal_stop (struct execution_control_state *ecs)
- {
- struct frame_info *frame;
- struct gdbarch *gdbarch;
- int stopped_by_watchpoint;
- enum stop_kind stop_soon;
- int random_signal;
- gdb_assert (ecs->ws.kind () == TARGET_WAITKIND_STOPPED);
- ecs->event_thread->set_stop_signal (ecs->ws.sig ());
- /* Do we need to clean up the state of a thread that has
- completed a displaced single-step? (Doing so usually affects
- the PC, so do it here, before we set stop_pc.) */
- if (finish_step_over (ecs))
- return;
- /* If we either finished a single-step or hit a breakpoint, but
- the user wanted this thread to be stopped, pretend we got a
- SIG0 (generic unsignaled stop). */
- if (ecs->event_thread->stop_requested
- && ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP)
- ecs->event_thread->set_stop_signal (GDB_SIGNAL_0);
- ecs->event_thread->set_stop_pc
- (regcache_read_pc (get_thread_regcache (ecs->event_thread)));
- context_switch (ecs);
- if (deprecated_context_hook)
- deprecated_context_hook (ecs->event_thread->global_num);
- if (debug_infrun)
- {
- struct regcache *regcache = get_thread_regcache (ecs->event_thread);
- struct gdbarch *reg_gdbarch = regcache->arch ();
- infrun_debug_printf
- ("stop_pc=%s", paddress (reg_gdbarch, ecs->event_thread->stop_pc ()));
- if (target_stopped_by_watchpoint ())
- {
- CORE_ADDR addr;
- infrun_debug_printf ("stopped by watchpoint");
- if (target_stopped_data_address (current_inferior ()->top_target (),
- &addr))
- infrun_debug_printf ("stopped data address=%s",
- paddress (reg_gdbarch, addr));
- else
- infrun_debug_printf ("(no data address available)");
- }
- }
- /* This is originated from start_remote(), start_inferior() and
- shared libraries hook functions. */
- stop_soon = get_inferior_stop_soon (ecs);
- if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
- {
- infrun_debug_printf ("quietly stopped");
- stop_print_frame = true;
- stop_waiting (ecs);
- return;
- }
- /* This originates from attach_command(). We need to overwrite
- the stop_signal here, because some kernels don't ignore a
- SIGSTOP in a subsequent ptrace(PTRACE_CONT,SIGSTOP) call.
- See more comments in inferior.h. On the other hand, if we
- get a non-SIGSTOP, report it to the user - assume the backend
- will handle the SIGSTOP if it should show up later.
- Also consider that the attach is complete when we see a
- SIGTRAP. Some systems (e.g. Windows), and stubs supporting
- target extended-remote report it instead of a SIGSTOP
- (e.g. gdbserver). We already rely on SIGTRAP being our
- signal, so this is no exception.
- Also consider that the attach is complete when we see a
- GDB_SIGNAL_0. In non-stop mode, GDB will explicitly tell
- the target to stop all threads of the inferior, in case the
- low level attach operation doesn't stop them implicitly. If
- they weren't stopped implicitly, then the stub will report a
- GDB_SIGNAL_0, meaning: stopped for no particular reason
- other than GDB's request. */
- if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
- && (ecs->event_thread->stop_signal () == GDB_SIGNAL_STOP
- || ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP
- || ecs->event_thread->stop_signal () == GDB_SIGNAL_0))
- {
- stop_print_frame = true;
- stop_waiting (ecs);
- ecs->event_thread->set_stop_signal (GDB_SIGNAL_0);
- return;
- }
- /* At this point, get hold of the now-current thread's frame. */
- frame = get_current_frame ();
- gdbarch = get_frame_arch (frame);
- /* Pull the single step breakpoints out of the target. */
- if (ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP)
- {
- struct regcache *regcache;
- CORE_ADDR pc;
- regcache = get_thread_regcache (ecs->event_thread);
- const address_space *aspace = regcache->aspace ();
- pc = regcache_read_pc (regcache);
- /* However, before doing so, if this single-step breakpoint was
- actually for another thread, set this thread up for moving
- past it. */
- if (!thread_has_single_step_breakpoint_here (ecs->event_thread,
- aspace, pc))
- {
- if (single_step_breakpoint_inserted_here_p (aspace, pc))
- {
- infrun_debug_printf ("[%s] hit another thread's single-step "
- "breakpoint",
- ecs->ptid.to_string ().c_str ());
- ecs->hit_singlestep_breakpoint = 1;
- }
- }
- else
- {
- infrun_debug_printf ("[%s] hit its single-step breakpoint",
- ecs->ptid.to_string ().c_str ());
- }
- }
- delete_just_stopped_threads_single_step_breakpoints ();
- if (ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP
- && ecs->event_thread->control.trap_expected
- && ecs->event_thread->stepping_over_watchpoint)
- stopped_by_watchpoint = 0;
- else
- stopped_by_watchpoint = watchpoints_triggered (ecs->ws);
- /* If necessary, step over this watchpoint. We'll be back to display
- it in a moment. */
- if (stopped_by_watchpoint
- && (target_have_steppable_watchpoint ()
- || gdbarch_have_nonsteppable_watchpoint (gdbarch)))
- {
- /* At this point, we are stopped at an instruction which has
- attempted to write to a piece of memory under control of
- a watchpoint. The instruction hasn't actually executed
- yet. If we were to evaluate the watchpoint expression
- now, we would get the old value, and therefore no change
- would seem to have occurred.
- In order to make watchpoints work `right', we really need
- to complete the memory write, and then evaluate the
- watchpoint expression. We do this by single-stepping the
- target.
- It may not be necessary to disable the watchpoint to step over
- it. For example, the PA can (with some kernel cooperation)
- single step over a watchpoint without disabling the watchpoint.
- It is far more common to need to disable a watchpoint to step
- the inferior over it. If we have non-steppable watchpoints,
- we must disable the current watchpoint; it's simplest to
- disable all watchpoints.
- Any breakpoint at PC must also be stepped over -- if there's
- one, it will have already triggered before the watchpoint
- triggered, and we either already reported it to the user, or
- it didn't cause a stop and we called keep_going. In either
- case, if there was a breakpoint at PC, we must be trying to
- step past it. */
- ecs->event_thread->stepping_over_watchpoint = 1;
- keep_going (ecs);
- return;
- }
- ecs->event_thread->stepping_over_breakpoint = 0;
- ecs->event_thread->stepping_over_watchpoint = 0;
- bpstat_clear (&ecs->event_thread->control.stop_bpstat);
- ecs->event_thread->control.stop_step = 0;
- stop_print_frame = true;
- stopped_by_random_signal = 0;
- bpstat *stop_chain = nullptr;
- /* Hide inlined functions starting here, unless we just performed stepi or
- nexti. After stepi and nexti, always show the innermost frame (not any
- inline function call sites). */
- if (ecs->event_thread->control.step_range_end != 1)
- {
- const address_space *aspace
- = get_thread_regcache (ecs->event_thread)->aspace ();
- /* skip_inline_frames is expensive, so we avoid it if we can
- determine that the address is one where functions cannot have
- been inlined. This improves performance with inferiors that
- load a lot of shared libraries, because the solib event
- breakpoint is defined as the address of a function (i.e. not
- inline). Note that we have to check the previous PC as well
- as the current one to catch cases when we have just
- single-stepped off a breakpoint prior to reinstating it.
- Note that we're assuming that the code we single-step to is
- not inline, but that's not definitive: there's nothing
- preventing the event breakpoint function from containing
- inlined code, and the single-step ending up there. If the
- user had set a breakpoint on that inlined code, the missing
- skip_inline_frames call would break things. Fortunately
- that's an extremely unlikely scenario. */
- if (!pc_at_non_inline_function (aspace,
- ecs->event_thread->stop_pc (),
- ecs->ws)
- && !(ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP
- && ecs->event_thread->control.trap_expected
- && pc_at_non_inline_function (aspace,
- ecs->event_thread->prev_pc,
- ecs->ws)))
- {
- stop_chain = build_bpstat_chain (aspace,
- ecs->event_thread->stop_pc (),
- ecs->ws);
- skip_inline_frames (ecs->event_thread, stop_chain);
- /* Re-fetch current thread's frame in case that invalidated
- the frame cache. */
- frame = get_current_frame ();
- gdbarch = get_frame_arch (frame);
- }
- }
- if (ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP
- && ecs->event_thread->control.trap_expected
- && gdbarch_single_step_through_delay_p (gdbarch)
- && currently_stepping (ecs->event_thread))
- {
- /* We're trying to step off a breakpoint. Turns out that we're
- also on an instruction that needs to be stepped multiple
- times before it's been fully executing. E.g., architectures
- with a delay slot. It needs to be stepped twice, once for
- the instruction and once for the delay slot. */
- int step_through_delay
- = gdbarch_single_step_through_delay (gdbarch, frame);
- if (step_through_delay)
- infrun_debug_printf ("step through delay");
- if (ecs->event_thread->control.step_range_end == 0
- && step_through_delay)
- {
- /* The user issued a continue when stopped at a breakpoint.
- Set up for another trap and get out of here. */
- ecs->event_thread->stepping_over_breakpoint = 1;
- keep_going (ecs);
- return;
- }
- else if (step_through_delay)
- {
- /* The user issued a step when stopped at a breakpoint.
- Maybe we should stop, maybe we should not - the delay
- slot *might* correspond to a line of source. In any
- case, don't decide that here, just set
- ecs->stepping_over_breakpoint, making sure we
- single-step again before breakpoints are re-inserted. */
- ecs->event_thread->stepping_over_breakpoint = 1;
- }
- }
- /* See if there is a breakpoint/watchpoint/catchpoint/etc. that
- handles this event. */
- ecs->event_thread->control.stop_bpstat
- = bpstat_stop_status (get_current_regcache ()->aspace (),
- ecs->event_thread->stop_pc (),
- ecs->event_thread, ecs->ws, stop_chain);
- /* Following in case break condition called a
- function. */
- stop_print_frame = true;
- /* This is where we handle "moribund" watchpoints. Unlike
- software breakpoints traps, hardware watchpoint traps are
- always distinguishable from random traps. If no high-level
- watchpoint is associated with the reported stop data address
- anymore, then the bpstat does not explain the signal ---
- simply make sure to ignore it if `stopped_by_watchpoint' is
- set. */
- if (ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP
- && !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
- GDB_SIGNAL_TRAP)
- && stopped_by_watchpoint)
- {
- infrun_debug_printf ("no user watchpoint explains watchpoint SIGTRAP, "
- "ignoring");
- }
- /* NOTE: cagney/2003-03-29: These checks for a random signal
- at one stage in the past included checks for an inferior
- function call's call dummy's return breakpoint. The original
- comment, that went with the test, read:
- ``End of a stack dummy. Some systems (e.g. Sony news) give
- another signal besides SIGTRAP, so check here as well as
- above.''
- If someone ever tries to get call dummys on a
- non-executable stack to work (where the target would stop
- with something like a SIGSEGV), then those tests might need
- to be re-instated. Given, however, that the tests were only
- enabled when momentary breakpoints were not being used, I
- suspect that it won't be the case.
- NOTE: kettenis/2004-02-05: Indeed such checks don't seem to
- be necessary for call dummies on a non-executable stack on
- SPARC. */
- /* See if the breakpoints module can explain the signal. */
- random_signal
- = !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
- ecs->event_thread->stop_signal ());
- /* Maybe this was a trap for a software breakpoint that has since
- been removed. */
- if (random_signal && target_stopped_by_sw_breakpoint ())
- {
- if (gdbarch_program_breakpoint_here_p (gdbarch,
- ecs->event_thread->stop_pc ()))
- {
- struct regcache *regcache;
- int decr_pc;
- /* Re-adjust PC to what the program would see if GDB was not
- debugging it. */
- regcache = get_thread_regcache (ecs->event_thread);
- decr_pc = gdbarch_decr_pc_after_break (gdbarch);
- if (decr_pc != 0)
- {
- gdb::optional<scoped_restore_tmpl<int>>
- restore_operation_disable;
- if (record_full_is_used ())
- restore_operation_disable.emplace
- (record_full_gdb_operation_disable_set ());
- regcache_write_pc (regcache,
- ecs->event_thread->stop_pc () + decr_pc);
- }
- }
- else
- {
- /* A delayed software breakpoint event. Ignore the trap. */
- infrun_debug_printf ("delayed software breakpoint trap, ignoring");
- random_signal = 0;
- }
- }
- /* Maybe this was a trap for a hardware breakpoint/watchpoint that
- has since been removed. */
- if (random_signal && target_stopped_by_hw_breakpoint ())
- {
- /* A delayed hardware breakpoint event. Ignore the trap. */
- infrun_debug_printf ("delayed hardware breakpoint/watchpoint "
- "trap, ignoring");
- random_signal = 0;
- }
- /* If not, perhaps stepping/nexting can. */
- if (random_signal)
- random_signal = !(ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP
- && currently_stepping (ecs->event_thread));
- /* Perhaps the thread hit a single-step breakpoint of _another_
- thread. Single-step breakpoints are transparent to the
- breakpoints module. */
- if (random_signal)
- random_signal = !ecs->hit_singlestep_breakpoint;
- /* No? Perhaps we got a moribund watchpoint. */
- if (random_signal)
- random_signal = !stopped_by_watchpoint;
- /* Always stop if the user explicitly requested this thread to
- remain stopped. */
- if (ecs->event_thread->stop_requested)
- {
- random_signal = 1;
- infrun_debug_printf ("user-requested stop");
- }
- /* For the program's own signals, act according to
- the signal handling tables. */
- if (random_signal)
- {
- /* Signal not for debugging purposes. */
- enum gdb_signal stop_signal = ecs->event_thread->stop_signal ();
- infrun_debug_printf ("random signal (%s)",
- gdb_signal_to_symbol_string (stop_signal));
- stopped_by_random_signal = 1;
- /* Always stop on signals if we're either just gaining control
- of the program, or the user explicitly requested this thread
- to remain stopped. */
- if (stop_soon != NO_STOP_QUIETLY
- || ecs->event_thread->stop_requested
- || signal_stop_state (ecs->event_thread->stop_signal ()))
- {
- stop_waiting (ecs);
- return;
- }
- /* Notify observers the signal has "handle print" set. Note we
- returned early above if stopping; normal_stop handles the
- printing in that case. */
- if (signal_print[ecs->event_thread->stop_signal ()])
- {
- /* The signal table tells us to print about this signal. */
- target_terminal::ours_for_output ();
- gdb::observers::signal_received.notify (ecs->event_thread->stop_signal ());
- target_terminal::inferior ();
- }
- /* Clear the signal if it should not be passed. */
- if (signal_program[ecs->event_thread->stop_signal ()] == 0)
- ecs->event_thread->set_stop_signal (GDB_SIGNAL_0);
- if (ecs->event_thread->prev_pc == ecs->event_thread->stop_pc ()
- && ecs->event_thread->control.trap_expected
- && ecs->event_thread->control.step_resume_breakpoint == NULL)
- {
- /* We were just starting a new sequence, attempting to
- single-step off of a breakpoint and expecting a SIGTRAP.
- Instead this signal arrives. This signal will take us out
- of the stepping range so GDB needs to remember to, when
- the signal handler returns, resume stepping off that
- breakpoint. */
- /* To simplify things, "continue" is forced to use the same
- code paths as single-step - set a breakpoint at the
- signal return address and then, once hit, step off that
- breakpoint. */
- infrun_debug_printf ("signal arrived while stepping over breakpoint");
- insert_hp_step_resume_breakpoint_at_frame (frame);
- ecs->event_thread->step_after_step_resume_breakpoint = 1;
- /* Reset trap_expected to ensure breakpoints are re-inserted. */
- ecs->event_thread->control.trap_expected = 0;
- /* If we were nexting/stepping some other thread, switch to
- it, so that we don't continue it, losing control. */
- if (!switch_back_to_stepped_thread (ecs))
- keep_going (ecs);
- return;
- }
- if (ecs->event_thread->stop_signal () != GDB_SIGNAL_0
- && (pc_in_thread_step_range (ecs->event_thread->stop_pc (),
- ecs->event_thread)
- || ecs->event_thread->control.step_range_end == 1)
- && frame_id_eq (get_stack_frame_id (frame),
- ecs->event_thread->control.step_stack_frame_id)
- && ecs->event_thread->control.step_resume_breakpoint == NULL)
- {
- /* The inferior is about to take a signal that will take it
- out of the single step range. Set a breakpoint at the
- current PC (which is presumably where the signal handler
- will eventually return) and then allow the inferior to
- run free.
- Note that this is only needed for a signal delivered
- while in the single-step range. Nested signals aren't a
- problem as they eventually all return. */
- infrun_debug_printf ("signal may take us out of single-step range");
- clear_step_over_info ();
- insert_hp_step_resume_breakpoint_at_frame (frame);
- ecs->event_thread->step_after_step_resume_breakpoint = 1;
- /* Reset trap_expected to ensure breakpoints are re-inserted. */
- ecs->event_thread->control.trap_expected = 0;
- keep_going (ecs);
- return;
- }
- /* Note: step_resume_breakpoint may be non-NULL. This occurs
- when either there's a nested signal, or when there's a
- pending signal enabled just as the signal handler returns
- (leaving the inferior at the step-resume-breakpoint without
- actually executing it). Either way continue until the
- breakpoint is really hit. */
- if (!switch_back_to_stepped_thread (ecs))
- {
- infrun_debug_printf ("random signal, keep going");
- keep_going (ecs);
- }
- return;
- }
- process_event_stop_test (ecs);
- }
- /* Come here when we've got some debug event / signal we can explain
- (IOW, not a random signal), and test whether it should cause a
- stop, or whether we should resume the inferior (transparently).
- E.g., could be a breakpoint whose condition evaluates false; we
- could be still stepping within the line; etc. */
- static void
- process_event_stop_test (struct execution_control_state *ecs)
- {
- struct symtab_and_line stop_pc_sal;
- struct frame_info *frame;
- struct gdbarch *gdbarch;
- CORE_ADDR jmp_buf_pc;
- struct bpstat_what what;
- /* Handle cases caused by hitting a breakpoint. */
- frame = get_current_frame ();
- gdbarch = get_frame_arch (frame);
- what = bpstat_what (ecs->event_thread->control.stop_bpstat);
- if (what.call_dummy)
- {
- stop_stack_dummy = what.call_dummy;
- }
- /* A few breakpoint types have callbacks associated (e.g.,
- bp_jit_event). Run them now. */
- bpstat_run_callbacks (ecs->event_thread->control.stop_bpstat);
- /* If we hit an internal event that triggers symbol changes, the
- current frame will be invalidated within bpstat_what (e.g., if we
- hit an internal solib event). Re-fetch it. */
- frame = get_current_frame ();
- gdbarch = get_frame_arch (frame);
- switch (what.main_action)
- {
- case BPSTAT_WHAT_SET_LONGJMP_RESUME:
- /* If we hit the breakpoint at longjmp while stepping, we
- install a momentary breakpoint at the target of the
- jmp_buf. */
- infrun_debug_printf ("BPSTAT_WHAT_SET_LONGJMP_RESUME");
- ecs->event_thread->stepping_over_breakpoint = 1;
- if (what.is_longjmp)
- {
- struct value *arg_value;
- /* If we set the longjmp breakpoint via a SystemTap probe,
- then use it to extract the arguments. The destination PC
- is the third argument to the probe. */
- arg_value = probe_safe_evaluate_at_pc (frame, 2);
- if (arg_value)
- {
- jmp_buf_pc = value_as_address (arg_value);
- jmp_buf_pc = gdbarch_addr_bits_remove (gdbarch, jmp_buf_pc);
- }
- else if (!gdbarch_get_longjmp_target_p (gdbarch)
- || !gdbarch_get_longjmp_target (gdbarch,
- frame, &jmp_buf_pc))
- {
- infrun_debug_printf ("BPSTAT_WHAT_SET_LONGJMP_RESUME "
- "(!gdbarch_get_longjmp_target)");
- keep_going (ecs);
- return;
- }
- /* Insert a breakpoint at resume address. */
- insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
- }
- else
- check_exception_resume (ecs, frame);
- keep_going (ecs);
- return;
- case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
- {
- struct frame_info *init_frame;
- /* There are several cases to consider.
- 1. The initiating frame no longer exists. In this case we
- must stop, because the exception or longjmp has gone too
- far.
- 2. The initiating frame exists, and is the same as the
- current frame. We stop, because the exception or longjmp
- has been caught.
- 3. The initiating frame exists and is different from the
- current frame. This means the exception or longjmp has
- been caught beneath the initiating frame, so keep going.
- 4. longjmp breakpoint has been placed just to protect
- against stale dummy frames and user is not interested in
- stopping around longjmps. */
- infrun_debug_printf ("BPSTAT_WHAT_CLEAR_LONGJMP_RESUME");
- gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
- != NULL);
- delete_exception_resume_breakpoint (ecs->event_thread);
- if (what.is_longjmp)
- {
- check_longjmp_breakpoint_for_call_dummy (ecs->event_thread);
- if (!frame_id_p (ecs->event_thread->initiating_frame))
- {
- /* Case 4. */
- keep_going (ecs);
- return;
- }
- }
- init_frame = frame_find_by_id (ecs->event_thread->initiating_frame);
- if (init_frame)
- {
- struct frame_id current_id
- = get_frame_id (get_current_frame ());
- if (frame_id_eq (current_id,
- ecs->event_thread->initiating_frame))
- {
- /* Case 2. Fall through. */
- }
- else
- {
- /* Case 3. */
- keep_going (ecs);
- return;
- }
- }
- /* For Cases 1 and 2, remove the step-resume breakpoint, if it
- exists. */
- delete_step_resume_breakpoint (ecs->event_thread);
- end_stepping_range (ecs);
- }
- return;
- case BPSTAT_WHAT_SINGLE:
- infrun_debug_printf ("BPSTAT_WHAT_SINGLE");
- ecs->event_thread->stepping_over_breakpoint = 1;
- /* Still need to check other stuff, at least the case where we
- are stepping and step out of the right range. */
- break;
- case BPSTAT_WHAT_STEP_RESUME:
- infrun_debug_printf ("BPSTAT_WHAT_STEP_RESUME");
- delete_step_resume_breakpoint (ecs->event_thread);
- if (ecs->event_thread->control.proceed_to_finish
- && execution_direction == EXEC_REVERSE)
- {
- struct thread_info *tp = ecs->event_thread;
- /* We are finishing a function in reverse, and just hit the
- step-resume breakpoint at the start address of the
- function, and we're almost there -- just need to back up
- by one more single-step, which should take us back to the
- function call. */
- tp->control.step_range_start = tp->control.step_range_end = 1;
- keep_going (ecs);
- return;
- }
- fill_in_stop_func (gdbarch, ecs);
- if (ecs->event_thread->stop_pc () == ecs->stop_func_start
- && execution_direction == EXEC_REVERSE)
- {
- /* We are stepping over a function call in reverse, and just
- hit the step-resume breakpoint at the start address of
- the function. Go back to single-stepping, which should
- take us back to the function call. */
- ecs->event_thread->stepping_over_breakpoint = 1;
- keep_going (ecs);
- return;
- }
- break;
- case BPSTAT_WHAT_STOP_NOISY:
- infrun_debug_printf ("BPSTAT_WHAT_STOP_NOISY");
- stop_print_frame = true;
- /* Assume the thread stopped for a breakpoint. We'll still check
- whether a/the breakpoint is there when the thread is next
- resumed. */
- ecs->event_thread->stepping_over_breakpoint = 1;
- stop_waiting (ecs);
- return;
- case BPSTAT_WHAT_STOP_SILENT:
- infrun_debug_printf ("BPSTAT_WHAT_STOP_SILENT");
- stop_print_frame = false;
- /* Assume the thread stopped for a breakpoint. We'll still check
- whether a/the breakpoint is there when the thread is next
- resumed. */
- ecs->event_thread->stepping_over_breakpoint = 1;
- stop_waiting (ecs);
- return;
- case BPSTAT_WHAT_HP_STEP_RESUME:
- infrun_debug_printf ("BPSTAT_WHAT_HP_STEP_RESUME");
- delete_step_resume_breakpoint (ecs->event_thread);
- if (ecs->event_thread->step_after_step_resume_breakpoint)
- {
- /* Back when the step-resume breakpoint was inserted, we
- were trying to single-step off a breakpoint. Go back to
- doing that. */
- ecs->event_thread->step_after_step_resume_breakpoint = 0;
- ecs->event_thread->stepping_over_breakpoint = 1;
- keep_going (ecs);
- return;
- }
- break;
- case BPSTAT_WHAT_KEEP_CHECKING:
- break;
- }
- /* If we stepped a permanent breakpoint and we had a high priority
- step-resume breakpoint for the address we stepped, but we didn't
- hit it, then we must have stepped into the signal handler. The
- step-resume was only necessary to catch the case of _not_
- stepping into the handler, so delete it, and fall through to
- checking whether the step finished. */
- if (ecs->event_thread->stepped_breakpoint)
- {
- struct breakpoint *sr_bp
- = ecs->event_thread->control.step_resume_breakpoint;
- if (sr_bp != NULL
- && sr_bp->loc->permanent
- && sr_bp->type == bp_hp_step_resume
- && sr_bp->loc->address == ecs->event_thread->prev_pc)
- {
- infrun_debug_printf ("stepped permanent breakpoint, stopped in handler");
- delete_step_resume_breakpoint (ecs->event_thread);
- ecs->event_thread->step_after_step_resume_breakpoint = 0;
- }
- }
- /* We come here if we hit a breakpoint but should not stop for it.
- Possibly we also were stepping and should stop for that. So fall
- through and test for stepping. But, if not stepping, do not
- stop. */
- /* In all-stop mode, if we're currently stepping but have stopped in
- some other thread, we need to switch back to the stepped thread. */
- if (switch_back_to_stepped_thread (ecs))
- return;
- if (ecs->event_thread->control.step_resume_breakpoint)
- {
- infrun_debug_printf ("step-resume breakpoint is inserted");
- /* Having a step-resume breakpoint overrides anything
- else having to do with stepping commands until
- that breakpoint is reached. */
- keep_going (ecs);
- return;
- }
- if (ecs->event_thread->control.step_range_end == 0)
- {
- infrun_debug_printf ("no stepping, continue");
- /* Likewise if we aren't even stepping. */
- keep_going (ecs);
- return;
- }
- /* Re-fetch current thread's frame in case the code above caused
- the frame cache to be re-initialized, making our FRAME variable
- a dangling pointer. */
- frame = get_current_frame ();
- gdbarch = get_frame_arch (frame);
- fill_in_stop_func (gdbarch, ecs);
- /* If stepping through a line, keep going if still within it.
- Note that step_range_end is the address of the first instruction
- beyond the step range, and NOT the address of the last instruction
- within it!
- Note also that during reverse execution, we may be stepping
- through a function epilogue and therefore must detect when
- the current-frame changes in the middle of a line. */
- if (pc_in_thread_step_range (ecs->event_thread->stop_pc (),
- ecs->event_thread)
- && (execution_direction != EXEC_REVERSE
- || frame_id_eq (get_frame_id (frame),
- ecs->event_thread->control.step_frame_id)))
- {
- infrun_debug_printf
- ("stepping inside range [%s-%s]",
- paddress (gdbarch, ecs->event_thread->control.step_range_start),
- paddress (gdbarch, ecs->event_thread->control.step_range_end));
- /* Tentatively re-enable range stepping; `resume' disables it if
- necessary (e.g., if we're stepping over a breakpoint or we
- have software watchpoints). */
- ecs->event_thread->control.may_range_step = 1;
- /* When stepping backward, stop at beginning of line range
- (unless it's the function entry point, in which case
- keep going back to the call point). */
- CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
- if (stop_pc == ecs->event_thread->control.step_range_start
- && stop_pc != ecs->stop_func_start
- && execution_direction == EXEC_REVERSE)
- end_stepping_range (ecs);
- else
- keep_going (ecs);
- return;
- }
- /* We stepped out of the stepping range. */
- /* If we are stepping at the source level and entered the runtime
- loader dynamic symbol resolution code...
- EXEC_FORWARD: we keep on single stepping until we exit the run
- time loader code and reach the callee's address.
- EXEC_REVERSE: we've already executed the callee (backward), and
- the runtime loader code is handled just like any other
- undebuggable function call. Now we need only keep stepping
- backward through the trampoline code, and that's handled further
- down, so there is nothing for us to do here. */
- if (execution_direction != EXEC_REVERSE
- && ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
- && in_solib_dynsym_resolve_code (ecs->event_thread->stop_pc ()))
- {
- CORE_ADDR pc_after_resolver =
- gdbarch_skip_solib_resolver (gdbarch, ecs->event_thread->stop_pc ());
- infrun_debug_printf ("stepped into dynsym resolve code");
- if (pc_after_resolver)
- {
- /* Set up a step-resume breakpoint at the address
- indicated by SKIP_SOLIB_RESOLVER. */
- symtab_and_line sr_sal;
- sr_sal.pc = pc_after_resolver;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
- }
- keep_going (ecs);
- return;
- }
- /* Step through an indirect branch thunk. */
- if (ecs->event_thread->control.step_over_calls != STEP_OVER_NONE
- && gdbarch_in_indirect_branch_thunk (gdbarch,
- ecs->event_thread->stop_pc ()))
- {
- infrun_debug_printf ("stepped into indirect branch thunk");
- keep_going (ecs);
- return;
- }
- if (ecs->event_thread->control.step_range_end != 1
- && (ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
- || ecs->event_thread->control.step_over_calls == STEP_OVER_ALL)
- && get_frame_type (frame) == SIGTRAMP_FRAME)
- {
- infrun_debug_printf ("stepped into signal trampoline");
- /* The inferior, while doing a "step" or "next", has ended up in
- a signal trampoline (either by a signal being delivered or by
- the signal handler returning). Just single-step until the
- inferior leaves the trampoline (either by calling the handler
- or returning). */
- keep_going (ecs);
- return;
- }
- /* If we're in the return path from a shared library trampoline,
- we want to proceed through the trampoline when stepping. */
- /* macro/2012-04-25: This needs to come before the subroutine
- call check below as on some targets return trampolines look
- like subroutine calls (MIPS16 return thunks). */
- if (gdbarch_in_solib_return_trampoline (gdbarch,
- ecs->event_thread->stop_pc (),
- ecs->stop_func_name)
- && ecs->event_thread->control.step_over_calls != STEP_OVER_NONE)
- {
- /* Determine where this trampoline returns. */
- CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
- CORE_ADDR real_stop_pc
- = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
- infrun_debug_printf ("stepped into solib return tramp");
- /* Only proceed through if we know where it's going. */
- if (real_stop_pc)
- {
- /* And put the step-breakpoint there and go until there. */
- symtab_and_line sr_sal;
- sr_sal.pc = real_stop_pc;
- sr_sal.section = find_pc_overlay (sr_sal.pc);
- sr_sal.pspace = get_frame_program_space (frame);
- /* Do not specify what the fp should be when we stop since
- on some machines the prologue is where the new fp value
- is established. */
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
- /* Restart without fiddling with the step ranges or
- other state. */
- keep_going (ecs);
- return;
- }
- }
- /* Check for subroutine calls. The check for the current frame
- equalling the step ID is not necessary - the check of the
- previous frame's ID is sufficient - but it is a common case and
- cheaper than checking the previous frame's ID.
- NOTE: frame_id_eq will never report two invalid frame IDs as
- being equal, so to get into this block, both the current and
- previous frame must have valid frame IDs. */
- /* The outer_frame_id check is a heuristic to detect stepping
- through startup code. If we step over an instruction which
- sets the stack pointer from an invalid value to a valid value,
- we may detect that as a subroutine call from the mythical
- "outermost" function. This could be fixed by marking
- outermost frames as !stack_p,code_p,special_p. Then the
- initial outermost frame, before sp was valid, would
- have code_addr == &_start. See the comment in frame_id_eq
- for more. */
- if (!frame_id_eq (get_stack_frame_id (frame),
- ecs->event_thread->control.step_stack_frame_id)
- && (frame_id_eq (frame_unwind_caller_id (get_current_frame ()),
- ecs->event_thread->control.step_stack_frame_id)
- && (!frame_id_eq (ecs->event_thread->control.step_stack_frame_id,
- outer_frame_id)
- || (ecs->event_thread->control.step_start_function
- != find_pc_function (ecs->event_thread->stop_pc ())))))
- {
- CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
- CORE_ADDR real_stop_pc;
- infrun_debug_printf ("stepped into subroutine");
- if (ecs->event_thread->control.step_over_calls == STEP_OVER_NONE)
- {
- /* I presume that step_over_calls is only 0 when we're
- supposed to be stepping at the assembly language level
- ("stepi"). Just stop. */
- /* And this works the same backward as frontward. MVS */
- end_stepping_range (ecs);
- return;
- }
- /* Reverse stepping through solib trampolines. */
- if (execution_direction == EXEC_REVERSE
- && ecs->event_thread->control.step_over_calls != STEP_OVER_NONE
- && (gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc)
- || (ecs->stop_func_start == 0
- && in_solib_dynsym_resolve_code (stop_pc))))
- {
- /* Any solib trampoline code can be handled in reverse
- by simply continuing to single-step. We have already
- executed the solib function (backwards), and a few
- steps will take us back through the trampoline to the
- caller. */
- keep_going (ecs);
- return;
- }
- if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL)
- {
- /* We're doing a "next".
- Normal (forward) execution: set a breakpoint at the
- callee's return address (the address at which the caller
- will resume).
- Reverse (backward) execution. set the step-resume
- breakpoint at the start of the function that we just
- stepped into (backwards), and continue to there. When we
- get there, we'll need to single-step back to the caller. */
- if (execution_direction == EXEC_REVERSE)
- {
- /* If we're already at the start of the function, we've either
- just stepped backward into a single instruction function,
- or stepped back out of a signal handler to the first instruction
- of the function. Just keep going, which will single-step back
- to the caller. */
- if (ecs->stop_func_start != stop_pc && ecs->stop_func_start != 0)
- {
- /* Normal function call return (static or dynamic). */
- symtab_and_line sr_sal;
- sr_sal.pc = ecs->stop_func_start;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
- }
- }
- else
- insert_step_resume_breakpoint_at_caller (frame);
- keep_going (ecs);
- return;
- }
- /* If we are in a function call trampoline (a stub between the
- calling routine and the real function), locate the real
- function. That's what tells us (a) whether we want to step
- into it at all, and (b) what prologue we want to run to the
- end of, if we do step into it. */
- real_stop_pc = skip_language_trampoline (frame, stop_pc);
- if (real_stop_pc == 0)
- real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
- if (real_stop_pc != 0)
- ecs->stop_func_start = real_stop_pc;
- if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc))
- {
- symtab_and_line sr_sal;
- sr_sal.pc = ecs->stop_func_start;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
- keep_going (ecs);
- return;
- }
- /* If we have line number information for the function we are
- thinking of stepping into and the function isn't on the skip
- list, step into it.
- If there are several symtabs at that PC (e.g. with include
- files), just want to know whether *any* of them have line
- numbers. find_pc_line handles this. */
- {
- struct symtab_and_line tmp_sal;
- tmp_sal = find_pc_line (ecs->stop_func_start, 0);
- if (tmp_sal.line != 0
- && !function_name_is_marked_for_skip (ecs->stop_func_name,
- tmp_sal)
- && !inline_frame_is_marked_for_skip (true, ecs->event_thread))
- {
- if (execution_direction == EXEC_REVERSE)
- handle_step_into_function_backward (gdbarch, ecs);
- else
- handle_step_into_function (gdbarch, ecs);
- return;
- }
- }
- /* If we have no line number and the step-stop-if-no-debug is
- set, we stop the step so that the user has a chance to switch
- in assembly mode. */
- if (ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
- && step_stop_if_no_debug)
- {
- end_stepping_range (ecs);
- return;
- }
- if (execution_direction == EXEC_REVERSE)
- {
- /* If we're already at the start of the function, we've either just
- stepped backward into a single instruction function without line
- number info, or stepped back out of a signal handler to the first
- instruction of the function without line number info. Just keep
- going, which will single-step back to the caller. */
- if (ecs->stop_func_start != stop_pc)
- {
- /* Set a breakpoint at callee's start address.
- From there we can step once and be back in the caller. */
- symtab_and_line sr_sal;
- sr_sal.pc = ecs->stop_func_start;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
- }
- }
- else
- /* Set a breakpoint at callee's return address (the address
- at which the caller will resume). */
- insert_step_resume_breakpoint_at_caller (frame);
- keep_going (ecs);
- return;
- }
- /* Reverse stepping through solib trampolines. */
- if (execution_direction == EXEC_REVERSE
- && ecs->event_thread->control.step_over_calls != STEP_OVER_NONE)
- {
- CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
- if (gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc)
- || (ecs->stop_func_start == 0
- && in_solib_dynsym_resolve_code (stop_pc)))
- {
- /* Any solib trampoline code can be handled in reverse
- by simply continuing to single-step. We have already
- executed the solib function (backwards), and a few
- steps will take us back through the trampoline to the
- caller. */
- keep_going (ecs);
- return;
- }
- else if (in_solib_dynsym_resolve_code (stop_pc))
- {
- /* Stepped backward into the solib dynsym resolver.
- Set a breakpoint at its start and continue, then
- one more step will take us out. */
- symtab_and_line sr_sal;
- sr_sal.pc = ecs->stop_func_start;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
- keep_going (ecs);
- return;
- }
- }
- /* This always returns the sal for the inner-most frame when we are in a
- stack of inlined frames, even if GDB actually believes that it is in a
- more outer frame. This is checked for below by calls to
- inline_skipped_frames. */
- stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (), 0);
- /* NOTE: tausq/2004-05-24: This if block used to be done before all
- the trampoline processing logic, however, there are some trampolines
- that have no names, so we should do trampoline handling first. */
- if (ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
- && ecs->stop_func_name == NULL
- && stop_pc_sal.line == 0)
- {
- infrun_debug_printf ("stepped into undebuggable function");
- /* The inferior just stepped into, or returned to, an
- undebuggable function (where there is no debugging information
- and no line number corresponding to the address where the
- inferior stopped). Since we want to skip this kind of code,
- we keep going until the inferior returns from this
- function - unless the user has asked us not to (via
- set step-mode) or we no longer know how to get back
- to the call site. */
- if (step_stop_if_no_debug
- || !frame_id_p (frame_unwind_caller_id (frame)))
- {
- /* If we have no line number and the step-stop-if-no-debug
- is set, we stop the step so that the user has a chance to
- switch in assembly mode. */
- end_stepping_range (ecs);
- return;
- }
- else
- {
- /* Set a breakpoint at callee's return address (the address
- at which the caller will resume). */
- insert_step_resume_breakpoint_at_caller (frame);
- keep_going (ecs);
- return;
- }
- }
- if (ecs->event_thread->control.step_range_end == 1)
- {
- /* It is stepi or nexti. We always want to stop stepping after
- one instruction. */
- infrun_debug_printf ("stepi/nexti");
- end_stepping_range (ecs);
- return;
- }
- if (stop_pc_sal.line == 0)
- {
- /* We have no line number information. That means to stop
- stepping (does this always happen right after one instruction,
- when we do "s" in a function with no line numbers,
- or can this happen as a result of a return or longjmp?). */
- infrun_debug_printf ("line number info");
- end_stepping_range (ecs);
- return;
- }
- /* Look for "calls" to inlined functions, part one. If the inline
- frame machinery detected some skipped call sites, we have entered
- a new inline function. */
- if (frame_id_eq (get_frame_id (get_current_frame ()),
- ecs->event_thread->control.step_frame_id)
- && inline_skipped_frames (ecs->event_thread))
- {
- infrun_debug_printf ("stepped into inlined function");
- symtab_and_line call_sal = find_frame_sal (get_current_frame ());
- if (ecs->event_thread->control.step_over_calls != STEP_OVER_ALL)
- {
- /* For "step", we're going to stop. But if the call site
- for this inlined function is on the same source line as
- we were previously stepping, go down into the function
- first. Otherwise stop at the call site. */
- if (call_sal.line == ecs->event_thread->current_line
- && call_sal.symtab == ecs->event_thread->current_symtab)
- {
- step_into_inline_frame (ecs->event_thread);
- if (inline_frame_is_marked_for_skip (false, ecs->event_thread))
- {
- keep_going (ecs);
- return;
- }
- }
- end_stepping_range (ecs);
- return;
- }
- else
- {
- /* For "next", we should stop at the call site if it is on a
- different source line. Otherwise continue through the
- inlined function. */
- if (call_sal.line == ecs->event_thread->current_line
- && call_sal.symtab == ecs->event_thread->current_symtab)
- keep_going (ecs);
- else
- end_stepping_range (ecs);
- return;
- }
- }
- /* Look for "calls" to inlined functions, part two. If we are still
- in the same real function we were stepping through, but we have
- to go further up to find the exact frame ID, we are stepping
- through a more inlined call beyond its call site. */
- if (get_frame_type (get_current_frame ()) == INLINE_FRAME
- && !frame_id_eq (get_frame_id (get_current_frame ()),
- ecs->event_thread->control.step_frame_id)
- && stepped_in_from (get_current_frame (),
- ecs->event_thread->control.step_frame_id))
- {
- infrun_debug_printf ("stepping through inlined function");
- if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL
- || inline_frame_is_marked_for_skip (false, ecs->event_thread))
- keep_going (ecs);
- else
- end_stepping_range (ecs);
- return;
- }
- bool refresh_step_info = true;
- if ((ecs->event_thread->stop_pc () == stop_pc_sal.pc)
- && (ecs->event_thread->current_line != stop_pc_sal.line
- || ecs->event_thread->current_symtab != stop_pc_sal.symtab))
- {
- /* We are at a different line. */
- if (stop_pc_sal.is_stmt)
- {
- /* We are at the start of a statement.
- So stop. Note that we don't stop if we step into the middle of a
- statement. That is said to make things like for (;;) statements
- work better. */
- infrun_debug_printf ("stepped to a different line");
- end_stepping_range (ecs);
- return;
- }
- else if (frame_id_eq (get_frame_id (get_current_frame ()),
- ecs->event_thread->control.step_frame_id))
- {
- /* We are not at the start of a statement, and we have not changed
- frame.
- We ignore this line table entry, and continue stepping forward,
- looking for a better place to stop. */
- refresh_step_info = false;
- infrun_debug_printf ("stepped to a different line, but "
- "it's not the start of a statement");
- }
- else
- {
- /* We are not the start of a statement, and we have changed frame.
- We ignore this line table entry, and continue stepping forward,
- looking for a better place to stop. Keep refresh_step_info at
- true to note that the frame has changed, but ignore the line
- number to make sure we don't ignore a subsequent entry with the
- same line number. */
- stop_pc_sal.line = 0;
- infrun_debug_printf ("stepped to a different frame, but "
- "it's not the start of a statement");
- }
- }
- /* We aren't done stepping.
- Optimize by setting the stepping range to the line.
- (We might not be in the original line, but if we entered a
- new line in mid-statement, we continue stepping. This makes
- things like for(;;) statements work better.)
- If we entered a SAL that indicates a non-statement line table entry,
- then we update the stepping range, but we don't update the step info,
- which includes things like the line number we are stepping away from.
- This means we will stop when we find a line table entry that is marked
- as is-statement, even if it matches the non-statement one we just
- stepped into. */
- ecs->event_thread->control.step_range_start = stop_pc_sal.pc;
- ecs->event_thread->control.step_range_end = stop_pc_sal.end;
- ecs->event_thread->control.may_range_step = 1;
- infrun_debug_printf
- ("updated step range, start = %s, end = %s, may_range_step = %d",
- paddress (gdbarch, ecs->event_thread->control.step_range_start),
- paddress (gdbarch, ecs->event_thread->control.step_range_end),
- ecs->event_thread->control.may_range_step);
- if (refresh_step_info)
- set_step_info (ecs->event_thread, frame, stop_pc_sal);
- infrun_debug_printf ("keep going");
- keep_going (ecs);
- }
- static bool restart_stepped_thread (process_stratum_target *resume_target,
- ptid_t resume_ptid);
- /* In all-stop mode, if we're currently stepping but have stopped in
- some other thread, we may need to switch back to the stepped
- thread. Returns true we set the inferior running, false if we left
- it stopped (and the event needs further processing). */
- static bool
- switch_back_to_stepped_thread (struct execution_control_state *ecs)
- {
- if (!target_is_non_stop_p ())
- {
- /* If any thread is blocked on some internal breakpoint, and we
- simply need to step over that breakpoint to get it going
- again, do that first. */
- /* However, if we see an event for the stepping thread, then we
- know all other threads have been moved past their breakpoints
- already. Let the caller check whether the step is finished,
- etc., before deciding to move it past a breakpoint. */
- if (ecs->event_thread->control.step_range_end != 0)
- return false;
- /* Check if the current thread is blocked on an incomplete
- step-over, interrupted by a random signal. */
- if (ecs->event_thread->control.trap_expected
- && ecs->event_thread->stop_signal () != GDB_SIGNAL_TRAP)
- {
- infrun_debug_printf
- ("need to finish step-over of [%s]",
- ecs->event_thread->ptid.to_string ().c_str ());
- keep_going (ecs);
- return true;
- }
- /* Check if the current thread is blocked by a single-step
- breakpoint of another thread. */
- if (ecs->hit_singlestep_breakpoint)
- {
- infrun_debug_printf ("need to step [%s] over single-step breakpoint",
- ecs->ptid.to_string ().c_str ());
- keep_going (ecs);
- return true;
- }
- /* If this thread needs yet another step-over (e.g., stepping
- through a delay slot), do it first before moving on to
- another thread. */
- if (thread_still_needs_step_over (ecs->event_thread))
- {
- infrun_debug_printf
- ("thread [%s] still needs step-over",
- ecs->event_thread->ptid.to_string ().c_str ());
- keep_going (ecs);
- return true;
- }
- /* If scheduler locking applies even if not stepping, there's no
- need to walk over threads. Above we've checked whether the
- current thread is stepping. If some other thread not the
- event thread is stepping, then it must be that scheduler
- locking is not in effect. */
- if (schedlock_applies (ecs->event_thread))
- return false;
- /* Otherwise, we no longer expect a trap in the current thread.
- Clear the trap_expected flag before switching back -- this is
- what keep_going does as well, if we call it. */
- ecs->event_thread->control.trap_expected = 0;
- /* Likewise, clear the signal if it should not be passed. */
- if (!signal_program[ecs->event_thread->stop_signal ()])
- ecs->event_thread->set_stop_signal (GDB_SIGNAL_0);
- if (restart_stepped_thread (ecs->target, ecs->ptid))
- {
- prepare_to_wait (ecs);
- return true;
- }
- switch_to_thread (ecs->event_thread);
- }
- return false;
- }
- /* Look for the thread that was stepping, and resume it.
- RESUME_TARGET / RESUME_PTID indicate the set of threads the caller
- is resuming. Return true if a thread was started, false
- otherwise. */
- static bool
- restart_stepped_thread (process_stratum_target *resume_target,
- ptid_t resume_ptid)
- {
- /* Do all pending step-overs before actually proceeding with
- step/next/etc. */
- if (start_step_over ())
- return true;
- for (thread_info *tp : all_threads_safe ())
- {
- if (tp->state == THREAD_EXITED)
- continue;
- if (tp->has_pending_waitstatus ())
- continue;
- /* Ignore threads of processes the caller is not
- resuming. */
- if (!sched_multi
- && (tp->inf->process_target () != resume_target
- || tp->inf->pid != resume_ptid.pid ()))
- continue;
- if (tp->control.trap_expected)
- {
- infrun_debug_printf ("switching back to stepped thread (step-over)");
- if (keep_going_stepped_thread (tp))
- return true;
- }
- }
- for (thread_info *tp : all_threads_safe ())
- {
- if (tp->state == THREAD_EXITED)
- continue;
- if (tp->has_pending_waitstatus ())
- continue;
- /* Ignore threads of processes the caller is not
- resuming. */
- if (!sched_multi
- && (tp->inf->process_target () != resume_target
- || tp->inf->pid != resume_ptid.pid ()))
- continue;
- /* Did we find the stepping thread? */
- if (tp->control.step_range_end)
- {
- infrun_debug_printf ("switching back to stepped thread (stepping)");
- if (keep_going_stepped_thread (tp))
- return true;
- }
- }
- return false;
- }
- /* See infrun.h. */
- void
- restart_after_all_stop_detach (process_stratum_target *proc_target)
- {
- /* Note we don't check target_is_non_stop_p() here, because the
- current inferior may no longer have a process_stratum target
- pushed, as we just detached. */
- /* See if we have a THREAD_RUNNING thread that need to be
- re-resumed. If we have any thread that is already executing,
- then we don't need to resume the target -- it is already been
- resumed. With the remote target (in all-stop), it's even
- impossible to issue another resumption if the target is already
- resumed, until the target reports a stop. */
- for (thread_info *thr : all_threads (proc_target))
- {
- if (thr->state != THREAD_RUNNING)
- continue;
- /* If we have any thread that is already executing, then we
- don't need to resume the target -- it is already been
- resumed. */
- if (thr->executing ())
- return;
- /* If we have a pending event to process, skip resuming the
- target and go straight to processing it. */
- if (thr->resumed () && thr->has_pending_waitstatus ())
- return;
- }
- /* Alright, we need to re-resume the target. If a thread was
- stepping, we need to restart it stepping. */
- if (restart_stepped_thread (proc_target, minus_one_ptid))
- return;
- /* Otherwise, find the first THREAD_RUNNING thread and resume
- it. */
- for (thread_info *thr : all_threads (proc_target))
- {
- if (thr->state != THREAD_RUNNING)
- continue;
- execution_control_state ecs;
- reset_ecs (&ecs, thr);
- switch_to_thread (thr);
- keep_going (&ecs);
- return;
- }
- }
- /* Set a previously stepped thread back to stepping. Returns true on
- success, false if the resume is not possible (e.g., the thread
- vanished). */
- static bool
- keep_going_stepped_thread (struct thread_info *tp)
- {
- struct frame_info *frame;
- struct execution_control_state ecss;
- struct execution_control_state *ecs = &ecss;
- /* If the stepping thread exited, then don't try to switch back and
- resume it, which could fail in several different ways depending
- on the target. Instead, just keep going.
- We can find a stepping dead thread in the thread list in two
- cases:
- - The target supports thread exit events, and when the target
- tries to delete the thread from the thread list, inferior_ptid
- pointed at the exiting thread. In such case, calling
- delete_thread does not really remove the thread from the list;
- instead, the thread is left listed, with 'exited' state.
- - The target's debug interface does not support thread exit
- events, and so we have no idea whatsoever if the previously
- stepping thread is still alive. For that reason, we need to
- synchronously query the target now. */
- if (tp->state == THREAD_EXITED || !target_thread_alive (tp->ptid))
- {
- infrun_debug_printf ("not resuming previously stepped thread, it has "
- "vanished");
- delete_thread (tp);
- return false;
- }
- infrun_debug_printf ("resuming previously stepped thread");
- reset_ecs (ecs, tp);
- switch_to_thread (tp);
- tp->set_stop_pc (regcache_read_pc (get_thread_regcache (tp)));
- frame = get_current_frame ();
- /* If the PC of the thread we were trying to single-step has
- changed, then that thread has trapped or been signaled, but the
- event has not been reported to GDB yet. Re-poll the target
- looking for this particular thread's event (i.e. temporarily
- enable schedlock) by:
- - setting a break at the current PC
- - resuming that particular thread, only (by setting trap
- expected)
- This prevents us continuously moving the single-step breakpoint
- forward, one instruction at a time, overstepping. */
- if (tp->stop_pc () != tp->prev_pc)
- {
- ptid_t resume_ptid;
- infrun_debug_printf ("expected thread advanced also (%s -> %s)",
- paddress (target_gdbarch (), tp->prev_pc),
- paddress (target_gdbarch (), tp->stop_pc ()));
- /* Clear the info of the previous step-over, as it's no longer
- valid (if the thread was trying to step over a breakpoint, it
- has already succeeded). It's what keep_going would do too,
- if we called it. Do this before trying to insert the sss
- breakpoint, otherwise if we were previously trying to step
- over this exact address in another thread, the breakpoint is
- skipped. */
- clear_step_over_info ();
- tp->control.trap_expected = 0;
- insert_single_step_breakpoint (get_frame_arch (frame),
- get_frame_address_space (frame),
- tp->stop_pc ());
- tp->set_resumed (true);
- resume_ptid = internal_resume_ptid (tp->control.stepping_command);
- do_target_resume (resume_ptid, false, GDB_SIGNAL_0);
- }
- else
- {
- infrun_debug_printf ("expected thread still hasn't advanced");
- keep_going_pass_signal (ecs);
- }
- return true;
- }
- /* Is thread TP in the middle of (software or hardware)
- single-stepping? (Note the result of this function must never be
- passed directly as target_resume's STEP parameter.) */
- static bool
- currently_stepping (struct thread_info *tp)
- {
- return ((tp->control.step_range_end
- && tp->control.step_resume_breakpoint == NULL)
- || tp->control.trap_expected
- || tp->stepped_breakpoint
- || bpstat_should_step ());
- }
- /* Inferior has stepped into a subroutine call with source code that
- we should not step over. Do step to the first line of code in
- it. */
- static void
- handle_step_into_function (struct gdbarch *gdbarch,
- struct execution_control_state *ecs)
- {
- fill_in_stop_func (gdbarch, ecs);
- compunit_symtab *cust
- = find_pc_compunit_symtab (ecs->event_thread->stop_pc ());
- if (cust != NULL && compunit_language (cust) != language_asm)
- ecs->stop_func_start
- = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start);
- symtab_and_line stop_func_sal = find_pc_line (ecs->stop_func_start, 0);
- /* Use the step_resume_break to step until the end of the prologue,
- even if that involves jumps (as it seems to on the vax under
- 4.2). */
- /* If the prologue ends in the middle of a source line, continue to
- the end of that source line (if it is still within the function).
- Otherwise, just go to end of prologue. */
- if (stop_func_sal.end
- && stop_func_sal.pc != ecs->stop_func_start
- && stop_func_sal.end < ecs->stop_func_end)
- ecs->stop_func_start = stop_func_sal.end;
- /* Architectures which require breakpoint adjustment might not be able
- to place a breakpoint at the computed address. If so, the test
- ``ecs->stop_func_start == stop_pc'' will never succeed. Adjust
- ecs->stop_func_start to an address at which a breakpoint may be
- legitimately placed.
- Note: kevinb/2004-01-19: On FR-V, if this adjustment is not
- made, GDB will enter an infinite loop when stepping through
- optimized code consisting of VLIW instructions which contain
- subinstructions corresponding to different source lines. On
- FR-V, it's not permitted to place a breakpoint on any but the
- first subinstruction of a VLIW instruction. When a breakpoint is
- set, GDB will adjust the breakpoint address to the beginning of
- the VLIW instruction. Thus, we need to make the corresponding
- adjustment here when computing the stop address. */
- if (gdbarch_adjust_breakpoint_address_p (gdbarch))
- {
- ecs->stop_func_start
- = gdbarch_adjust_breakpoint_address (gdbarch,
- ecs->stop_func_start);
- }
- if (ecs->stop_func_start == ecs->event_thread->stop_pc ())
- {
- /* We are already there: stop now. */
- end_stepping_range (ecs);
- return;
- }
- else
- {
- /* Put the step-breakpoint there and go until there. */
- symtab_and_line sr_sal;
- sr_sal.pc = ecs->stop_func_start;
- sr_sal.section = find_pc_overlay (ecs->stop_func_start);
- sr_sal.pspace = get_frame_program_space (get_current_frame ());
- /* Do not specify what the fp should be when we stop since on
- some machines the prologue is where the new fp value is
- established. */
- insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal, null_frame_id);
- /* And make sure stepping stops right away then. */
- ecs->event_thread->control.step_range_end
- = ecs->event_thread->control.step_range_start;
- }
- keep_going (ecs);
- }
- /* Inferior has stepped backward into a subroutine call with source
- code that we should not step over. Do step to the beginning of the
- last line of code in it. */
- static void
- handle_step_into_function_backward (struct gdbarch *gdbarch,
- struct execution_control_state *ecs)
- {
- struct compunit_symtab *cust;
- struct symtab_and_line stop_func_sal;
- fill_in_stop_func (gdbarch, ecs);
- cust = find_pc_compunit_symtab (ecs->event_thread->stop_pc ());
- if (cust != NULL && compunit_language (cust) != language_asm)
- ecs->stop_func_start
- = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start);
- stop_func_sal = find_pc_line (ecs->event_thread->stop_pc (), 0);
- /* OK, we're just going to keep stepping here. */
- if (stop_func_sal.pc == ecs->event_thread->stop_pc ())
- {
- /* We're there already. Just stop stepping now. */
- end_stepping_range (ecs);
- }
- else
- {
- /* Else just reset the step range and keep going.
- No step-resume breakpoint, they don't work for
- epilogues, which can have multiple entry paths. */
- ecs->event_thread->control.step_range_start = stop_func_sal.pc;
- ecs->event_thread->control.step_range_end = stop_func_sal.end;
- keep_going (ecs);
- }
- return;
- }
- /* Insert a "step-resume breakpoint" at SR_SAL with frame ID SR_ID.
- This is used to both functions and to skip over code. */
- static void
- insert_step_resume_breakpoint_at_sal_1 (struct gdbarch *gdbarch,
- struct symtab_and_line sr_sal,
- struct frame_id sr_id,
- enum bptype sr_type)
- {
- /* There should never be more than one step-resume or longjmp-resume
- breakpoint per thread, so we should never be setting a new
- step_resume_breakpoint when one is already active. */
- gdb_assert (inferior_thread ()->control.step_resume_breakpoint == NULL);
- gdb_assert (sr_type == bp_step_resume || sr_type == bp_hp_step_resume);
- infrun_debug_printf ("inserting step-resume breakpoint at %s",
- paddress (gdbarch, sr_sal.pc));
- inferior_thread ()->control.step_resume_breakpoint
- = set_momentary_breakpoint (gdbarch, sr_sal, sr_id, sr_type).release ();
- }
- void
- insert_step_resume_breakpoint_at_sal (struct gdbarch *gdbarch,
- struct symtab_and_line sr_sal,
- struct frame_id sr_id)
- {
- insert_step_resume_breakpoint_at_sal_1 (gdbarch,
- sr_sal, sr_id,
- bp_step_resume);
- }
- /* Insert a "high-priority step-resume breakpoint" at RETURN_FRAME.pc.
- This is used to skip a potential signal handler.
- This is called with the interrupted function's frame. The signal
- handler, when it returns, will resume the interrupted function at
- RETURN_FRAME.pc. */
- static void
- insert_hp_step_resume_breakpoint_at_frame (struct frame_info *return_frame)
- {
- gdb_assert (return_frame != NULL);
- struct gdbarch *gdbarch = get_frame_arch (return_frame);
- symtab_and_line sr_sal;
- sr_sal.pc = gdbarch_addr_bits_remove (gdbarch, get_frame_pc (return_frame));
- sr_sal.section = find_pc_overlay (sr_sal.pc);
- sr_sal.pspace = get_frame_program_space (return_frame);
- insert_step_resume_breakpoint_at_sal_1 (gdbarch, sr_sal,
- get_stack_frame_id (return_frame),
- bp_hp_step_resume);
- }
- /* Insert a "step-resume breakpoint" at the previous frame's PC. This
- is used to skip a function after stepping into it (for "next" or if
- the called function has no debugging information).
- The current function has almost always been reached by single
- stepping a call or return instruction. NEXT_FRAME belongs to the
- current function, and the breakpoint will be set at the caller's
- resume address.
- This is a separate function rather than reusing
- insert_hp_step_resume_breakpoint_at_frame in order to avoid
- get_prev_frame, which may stop prematurely (see the implementation
- of frame_unwind_caller_id for an example). */
- static void
- insert_step_resume_breakpoint_at_caller (struct frame_info *next_frame)
- {
- /* We shouldn't have gotten here if we don't know where the call site
- is. */
- gdb_assert (frame_id_p (frame_unwind_caller_id (next_frame)));
- struct gdbarch *gdbarch = frame_unwind_caller_arch (next_frame);
- symtab_and_line sr_sal;
- sr_sal.pc = gdbarch_addr_bits_remove (gdbarch,
- frame_unwind_caller_pc (next_frame));
- sr_sal.section = find_pc_overlay (sr_sal.pc);
- sr_sal.pspace = frame_unwind_program_space (next_frame);
- insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
- frame_unwind_caller_id (next_frame));
- }
- /* Insert a "longjmp-resume" breakpoint at PC. This is used to set a
- new breakpoint at the target of a jmp_buf. The handling of
- longjmp-resume uses the same mechanisms used for handling
- "step-resume" breakpoints. */
- static void
- insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- /* There should never be more than one longjmp-resume breakpoint per
- thread, so we should never be setting a new
- longjmp_resume_breakpoint when one is already active. */
- gdb_assert (inferior_thread ()->control.exception_resume_breakpoint == NULL);
- infrun_debug_printf ("inserting longjmp-resume breakpoint at %s",
- paddress (gdbarch, pc));
- inferior_thread ()->control.exception_resume_breakpoint =
- set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume).release ();
- }
- /* Insert an exception resume breakpoint. TP is the thread throwing
- the exception. The block B is the block of the unwinder debug hook
- function. FRAME is the frame corresponding to the call to this
- function. SYM is the symbol of the function argument holding the
- target PC of the exception. */
- static void
- insert_exception_resume_breakpoint (struct thread_info *tp,
- const struct block *b,
- struct frame_info *frame,
- struct symbol *sym)
- {
- try
- {
- struct block_symbol vsym;
- struct value *value;
- CORE_ADDR handler;
- struct breakpoint *bp;
- vsym = lookup_symbol_search_name (sym->search_name (),
- b, VAR_DOMAIN);
- value = read_var_value (vsym.symbol, vsym.block, frame);
- /* If the value was optimized out, revert to the old behavior. */
- if (! value_optimized_out (value))
- {
- handler = value_as_address (value);
- infrun_debug_printf ("exception resume at %lx",
- (unsigned long) handler);
- bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
- handler,
- bp_exception_resume).release ();
- /* set_momentary_breakpoint_at_pc invalidates FRAME. */
- frame = NULL;
- bp->thread = tp->global_num;
- inferior_thread ()->control.exception_resume_breakpoint = bp;
- }
- }
- catch (const gdb_exception_error &e)
- {
- /* We want to ignore errors here. */
- }
- }
- /* A helper for check_exception_resume that sets an
- exception-breakpoint based on a SystemTap probe. */
- static void
- insert_exception_resume_from_probe (struct thread_info *tp,
- const struct bound_probe *probe,
- struct frame_info *frame)
- {
- struct value *arg_value;
- CORE_ADDR handler;
- struct breakpoint *bp;
- arg_value = probe_safe_evaluate_at_pc (frame, 1);
- if (!arg_value)
- return;
- handler = value_as_address (arg_value);
- infrun_debug_printf ("exception resume at %s",
- paddress (probe->objfile->arch (), handler));
- bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
- handler, bp_exception_resume).release ();
- bp->thread = tp->global_num;
- inferior_thread ()->control.exception_resume_breakpoint = bp;
- }
- /* This is called when an exception has been intercepted. Check to
- see whether the exception's destination is of interest, and if so,
- set an exception resume breakpoint there. */
- static void
- check_exception_resume (struct execution_control_state *ecs,
- struct frame_info *frame)
- {
- struct bound_probe probe;
- struct symbol *func;
- /* First see if this exception unwinding breakpoint was set via a
- SystemTap probe point. If so, the probe has two arguments: the
- CFA and the HANDLER. We ignore the CFA, extract the handler, and
- set a breakpoint there. */
- probe = find_probe_by_pc (get_frame_pc (frame));
- if (probe.prob)
- {
- insert_exception_resume_from_probe (ecs->event_thread, &probe, frame);
- return;
- }
- func = get_frame_function (frame);
- if (!func)
- return;
- try
- {
- const struct block *b;
- struct block_iterator iter;
- struct symbol *sym;
- int argno = 0;
- /* The exception breakpoint is a thread-specific breakpoint on
- the unwinder's debug hook, declared as:
-
- void _Unwind_DebugHook (void *cfa, void *handler);
-
- The CFA argument indicates the frame to which control is
- about to be transferred. HANDLER is the destination PC.
-
- We ignore the CFA and set a temporary breakpoint at HANDLER.
- This is not extremely efficient but it avoids issues in gdb
- with computing the DWARF CFA, and it also works even in weird
- cases such as throwing an exception from inside a signal
- handler. */
- b = SYMBOL_BLOCK_VALUE (func);
- ALL_BLOCK_SYMBOLS (b, iter, sym)
- {
- if (!sym->is_argument ())
- continue;
- if (argno == 0)
- ++argno;
- else
- {
- insert_exception_resume_breakpoint (ecs->event_thread,
- b, frame, sym);
- break;
- }
- }
- }
- catch (const gdb_exception_error &e)
- {
- }
- }
- static void
- stop_waiting (struct execution_control_state *ecs)
- {
- infrun_debug_printf ("stop_waiting");
- /* Let callers know we don't want to wait for the inferior anymore. */
- ecs->wait_some_more = 0;
- /* If all-stop, but there exists a non-stop target, stop all
- threads now that we're presenting the stop to the user. */
- if (!non_stop && exists_non_stop_target ())
- stop_all_threads ("presenting stop to user in all-stop");
- }
- /* Like keep_going, but passes the signal to the inferior, even if the
- signal is set to nopass. */
- static void
- keep_going_pass_signal (struct execution_control_state *ecs)
- {
- gdb_assert (ecs->event_thread->ptid == inferior_ptid);
- gdb_assert (!ecs->event_thread->resumed ());
- /* Save the pc before execution, to compare with pc after stop. */
- ecs->event_thread->prev_pc
- = regcache_read_pc_protected (get_thread_regcache (ecs->event_thread));
- if (ecs->event_thread->control.trap_expected)
- {
- struct thread_info *tp = ecs->event_thread;
- infrun_debug_printf ("%s has trap_expected set, "
- "resuming to collect trap",
- tp->ptid.to_string ().c_str ());
- /* We haven't yet gotten our trap, and either: intercepted a
- non-signal event (e.g., a fork); or took a signal which we
- are supposed to pass through to the inferior. Simply
- continue. */
- resume (ecs->event_thread->stop_signal ());
- }
- else if (step_over_info_valid_p ())
- {
- /* Another thread is stepping over a breakpoint in-line. If
- this thread needs a step-over too, queue the request. In
- either case, this resume must be deferred for later. */
- struct thread_info *tp = ecs->event_thread;
- if (ecs->hit_singlestep_breakpoint
- || thread_still_needs_step_over (tp))
- {
- infrun_debug_printf ("step-over already in progress: "
- "step-over for %s deferred",
- tp->ptid.to_string ().c_str ());
- global_thread_step_over_chain_enqueue (tp);
- }
- else
- infrun_debug_printf ("step-over in progress: resume of %s deferred",
- tp->ptid.to_string ().c_str ());
- }
- else
- {
- struct regcache *regcache = get_current_regcache ();
- int remove_bp;
- int remove_wps;
- step_over_what step_what;
- /* Either the trap was not expected, but we are continuing
- anyway (if we got a signal, the user asked it be passed to
- the child)
- -- or --
- We got our expected trap, but decided we should resume from
- it.
- We're going to run this baby now!
- Note that insert_breakpoints won't try to re-insert
- already inserted breakpoints. Therefore, we don't
- care if breakpoints were already inserted, or not. */
- /* If we need to step over a breakpoint, and we're not using
- displaced stepping to do so, insert all breakpoints
- (watchpoints, etc.) but the one we're stepping over, step one
- instruction, and then re-insert the breakpoint when that step
- is finished. */
- step_what = thread_still_needs_step_over (ecs->event_thread);
- remove_bp = (ecs->hit_singlestep_breakpoint
- || (step_what & STEP_OVER_BREAKPOINT));
- remove_wps = (step_what & STEP_OVER_WATCHPOINT);
- /* We can't use displaced stepping if we need to step past a
- watchpoint. The instruction copied to the scratch pad would
- still trigger the watchpoint. */
- if (remove_bp
- && (remove_wps || !use_displaced_stepping (ecs->event_thread)))
- {
- set_step_over_info (regcache->aspace (),
- regcache_read_pc (regcache), remove_wps,
- ecs->event_thread->global_num);
- }
- else if (remove_wps)
- set_step_over_info (NULL, 0, remove_wps, -1);
- /* If we now need to do an in-line step-over, we need to stop
- all other threads. Note this must be done before
- insert_breakpoints below, because that removes the breakpoint
- we're about to step over, otherwise other threads could miss
- it. */
- if (step_over_info_valid_p () && target_is_non_stop_p ())
- stop_all_threads ("starting in-line step-over");
- /* Stop stepping if inserting breakpoints fails. */
- try
- {
- insert_breakpoints ();
- }
- catch (const gdb_exception_error &e)
- {
- exception_print (gdb_stderr, e);
- stop_waiting (ecs);
- clear_step_over_info ();
- return;
- }
- ecs->event_thread->control.trap_expected = (remove_bp || remove_wps);
- resume (ecs->event_thread->stop_signal ());
- }
- prepare_to_wait (ecs);
- }
- /* Called when we should continue running the inferior, because the
- current event doesn't cause a user visible stop. This does the
- resuming part; waiting for the next event is done elsewhere. */
- static void
- keep_going (struct execution_control_state *ecs)
- {
- if (ecs->event_thread->control.trap_expected
- && ecs->event_thread->stop_signal () == GDB_SIGNAL_TRAP)
- ecs->event_thread->control.trap_expected = 0;
- if (!signal_program[ecs->event_thread->stop_signal ()])
- ecs->event_thread->set_stop_signal (GDB_SIGNAL_0);
- keep_going_pass_signal (ecs);
- }
- /* This function normally comes after a resume, before
- handle_inferior_event exits. It takes care of any last bits of
- housekeeping, and sets the all-important wait_some_more flag. */
- static void
- prepare_to_wait (struct execution_control_state *ecs)
- {
- infrun_debug_printf ("prepare_to_wait");
- ecs->wait_some_more = 1;
- /* If the target can't async, emulate it by marking the infrun event
- handler such that as soon as we get back to the event-loop, we
- immediately end up in fetch_inferior_event again calling
- target_wait. */
- if (!target_can_async_p ())
- mark_infrun_async_event_handler ();
- }
- /* We are done with the step range of a step/next/si/ni command.
- Called once for each n of a "step n" operation. */
- static void
- end_stepping_range (struct execution_control_state *ecs)
- {
- ecs->event_thread->control.stop_step = 1;
- stop_waiting (ecs);
- }
- /* Several print_*_reason functions to print why the inferior has stopped.
- We always print something when the inferior exits, or receives a signal.
- The rest of the cases are dealt with later on in normal_stop and
- print_it_typical. Ideally there should be a call to one of these
- print_*_reason functions functions from handle_inferior_event each time
- stop_waiting is called.
- Note that we don't call these directly, instead we delegate that to
- the interpreters, through observers. Interpreters then call these
- with whatever uiout is right. */
- void
- print_end_stepping_range_reason (struct ui_out *uiout)
- {
- /* For CLI-like interpreters, print nothing. */
- if (uiout->is_mi_like_p ())
- {
- uiout->field_string ("reason",
- async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
- }
- }
- void
- print_signal_exited_reason (struct ui_out *uiout, enum gdb_signal siggnal)
- {
- annotate_signalled ();
- if (uiout->is_mi_like_p ())
- uiout->field_string
- ("reason", async_reason_lookup (EXEC_ASYNC_EXITED_SIGNALLED));
- uiout->text ("\nProgram terminated with signal ");
- annotate_signal_name ();
- uiout->field_string ("signal-name",
- gdb_signal_to_name (siggnal));
- annotate_signal_name_end ();
- uiout->text (", ");
- annotate_signal_string ();
- uiout->field_string ("signal-meaning",
- gdb_signal_to_string (siggnal));
- annotate_signal_string_end ();
- uiout->text (".\n");
- uiout->text ("The program no longer exists.\n");
- }
- void
- print_exited_reason (struct ui_out *uiout, int exitstatus)
- {
- struct inferior *inf = current_inferior ();
- std::string pidstr = target_pid_to_str (ptid_t (inf->pid));
- annotate_exited (exitstatus);
- if (exitstatus)
- {
- if (uiout->is_mi_like_p ())
- uiout->field_string ("reason", async_reason_lookup (EXEC_ASYNC_EXITED));
- std::string exit_code_str
- = string_printf ("0%o", (unsigned int) exitstatus);
- uiout->message ("[Inferior %s (%s) exited with code %pF]\n",
- plongest (inf->num), pidstr.c_str (),
- string_field ("exit-code", exit_code_str.c_str ()));
- }
- else
- {
- if (uiout->is_mi_like_p ())
- uiout->field_string
- ("reason", async_reason_lookup (EXEC_ASYNC_EXITED_NORMALLY));
- uiout->message ("[Inferior %s (%s) exited normally]\n",
- plongest (inf->num), pidstr.c_str ());
- }
- }
- void
- print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
- {
- struct thread_info *thr = inferior_thread ();
- annotate_signal ();
- if (uiout->is_mi_like_p ())
- ;
- else if (show_thread_that_caused_stop ())
- {
- uiout->text ("\nThread ");
- uiout->field_string ("thread-id", print_thread_id (thr));
- const char *name = thread_name (thr);
- if (name != NULL)
- {
- uiout->text (" \"");
- uiout->field_string ("name", name);
- uiout->text ("\"");
- }
- }
- else
- uiout->text ("\nProgram");
- if (siggnal == GDB_SIGNAL_0 && !uiout->is_mi_like_p ())
- uiout->text (" stopped");
- else
- {
- uiout->text (" received signal ");
- annotate_signal_name ();
- if (uiout->is_mi_like_p ())
- uiout->field_string
- ("reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
- uiout->field_string ("signal-name", gdb_signal_to_name (siggnal));
- annotate_signal_name_end ();
- uiout->text (", ");
- annotate_signal_string ();
- uiout->field_string ("signal-meaning", gdb_signal_to_string (siggnal));
- struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = regcache->arch ();
- if (gdbarch_report_signal_info_p (gdbarch))
- gdbarch_report_signal_info (gdbarch, uiout, siggnal);
- annotate_signal_string_end ();
- }
- uiout->text (".\n");
- }
- void
- print_no_history_reason (struct ui_out *uiout)
- {
- uiout->text ("\nNo more reverse-execution history.\n");
- }
- /* Print current location without a level number, if we have changed
- functions or hit a breakpoint. Print source line if we have one.
- bpstat_print contains the logic deciding in detail what to print,
- based on the event(s) that just occurred. */
- static void
- print_stop_location (const target_waitstatus &ws)
- {
- int bpstat_ret;
- enum print_what source_flag;
- int do_frame_printing = 1;
- struct thread_info *tp = inferior_thread ();
- bpstat_ret = bpstat_print (tp->control.stop_bpstat, ws.kind ());
- switch (bpstat_ret)
- {
- case PRINT_UNKNOWN:
- /* FIXME: cagney/2002-12-01: Given that a frame ID does (or
- should) carry around the function and does (or should) use
- that when doing a frame comparison. */
- if (tp->control.stop_step
- && frame_id_eq (tp->control.step_frame_id,
- get_frame_id (get_current_frame ()))
- && (tp->control.step_start_function
- == find_pc_function (tp->stop_pc ())))
- {
- /* Finished step, just print source line. */
- source_flag = SRC_LINE;
- }
- else
- {
- /* Print location and source line. */
- source_flag = SRC_AND_LOC;
- }
- break;
- case PRINT_SRC_AND_LOC:
- /* Print location and source line. */
- source_flag = SRC_AND_LOC;
- break;
- case PRINT_SRC_ONLY:
- source_flag = SRC_LINE;
- break;
- case PRINT_NOTHING:
- /* Something bogus. */
- source_flag = SRC_LINE;
- do_frame_printing = 0;
- break;
- default:
- internal_error (__FILE__, __LINE__, _("Unknown value."));
- }
- /* The behavior of this routine with respect to the source
- flag is:
- SRC_LINE: Print only source line
- LOCATION: Print only location
- SRC_AND_LOC: Print location and source line. */
- if (do_frame_printing)
- print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
- }
- /* See infrun.h. */
- void
- print_stop_event (struct ui_out *uiout, bool displays)
- {
- struct target_waitstatus last;
- struct thread_info *tp;
- get_last_target_status (nullptr, nullptr, &last);
- {
- scoped_restore save_uiout = make_scoped_restore (¤t_uiout, uiout);
- print_stop_location (last);
- /* Display the auto-display expressions. */
- if (displays)
- do_displays ();
- }
- tp = inferior_thread ();
- if (tp->thread_fsm () != nullptr
- && tp->thread_fsm ()->finished_p ())
- {
- struct return_value_info *rv;
- rv = tp->thread_fsm ()->return_value ();
- if (rv != nullptr)
- print_return_value (uiout, rv);
- }
- }
- /* See infrun.h. */
- void
- maybe_remove_breakpoints (void)
- {
- if (!breakpoints_should_be_inserted_now () && target_has_execution ())
- {
- if (remove_breakpoints ())
- {
- target_terminal::ours_for_output ();
- gdb_printf (_("Cannot remove breakpoints because "
- "program is no longer writable.\nFurther "
- "execution is probably impossible.\n"));
- }
- }
- }
- /* The execution context that just caused a normal stop. */
- struct stop_context
- {
- stop_context ();
- DISABLE_COPY_AND_ASSIGN (stop_context);
- bool changed () const;
- /* The stop ID. */
- ULONGEST stop_id;
- /* The event PTID. */
- ptid_t ptid;
- /* If stopp for a thread event, this is the thread that caused the
- stop. */
- thread_info_ref thread;
- /* The inferior that caused the stop. */
- int inf_num;
- };
- /* Initializes a new stop context. If stopped for a thread event, this
- takes a strong reference to the thread. */
- stop_context::stop_context ()
- {
- stop_id = get_stop_id ();
- ptid = inferior_ptid;
- inf_num = current_inferior ()->num;
- if (inferior_ptid != null_ptid)
- {
- /* Take a strong reference so that the thread can't be deleted
- yet. */
- thread = thread_info_ref::new_reference (inferior_thread ());
- }
- }
- /* Return true if the current context no longer matches the saved stop
- context. */
- bool
- stop_context::changed () const
- {
- if (ptid != inferior_ptid)
- return true;
- if (inf_num != current_inferior ()->num)
- return true;
- if (thread != NULL && thread->state != THREAD_STOPPED)
- return true;
- if (get_stop_id () != stop_id)
- return true;
- return false;
- }
- /* See infrun.h. */
- int
- normal_stop (void)
- {
- struct target_waitstatus last;
- get_last_target_status (nullptr, nullptr, &last);
- new_stop_id ();
- /* If an exception is thrown from this point on, make sure to
- propagate GDB's knowledge of the executing state to the
- frontend/user running state. A QUIT is an easy exception to see
- here, so do this before any filtered output. */
- ptid_t finish_ptid = null_ptid;
- if (!non_stop)
- finish_ptid = minus_one_ptid;
- else if (last.kind () == TARGET_WAITKIND_SIGNALLED
- || last.kind () == TARGET_WAITKIND_EXITED)
- {
- /* On some targets, we may still have live threads in the
- inferior when we get a process exit event. E.g., for
- "checkpoint", when the current checkpoint/fork exits,
- linux-fork.c automatically switches to another fork from
- within target_mourn_inferior. */
- if (inferior_ptid != null_ptid)
- finish_ptid = ptid_t (inferior_ptid.pid ());
- }
- else if (last.kind () != TARGET_WAITKIND_NO_RESUMED)
- finish_ptid = inferior_ptid;
- gdb::optional<scoped_finish_thread_state> maybe_finish_thread_state;
- if (finish_ptid != null_ptid)
- {
- maybe_finish_thread_state.emplace
- (user_visible_resume_target (finish_ptid), finish_ptid);
- }
- /* As we're presenting a stop, and potentially removing breakpoints,
- update the thread list so we can tell whether there are threads
- running on the target. With target remote, for example, we can
- only learn about new threads when we explicitly update the thread
- list. Do this before notifying the interpreters about signal
- stops, end of stepping ranges, etc., so that the "new thread"
- output is emitted before e.g., "Program received signal FOO",
- instead of after. */
- update_thread_list ();
- if (last.kind () == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
- gdb::observers::signal_received.notify (inferior_thread ()->stop_signal ());
- /* As with the notification of thread events, we want to delay
- notifying the user that we've switched thread context until
- the inferior actually stops.
- There's no point in saying anything if the inferior has exited.
- Note that SIGNALLED here means "exited with a signal", not
- "received a signal".
- Also skip saying anything in non-stop mode. In that mode, as we
- don't want GDB to switch threads behind the user's back, to avoid
- races where the user is typing a command to apply to thread x,
- but GDB switches to thread y before the user finishes entering
- the command, fetch_inferior_event installs a cleanup to restore
- the current thread back to the thread the user had selected right
- after this event is handled, so we're not really switching, only
- informing of a stop. */
- if (!non_stop
- && previous_inferior_ptid != inferior_ptid
- && target_has_execution ()
- && last.kind () != TARGET_WAITKIND_SIGNALLED
- && last.kind () != TARGET_WAITKIND_EXITED
- && last.kind () != TARGET_WAITKIND_NO_RESUMED)
- {
- SWITCH_THRU_ALL_UIS ()
- {
- target_terminal::ours_for_output ();
- gdb_printf (_("[Switching to %s]\n"),
- target_pid_to_str (inferior_ptid).c_str ());
- annotate_thread_changed ();
- }
- previous_inferior_ptid = inferior_ptid;
- }
- if (last.kind () == TARGET_WAITKIND_NO_RESUMED)
- {
- SWITCH_THRU_ALL_UIS ()
- if (current_ui->prompt_state == PROMPT_BLOCKED)
- {
- target_terminal::ours_for_output ();
- gdb_printf (_("No unwaited-for children left.\n"));
- }
- }
- /* Note: this depends on the update_thread_list call above. */
- maybe_remove_breakpoints ();
- /* If an auto-display called a function and that got a signal,
- delete that auto-display to avoid an infinite recursion. */
- if (stopped_by_random_signal)
- disable_current_display ();
- SWITCH_THRU_ALL_UIS ()
- {
- async_enable_stdin ();
- }
- /* Let the user/frontend see the threads as stopped. */
- maybe_finish_thread_state.reset ();
- /* Select innermost stack frame - i.e., current frame is frame 0,
- and current location is based on that. Handle the case where the
- dummy call is returning after being stopped. E.g. the dummy call
- previously hit a breakpoint. (If the dummy call returns
- normally, we won't reach here.) Do this before the stop hook is
- run, so that it doesn't get to see the temporary dummy frame,
- which is not where we'll present the stop. */
- if (has_stack_frames ())
- {
- if (stop_stack_dummy == STOP_STACK_DUMMY)
- {
- /* Pop the empty frame that contains the stack dummy. This
- also restores inferior state prior to the call (struct
- infcall_suspend_state). */
- struct frame_info *frame = get_current_frame ();
- gdb_assert (get_frame_type (frame) == DUMMY_FRAME);
- frame_pop (frame);
- /* frame_pop calls reinit_frame_cache as the last thing it
- does which means there's now no selected frame. */
- }
- select_frame (get_current_frame ());
- /* Set the current source location. */
- set_current_sal_from_frame (get_current_frame ());
- }
- /* Look up the hook_stop and run it (CLI internally handles problem
- of stop_command's pre-hook not existing). */
- stop_context saved_context;
- try
- {
- execute_cmd_pre_hook (stop_command);
- }
- catch (const gdb_exception &ex)
- {
- exception_fprintf (gdb_stderr, ex,
- "Error while running hook_stop:\n");
- }
- /* If the stop hook resumes the target, then there's no point in
- trying to notify about the previous stop; its context is
- gone. Likewise if the command switches thread or inferior --
- the observers would print a stop for the wrong
- thread/inferior. */
- if (saved_context.changed ())
- return 1;
- /* Notify observers about the stop. This is where the interpreters
- print the stop event. */
- if (inferior_ptid != null_ptid)
- gdb::observers::normal_stop.notify (inferior_thread ()->control.stop_bpstat,
- stop_print_frame);
- else
- gdb::observers::normal_stop.notify (NULL, stop_print_frame);
- annotate_stopped ();
- if (target_has_execution ())
- {
- if (last.kind () != TARGET_WAITKIND_SIGNALLED
- && last.kind () != TARGET_WAITKIND_EXITED
- && last.kind () != TARGET_WAITKIND_NO_RESUMED)
- /* Delete the breakpoint we stopped at, if it wants to be deleted.
- Delete any breakpoint that is to be deleted at the next stop. */
- breakpoint_auto_delete (inferior_thread ()->control.stop_bpstat);
- }
- /* Try to get rid of automatically added inferiors that are no
- longer needed. Keeping those around slows down things linearly.
- Note that this never removes the current inferior. */
- prune_inferiors ();
- return 0;
- }
- int
- signal_stop_state (int signo)
- {
- return signal_stop[signo];
- }
- int
- signal_print_state (int signo)
- {
- return signal_print[signo];
- }
- int
- signal_pass_state (int signo)
- {
- return signal_program[signo];
- }
- static void
- signal_cache_update (int signo)
- {
- if (signo == -1)
- {
- for (signo = 0; signo < (int) GDB_SIGNAL_LAST; signo++)
- signal_cache_update (signo);
- return;
- }
- signal_pass[signo] = (signal_stop[signo] == 0
- && signal_print[signo] == 0
- && signal_program[signo] == 1
- && signal_catch[signo] == 0);
- }
- int
- signal_stop_update (int signo, int state)
- {
- int ret = signal_stop[signo];
- signal_stop[signo] = state;
- signal_cache_update (signo);
- return ret;
- }
- int
- signal_print_update (int signo, int state)
- {
- int ret = signal_print[signo];
- signal_print[signo] = state;
- signal_cache_update (signo);
- return ret;
- }
- int
- signal_pass_update (int signo, int state)
- {
- int ret = signal_program[signo];
- signal_program[signo] = state;
- signal_cache_update (signo);
- return ret;
- }
- /* Update the global 'signal_catch' from INFO and notify the
- target. */
- void
- signal_catch_update (const unsigned int *info)
- {
- int i;
- for (i = 0; i < GDB_SIGNAL_LAST; ++i)
- signal_catch[i] = info[i] > 0;
- signal_cache_update (-1);
- target_pass_signals (signal_pass);
- }
- static void
- sig_print_header (void)
- {
- gdb_printf (_("Signal Stop\tPrint\tPass "
- "to program\tDescription\n"));
- }
- static void
- sig_print_info (enum gdb_signal oursig)
- {
- const char *name = gdb_signal_to_name (oursig);
- int name_padding = 13 - strlen (name);
- if (name_padding <= 0)
- name_padding = 0;
- gdb_printf ("%s", name);
- gdb_printf ("%*.*s ", name_padding, name_padding, " ");
- gdb_printf ("%s\t", signal_stop[oursig] ? "Yes" : "No");
- gdb_printf ("%s\t", signal_print[oursig] ? "Yes" : "No");
- gdb_printf ("%s\t\t", signal_program[oursig] ? "Yes" : "No");
- gdb_printf ("%s\n", gdb_signal_to_string (oursig));
- }
- /* Specify how various signals in the inferior should be handled. */
- static void
- handle_command (const char *args, int from_tty)
- {
- int digits, wordlen;
- int sigfirst, siglast;
- enum gdb_signal oursig;
- int allsigs;
- if (args == NULL)
- {
- error_no_arg (_("signal to handle"));
- }
- /* Allocate and zero an array of flags for which signals to handle. */
- const size_t nsigs = GDB_SIGNAL_LAST;
- unsigned char sigs[nsigs] {};
- /* Break the command line up into args. */
- gdb_argv built_argv (args);
- /* Walk through the args, looking for signal oursigs, signal names, and
- actions. Signal numbers and signal names may be interspersed with
- actions, with the actions being performed for all signals cumulatively
- specified. Signal ranges can be specified as <LOW>-<HIGH>. */
- for (char *arg : built_argv)
- {
- wordlen = strlen (arg);
- for (digits = 0; isdigit (arg[digits]); digits++)
- {;
- }
- allsigs = 0;
- sigfirst = siglast = -1;
- if (wordlen >= 1 && !strncmp (arg, "all", wordlen))
- {
- /* Apply action to all signals except those used by the
- debugger. Silently skip those. */
- allsigs = 1;
- sigfirst = 0;
- siglast = nsigs - 1;
- }
- else if (wordlen >= 1 && !strncmp (arg, "stop", wordlen))
- {
- SET_SIGS (nsigs, sigs, signal_stop);
- SET_SIGS (nsigs, sigs, signal_print);
- }
- else if (wordlen >= 1 && !strncmp (arg, "ignore", wordlen))
- {
- UNSET_SIGS (nsigs, sigs, signal_program);
- }
- else if (wordlen >= 2 && !strncmp (arg, "print", wordlen))
- {
- SET_SIGS (nsigs, sigs, signal_print);
- }
- else if (wordlen >= 2 && !strncmp (arg, "pass", wordlen))
- {
- SET_SIGS (nsigs, sigs, signal_program);
- }
- else if (wordlen >= 3 && !strncmp (arg, "nostop", wordlen))
- {
- UNSET_SIGS (nsigs, sigs, signal_stop);
- }
- else if (wordlen >= 3 && !strncmp (arg, "noignore", wordlen))
- {
- SET_SIGS (nsigs, sigs, signal_program);
- }
- else if (wordlen >= 4 && !strncmp (arg, "noprint", wordlen))
- {
- UNSET_SIGS (nsigs, sigs, signal_print);
- UNSET_SIGS (nsigs, sigs, signal_stop);
- }
- else if (wordlen >= 4 && !strncmp (arg, "nopass", wordlen))
- {
- UNSET_SIGS (nsigs, sigs, signal_program);
- }
- else if (digits > 0)
- {
- /* It is numeric. The numeric signal refers to our own
- internal signal numbering from target.h, not to host/target
- signal number. This is a feature; users really should be
- using symbolic names anyway, and the common ones like
- SIGHUP, SIGINT, SIGALRM, etc. will work right anyway. */
- sigfirst = siglast = (int)
- gdb_signal_from_command (atoi (arg));
- if (arg[digits] == '-')
- {
- siglast = (int)
- gdb_signal_from_command (atoi (arg + digits + 1));
- }
- if (sigfirst > siglast)
- {
- /* Bet he didn't figure we'd think of this case... */
- std::swap (sigfirst, siglast);
- }
- }
- else
- {
- oursig = gdb_signal_from_name (arg);
- if (oursig != GDB_SIGNAL_UNKNOWN)
- {
- sigfirst = siglast = (int) oursig;
- }
- else
- {
- /* Not a number and not a recognized flag word => complain. */
- error (_("Unrecognized or ambiguous flag word: \"%s\"."), arg);
- }
- }
- /* If any signal numbers or symbol names were found, set flags for
- which signals to apply actions to. */
- for (int signum = sigfirst; signum >= 0 && signum <= siglast; signum++)
- {
- switch ((enum gdb_signal) signum)
- {
- case GDB_SIGNAL_TRAP:
- case GDB_SIGNAL_INT:
- if (!allsigs && !sigs[signum])
- {
- if (query (_("%s is used by the debugger.\n\
- Are you sure you want to change it? "),
- gdb_signal_to_name ((enum gdb_signal) signum)))
- {
- sigs[signum] = 1;
- }
- else
- gdb_printf (_("Not confirmed, unchanged.\n"));
- }
- break;
- case GDB_SIGNAL_0:
- case GDB_SIGNAL_DEFAULT:
- case GDB_SIGNAL_UNKNOWN:
- /* Make sure that "all" doesn't print these. */
- break;
- default:
- sigs[signum] = 1;
- break;
- }
- }
- }
- for (int signum = 0; signum < nsigs; signum++)
- if (sigs[signum])
- {
- signal_cache_update (-1);
- target_pass_signals (signal_pass);
- target_program_signals (signal_program);
- if (from_tty)
- {
- /* Show the results. */
- sig_print_header ();
- for (; signum < nsigs; signum++)
- if (sigs[signum])
- sig_print_info ((enum gdb_signal) signum);
- }
- break;
- }
- }
- /* Complete the "handle" command. */
- static void
- handle_completer (struct cmd_list_element *ignore,
- completion_tracker &tracker,
- const char *text, const char *word)
- {
- static const char * const keywords[] =
- {
- "all",
- "stop",
- "ignore",
- "print",
- "pass",
- "nostop",
- "noignore",
- "noprint",
- "nopass",
- NULL,
- };
- signal_completer (ignore, tracker, text, word);
- complete_on_enum (tracker, keywords, word, word);
- }
- enum gdb_signal
- gdb_signal_from_command (int num)
- {
- if (num >= 1 && num <= 15)
- return (enum gdb_signal) num;
- error (_("Only signals 1-15 are valid as numeric signals.\n\
- Use \"info signals\" for a list of symbolic signals."));
- }
- /* Print current contents of the tables set by the handle command.
- It is possible we should just be printing signals actually used
- by the current target (but for things to work right when switching
- targets, all signals should be in the signal tables). */
- static void
- info_signals_command (const char *signum_exp, int from_tty)
- {
- enum gdb_signal oursig;
- sig_print_header ();
- if (signum_exp)
- {
- /* First see if this is a symbol name. */
- oursig = gdb_signal_from_name (signum_exp);
- if (oursig == GDB_SIGNAL_UNKNOWN)
- {
- /* No, try numeric. */
- oursig =
- gdb_signal_from_command (parse_and_eval_long (signum_exp));
- }
- sig_print_info (oursig);
- return;
- }
- gdb_printf ("\n");
- /* These ugly casts brought to you by the native VAX compiler. */
- for (oursig = GDB_SIGNAL_FIRST;
- (int) oursig < (int) GDB_SIGNAL_LAST;
- oursig = (enum gdb_signal) ((int) oursig + 1))
- {
- QUIT;
- if (oursig != GDB_SIGNAL_UNKNOWN
- && oursig != GDB_SIGNAL_DEFAULT && oursig != GDB_SIGNAL_0)
- sig_print_info (oursig);
- }
- gdb_printf (_("\nUse the \"handle\" command "
- "to change these tables.\n"));
- }
- /* The $_siginfo convenience variable is a bit special. We don't know
- for sure the type of the value until we actually have a chance to
- fetch the data. The type can change depending on gdbarch, so it is
- also dependent on which thread you have selected.
- 1. making $_siginfo be an internalvar that creates a new value on
- access.
- 2. making the value of $_siginfo be an lval_computed value. */
- /* This function implements the lval_computed support for reading a
- $_siginfo value. */
- static void
- siginfo_value_read (struct value *v)
- {
- LONGEST transferred;
- /* If we can access registers, so can we access $_siginfo. Likewise
- vice versa. */
- validate_registers_access ();
- transferred =
- target_read (current_inferior ()->top_target (),
- TARGET_OBJECT_SIGNAL_INFO,
- NULL,
- value_contents_all_raw (v).data (),
- value_offset (v),
- TYPE_LENGTH (value_type (v)));
- if (transferred != TYPE_LENGTH (value_type (v)))
- error (_("Unable to read siginfo"));
- }
- /* This function implements the lval_computed support for writing a
- $_siginfo value. */
- static void
- siginfo_value_write (struct value *v, struct value *fromval)
- {
- LONGEST transferred;
- /* If we can access registers, so can we access $_siginfo. Likewise
- vice versa. */
- validate_registers_access ();
- transferred = target_write (current_inferior ()->top_target (),
- TARGET_OBJECT_SIGNAL_INFO,
- NULL,
- value_contents_all_raw (fromval).data (),
- value_offset (v),
- TYPE_LENGTH (value_type (fromval)));
- if (transferred != TYPE_LENGTH (value_type (fromval)))
- error (_("Unable to write siginfo"));
- }
- static const struct lval_funcs siginfo_value_funcs =
- {
- siginfo_value_read,
- siginfo_value_write
- };
- /* Return a new value with the correct type for the siginfo object of
- the current thread using architecture GDBARCH. Return a void value
- if there's no object available. */
- static struct value *
- siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var,
- void *ignore)
- {
- if (target_has_stack ()
- && inferior_ptid != null_ptid
- && gdbarch_get_siginfo_type_p (gdbarch))
- {
- struct type *type = gdbarch_get_siginfo_type (gdbarch);
- return allocate_computed_value (type, &siginfo_value_funcs, NULL);
- }
- return allocate_value (builtin_type (gdbarch)->builtin_void);
- }
- /* infcall_suspend_state contains state about the program itself like its
- registers and any signal it received when it last stopped.
- This state must be restored regardless of how the inferior function call
- ends (either successfully, or after it hits a breakpoint or signal)
- if the program is to properly continue where it left off. */
- class infcall_suspend_state
- {
- public:
- /* Capture state from GDBARCH, TP, and REGCACHE that must be restored
- once the inferior function call has finished. */
- infcall_suspend_state (struct gdbarch *gdbarch,
- const struct thread_info *tp,
- struct regcache *regcache)
- : m_registers (new readonly_detached_regcache (*regcache))
- {
- tp->save_suspend_to (m_thread_suspend);
- gdb::unique_xmalloc_ptr<gdb_byte> siginfo_data;
- if (gdbarch_get_siginfo_type_p (gdbarch))
- {
- struct type *type = gdbarch_get_siginfo_type (gdbarch);
- size_t len = TYPE_LENGTH (type);
- siginfo_data.reset ((gdb_byte *) xmalloc (len));
- if (target_read (current_inferior ()->top_target (),
- TARGET_OBJECT_SIGNAL_INFO, NULL,
- siginfo_data.get (), 0, len) != len)
- {
- /* Errors ignored. */
- siginfo_data.reset (nullptr);
- }
- }
- if (siginfo_data)
- {
- m_siginfo_gdbarch = gdbarch;
- m_siginfo_data = std::move (siginfo_data);
- }
- }
- /* Return a pointer to the stored register state. */
- readonly_detached_regcache *registers () const
- {
- return m_registers.get ();
- }
- /* Restores the stored state into GDBARCH, TP, and REGCACHE. */
- void restore (struct gdbarch *gdbarch,
- struct thread_info *tp,
- struct regcache *regcache) const
- {
- tp->restore_suspend_from (m_thread_suspend);
- if (m_siginfo_gdbarch == gdbarch)
- {
- struct type *type = gdbarch_get_siginfo_type (gdbarch);
- /* Errors ignored. */
- target_write (current_inferior ()->top_target (),
- TARGET_OBJECT_SIGNAL_INFO, NULL,
- m_siginfo_data.get (), 0, TYPE_LENGTH (type));
- }
- /* The inferior can be gone if the user types "print exit(0)"
- (and perhaps other times). */
- if (target_has_execution ())
- /* NB: The register write goes through to the target. */
- regcache->restore (registers ());
- }
- private:
- /* How the current thread stopped before the inferior function call was
- executed. */
- struct thread_suspend_state m_thread_suspend;
- /* The registers before the inferior function call was executed. */
- std::unique_ptr<readonly_detached_regcache> m_registers;
- /* Format of SIGINFO_DATA or NULL if it is not present. */
- struct gdbarch *m_siginfo_gdbarch = nullptr;
- /* The inferior format depends on SIGINFO_GDBARCH and it has a length of
- TYPE_LENGTH (gdbarch_get_siginfo_type ()). For different gdbarch the
- content would be invalid. */
- gdb::unique_xmalloc_ptr<gdb_byte> m_siginfo_data;
- };
- infcall_suspend_state_up
- save_infcall_suspend_state ()
- {
- struct thread_info *tp = inferior_thread ();
- struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = regcache->arch ();
- infcall_suspend_state_up inf_state
- (new struct infcall_suspend_state (gdbarch, tp, regcache));
- /* Having saved the current state, adjust the thread state, discarding
- any stop signal information. The stop signal is not useful when
- starting an inferior function call, and run_inferior_call will not use
- the signal due to its `proceed' call with GDB_SIGNAL_0. */
- tp->set_stop_signal (GDB_SIGNAL_0);
- return inf_state;
- }
- /* Restore inferior session state to INF_STATE. */
- void
- restore_infcall_suspend_state (struct infcall_suspend_state *inf_state)
- {
- struct thread_info *tp = inferior_thread ();
- struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = regcache->arch ();
- inf_state->restore (gdbarch, tp, regcache);
- discard_infcall_suspend_state (inf_state);
- }
- void
- discard_infcall_suspend_state (struct infcall_suspend_state *inf_state)
- {
- delete inf_state;
- }
- readonly_detached_regcache *
- get_infcall_suspend_state_regcache (struct infcall_suspend_state *inf_state)
- {
- return inf_state->registers ();
- }
- /* infcall_control_state contains state regarding gdb's control of the
- inferior itself like stepping control. It also contains session state like
- the user's currently selected frame. */
- struct infcall_control_state
- {
- struct thread_control_state thread_control;
- struct inferior_control_state inferior_control;
- /* Other fields: */
- enum stop_stack_kind stop_stack_dummy = STOP_NONE;
- int stopped_by_random_signal = 0;
- /* ID and level of the selected frame when the inferior function
- call was made. */
- struct frame_id selected_frame_id {};
- int selected_frame_level = -1;
- };
- /* Save all of the information associated with the inferior<==>gdb
- connection. */
- infcall_control_state_up
- save_infcall_control_state ()
- {
- infcall_control_state_up inf_status (new struct infcall_control_state);
- struct thread_info *tp = inferior_thread ();
- struct inferior *inf = current_inferior ();
- inf_status->thread_control = tp->control;
- inf_status->inferior_control = inf->control;
- tp->control.step_resume_breakpoint = NULL;
- tp->control.exception_resume_breakpoint = NULL;
- /* Save original bpstat chain to INF_STATUS; replace it in TP with copy of
- chain. If caller's caller is walking the chain, they'll be happier if we
- hand them back the original chain when restore_infcall_control_state is
- called. */
- tp->control.stop_bpstat = bpstat_copy (tp->control.stop_bpstat);
- /* Other fields: */
- inf_status->stop_stack_dummy = stop_stack_dummy;
- inf_status->stopped_by_random_signal = stopped_by_random_signal;
- save_selected_frame (&inf_status->selected_frame_id,
- &inf_status->selected_frame_level);
- return inf_status;
- }
- /* Restore inferior session state to INF_STATUS. */
- void
- restore_infcall_control_state (struct infcall_control_state *inf_status)
- {
- struct thread_info *tp = inferior_thread ();
- struct inferior *inf = current_inferior ();
- if (tp->control.step_resume_breakpoint)
- tp->control.step_resume_breakpoint->disposition = disp_del_at_next_stop;
- if (tp->control.exception_resume_breakpoint)
- tp->control.exception_resume_breakpoint->disposition
- = disp_del_at_next_stop;
- /* Handle the bpstat_copy of the chain. */
- bpstat_clear (&tp->control.stop_bpstat);
- tp->control = inf_status->thread_control;
- inf->control = inf_status->inferior_control;
- /* Other fields: */
- stop_stack_dummy = inf_status->stop_stack_dummy;
- stopped_by_random_signal = inf_status->stopped_by_random_signal;
- if (target_has_stack ())
- {
- restore_selected_frame (inf_status->selected_frame_id,
- inf_status->selected_frame_level);
- }
- delete inf_status;
- }
- void
- discard_infcall_control_state (struct infcall_control_state *inf_status)
- {
- if (inf_status->thread_control.step_resume_breakpoint)
- inf_status->thread_control.step_resume_breakpoint->disposition
- = disp_del_at_next_stop;
- if (inf_status->thread_control.exception_resume_breakpoint)
- inf_status->thread_control.exception_resume_breakpoint->disposition
- = disp_del_at_next_stop;
- /* See save_infcall_control_state for info on stop_bpstat. */
- bpstat_clear (&inf_status->thread_control.stop_bpstat);
- delete inf_status;
- }
- /* See infrun.h. */
- void
- clear_exit_convenience_vars (void)
- {
- clear_internalvar (lookup_internalvar ("_exitsignal"));
- clear_internalvar (lookup_internalvar ("_exitcode"));
- }
- /* User interface for reverse debugging:
- Set exec-direction / show exec-direction commands
- (returns error unless target implements to_set_exec_direction method). */
- enum exec_direction_kind execution_direction = EXEC_FORWARD;
- static const char exec_forward[] = "forward";
- static const char exec_reverse[] = "reverse";
- static const char *exec_direction = exec_forward;
- static const char *const exec_direction_names[] = {
- exec_forward,
- exec_reverse,
- NULL
- };
- static void
- set_exec_direction_func (const char *args, int from_tty,
- struct cmd_list_element *cmd)
- {
- if (target_can_execute_reverse ())
- {
- if (!strcmp (exec_direction, exec_forward))
- execution_direction = EXEC_FORWARD;
- else if (!strcmp (exec_direction, exec_reverse))
- execution_direction = EXEC_REVERSE;
- }
- else
- {
- exec_direction = exec_forward;
- error (_("Target does not support this operation."));
- }
- }
- static void
- show_exec_direction_func (struct ui_file *out, int from_tty,
- struct cmd_list_element *cmd, const char *value)
- {
- switch (execution_direction) {
- case EXEC_FORWARD:
- gdb_printf (out, _("Forward.\n"));
- break;
- case EXEC_REVERSE:
- gdb_printf (out, _("Reverse.\n"));
- break;
- default:
- internal_error (__FILE__, __LINE__,
- _("bogus execution_direction value: %d"),
- (int) execution_direction);
- }
- }
- static void
- show_schedule_multiple (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- gdb_printf (file, _("Resuming the execution of threads "
- "of all processes is %s.\n"), value);
- }
- /* Implementation of `siginfo' variable. */
- static const struct internalvar_funcs siginfo_funcs =
- {
- siginfo_make_value,
- NULL,
- };
- /* Callback for infrun's target events source. This is marked when a
- thread has a pending status to process. */
- static void
- infrun_async_inferior_event_handler (gdb_client_data data)
- {
- clear_async_event_handler (infrun_async_inferior_event_token);
- inferior_event_handler (INF_REG_EVENT);
- }
- #if GDB_SELF_TEST
- namespace selftests
- {
- /* Verify that when two threads with the same ptid exist (from two different
- targets) and one of them changes ptid, we only update inferior_ptid if
- it is appropriate. */
- static void
- infrun_thread_ptid_changed ()
- {
- gdbarch *arch = current_inferior ()->gdbarch;
- /* The thread which inferior_ptid represents changes ptid. */
- {
- scoped_restore_current_pspace_and_thread restore;
- scoped_mock_context<test_target_ops> target1 (arch);
- scoped_mock_context<test_target_ops> target2 (arch);
- ptid_t old_ptid (111, 222);
- ptid_t new_ptid (111, 333);
- target1.mock_inferior.pid = old_ptid.pid ();
- target1.mock_thread.ptid = old_ptid;
- target1.mock_inferior.ptid_thread_map.clear ();
- target1.mock_inferior.ptid_thread_map[old_ptid] = &target1.mock_thread;
- target2.mock_inferior.pid = old_ptid.pid ();
- target2.mock_thread.ptid = old_ptid;
- target2.mock_inferior.ptid_thread_map.clear ();
- target2.mock_inferior.ptid_thread_map[old_ptid] = &target2.mock_thread;
- auto restore_inferior_ptid = make_scoped_restore (&inferior_ptid, old_ptid);
- set_current_inferior (&target1.mock_inferior);
- thread_change_ptid (&target1.mock_target, old_ptid, new_ptid);
- gdb_assert (inferior_ptid == new_ptid);
- }
- /* A thread with the same ptid as inferior_ptid, but from another target,
- changes ptid. */
- {
- scoped_restore_current_pspace_and_thread restore;
- scoped_mock_context<test_target_ops> target1 (arch);
- scoped_mock_context<test_target_ops> target2 (arch);
- ptid_t old_ptid (111, 222);
- ptid_t new_ptid (111, 333);
- target1.mock_inferior.pid = old_ptid.pid ();
- target1.mock_thread.ptid = old_ptid;
- target1.mock_inferior.ptid_thread_map.clear ();
- target1.mock_inferior.ptid_thread_map[old_ptid] = &target1.mock_thread;
- target2.mock_inferior.pid = old_ptid.pid ();
- target2.mock_thread.ptid = old_ptid;
- target2.mock_inferior.ptid_thread_map.clear ();
- target2.mock_inferior.ptid_thread_map[old_ptid] = &target2.mock_thread;
- auto restore_inferior_ptid = make_scoped_restore (&inferior_ptid, old_ptid);
- set_current_inferior (&target2.mock_inferior);
- thread_change_ptid (&target1.mock_target, old_ptid, new_ptid);
- gdb_assert (inferior_ptid == old_ptid);
- }
- }
- } /* namespace selftests */
- #endif /* GDB_SELF_TEST */
- void _initialize_infrun ();
- void
- _initialize_infrun ()
- {
- struct cmd_list_element *c;
- /* Register extra event sources in the event loop. */
- infrun_async_inferior_event_token
- = create_async_event_handler (infrun_async_inferior_event_handler, NULL,
- "infrun");
- cmd_list_element *info_signals_cmd
- = add_info ("signals", info_signals_command, _("\
- What debugger does when program gets various signals.\n\
- Specify a signal as argument to print info on that signal only."));
- add_info_alias ("handle", info_signals_cmd, 0);
- c = add_com ("handle", class_run, handle_command, _("\
- Specify how to handle signals.\n\
- Usage: handle SIGNAL [ACTIONS]\n\
- Args are signals and actions to apply to those signals.\n\
- If no actions are specified, the current settings for the specified signals\n\
- will be displayed instead.\n\
- \n\
- Symbolic signals (e.g. SIGSEGV) are recommended but numeric signals\n\
- from 1-15 are allowed for compatibility with old versions of GDB.\n\
- Numeric ranges may be specified with the form LOW-HIGH (e.g. 1-5).\n\
- The special arg \"all\" is recognized to mean all signals except those\n\
- used by the debugger, typically SIGTRAP and SIGINT.\n\
- \n\
- Recognized actions include \"stop\", \"nostop\", \"print\", \"noprint\",\n\
- \"pass\", \"nopass\", \"ignore\", or \"noignore\".\n\
- Stop means reenter debugger if this signal happens (implies print).\n\
- Print means print a message if this signal happens.\n\
- Pass means let program see this signal; otherwise program doesn't know.\n\
- Ignore is a synonym for nopass and noignore is a synonym for pass.\n\
- Pass and Stop may be combined.\n\
- \n\
- Multiple signals may be specified. Signal numbers and signal names\n\
- may be interspersed with actions, with the actions being performed for\n\
- all signals cumulatively specified."));
- set_cmd_completer (c, handle_completer);
- stop_command = add_cmd ("stop", class_obscure,
- not_just_help_class_command, _("\
- There is no `stop' command, but you can set a hook on `stop'.\n\
- This allows you to set a list of commands to be run each time execution\n\
- of the program stops."), &cmdlist);
- add_setshow_boolean_cmd
- ("infrun", class_maintenance, &debug_infrun,
- _("Set inferior debugging."),
- _("Show inferior debugging."),
- _("When non-zero, inferior specific debugging is enabled."),
- NULL, show_debug_infrun, &setdebuglist, &showdebuglist);
- add_setshow_boolean_cmd ("non-stop", no_class,
- &non_stop_1, _("\
- Set whether gdb controls the inferior in non-stop mode."), _("\
- Show whether gdb controls the inferior in non-stop mode."), _("\
- When debugging a multi-threaded program and this setting is\n\
- off (the default, also called all-stop mode), when one thread stops\n\
- (for a breakpoint, watchpoint, exception, or similar events), GDB stops\n\
- all other threads in the program while you interact with the thread of\n\
- interest. When you continue or step a thread, you can allow the other\n\
- threads to run, or have them remain stopped, but while you inspect any\n\
- thread's state, all threads stop.\n\
- \n\
- In non-stop mode, when one thread stops, other threads can continue\n\
- to run freely. You'll be able to step each thread independently,\n\
- leave it stopped or free to run as needed."),
- set_non_stop,
- show_non_stop,
- &setlist,
- &showlist);
- for (size_t i = 0; i < GDB_SIGNAL_LAST; i++)
- {
- signal_stop[i] = 1;
- signal_print[i] = 1;
- signal_program[i] = 1;
- signal_catch[i] = 0;
- }
- /* Signals caused by debugger's own actions should not be given to
- the program afterwards.
- Do not deliver GDB_SIGNAL_TRAP by default, except when the user
- explicitly specifies that it should be delivered to the target
- program. Typically, that would occur when a user is debugging a
- target monitor on a simulator: the target monitor sets a
- breakpoint; the simulator encounters this breakpoint and halts
- the simulation handing control to GDB; GDB, noting that the stop
- address doesn't map to any known breakpoint, returns control back
- to the simulator; the simulator then delivers the hardware
- equivalent of a GDB_SIGNAL_TRAP to the program being
- debugged. */
- signal_program[GDB_SIGNAL_TRAP] = 0;
- signal_program[GDB_SIGNAL_INT] = 0;
- /* Signals that are not errors should not normally enter the debugger. */
- signal_stop[GDB_SIGNAL_ALRM] = 0;
- signal_print[GDB_SIGNAL_ALRM] = 0;
- signal_stop[GDB_SIGNAL_VTALRM] = 0;
- signal_print[GDB_SIGNAL_VTALRM] = 0;
- signal_stop[GDB_SIGNAL_PROF] = 0;
- signal_print[GDB_SIGNAL_PROF] = 0;
- signal_stop[GDB_SIGNAL_CHLD] = 0;
- signal_print[GDB_SIGNAL_CHLD] = 0;
- signal_stop[GDB_SIGNAL_IO] = 0;
- signal_print[GDB_SIGNAL_IO] = 0;
- signal_stop[GDB_SIGNAL_POLL] = 0;
- signal_print[GDB_SIGNAL_POLL] = 0;
- signal_stop[GDB_SIGNAL_URG] = 0;
- signal_print[GDB_SIGNAL_URG] = 0;
- signal_stop[GDB_SIGNAL_WINCH] = 0;
- signal_print[GDB_SIGNAL_WINCH] = 0;
- signal_stop[GDB_SIGNAL_PRIO] = 0;
- signal_print[GDB_SIGNAL_PRIO] = 0;
- /* These signals are used internally by user-level thread
- implementations. (See signal(5) on Solaris.) Like the above
- signals, a healthy program receives and handles them as part of
- its normal operation. */
- signal_stop[GDB_SIGNAL_LWP] = 0;
- signal_print[GDB_SIGNAL_LWP] = 0;
- signal_stop[GDB_SIGNAL_WAITING] = 0;
- signal_print[GDB_SIGNAL_WAITING] = 0;
- signal_stop[GDB_SIGNAL_CANCEL] = 0;
- signal_print[GDB_SIGNAL_CANCEL] = 0;
- signal_stop[GDB_SIGNAL_LIBRT] = 0;
- signal_print[GDB_SIGNAL_LIBRT] = 0;
- /* Update cached state. */
- signal_cache_update (-1);
- add_setshow_zinteger_cmd ("stop-on-solib-events", class_support,
- &stop_on_solib_events, _("\
- Set stopping for shared library events."), _("\
- Show stopping for shared library events."), _("\
- If nonzero, gdb will give control to the user when the dynamic linker\n\
- notifies gdb of shared library events. The most common event of interest\n\
- to the user would be loading/unloading of a new library."),
- set_stop_on_solib_events,
- show_stop_on_solib_events,
- &setlist, &showlist);
- add_setshow_enum_cmd ("follow-fork-mode", class_run,
- follow_fork_mode_kind_names,
- &follow_fork_mode_string, _("\
- Set debugger response to a program call of fork or vfork."), _("\
- Show debugger response to a program call of fork or vfork."), _("\
- A fork or vfork creates a new process. follow-fork-mode can be:\n\
- parent - the original process is debugged after a fork\n\
- child - the new process is debugged after a fork\n\
- The unfollowed process will continue to run.\n\
- By default, the debugger will follow the parent process."),
- NULL,
- show_follow_fork_mode_string,
- &setlist, &showlist);
- add_setshow_enum_cmd ("follow-exec-mode", class_run,
- follow_exec_mode_names,
- &follow_exec_mode_string, _("\
- Set debugger response to a program call of exec."), _("\
- Show debugger response to a program call of exec."), _("\
- An exec call replaces the program image of a process.\n\
- \n\
- follow-exec-mode can be:\n\
- \n\
- new - the debugger creates a new inferior and rebinds the process\n\
- to this new inferior. The program the process was running before\n\
- the exec call can be restarted afterwards by restarting the original\n\
- inferior.\n\
- \n\
- same - the debugger keeps the process bound to the same inferior.\n\
- The new executable image replaces the previous executable loaded in\n\
- the inferior. Restarting the inferior after the exec call restarts\n\
- the executable the process was running after the exec call.\n\
- \n\
- By default, the debugger will use the same inferior."),
- NULL,
- show_follow_exec_mode_string,
- &setlist, &showlist);
- add_setshow_enum_cmd ("scheduler-locking", class_run,
- scheduler_enums, &scheduler_mode, _("\
- Set mode for locking scheduler during execution."), _("\
- Show mode for locking scheduler during execution."), _("\
- off == no locking (threads may preempt at any time)\n\
- on == full locking (no thread except the current thread may run)\n\
- This applies to both normal execution and replay mode.\n\
- step == scheduler locked during stepping commands (step, next, stepi, nexti).\n\
- In this mode, other threads may run during other commands.\n\
- This applies to both normal execution and replay mode.\n\
- replay == scheduler locked in replay mode and unlocked during normal execution."),
- set_schedlock_func, /* traps on target vector */
- show_scheduler_mode,
- &setlist, &showlist);
- add_setshow_boolean_cmd ("schedule-multiple", class_run, &sched_multi, _("\
- Set mode for resuming threads of all processes."), _("\
- Show mode for resuming threads of all processes."), _("\
- When on, execution commands (such as 'continue' or 'next') resume all\n\
- threads of all processes. When off (which is the default), execution\n\
- commands only resume the threads of the current process. The set of\n\
- threads that are resumed is further refined by the scheduler-locking\n\
- mode (see help set scheduler-locking)."),
- NULL,
- show_schedule_multiple,
- &setlist, &showlist);
- add_setshow_boolean_cmd ("step-mode", class_run, &step_stop_if_no_debug, _("\
- Set mode of the step operation."), _("\
- Show mode of the step operation."), _("\
- When set, doing a step over a function without debug line information\n\
- will stop at the first instruction of that function. Otherwise, the\n\
- function is skipped and the step command stops at a different source line."),
- NULL,
- show_step_stop_if_no_debug,
- &setlist, &showlist);
- add_setshow_auto_boolean_cmd ("displaced-stepping", class_run,
- &can_use_displaced_stepping, _("\
- Set debugger's willingness to use displaced stepping."), _("\
- Show debugger's willingness to use displaced stepping."), _("\
- If on, gdb will use displaced stepping to step over breakpoints if it is\n\
- supported by the target architecture. If off, gdb will not use displaced\n\
- stepping to step over breakpoints, even if such is supported by the target\n\
- architecture. If auto (which is the default), gdb will use displaced stepping\n\
- if the target architecture supports it and non-stop mode is active, but will not\n\
- use it in all-stop mode (see help set non-stop)."),
- NULL,
- show_can_use_displaced_stepping,
- &setlist, &showlist);
- add_setshow_enum_cmd ("exec-direction", class_run, exec_direction_names,
- &exec_direction, _("Set direction of execution.\n\
- Options are 'forward' or 'reverse'."),
- _("Show direction of execution (forward/reverse)."),
- _("Tells gdb whether to execute forward or backward."),
- set_exec_direction_func, show_exec_direction_func,
- &setlist, &showlist);
- /* Set/show detach-on-fork: user-settable mode. */
- add_setshow_boolean_cmd ("detach-on-fork", class_run, &detach_fork, _("\
- Set whether gdb will detach the child of a fork."), _("\
- Show whether gdb will detach the child of a fork."), _("\
- Tells gdb whether to detach the child of a fork."),
- NULL, NULL, &setlist, &showlist);
- /* Set/show disable address space randomization mode. */
- add_setshow_boolean_cmd ("disable-randomization", class_support,
- &disable_randomization, _("\
- Set disabling of debuggee's virtual address space randomization."), _("\
- Show disabling of debuggee's virtual address space randomization."), _("\
- When this mode is on (which is the default), randomization of the virtual\n\
- address space is disabled. Standalone programs run with the randomization\n\
- enabled by default on some platforms."),
- &set_disable_randomization,
- &show_disable_randomization,
- &setlist, &showlist);
- /* ptid initializations */
- inferior_ptid = null_ptid;
- target_last_wait_ptid = minus_one_ptid;
- gdb::observers::thread_ptid_changed.attach (infrun_thread_ptid_changed,
- "infrun");
- gdb::observers::thread_stop_requested.attach (infrun_thread_stop_requested,
- "infrun");
- gdb::observers::thread_exit.attach (infrun_thread_thread_exit, "infrun");
- gdb::observers::inferior_exit.attach (infrun_inferior_exit, "infrun");
- gdb::observers::inferior_execd.attach (infrun_inferior_execd, "infrun");
- /* Explicitly create without lookup, since that tries to create a
- value with a void typed value, and when we get here, gdbarch
- isn't initialized yet. At this point, we're quite sure there
- isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_siginfo", &siginfo_funcs, NULL);
- add_setshow_boolean_cmd ("observer", no_class,
- &observer_mode_1, _("\
- Set whether gdb controls the inferior in observer mode."), _("\
- Show whether gdb controls the inferior in observer mode."), _("\
- In observer mode, GDB can get data from the inferior, but not\n\
- affect its execution. Registers and memory may not be changed,\n\
- breakpoints may not be set, and the program cannot be interrupted\n\
- or signalled."),
- set_observer_mode,
- show_observer_mode,
- &setlist,
- &showlist);
- #if GDB_SELF_TEST
- selftests::register_test ("infrun_thread_ptid_changed",
- selftests::infrun_thread_ptid_changed);
- #endif
- }
|