123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721 |
- /*++
- Copyright (c) 2012 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- dbgrcomm.c
- Abstract:
- This module implements much of the debugger protocol communication for the
- debugger client.
- Author:
- Evan Green 3-Jul-2012
- Environment:
- Debugger client
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "dbgrtl.h"
- #include <minoca/debug/spproto.h>
- #include <minoca/lib/im.h>
- #include <minoca/debug/dbgext.h>
- #include "disasm.h"
- #include "dbgapi.h"
- #include "dbgrprof.h"
- #include "console.h"
- #include "symbols.h"
- #include "dbgrcomm.h"
- #include "dbgsym.h"
- #include "extsp.h"
- #include "remsrv.h"
- #include <assert.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <time.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define DEFAULT_DISASSEMBLED_INSTRUCTIONS 10
- #define DEFAULT_RECURSION_DEPTH 3
- #define BYTES_PER_INSTRUCTION 15
- #define DEFAULT_MEMORY_PRINT_ROWS 10
- #define DEFAULT_DUMP_POINTERS_ROWS 100
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- INT
- DbgrpSetBreakpointAtAddress (
- PDEBUGGER_CONTEXT Context,
- ULONGLONG Address,
- PULONG OriginalValue
- );
- INT
- DbgrpClearBreakpointAtAddress (
- PDEBUGGER_CONTEXT Context,
- ULONGLONG Address,
- ULONG OriginalValue
- );
- ULONG
- DbgrpHandleBreakpoints (
- PDEBUGGER_CONTEXT Context
- );
- INT
- DbgrpAdjustInstructionPointerForBreakpoint (
- PDEBUGGER_CONTEXT Context,
- ULONG OriginalValue
- );
- INT
- DbgrpProcessBreakNotification (
- PDEBUGGER_CONTEXT Context
- );
- INT
- DbgrpRangeStep (
- PDEBUGGER_CONTEXT Context,
- PRANGE_STEP RangeStep
- );
- INT
- DbgrpValidateLoadedModules (
- PDEBUGGER_CONTEXT Context,
- ULONG ModuleCount,
- ULONGLONG Signature,
- BOOL ForceReload
- );
- VOID
- DbgrpUnloadModule (
- PDEBUGGER_CONTEXT Context,
- PDEBUGGER_MODULE Module,
- BOOL Verbose
- );
- VOID
- DbgrpUnloadAllModules (
- PDEBUGGER_CONTEXT Context,
- BOOL Verbose
- );
- INT
- DbgrpPrintDisassembly (
- PDEBUGGER_CONTEXT Context,
- PBYTE InstructionStream,
- ULONGLONG InstructionPointer,
- ULONG InstructionCount,
- PULONG BytesDecoded
- );
- PDATA_SYMBOL
- DbgpGetLocal (
- PFUNCTION_SYMBOL Function,
- PSTR LocalName,
- ULONGLONG ExecutionAddress
- );
- PSTR
- DbgrpCreateFullPath (
- PSOURCE_FILE_SYMBOL Source
- );
- INT
- DbgrpPrintMemory (
- PDEBUGGER_CONTEXT Context,
- ULONGLONG Address,
- BOOL VirtualAddress,
- ULONG TypeSize,
- ULONG Columns,
- ULONG TotalValues,
- BOOL PrintCharacters
- );
- VOID
- DbgrpProcessShutdown (
- PDEBUGGER_CONTEXT Context
- );
- PDEBUGGER_MODULE
- DbgpLoadModule (
- PDEBUGGER_CONTEXT Context,
- PSTR BinaryName,
- PSTR FriendlyName,
- ULONGLONG Size,
- ULONGLONG LowestAddress,
- ULONGLONG Timestamp,
- ULONG Process
- );
- INT
- DbgrpResolveDumpType (
- PDEBUGGER_CONTEXT Context,
- PTYPE_SYMBOL *Type,
- PVOID *Data,
- PUINTN DataSize,
- PULONGLONG Address
- );
- INT
- DbgrpSetFrame (
- PDEBUGGER_CONTEXT Context,
- ULONG FrameNumber
- );
- INT
- DbgrpEnableBreakPoint (
- PDEBUGGER_CONTEXT Context,
- LONG BreakPointIndex,
- BOOL Enable
- );
- VOID
- DbgrpDestroySourcePath (
- PDEBUGGER_SOURCE_PATH SourcePath
- );
- INT
- DbgrpLoadFile (
- PSTR Path,
- PVOID *Contents,
- PULONGLONG Size
- );
- VOID
- DbgrpPrintEflags (
- ULONGLONG Eflags
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store a pointer to the global context, which is needed for requesting
- // break-ins.
- //
- extern PDEBUGGER_CONTEXT DbgConsoleContext;
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- DbgrInitialize (
- PDEBUGGER_CONTEXT Context,
- DEBUG_CONNECTION_TYPE ConnectionType
- )
- /*++
- Routine Description:
- This routine initializes data structures for common debugger functionality.
- Arguments:
- Context - Supplies a pointer to the application context.
- ConnectionType - Supplies the type of debug connection to set the debugger
- up in.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- INT Status;
- Status = EINVAL;
- Context->Flags |= DEBUGGER_FLAG_SOURCE_LINE_STEPPING;
- //
- // Initialize the loaded modules list.
- //
- if (Context->ModuleList.ModuleCount == 0) {
- Context->ModuleList.Signature = 0;
- INITIALIZE_LIST_HEAD(&(Context->ModuleList.ModulesHead));
- }
- if (Context->BreakpointList.Next == NULL) {
- INITIALIZE_LIST_HEAD(&(Context->BreakpointList));
- }
- //
- // Initialize the profiler.
- //
- Status = DbgrProfilerInitialize(Context);
- if (Status != 0) {
- goto InitializeEnd;
- }
- Status = DbgInitialize(Context, ConnectionType);
- if (Status != 0) {
- goto InitializeEnd;
- }
- Status = 0;
- InitializeEnd:
- return Status;
- }
- VOID
- DbgrDestroy (
- PDEBUGGER_CONTEXT Context,
- DEBUG_CONNECTION_TYPE ConnectionType
- )
- /*++
- Routine Description:
- This routine destroys any data structures used for common debugger
- functionality.
- Arguments:
- Context - Supplies a pointer to the application context.
- ConnectionType - Supplies the type of debug connection the debugger was set
- up in.
- Return Value:
- None.
- --*/
- {
- //
- // Destroy the profiler structures.
- //
- DbgrProfilerDestroy(Context);
- DbgDestroy(Context, ConnectionType);
- return;
- }
- INT
- DbgrConnect (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine establishes a link with the target debuggee. It is assumed that
- the underlying communication layer has already been established (COM ports
- have been opened and initialized, etc).
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR Architecture;
- PSTR BuildDebugString;
- PSTR BuildString;
- CHAR BuildTime[50];
- PCONNECTION_RESPONSE ConnectionResponse;
- BOOL InitialBreak;
- PSTR ProductName;
- INT Result;
- ULONG Size;
- time_t Time;
- struct tm *TimeStructure;
- InitialBreak = FALSE;
- if ((Context->Flags & DEBUGGER_FLAG_INITIAL_BREAK) != 0) {
- InitialBreak = TRUE;
- }
- //
- // Connect to the target.
- //
- DbgOut("Waiting to connect...\n");
- Result = DbgKdConnect(Context, InitialBreak, &ConnectionResponse, &Size);
- if (Result != 0) {
- DbgOut("Error: Unable to connect.\n");
- return Result;
- }
- //
- // A connection was successfully established. Print the banner and
- // return.
- //
- Context->MachineType = ConnectionResponse->Machine;
- switch (ConnectionResponse->Machine) {
- case MACHINE_TYPE_X86:
- Architecture = "x86";
- break;
- case MACHINE_TYPE_ARM:
- Architecture = "ARM";
- break;
- case MACHINE_TYPE_X64:
- Architecture = "x64";
- break;
- default:
- Architecture = "Unknown";
- break;
- }
- ProductName = "Unknown Target";
- if ((ConnectionResponse->ProductNameOffset != 0) &&
- (ConnectionResponse->ProductNameOffset < Size)) {
- ProductName = (PSTR)ConnectionResponse +
- ConnectionResponse->ProductNameOffset;
- }
- BuildString = "";
- if ((ConnectionResponse->BuildStringOffset != 0) &&
- (ConnectionResponse->BuildStringOffset < Size)) {
- BuildString = (PSTR)ConnectionResponse +
- ConnectionResponse->BuildStringOffset;
- }
- BuildDebugString = RtlGetBuildDebugLevelString(
- ConnectionResponse->SystemBuildDebugLevel);
- DbgOut("Connected to %s on %s\nSystem Version %d.%d.%d.%I64d %s %s %s\n",
- ProductName,
- Architecture,
- ConnectionResponse->SystemMajorVersion,
- ConnectionResponse->SystemMinorVersion,
- ConnectionResponse->SystemRevision,
- ConnectionResponse->SystemSerialVersion,
- RtlGetReleaseLevelString(ConnectionResponse->SystemReleaseLevel),
- BuildDebugString,
- BuildString);
- Time = ConnectionResponse->SystemBuildTime + SYSTEM_TIME_TO_EPOCH_DELTA;
- TimeStructure = localtime(&Time);
- strftime(BuildTime,
- sizeof(BuildTime),
- "%a %b %d, %Y %I:%M %p",
- TimeStructure);
- DbgOut("Built on %s.\n", BuildTime);
- free(ConnectionResponse);
- return 0;
- }
- INT
- DbgrQuit (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine exits the local debugger.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- DbgOut("\n*** Exiting ***\n");
- Context->Flags |= DEBUGGER_FLAG_EXITING;
- return 0;
- }
- INT
- DbgrGo (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine interprets the "go" command from the user.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG Evaluation;
- PSTR GoUntilAddress;
- INT Result;
- GoUntilAddress = NULL;
- if (ArgumentCount > 1) {
- GoUntilAddress = Arguments[1];
- }
- //
- // If no argument was specified, send the unconditional go.
- //
- if (GoUntilAddress == NULL) {
- Result = DbgrContinue(Context, FALSE, 0);
- return Result;
- }
- //
- // Evaluate the argument. If it fails, print a message, and do not send the
- // command.
- //
- Result = DbgEvaluate(Context, GoUntilAddress, &Evaluation);
- if (Result != 0) {
- DbgOut("Error: Unable to evaluate \"%s\".\n", GoUntilAddress);
- return Result;
- }
- //
- // Send the command with a one-time breakpoint.
- //
- Result = DbgrContinue(Context, TRUE, Evaluation);
- return Result;
- }
- INT
- DbgrSingleStep (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine steps the target by a single instruction.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- INT Result;
- ULONG SignalToDeliver;
- SignalToDeliver = DbgGetSignalToDeliver(Context);
- Result = DbgSingleStep(Context, SignalToDeliver);
- return Result;
- }
- INT
- DbgrGetSetRegisters (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine prints or modifies the target machine's registers.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PARM_GENERAL_REGISTERS ArmRegisters;
- ULONG Psr;
- PSTR RegisterString;
- INT Result;
- ULONGLONG Value;
- PSTR ValueString;
- PX64_GENERAL_REGISTERS X64Registers;
- PX86_GENERAL_REGISTERS X86Registers;
- RegisterString = NULL;
- Result = 0;
- ValueString = NULL;
- if (ArgumentCount >= 2) {
- RegisterString = Arguments[1];
- if (ArgumentCount >= 3) {
- ValueString = Arguments[2];
- }
- }
- assert(Context->CurrentEvent.Type == DebuggerEventBreak);
- ArmRegisters = &(Context->CurrentEvent.BreakNotification.Registers.Arm);
- X64Registers = &(Context->CurrentEvent.BreakNotification.Registers.X64);
- X86Registers = &(Context->CurrentEvent.BreakNotification.Registers.X86);
- if (Context->CurrentFrame != 0) {
- ArmRegisters = &(Context->FrameRegisters.Arm);
- X64Registers = &(Context->FrameRegisters.X64);
- X86Registers = &(Context->FrameRegisters.X86);
- }
- //
- // If the first parameter is not NULL, find the register the user is
- // talking about.
- //
- if (RegisterString != NULL) {
- //
- // If no other parameter was specified, print out the value of the
- // specified register.
- //
- if (ValueString == NULL) {
- if (EvalGetRegister(Context, RegisterString, &Value) == FALSE) {
- DbgOut("Error: Invalid Register \"%s\".\n", RegisterString);
- goto GetSetRegistersEnd;
- }
- DbgOut("%0*llx\n", DbgGetTargetPointerSize(Context) * 2, Value);
- goto GetSetRegistersEnd;
- //
- // A value to write into the register was supplied. Attempt to evaluate
- // and write the register.
- //
- } else {
- if (Context->CurrentFrame != 0) {
- DbgOut("Error: Registers can only be set in frame 0.\n");
- goto GetSetRegistersEnd;
- }
- Result = DbgEvaluate(Context, ValueString, &Value);
- if (Result != 0) {
- DbgOut("Error: Unable to evaluate \"%s\".\n", ValueString);
- goto GetSetRegistersEnd;
- }
- if (EvalSetRegister(Context, RegisterString, Value) == FALSE) {
- DbgOut("Error: Invalid Register \"%s\".\n", RegisterString);
- goto GetSetRegistersEnd;
- }
- Result = DbgSetRegisters(
- Context,
- &(Context->CurrentEvent.BreakNotification.Registers));
- goto GetSetRegistersEnd;
- }
- //
- // No parameters were specified, just dump all the register contents.
- //
- } else {
- if (Context->CurrentFrame != 0) {
- DbgOut("Frame %d Registers:\n", Context->CurrentFrame);
- }
- switch (Context->MachineType) {
- //
- // Dump x86 registers.
- //
- case MACHINE_TYPE_X86:
- DbgOut("eax=%08I64x ebx=%08I64x ecx=%08I64x edx=%08I64x "
- "eip=%08I64x\n"
- "esi=%08I64x edi=%08I64x ebp=%08I64x esp=%08I64x "
- "eflags=%08I64x\n",
- X86Registers->Eax,
- X86Registers->Ebx,
- X86Registers->Ecx,
- X86Registers->Edx,
- X86Registers->Eip,
- X86Registers->Esi,
- X86Registers->Edi,
- X86Registers->Ebp,
- X86Registers->Esp,
- X86Registers->Eflags);
- DbgOut("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\n",
- X86Registers->Cs,
- X86Registers->Ds,
- X86Registers->Es,
- X86Registers->Fs,
- X86Registers->Gs,
- X86Registers->Ss);
- DbgrpPrintEflags(X86Registers->Eflags);
- DbgOut("\n");
- break;
- case MACHINE_TYPE_X64:
- DbgOut("rax=%016llx rdx=%016llx rcx=%016llx\n"
- "rbx=%016llx rsi=%016llx rdi=%016llx\n"
- "r8 =%016llx r9 =%016llx r10=%016llx\n"
- "r11=%016llx r12=%016llx r13=%016llx\n"
- "r14=%016llx r15=%016llx rbp=%016llx\n"
- "rip=%016llx rsp=%016llx\n",
- X64Registers->Rax,
- X64Registers->Rdx,
- X64Registers->Rcx,
- X64Registers->Rbx,
- X64Registers->Rsi,
- X64Registers->Rdi,
- X64Registers->R8,
- X64Registers->R9,
- X64Registers->R10,
- X64Registers->R11,
- X64Registers->R12,
- X64Registers->R13,
- X64Registers->R14,
- X64Registers->R15,
- X64Registers->Rbp,
- X64Registers->Rip,
- X64Registers->Rsp);
- DbgOut("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\n"
- "rflags=%016llx ",
- X64Registers->Cs,
- X64Registers->Ds,
- X64Registers->Es,
- X64Registers->Fs,
- X64Registers->Gs,
- X64Registers->Ss,
- X64Registers->Rflags);
- DbgrpPrintEflags(X64Registers->Rflags);
- DbgOut("\n");
- break;
- //
- // Dump ARM registers.
- //
- case MACHINE_TYPE_ARM:
- DbgOut("r0=%08x r1=%08x r2=%08x r3=%08x r4=%08x r5=%08x\n"
- "r6=%08x r7=%08x r8=%08x r9=%08x r10=%08x fp=%08x\n"
- "ip=%08x sp=%08x lr=%08x pc=%08x cpsr=%08x\n",
- ArmRegisters->R0,
- ArmRegisters->R1,
- ArmRegisters->R2,
- ArmRegisters->R3,
- ArmRegisters->R4,
- ArmRegisters->R5,
- ArmRegisters->R6,
- ArmRegisters->R7,
- ArmRegisters->R8,
- ArmRegisters->R9,
- ArmRegisters->R10,
- ArmRegisters->R11Fp,
- ArmRegisters->R12Ip,
- ArmRegisters->R13Sp,
- ArmRegisters->R14Lr,
- ArmRegisters->R15Pc,
- ArmRegisters->Cpsr);
- DbgOut("Mode: ");
- Psr = ArmRegisters->Cpsr;
- switch (Psr & ARM_MODE_MASK) {
- case ARM_MODE_ABORT:
- DbgOut("Abort");
- break;
- case ARM_MODE_FIQ:
- DbgOut("FIQ");
- break;
- case ARM_MODE_IRQ:
- DbgOut("IRQ");
- break;
- case ARM_MODE_SVC:
- DbgOut("SVC");
- break;
- case ARM_MODE_SYSTEM:
- DbgOut("System");
- break;
- case ARM_MODE_UNDEF:
- DbgOut("Undefined Instruction");
- break;
- case ARM_MODE_USER:
- DbgOut("User");
- break;
- default:
- DbgOut("*** Unknown ***");
- break;
- }
- if ((Psr & PSR_FLAG_NEGATIVE) != 0) {
- DbgOut(" N");
- }
- if ((Psr & PSR_FLAG_ZERO) != 0) {
- DbgOut(" Z");
- }
- if ((Psr & PSR_FLAG_CARRY) != 0) {
- DbgOut(" C");
- }
- if ((Psr & PSR_FLAG_OVERFLOW) != 0) {
- DbgOut(" V");
- }
- if ((Psr & PSR_FLAG_SATURATION) != 0) {
- DbgOut(" Q");
- }
- if ((Psr & PSR_FLAG_JAZELLE) != 0) {
- DbgOut(" Jazelle");
- }
- if ((Psr & PSR_FLAG_THUMB) != 0) {
- DbgOut(" Thumb");
- }
- if ((Psr & PSR_FLAG_FIQ) != 0) {
- DbgOut(" FIQ");
- }
- if ((Psr & PSR_FLAG_IRQ) != 0) {
- DbgOut(" IRQ");
- }
- DbgOut("\n");
- break;
- default:
- DbgOut("Error: Unknown machine type %d.\n", Context->MachineType);
- goto GetSetRegistersEnd;
- }
- }
- GetSetRegistersEnd:
- return Result;
- }
- INT
- DbgrGetSetSpecialRegisters (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine prints or modifies the target machine's special registers.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSPECIAL_REGISTERS_UNION Original;
- PVOID Register;
- PVOID Register2;
- ULONG RegisterSize;
- PSTR RegisterString;
- INT Result;
- SET_SPECIAL_REGISTERS SetCommand;
- ULONGLONG Value;
- ULONGLONG Value2;
- PSTR ValueCopy;
- PSTR ValueString;
- PSTR ValueString2;
- Register = NULL;
- RegisterString = NULL;
- Register2 = NULL;
- ValueCopy = NULL;
- ValueString = NULL;
- if (ArgumentCount >= 2) {
- RegisterString = Arguments[1];
- if (ArgumentCount >= 3) {
- ValueString = Arguments[2];
- }
- }
- //
- // Fill in the new registers as if they were the originals so they can be
- // modified in place.
- //
- Original = &(SetCommand.New);
- Result = DbgGetSpecialRegisters(Context, Original);
- if (Result != 0) {
- goto GetSetSpecialRegistersEnd;
- }
- //
- // A specific register is being read or written to.
- //
- if (RegisterString != NULL) {
- switch (Context->MachineType) {
- case MACHINE_TYPE_X86:
- case MACHINE_TYPE_X64:
- RegisterSize = 8;
- if (strcasecmp(RegisterString, "cr0") == 0) {
- Register = &(Original->Ia.Cr0);
- } else if (strcasecmp(RegisterString, "cr2") == 0) {
- Register = &(Original->Ia.Cr2);
- } else if (strcasecmp(RegisterString, "cr3") == 0) {
- Register = &(Original->Ia.Cr3);
- } else if (strcasecmp(RegisterString, "cr4") == 0) {
- Register = &(Original->Ia.Cr4);
- } else if (strcasecmp(RegisterString, "dr0") == 0) {
- Register = &(Original->Ia.Dr0);
- } else if (strcasecmp(RegisterString, "dr1") == 0) {
- Register = &(Original->Ia.Dr1);
- } else if (strcasecmp(RegisterString, "dr2") == 0) {
- Register = &(Original->Ia.Dr2);
- } else if (strcasecmp(RegisterString, "dr3") == 0) {
- Register = &(Original->Ia.Dr3);
- } else if (strcasecmp(RegisterString, "dr6") == 0) {
- Register = &(Original->Ia.Dr6);
- } else if (strcasecmp(RegisterString, "dr7") == 0) {
- Register = &(Original->Ia.Dr7);
- } else if (strcasecmp(RegisterString, "idtr") == 0) {
- RegisterSize = 4;
- Register = &(Original->Ia.Idtr.Base);
- Register2 = &(Original->Ia.Idtr.Limit);
- } else if (strcasecmp(RegisterString, "gdtr") == 0) {
- RegisterSize = 4;
- Register = &(Original->Ia.Gdtr.Base);
- Register2 = &(Original->Ia.Gdtr.Limit);
- } else if (strcasecmp(RegisterString, "tr") == 0) {
- RegisterSize = 2;
- Register = &(Original->Ia.Tr);
- } else {
- DbgOut("Error: Unknown register '%s'.\n", RegisterString);
- Result = EINVAL;
- goto GetSetSpecialRegistersEnd;
- }
- break;
- case MACHINE_TYPE_ARM:
- RegisterSize = 4;
- if (strcasecmp(RegisterString, "sctlr") == 0) {
- Register = &(Original->Arm.Sctlr);
- } else if (strcasecmp(RegisterString, "actlr") == 0) {
- Register = &(Original->Arm.Actlr);
- } else if (strcasecmp(RegisterString, "ttbr0") == 0) {
- Register = &(Original->Arm.Ttbr0);
- } else if (strcasecmp(RegisterString, "ttbr1") == 0) {
- Register = &(Original->Arm.Ttbr1);
- } else if (strcasecmp(RegisterString, "dfsr") == 0) {
- Register = &(Original->Arm.Dfsr);
- } else if (strcasecmp(RegisterString, "ifsr") == 0) {
- Register = &(Original->Arm.Ifsr);
- } else if (strcasecmp(RegisterString, "dfar") == 0) {
- Register = &(Original->Arm.Dfar);
- } else if (strcasecmp(RegisterString, "ifar") == 0) {
- Register = &(Original->Arm.Ifar);
- } else if (strcasecmp(RegisterString, "prrr") == 0) {
- Register = &(Original->Arm.Prrr);
- } else if (strcasecmp(RegisterString, "nmrr") == 0) {
- Register = &(Original->Arm.Nmrr);
- } else if (strcasecmp(RegisterString, "vbar") == 0) {
- Register = &(Original->Arm.Vbar);
- } else if (strcasecmp(RegisterString, "par") == 0) {
- Register = &(Original->Arm.Par);
- } else if (strcasecmp(RegisterString, "ats1cpr") == 0) {
- Register = &(Original->Arm.Ats1Cpr);
- } else if (strcasecmp(RegisterString, "ats1cpw") == 0) {
- Register = &(Original->Arm.Ats1Cpw);
- } else if (strcasecmp(RegisterString, "ats1cur") == 0) {
- Register = &(Original->Arm.Ats1Cur);
- } else if (strcasecmp(RegisterString, "ats1cuw") == 0) {
- Register = &(Original->Arm.Ats1Cuw);
- } else if (strcasecmp(RegisterString, "tpidrprw") == 0) {
- Register = &(Original->Arm.Tpidrprw);
- } else {
- DbgOut("Error: Unknown register '%s'.\n", RegisterString);
- Result = EINVAL;
- goto GetSetSpecialRegistersEnd;
- }
- break;
- default:
- DbgOut("GetSetSpecialRegisters: Unknown architecture.\n");
- Result = EINVAL;
- goto GetSetSpecialRegistersEnd;
- }
- //
- // Set a register.
- //
- if (ValueString != NULL) {
- ValueCopy = strdup(ValueString);
- if (ValueCopy == NULL) {
- Result = ENOMEM;
- goto GetSetSpecialRegistersEnd;
- }
- ValueString2 = strchr(ValueCopy, ',');
- if (ValueString2 != NULL) {
- *ValueString2 = '\0';
- ValueString2 += 1;
- }
- Result = DbgEvaluate(Context, ValueCopy, &Value);
- if (Result != 0) {
- DbgOut("Failed to evaluate '%s'.\n", ValueCopy);
- goto GetSetSpecialRegistersEnd;
- }
- if (ValueString2 != NULL) {
- Result = DbgEvaluate(Context, ValueString2, &Value2);
- if (Result != 0) {
- DbgOut("Failed to evaluate '%s'.\n", ValueCopy);
- goto GetSetSpecialRegistersEnd;
- }
- }
- if ((ValueString2 != NULL) && (Register2 == NULL)) {
- DbgOut("Error: %s takes only one argument.\n", RegisterString);
- Result = EINVAL;
- goto GetSetSpecialRegistersEnd;
- } else if ((ValueString2 == NULL) && (Register2 != NULL)) {
- DbgOut("Error: %s takes two arguments (in the form "
- "'base,limit').\n",
- RegisterString);
- Result = EINVAL;
- goto GetSetSpecialRegistersEnd;
- }
- //
- // Set the register. Copy the originals to the originals position
- // first.
- //
- memcpy(&(SetCommand.Original),
- &(SetCommand.New),
- sizeof(SPECIAL_REGISTERS_UNION));
- memcpy(Register, &Value, RegisterSize);
- if (Register2 != NULL) {
- memcpy(Register2, &Value2, sizeof(ULONG));
- }
- Result = DbgSetSpecialRegisters(Context, &SetCommand);
- if (Result != 0) {
- goto GetSetSpecialRegistersEnd;
- }
- } else {
- Value = 0;
- memcpy(&Value, Register, RegisterSize);
- if (Register2 != NULL) {
- Value2 = 0;
- memcpy(&Value2, Register2, sizeof(USHORT));
- DbgOut("%I64x,%x\n", Value, (USHORT)Value2);
- } else {
- DbgOut("%I64x\n", Value);
- }
- }
- //
- // Just print all the registers.
- //
- } else {
- switch (Context->MachineType) {
- case MACHINE_TYPE_X86:
- case MACHINE_TYPE_X64:
- DbgOut("cr0=%08I64x cr2=%08I64x cr3=%08I64x cr4=%08I64x tr=%04x\n"
- "dr0=%08I64x dr1=%08I64x dr2=%08I64x dr3=%08I64x\n"
- "dr6=%08I64x dr7=%08I64x\n"
- "idtr=%08x,%04x gdtr=%08x,%04x\n",
- Original->Ia.Cr0,
- Original->Ia.Cr2,
- Original->Ia.Cr3,
- Original->Ia.Cr4,
- Original->Ia.Tr,
- Original->Ia.Dr0,
- Original->Ia.Dr1,
- Original->Ia.Dr2,
- Original->Ia.Dr3,
- Original->Ia.Dr6,
- Original->Ia.Dr7,
- Original->Ia.Idtr.Base,
- Original->Ia.Idtr.Limit,
- Original->Ia.Gdtr.Base,
- Original->Ia.Gdtr.Limit);
- break;
- case MACHINE_TYPE_ARM:
- DbgOut("Not shown: ats1cpr, ats1cpw, ats1cur, ats1cuw\n"
- "sctlr=%08x actlr=%08x ttbr0=%08I64x ttbr1=%08I64x\n"
- " dfsr=%08x dfar=%08I64x ifsr=%08x ifar=%08I64x\n"
- " prrr=%08x nmrr=%08x vbar=%08x par=%08I64x\n"
- "tpidrprw=%08I64x\n",
- Original->Arm.Sctlr,
- Original->Arm.Actlr,
- Original->Arm.Ttbr0,
- Original->Arm.Ttbr1,
- Original->Arm.Dfsr,
- Original->Arm.Dfar,
- Original->Arm.Ifsr,
- Original->Arm.Ifar,
- Original->Arm.Prrr,
- Original->Arm.Nmrr,
- Original->Arm.Vbar,
- Original->Arm.Par,
- Original->Arm.Tpidrprw);
- break;
- default:
- DbgOut("GetSetSpecialRegisters: Unknown architecture.\n");
- Result = EINVAL;
- goto GetSetSpecialRegistersEnd;
- }
- }
- Result = 0;
- GetSetSpecialRegistersEnd:
- if (ValueCopy != NULL) {
- free(ValueCopy);
- }
- return Result;
- }
- INT
- DbgrPrintCallStack (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine prints the current call stack.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG BasePointer;
- ULONGLONG InstructionPointer;
- REGISTERS_UNION LocalRegisters;
- BOOL PrintFrameNumbers;
- PREGISTERS_UNION Registers;
- INT Result;
- ULONGLONG StackPointer;
- Registers = NULL;
- assert(Context->CurrentEvent.Type == DebuggerEventBreak);
- if ((ArgumentCount != 1) && (ArgumentCount != 4)) {
- DbgOut("Usage: k [<InstructionPointer> <StackPointer> "
- "<BasePointer>]\n");
- return EINVAL;
- }
- PrintFrameNumbers = FALSE;
- if (strcasecmp(Arguments[0], "kn") == 0) {
- PrintFrameNumbers = TRUE;
- } else {
- assert(strcasecmp(Arguments[0], "k") == 0);
- }
- if (ArgumentCount == 4) {
- RtlCopyMemory(&LocalRegisters,
- &(Context->CurrentEvent.BreakNotification.Registers),
- sizeof(REGISTERS_UNION));
- Registers = &LocalRegisters;
- Result = DbgEvaluate(Context, Arguments[1], &InstructionPointer);
- if (Result != 0) {
- DbgOut("Failed to evaluate \"%s\".\n", Arguments[1]);
- goto PrintCallStackEnd;
- }
- Result = DbgEvaluate(Context, Arguments[2], &StackPointer);
- if (Result != 0) {
- DbgOut("Failed to evaluate \"%s\".\n", Arguments[2]);
- goto PrintCallStackEnd;
- }
- Result = DbgEvaluate(Context, Arguments[3], &BasePointer);
- if (Result != 0) {
- DbgOut("Failed to evaluate \"%s\".\n", Arguments[3]);
- goto PrintCallStackEnd;
- }
- switch (Context->MachineType) {
- case MACHINE_TYPE_X86:
- LocalRegisters.X86.Eip = InstructionPointer;
- LocalRegisters.X86.Esp = StackPointer;
- LocalRegisters.X86.Ebp = BasePointer;
- break;
- case MACHINE_TYPE_ARM:
- LocalRegisters.Arm.R15Pc = InstructionPointer;
- LocalRegisters.Arm.R13Sp = StackPointer;
- if ((LocalRegisters.Arm.Cpsr & PSR_FLAG_THUMB) != 0) {
- LocalRegisters.Arm.R7 = BasePointer;
- } else {
- LocalRegisters.Arm.R11Fp = BasePointer;
- }
- break;
- case MACHINE_TYPE_X64:
- LocalRegisters.X64.Rip = InstructionPointer;
- LocalRegisters.X64.Rsp = StackPointer;
- LocalRegisters.X64.Rbp = BasePointer;
- break;
- }
- }
- Result = DbgPrintCallStack(Context, Registers, PrintFrameNumbers);
- if (Result != 0) {
- goto PrintCallStackEnd;
- }
- Result = 0;
- PrintCallStackEnd:
- return Result;
- }
- INT
- DbgrSetFrame (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine changes the current stack frame, so that local variables may
- come from a different function in the call stack.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR AfterScan;
- ULONG FrameNumber;
- PSTR FrameNumberString;
- INT Status;
- if (ArgumentCount < 2) {
- DbgOut("Usage: frame <N>\nSets the current call stack frame, where "
- "N is a number between 0 and the number of stack frames (use "
- "kn to dump numbered frames).\n");
- Status = EINVAL;
- goto SetFrameEnd;
- }
- FrameNumberString = Arguments[1];
- FrameNumber = strtoul(FrameNumberString, &AfterScan, 0);
- if (FrameNumberString == AfterScan) {
- DbgOut("Failed to convert '%s' to a number.\n", FrameNumberString);
- Status = EINVAL;
- goto SetFrameEnd;
- }
- Status = DbgrpSetFrame(Context, FrameNumber);
- SetFrameEnd:
- return Status;
- }
- INT
- DbgrDisassemble (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine disassembles instructions from the target.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG ActualAddress;
- ULONG BufferSize;
- ULONG BytesConsumed;
- ULONG BytesRead;
- ULONG InstructionCount;
- PBYTE InstructionStream;
- ULONGLONG NewAddress;
- BOOL Result;
- InstructionCount = DEFAULT_DISASSEMBLED_INSTRUCTIONS;
- BufferSize = InstructionCount * BYTES_PER_INSTRUCTION;
- InstructionStream = NULL;
- //
- // If an address string was supplied, parse that. Otherwise, print from
- // where disassembly left off.
- //
- if (ArgumentCount >= 2) {
- Result = DbgEvaluate(Context, Arguments[1], &NewAddress);
- if (Result != 0) {
- DbgOut("Error: Unable to parse address '%s'.\n", Arguments[1]);
- goto DisassembleEnd;
- } else {
- Context->DisassemblyAddress = NewAddress;
- }
- }
- //
- // Allocate memory to hold the binary instructions.
- //
- InstructionStream = malloc(BufferSize);
- if (InstructionStream == NULL) {
- Result = ENOMEM;
- goto DisassembleEnd;
- }
- memset(InstructionStream, 0, BufferSize);
- //
- // Read the memory from the target.
- //
- ActualAddress = Context->DisassemblyAddress;
- if (Context->MachineType == MACHINE_TYPE_ARM) {
- ActualAddress &= ~ARM_THUMB_BIT;
- }
- Result = DbgReadMemory(Context,
- TRUE,
- ActualAddress,
- BufferSize,
- InstructionStream,
- &BytesRead);
- if (Result != 0) {
- goto DisassembleEnd;
- }
- if (BytesRead < BufferSize) {
- BufferSize = BytesRead;
- }
- //
- // Print out the disassembly and advance the disassembly address.
- //
- Result = DbgrpPrintDisassembly(Context,
- InstructionStream,
- Context->DisassemblyAddress,
- BufferSize / BYTES_PER_INSTRUCTION,
- &BytesConsumed);
- if (Result != 0) {
- goto DisassembleEnd;
- }
- Result = 0;
- Context->DisassemblyAddress += BytesConsumed;
- DisassembleEnd:
- if (InstructionStream != NULL) {
- free(InstructionStream);
- }
- return Result;
- }
- INT
- DbgrWaitForEvent (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine gets an event from the target, such as a break event or other
- exception.
- Arguments:
- Context - Supplies a pointer to the debugger context.
- Return Value:
- 0 on success,
- Returns an error code on failure.
- --*/
- {
- INT Result;
- while ((Context->TargetFlags & DEBUGGER_TARGET_RUNNING) != 0) {
- Result = DbgWaitForEvent(Context);
- if (Result != 0) {
- DbgOut("Error: Failed to get next debugging event.\n");
- return Result;
- }
- switch (Context->CurrentEvent.Type) {
- case DebuggerEventBreak:
- Result = DbgrpProcessBreakNotification(Context);
- if (Result != 0) {
- goto WaitForEventEnd;
- }
- break;
- case DebuggerEventShutdown:
- DbgrpProcessShutdown(Context);
- break;
- case DebuggerEventProfiler:
- DbgrProcessProfilerNotification(Context);
- break;
- default:
- //
- // The target sent an unknown command.
- //
- DbgOut("Unknown event received: 0x%x\n",
- Context->CurrentEvent.Type);
- break;
- }
- }
- Result = 0;
- WaitForEventEnd:
- return Result;
- }
- INT
- DbgrSearchSymbols (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine searches for symbols. Wildcards are accepted. If the search
- string is preceded by "modulename!" then only that module will be searched.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG Address;
- PDEBUGGER_MODULE CurrentModule;
- PLIST_ENTRY CurrentModuleEntry;
- PSTR ModuleEnd;
- ULONG ModuleLength;
- ULONGLONG Pc;
- INT Result;
- PSYMBOL_SEARCH_RESULT ResultValid;
- SYMBOL_SEARCH_RESULT SearchResult;
- PSTR SearchString;
- PDEBUGGER_MODULE UserModule;
- UserModule = NULL;
- if (ArgumentCount != 2) {
- DbgOut("Usage: x <query>\nThe x command searches for a symbol with "
- "the given name. Wildcards are accepted.");
- Result = EINVAL;
- goto SearchSymbolsEnd;
- }
- SearchString = Arguments[1];
- //
- // If an exclamation point exists, then the module was specified. Find that
- // module.
- //
- ModuleEnd = strchr(SearchString, '!');
- if (ModuleEnd != NULL) {
- ModuleLength = (UINTN)ModuleEnd - (UINTN)SearchString;
- UserModule = DbgpGetModule(Context, SearchString, ModuleLength);
- if (UserModule == NULL) {
- DbgOut("Module %s not found.\n", SearchString);
- Result = ENOENT;
- goto SearchSymbolsEnd;
- }
- //
- // Move the search string and initialize the list entry.
- //
- SearchString = ModuleEnd + 1;
- CurrentModuleEntry = &(UserModule->ListEntry);
- //
- // If a module was not specified, simply start with the first one.
- //
- } else {
- CurrentModuleEntry = Context->ModuleList.ModulesHead.Next;
- }
- //
- // Loop over all modules.
- //
- while (CurrentModuleEntry != &(Context->ModuleList.ModulesHead)) {
- CurrentModule = LIST_VALUE(CurrentModuleEntry,
- DEBUGGER_MODULE,
- ListEntry);
- CurrentModuleEntry = CurrentModuleEntry->Next;
- if (!IS_MODULE_IN_CURRENT_PROCESS(Context, CurrentModule)) {
- if (UserModule != NULL) {
- break;
- }
- continue;
- }
- //
- // Loop over all symbol search results.
- //
- SearchResult.Variety = SymbolResultInvalid;
- while (TRUE) {
- //
- // Perform the search. If it fails, break out of this loop.
- //
- ResultValid = DbgpFindSymbolInModule(CurrentModule->Symbols,
- SearchString,
- &SearchResult);
- if (ResultValid == NULL) {
- break;
- }
- //
- // Print out the result.
- //
- Result = TRUE;
- switch (SearchResult.Variety) {
- case SymbolResultFunction:
- Address = SearchResult.U.FunctionResult->StartAddress +
- CurrentModule->BaseDifference;
- DbgPrintFunctionPrototype(SearchResult.U.FunctionResult,
- CurrentModule->ModuleName,
- Address);
- DbgOut("\n");
- break;
- case SymbolResultData:
- Pc = DbgGetPc(Context, &(Context->FrameRegisters)) -
- CurrentModule->BaseDifference;
- Result = DbgGetDataSymbolAddress(Context,
- CurrentModule->Symbols,
- SearchResult.U.DataResult,
- Pc,
- &Address);
- if (Result == 0) {
- DbgOut("%s!%s @ 0x%08llx\n",
- CurrentModule->ModuleName,
- SearchResult.U.DataResult->Name,
- Address + CurrentModule->BaseDifference);
- }
- Result = TRUE;
- break;
- case SymbolResultType:
- DbgOut("%s!%s\n",
- CurrentModule->ModuleName,
- SearchResult.U.TypeResult->Name);
- break;
- default:
- DbgOut("ERROR: Unknown search result type %d returned!",
- SearchResult.U.TypeResult);
- Result = EINVAL;
- goto SearchSymbolsEnd;
- }
- if (Result == FALSE) {
- Result = ENOENT;
- goto SearchSymbolsEnd;
- }
- }
- //
- // If a specific user module was specified, do not loop over more
- // modules.
- //
- if (UserModule != NULL) {
- break;
- }
- }
- Result = 0;
- SearchSymbolsEnd:
- return Result;
- }
- INT
- DbgrDumpTypeCommand (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine prints information about a type description or value. If only
- a type is specified, the type format will be printed. If an address is
- passed as a second parameter, then the values will be dumped. If a global
- or local variable is passed as the first parameter, the values will also be
- dumped.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- INT Result;
- if (ArgumentCount < 2) {
- DbgOut("Usage: dt <type name> [<address...> | <variable name>]\n");
- Result = EINVAL;
- goto DumpTypeCommandEnd;
- }
- Result = DbgrDumpType(Context, Arguments + 1, ArgumentCount - 1, NULL, 0);
- if (Result != 0) {
- goto DumpTypeCommandEnd;
- }
- DbgOut("\n");
- Result = 0;
- DumpTypeCommandEnd:
- return Result;
- }
- INT
- DbgrDumpMemory (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine prints the contents of debuggee memory to the screen.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG Address;
- PSTR Argument;
- ULONG ArgumentIndex;
- ULONGLONG Columns;
- PSTR MemoryType;
- BOOL PrintCharacters;
- INT Status;
- ULONGLONG TotalValues;
- ULONG TypeSize;
- BOOL VirtualAddress;
- Columns = 0;
- PrintCharacters = TRUE;
- TotalValues = 0;
- VirtualAddress = TRUE;
- MemoryType = Arguments[0];
- //
- // Get the type size.
- //
- if (strcasecmp(MemoryType, "db") == 0) {
- TypeSize = 1;
- } else if (strcasecmp(MemoryType, "dc") == 0) {
- TypeSize = 1;
- } else if (strcasecmp(MemoryType, "dw") == 0) {
- TypeSize = 2;
- } else if (strcasecmp(MemoryType, "dd") == 0) {
- TypeSize = 4;
- } else if (strcasecmp(MemoryType, "dq") == 0) {
- TypeSize = 8;
- } else {
- DbgOut("Error: unrecognized command. Valid dump commands are db (byte),"
- " dc (char), dw (word), dd (double-word), dq (quad-word), and "
- "dt (type).\n");
- Status = EINVAL;
- goto DebuggerDumpMemoryEnd;
- }
- //
- // Go through the arguments.
- //
- for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
- Argument = Arguments[ArgumentIndex];
- assert(Argument != NULL);
- if (Argument[0] == '-') {
- Argument += 1;
- //
- // 'c' specifies the number of columns.
- //
- if (Argument[0] == 'c') {
- Status = DbgEvaluate(Context, Argument + 1, &Columns);
- if (Status != 0) {
- DbgOut("Error: Invalid column argument \"%s\". The correct "
- "form looks something like \"c4\".\n",
- Argument);
- goto DebuggerDumpMemoryEnd;
- }
- }
- //
- // 'l' specifies the number of values to print.
- //
- if (Argument[0] == 'l') {
- Status = DbgEvaluate(Context, Argument + 1, &TotalValues);
- if (Status != 0) {
- DbgOut("Error: Invalid total values argument \"%s\". The "
- "correct form looks something like \"l8\".\n",
- Argument);
- goto DebuggerDumpMemoryEnd;
- }
- }
- //
- // 'p' specifies physical addressing.
- //
- if (Argument[0] == 'p') {
- VirtualAddress = FALSE;
- }
- }
- //
- // The last argument is the address to dump.
- //
- if (ArgumentIndex == ArgumentCount - 1) {
- Status = DbgEvaluate(Context, Argument, &Address);
- if (Status != 0) {
- DbgOut("Error: unable to parse address \"%s\".\n", Argument);
- goto DebuggerDumpMemoryEnd;
- }
- }
- }
- //
- // If the argument count is 0, continue from the previous dump or print the
- // default dump.
- //
- if (ArgumentCount <= 1) {
- Address = Context->LastMemoryDump.NextAddress;
- VirtualAddress = Context->LastMemoryDump.Virtual;
- Columns = Context->LastMemoryDump.Columns;
- TotalValues = Context->LastMemoryDump.TotalValues;
- PrintCharacters = Context->LastMemoryDump.PrintCharacters;
- //
- // Save the current dump parameters.
- //
- } else {
- Context->LastMemoryDump.NextAddress = Address +
- (TypeSize * TotalValues);
- Context->LastMemoryDump.Virtual = VirtualAddress;
- Context->LastMemoryDump.Columns = Columns;
- Context->LastMemoryDump.TotalValues = TotalValues;
- Context->LastMemoryDump.PrintCharacters = PrintCharacters;
- }
- //
- // Update the last dump address.
- //
- if (TotalValues == 0) {
- Context->LastMemoryDump.NextAddress += 16 * DEFAULT_MEMORY_PRINT_ROWS;
- } else {
- Context->LastMemoryDump.NextAddress += TotalValues * TypeSize;
- }
- //
- // All the information has been collected. Attempt to print the memory.
- //
- Status = DbgrpPrintMemory(Context,
- Address,
- VirtualAddress,
- TypeSize,
- Columns,
- TotalValues,
- PrintCharacters);
- if (Status != 0) {
- goto DebuggerDumpMemoryEnd;
- }
- Status = 0;
- DebuggerDumpMemoryEnd:
- return Status;
- }
- INT
- DbgrDumpList (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine interates over a linked list and prints out the structure
- information for each entry. It also performs basic validation on the list,
- checking for bad previous pointers.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONG BytesRead;
- ULONG Count;
- ULONGLONG CurrentAddress;
- ULONG FieldOffset;
- ULONG FieldSize;
- ULONGLONG ListEntry[2];
- PSTR ListEntryName;
- ULONG ListEntrySize;
- ULONGLONG ListHeadAddress;
- PSTR ListHeadAddressString;
- ULONG PointerSize;
- ULONGLONG PreviousAddress;
- PTYPE_SYMBOL ResolvedType;
- BOOL Result;
- SYMBOL_SEARCH_RESULT SearchResult;
- INT Status;
- ULONGLONG StructureAddress;
- PVOID StructureBuffer;
- PDATA_TYPE_STRUCTURE StructureData;
- ULONG StructureSize;
- PSTR TypeNameString;
- Status = EINVAL;
- //
- // Argument validation.
- //
- if (ArgumentCount < 3) {
- DbgOut("Usage: dl <list head address> <type name> "
- "[<list entry name>]\n");
- goto DumpListEnd;
- }
- ListHeadAddressString = Arguments[1];
- TypeNameString = Arguments[2];
- //
- // Evaluate the first argument, converting it to the list head address.
- //
- Status = DbgEvaluate(Context, ListHeadAddressString, &ListHeadAddress);
- if (Status != 0) {
- DbgOut("Error: Could not evaluate address from string %s\n",
- Arguments[0]);
- goto DumpListEnd;
- }
- //
- // Serach through all modules to find the supplied symbol.
- //
- SearchResult.Variety = SymbolResultType;
- Result = DbgpFindSymbol(Context, TypeNameString, &SearchResult);
- if (Result == FALSE) {
- DbgOut("Error: Unknown type name %s\n", TypeNameString);
- goto DumpListEnd;
- }
- //
- // Validate that the given symbol is a structure. It must at least be a
- // type.
- //
- if (SearchResult.Variety != SymbolResultType) {
- DbgOut("Error: %s is not a structure.\n", TypeNameString);
- goto DumpListEnd;
- }
- //
- // If the symbol is a relation type, then test to see if it resolves to a
- // structure type.
- //
- if (SearchResult.U.TypeResult->Type == DataTypeRelation) {
- ResolvedType = DbgSkipTypedefs(SearchResult.U.TypeResult);
- if ((ResolvedType == NULL) ||
- (ResolvedType->Type != DataTypeStructure)) {
- DbgOut("Error: %s could not be resolved as a structure.\n",
- TypeNameString);
- goto DumpListEnd;
- }
- //
- // If the symbol is not a structure type, then this is an error.
- //
- } else if (SearchResult.U.TypeResult->Type != DataTypeStructure) {
- DbgOut("Error: %s is not a structure.\n", TypeNameString);
- goto DumpListEnd;
- } else {
- ResolvedType = SearchResult.U.TypeResult;
- }
- //
- // If the list entry name is not supplied, assume the field is called
- // "ListEntry".
- //
- ListEntryName = "ListEntry";
- if (ArgumentCount > 3) {
- ListEntryName = Arguments[3];
- }
- //
- // Get the offset and size of the list entry field.
- //
- Status = DbgGetMemberOffset(ResolvedType,
- ListEntryName,
- &FieldOffset,
- &FieldSize);
- if (Status != 0) {
- DbgOut("Error: Unknown structure member %s\n", ListEntryName);
- goto DumpListEnd;
- }
- if ((FieldOffset % BITS_PER_BYTE) != 0) {
- DbgOut("Error: Structure member %s is not byte align\n", ListEntryName);
- goto DumpListEnd;
- }
- //
- // Read the Next and Previous pointers from the list head.
- //
- PointerSize = DbgGetTargetPointerSize(Context);
- ListEntrySize = PointerSize * 2;
- Status = DbgReadMemory(Context,
- TRUE,
- ListHeadAddress,
- ListEntrySize,
- ListEntry,
- &BytesRead);
- if ((Status != 0) || (BytesRead != ListEntrySize)) {
- if (Status == 0) {
- Status = EINVAL;
- }
- DbgOut("Error: Unable to read data at address 0x%I64x\n",
- ListHeadAddress);
- goto DumpListEnd;
- }
- //
- // If the target's pointer size is 32-bits modify the ListEntry array to
- // hold a list pointer in each index.
- //
- if (PointerSize == sizeof(ULONG)) {
- ListEntry[1] = ListEntry[0] >> (sizeof(ULONG) * BITS_PER_BYTE);
- ListEntry[0] &= MAX_ULONG;
- }
- //
- // If the list is empty validate the Previous pointer and exit.
- //
- if (ListEntry[0] == ListHeadAddress) {
- DbgOut("Empty List\n");
- if (ListEntry[1] != ListHeadAddress) {
- DbgOut("Error: Corrupted empty list head Previous.\n"
- "\tExpected Value: 0x%I64x\n"
- "\tActual Value: 0x%I64x\n",
- ListHeadAddress,
- ListEntry[1]);
- }
- goto DumpListEnd;
- }
- //
- // Get the given data structure's size and allocate a buffer for reading
- // each structure entry in the list.
- //
- StructureData = &(ResolvedType->U.Structure);
- StructureSize = StructureData->SizeInBytes;
- StructureBuffer = malloc(StructureSize);
- if (StructureBuffer == NULL) {
- DbgOut("Error: Failed to allocate %d bytes\n", StructureSize);
- goto DumpListEnd;
- }
- //
- // Loop through the list, printing each element.
- //
- Count = 0;
- CurrentAddress = ListEntry[0];
- PreviousAddress = ListHeadAddress;
- while (CurrentAddress != ListHeadAddress) {
- if (CurrentAddress == (UINTN)NULL) {
- DbgOut("Error: Found NULL list entry Next pointer\n");
- break;
- }
- //
- // Calculate the structure's base pointer and read it from memory.
- //
- StructureAddress = CurrentAddress - (FieldOffset / BITS_PER_BYTE);
- Status = DbgReadMemory(Context,
- TRUE,
- StructureAddress,
- StructureSize,
- StructureBuffer,
- &BytesRead);
- if ((Status != 0) || (BytesRead != StructureSize)) {
- if (Status == 0) {
- Status = EINVAL;
- }
- DbgOut("Error: Unable to read %d bytes at address 0x%I64x\n",
- StructureSize,
- StructureAddress);
- goto DumpListEnd;
- }
- //
- // Print the structure's contents.
- //
- DbgOut("----------------------------------------\n");
- DbgOut("List Entry %d at address 0x%I64x\n", Count, StructureAddress);
- DbgOut("----------------------------------------\n");
- DbgPrintType(Context,
- ResolvedType,
- StructureBuffer,
- StructureSize,
- 1,
- DEFAULT_RECURSION_DEPTH);
- DbgOut("\n");
- //
- // Read the current structure's list entry data.
- //
- Status = DbgReadMemory(Context,
- TRUE,
- CurrentAddress,
- ListEntrySize,
- ListEntry,
- &BytesRead);
- if ((Status != 0) || (BytesRead != ListEntrySize)) {
- if (Status == 0) {
- Status = EINVAL;
- }
- DbgOut("Error: Unable to read data at address 0x%I64x\n",
- CurrentAddress);
- goto DumpListEnd;
- }
- //
- // Perform the same pointer magic as we did above for the head.
- //
- if (PointerSize == sizeof(ULONG)) {
- ListEntry[1] = ListEntry[0] >> (sizeof(ULONG) * BITS_PER_BYTE);
- ListEntry[0] &= MAX_ULONG;
- }
- //
- // Validate that the current list entry's Previous field points to the
- // previous element in the list.
- //
- if (PreviousAddress != ListEntry[1]) {
- DbgOut("Error: Corrupted previous pointer:\n"
- "\tExpected Value: 0x%I64x\n"
- "\tActual Value: 0x%I64x\n",
- PreviousAddress,
- ListEntry[1]);
- goto DumpListEnd;
- }
- PreviousAddress = CurrentAddress;
- CurrentAddress = ListEntry[0];
- Count += 1;
- }
- Status = 0;
- DumpListEnd:
- return Status;
- }
- INT
- DbgrEditMemory (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine writes to the target memory space.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG Address;
- PSTR Argument;
- ULONG ArgumentIndex;
- ULONG BufferSize;
- ULONG BytesWritten;
- PVOID CurrentValue;
- PVOID DataBuffer;
- PSTR MemoryType;
- INT Status;
- ULONG TypeSize;
- ULONGLONG Value;
- BOOL VirtualAddress;
- Address = 0;
- DataBuffer = NULL;
- MemoryType = Arguments[0];
- VirtualAddress = TRUE;
- //
- // Get the type size.
- //
- if (strcasecmp(MemoryType, "eb") == 0) {
- TypeSize = 1;
- } else if (strcasecmp(MemoryType, "ew") == 0) {
- TypeSize = 2;
- } else if (strcasecmp(MemoryType, "ed") == 0) {
- TypeSize = 4;
- } else if (strcasecmp(MemoryType, "eq") == 0) {
- TypeSize = 8;
- } else {
- DbgOut("Error: unrecognized command. Valid edit commands are eb "
- "(byte), ew (word), ed (double-word), and eq (quad-word).\n");
- Status = EINVAL;
- goto DebuggerEditMemoryEnd;
- }
- //
- // Go through the argument options.
- //
- for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
- Argument = Arguments[ArgumentIndex];
- assert(Argument != NULL);
- //
- // 'p' specifies physical addressing.
- //
- if ((Argument[0] == 'p') && (Argument[1] == '\0')) {
- VirtualAddress = FALSE;
- continue;
- }
- break;
- }
- //
- // The next argument is the address to edit.
- //
- if (ArgumentIndex == ArgumentCount) {
- DbgOut("Error: Not enough arguments.\n");
- Status = EINVAL;
- goto DebuggerEditMemoryEnd;
- }
- Status = DbgEvaluate(Context, Arguments[ArgumentIndex], &Address);
- if (Status != 0) {
- DbgOut("Error: unable to parse address \"%s\".\n",
- Arguments[ArgumentIndex]);
- goto DebuggerEditMemoryEnd;
- }
- ArgumentIndex += 1;
- if (ArgumentIndex == ArgumentCount) {
- DbgOut("Error: Not enough arguments!\n");
- Status = EINVAL;
- goto DebuggerEditMemoryEnd;
- }
- //
- // All other arguments are values to write, sequentially. Start by
- // allocating space for the data to be written.
- //
- BufferSize = (ArgumentCount - ArgumentIndex) * TypeSize;
- DataBuffer = malloc(BufferSize);
- if (DataBuffer == NULL) {
- DbgOut("Error: Unable to allocate %d bytes.\n", BufferSize);
- Status = ENOMEM;
- goto DebuggerEditMemoryEnd;
- }
- CurrentValue = DataBuffer;
- for (NOTHING; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
- Status = DbgEvaluate(Context, Arguments[ArgumentIndex], &Value);
- if (Status != 0) {
- DbgOut("Error: Unable to parse value \"%s\".\n",
- Arguments[ArgumentIndex]);
- goto DebuggerEditMemoryEnd;
- }
- memcpy(CurrentValue, &Value, TypeSize);
- CurrentValue += TypeSize;
- }
- //
- // Attempt to write the values to memory.
- //
- Status = DbgWriteMemory(Context,
- VirtualAddress,
- Address,
- BufferSize,
- DataBuffer,
- &BytesWritten);
- if (Status != 0) {
- goto DebuggerEditMemoryEnd;
- }
- if (BytesWritten != BufferSize) {
- DbgOut("Only %d of %d bytes written.\n", BytesWritten, BufferSize);
- }
- Context->LastMemoryDump.NextAddress = Address;
- Context->LastMemoryDump.Virtual = VirtualAddress;
- Status = 0;
- DebuggerEditMemoryEnd:
- if (DataBuffer != NULL) {
- free(DataBuffer);
- }
- return Status;
- }
- INT
- DbgrEvaluate (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine evaluates a numerical expression and prints it out in both
- decimal and hexadecimal.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG Result;
- BOOL Status;
- if (ArgumentCount < 2) {
- DbgOut("Usage: %s <expr>.\nExpressions can be numeric (3+4) or \n"
- "symbolic (DbgSymbolTable+(0x10*4)).\n",
- Arguments[0]);
- return EINVAL;
- }
- Status = DbgEvaluate(Context, Arguments[1], &Result);
- if (Status != 0) {
- DbgOut("Syntax error in expression.\n");
- goto EvaluateEnd;
- }
- DbgOut(" 0x%I64x = %I64d\n", Result, Result);
- Status = 0;
- EvaluateEnd:
- return Status;
- }
- INT
- DbgrPrintLocals (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine prints the values of the local variables inside the currently
- selected stack frame.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PDATA_SYMBOL BestLocal;
- PDATA_SYMBOL CurrentLocal;
- PLIST_ENTRY CurrentLocalEntry;
- PFUNCTION_SYMBOL Function;
- ULONGLONG InstructionPointer;
- PDEBUGGER_MODULE Module;
- BOOL ParameterPrinted;
- PSYMBOL_SEARCH_RESULT ResultValid;
- SYMBOL_SEARCH_RESULT SearchResult;
- INT Status;
- //
- // Attempt to get the module this address is in. If one cannot be found,
- // then there is no useful information to print, so exit.
- //
- InstructionPointer = DbgGetPc(Context, &(Context->FrameRegisters));
- Module = DbgpFindModuleFromAddress(Context,
- InstructionPointer,
- &InstructionPointer);
- if (Module == NULL) {
- DbgOut("Error: Execution is not in any module!\n");
- Status = ENOENT;
- goto PrintLocalsEnd;
- }
- //
- // Attempt to find the current function symbol in the module.
- //
- SearchResult.Variety = SymbolResultInvalid;
- ResultValid = NULL;
- if (Module->Symbols != NULL) {
- ResultValid = DbgFindFunctionSymbol(Module->Symbols,
- NULL,
- InstructionPointer,
- &SearchResult);
- } else {
- DbgOut("Error: Module %s has no symbols loaded for it!\n",
- Module->ModuleName);
- Status = ESRCH;
- goto PrintLocalsEnd;
- }
- //
- // If a function could not be found, bail.
- //
- if ((ResultValid == NULL) ||
- (SearchResult.Variety != SymbolResultFunction)) {
- DbgOut("Error: Function symbol could not be found in module %s!\n",
- Module->ModuleName);
- Status = ENOENT;
- goto PrintLocalsEnd;
- }
- Function = SearchResult.U.FunctionResult;
- //
- // Print all function parameters.
- //
- ParameterPrinted = FALSE;
- CurrentLocalEntry = Function->ParametersHead.Next;
- while (CurrentLocalEntry != &(Function->ParametersHead)) {
- CurrentLocal = LIST_VALUE(CurrentLocalEntry, DATA_SYMBOL, ListEntry);
- CurrentLocalEntry = CurrentLocalEntry->Next;
- Status = DbgPrintDataSymbol(Context,
- Module->Symbols,
- CurrentLocal,
- InstructionPointer,
- 4,
- DEFAULT_RECURSION_DEPTH);
- if (Status != ENOENT) {
- if (Status == 0) {
- ParameterPrinted = TRUE;
- }
- DbgOut("\n");
- }
- }
- if (ParameterPrinted != FALSE) {
- DbgOut("\n");
- }
- //
- // Loop through every local in the function.
- //
- CurrentLocalEntry = Function->LocalsHead.Next;
- while (CurrentLocalEntry != &(Function->LocalsHead)) {
- CurrentLocal = LIST_VALUE(CurrentLocalEntry, DATA_SYMBOL, ListEntry);
- CurrentLocalEntry = CurrentLocalEntry->Next;
- if (CurrentLocal->MinimumValidExecutionAddress != 0) {
- //
- // Skip this local if it's not yet valid.
- //
- if (InstructionPointer <
- CurrentLocal->MinimumValidExecutionAddress) {
- continue;
- }
- //
- // Attempt to find the most updated version of this local. Skip
- // this one if a different local is determined to be the most up to
- // date.
- //
- BestLocal = DbgpGetLocal(Function,
- CurrentLocal->Name,
- InstructionPointer);
- //
- // The function should definitely not fail to find any local, since
- // this function found it.
- //
- assert(BestLocal != NULL);
- if (BestLocal != CurrentLocal) {
- continue;
- }
- }
- //
- // Print out this local.
- //
- Status = DbgPrintDataSymbol(Context,
- Module->Symbols,
- CurrentLocal,
- InstructionPointer,
- 4,
- DEFAULT_RECURSION_DEPTH);
- if (Status != ENOENT) {
- DbgOut("\n");
- }
- }
- Status = 0;
- PrintLocalsEnd:
- return Status;
- }
- INT
- DbgrShowSourceAtAddressCommand (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine shows the source file for the provided address and highlights
- the specific line associated with the address.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG Address;
- PSTR AddressString;
- INT Result;
- if (ArgumentCount != 2) {
- DbgOut("Usage: so <address>.\nThis command displays the current "
- "source file and line for the given address.\n");
- return EINVAL;
- }
- AddressString = Arguments[1];
- Result = DbgEvaluate(Context, AddressString, &Address);
- if (Result != 0) {
- DbgOut("Error: Unable to parse address %s.\n", Address);
- goto ShowSourceAtAddressEnd;
- }
- DbgrShowSourceAtAddress(Context, Address);
- Result = 0;
- ShowSourceAtAddressEnd:
- return Result;
- }
- VOID
- DbgrUnhighlightCurrentLine (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine restores the currently executing line to the normal background
- color in the source window.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- None.
- --*/
- {
- //
- // Remove the highlight on the previous line.
- //
- DbgrpHighlightExecutingLine(Context, 0);
- return;
- }
- INT
- DbgrListBreakPoints (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine lists all valid breakpoints in the target.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PDEBUGGER_BREAK_POINT Breakpoint;
- PLIST_ENTRY CurrentEntry;
- INT Status;
- DbgOut("Breakpoints: \n");
- if (LIST_EMPTY(&(Context->BreakpointList)) != FALSE) {
- DbgOut("(None)\n");
- return 0;
- }
- //
- // Loop and print every breakpoint.
- //
- CurrentEntry = Context->BreakpointList.Next;
- while (CurrentEntry != &(Context->BreakpointList)) {
- Breakpoint = LIST_VALUE(CurrentEntry, DEBUGGER_BREAK_POINT, ListEntry);
- //
- // Check that this is a valid entry.
- //
- if (Breakpoint->Type == BreakpointTypeInvalid) {
- DbgOut("Error: Invalid breakpoint type!\n");
- Status = EINVAL;
- goto ListBreakPointsEnd;
- }
- //
- // Print the breakpoint index and whether or not the breakpoint is
- // disabled.
- //
- DbgOut("%d: ", Breakpoint->Index);
- if (Breakpoint->Enabled == FALSE) {
- DbgOut("(Disabled) ");
- }
- //
- // Print the breakpoint address, with symbol information if possible.
- //
- DbgOut("%08I64x ", Breakpoint->Address);
- Status = DbgPrintAddressSymbol(Context, Breakpoint->Address);
- if (Status == 0) {
- DbgOut(" ");
- }
- //
- // If it's a break on access, print out the access type and size.
- //
- if (Breakpoint->Type == BreakpointTypeRead) {
- DbgOut("Read ");
- } else if (Breakpoint->Type == BreakpointTypeWrite) {
- DbgOut("Write ");
- } else if (Breakpoint->Type == BreakpointTypeReadWrite) {
- DbgOut("Read/Write ");
- }
- if ((Breakpoint->Type == BreakpointTypeRead) ||
- (Breakpoint->Type == BreakpointTypeWrite) ||
- (Breakpoint->Type == BreakpointTypeReadWrite)) {
- DbgOut("%d Bytes", Breakpoint->AccessSize);
- }
- //
- // Advance to the next breakpoint.
- //
- DbgOut("\n");
- CurrentEntry = CurrentEntry->Next;
- }
- Status = 0;
- ListBreakPointsEnd:
- return Status;
- }
- INT
- DbgrEnableBreakPoint (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine lists all valid breakpoints in the target.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR AfterScan;
- BOOL Enable;
- LONG Number;
- PSTR NumberString;
- INT Status;
- if (ArgumentCount < 2) {
- DbgOut("Usage: %s <N>\nEnable or disable the break point with the "
- "given number N. Use bl to list all breakpoints.\n",
- Arguments[0]);
- Status = EINVAL;
- goto EnableBreakPointEnd;
- }
- Enable = FALSE;
- if (strcasecmp(Arguments[0], "be") == 0) {
- Enable = TRUE;
- } else {
- assert(strcasecmp(Arguments[0], "bd") == 0);
- }
- NumberString = Arguments[1];
- //
- // A star specifies all breakpoints.
- //
- if (strcmp(NumberString, "*") == 0) {
- Number = -1;
- } else {
- Number = strtol(NumberString, &AfterScan, 0);
- if (AfterScan == NumberString) {
- DbgOut("Failed to convert '%s' into a number.\n", NumberString);
- Status = EINVAL;
- goto EnableBreakPointEnd;
- }
- }
- Status = DbgrpEnableBreakPoint(Context, Number, Enable);
- if (Status != 0) {
- goto EnableBreakPointEnd;
- }
- EnableBreakPointEnd:
- return Status;
- }
- INT
- DbgrDeleteBreakPoint (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine deletes a breakpoint from the target.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR AfterScan;
- PDEBUGGER_BREAK_POINT Breakpoint;
- PLIST_ENTRY CurrentEntry;
- BOOL Found;
- LONG Number;
- PSTR NumberString;
- INT Status;
- if (ArgumentCount < 2) {
- DbgOut("Usage: %s <N>\nDelete a breakpoint with the given number N. "
- "Use * for all breakpoints. Use bl to list all breakpoints.\n",
- Arguments[0]);
- Status = EINVAL;
- goto DeleteBreakPointEnd;
- }
- NumberString = Arguments[1];
- //
- // A star specifies all breakpoints.
- //
- if (strcmp(NumberString, "*") == 0) {
- Number = -1;
- } else {
- Number = strtol(NumberString, &AfterScan, 0);
- if (AfterScan == NumberString) {
- DbgOut("Failed to convert '%s' into a number.\n", NumberString);
- Status = EINVAL;
- goto DeleteBreakPointEnd;
- }
- }
- //
- // Loop through looking for the breakpoint in the list.
- //
- Found = FALSE;
- CurrentEntry = Context->BreakpointList.Next;
- while (CurrentEntry != &(Context->BreakpointList)) {
- Breakpoint = LIST_VALUE(CurrentEntry, DEBUGGER_BREAK_POINT, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if ((Breakpoint->Index == Number) || (Number == -1)) {
- Found = TRUE;
- if (Context->BreakpointToRestore == Breakpoint) {
- Context->BreakpointToRestore = NULL;
- }
- if (Breakpoint->Enabled != FALSE) {
- DbgrpClearBreakpointAtAddress(Context,
- Breakpoint->Address,
- Breakpoint->OriginalValue);
- }
- LIST_REMOVE(&(Breakpoint->ListEntry));
- free(Breakpoint);
- if (Number != -1) {
- break;
- }
- }
- }
- if (Found == FALSE) {
- DbgOut("Breakpoint %d not found.\n", Number);
- Status = ESRCH;
- goto DeleteBreakPointEnd;
- }
- Status = 0;
- DeleteBreakPointEnd:
- return Status;
- }
- INT
- DbgrCreateBreakPoint (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine creates a new breakpoint in the debuggee.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR AccessType;
- PDEBUGGER_BREAK_POINT Breakpoint;
- PSTR BreakPointAddress;
- PDEBUGGER_BREAK_POINT BreakpointAfter;
- PDEBUGGER_BREAK_POINT CurrentBreakpoint;
- PLIST_ENTRY CurrentEntry;
- LONG Index;
- INT Status;
- AccessType = NULL;
- Breakpoint = NULL;
- if ((ArgumentCount <= 1) || (ArgumentCount > 3)) {
- DbgOut("Usage: bp [<access>] <address>.\n"
- "Set a new breakpoint. The access takes the form "
- "<type><width>, where type is 'r' for read, 'w' for write, or "
- "'x' for execute, and width is 1, 2, 4, or 8. The address is "
- "where to set the breakpoint.\n"
- "Example: \"bp w2 0x1004\" -- Breaks in when a two-byte write "
- "occurs to address 0x1004. If no access type is specified, a "
- "regular software execution breakpoint is created.\n");
- Status = EINVAL;
- goto CreateBreakPointEnd;
- }
- if (ArgumentCount > 2) {
- AccessType = Arguments[1];
- BreakPointAddress = Arguments[2];
- } else {
- assert(ArgumentCount == 2);
- BreakPointAddress = Arguments[1];
- }
- Breakpoint = malloc(sizeof(DEBUGGER_BREAK_POINT));
- if (Breakpoint == NULL) {
- DbgOut("Error: Failed to allocate space for a breakpoint.\n");
- Status = ENOMEM;
- goto CreateBreakPointEnd;
- }
- RtlZeroMemory(Breakpoint, sizeof(DEBUGGER_BREAK_POINT));
- //
- // Parse the access type.
- //
- if (AccessType != NULL) {
- //
- // It's a break on read or break on read/write.
- //
- if (*AccessType == 'r') {
- AccessType += 1;
- if (*AccessType == 'w') {
- AccessType += 1;
- Breakpoint->Type = BreakpointTypeReadWrite;
- } else {
- Breakpoint->Type = BreakpointTypeRead;
- }
- //
- // It's a break on write.
- //
- } else if (*AccessType == 'w') {
- AccessType += 1;
- Breakpoint->Type = BreakpointTypeWrite;
- //
- // It's an invalid specification.
- //
- } else {
- DbgOut("Error: Invalid access type specified. Valid values are "
- "r, w, and rw, but not %c.\n",
- *AccessType);
- Status = EINVAL;
- goto CreateBreakPointEnd;
- }
- //
- // Get the access size.
- //
- Breakpoint->AccessSize = strtoul(AccessType, NULL, 10);
- //
- // Check the validity of the result.
- //
- if ((Breakpoint->AccessSize != 1) &&
- (Breakpoint->AccessSize != 2) &&
- (Breakpoint->AccessSize != 4) &&
- (Breakpoint->AccessSize != 8) &&
- (Breakpoint->AccessSize != 16)) {
- DbgOut("Error: Invalid access size specified. Valid values are "
- "1, 2, 4, 8, and 16.\n");
- Status = EINVAL;
- goto CreateBreakPointEnd;
- }
- //
- // The access type parameter was NULL, so this must be a standard execution
- // breakpoint.
- //
- } else {
- Breakpoint->Type = BreakpointTypeExecution;
- }
- //
- // Parse the address parameter.
- //
- Status = DbgEvaluate(Context, BreakPointAddress, &(Breakpoint->Address));
- if (Status != 0) {
- DbgOut("Error: Unable to parse breakpoint address.\n");
- goto CreateBreakPointEnd;
- }
- //
- // TODO: Enable hardware breakpoints.
- //
- if (Breakpoint->Type != BreakpointTypeExecution) {
- DbgOut("Error: Break on access is currently not implemented.\n");
- Status = ENOSYS;
- goto CreateBreakPointEnd;
- }
- //
- // Loop through once and ensure there's not the same breakpoint already in
- // there (for software breakpoints only).
- //
- if (Breakpoint->Type == BreakpointTypeExecution) {
- CurrentEntry = Context->BreakpointList.Next;
- Index = 0;
- while (CurrentEntry != &(Context->BreakpointList)) {
- CurrentBreakpoint = LIST_VALUE(CurrentEntry,
- DEBUGGER_BREAK_POINT,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if ((CurrentBreakpoint->Type == Breakpoint->Type) &&
- (CurrentBreakpoint->Address == Breakpoint->Address)) {
- //
- // If the existing breakpoint is currently disabled, enable it.
- //
- if (CurrentBreakpoint->Enabled == FALSE) {
- Status = DbgrpEnableBreakPoint(Context,
- CurrentBreakpoint->Index,
- TRUE);
- if (Status != 0) {
- DbgOut("Error: Failed to re-enable existing breakpoint "
- "%d at %I64x.\n",
- CurrentBreakpoint->Index,
- CurrentBreakpoint->Address);
- goto CreateBreakPointEnd;
- }
- }
- Status = 0;
- goto CreateBreakPointEnd;
- }
- }
- }
- //
- // Find an index and location in the list for this breakpoint. The list is
- // always in sorted order by index.
- //
- BreakpointAfter = NULL;
- CurrentEntry = Context->BreakpointList.Next;
- Index = 0;
- while (CurrentEntry != &(Context->BreakpointList)) {
- BreakpointAfter = LIST_VALUE(CurrentEntry,
- DEBUGGER_BREAK_POINT,
- ListEntry);
- //
- // If the entry here is bigger than the index, then a free slot was
- // found.
- //
- if (BreakpointAfter->Index > Index) {
- break;
- }
- //
- // The index must be equal to this entrie's index. Move up to the next
- // slot.
- //
- Index += 1;
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // If the list is empty or entirely in order, then just put this one at
- // the back of the list.
- //
- Breakpoint->Index = Index;
- if (CurrentEntry == &(Context->BreakpointList)) {
- INSERT_BEFORE(&(Breakpoint->ListEntry), &(Context->BreakpointList));
- } else {
- INSERT_BEFORE(&(Breakpoint->ListEntry), &(BreakpointAfter->ListEntry));
- }
- Breakpoint->Enabled = FALSE;
- DbgrpEnableBreakPoint(Context, Breakpoint->Index, TRUE);
- Breakpoint = NULL;
- Status = 0;
- CreateBreakPointEnd:
- if (Breakpoint != NULL) {
- free(Breakpoint);
- }
- return Status;
- }
- INT
- DbgrStep (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine performs a source or assembly line step in the debugger.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG BaseDifference;
- PFUNCTION_SYMBOL CurrentFunction;
- PDEBUGGER_MODULE CurrentModule;
- PSOURCE_FILE_SYMBOL CurrentSource;
- ULONGLONG DebasedInstructionPointer;
- ULONGLONG FunctionEndAddress;
- SYMBOL_SEARCH_RESULT FunctionSearch;
- ULONGLONG InstructionPointer;
- ULONGLONG LineEndAddress;
- RANGE_STEP RangeStep;
- INT Result;
- PSYMBOL_SEARCH_RESULT ResultValid;
- PSOURCE_LINE_SYMBOL SourceLine;
- BOOL StepInto;
- BaseDifference = 0;
- CurrentFunction = NULL;
- CurrentSource = NULL;
- FunctionEndAddress = 0;
- InstructionPointer =
- Context->CurrentEvent.BreakNotification.InstructionPointer;
- DebasedInstructionPointer = InstructionPointer;
- SourceLine = NULL;
- StepInto = FALSE;
- if (strcasecmp(Arguments[0], "t") == 0) {
- StepInto = TRUE;
- } else {
- assert(strcasecmp(Arguments[0], "p") == 0);
- }
- //
- // Attempt to get the currently executing source line and function.
- //
- CurrentModule = DbgpFindModuleFromAddress(Context,
- InstructionPointer,
- &DebasedInstructionPointer);
- if (CurrentModule != NULL) {
- BaseDifference = CurrentModule->BaseDifference;
- SourceLine = DbgLookupSourceLine(CurrentModule->Symbols,
- DebasedInstructionPointer);
- if (SourceLine != NULL) {
- CurrentSource = SourceLine->ParentSource;
- }
- FunctionSearch.Variety = SymbolResultInvalid;
- ResultValid = DbgFindFunctionSymbol(CurrentModule->Symbols,
- NULL,
- DebasedInstructionPointer,
- &FunctionSearch);
- if (ResultValid != NULL) {
- assert(FunctionSearch.Variety == SymbolResultFunction);
- CurrentFunction = FunctionSearch.U.FunctionResult;
- }
- }
- //
- // If the source line or current function could not be found, or source
- // stepping is disabled, fall back to stepping over the current instruction.
- //
- if ((SourceLine == NULL) ||
- ((Context->Flags & DEBUGGER_FLAG_SOURCE_LINE_STEPPING) == 0)) {
- //
- // If stepping into, just execute a single step.
- //
- if (StepInto != FALSE) {
- Result = DbgrSingleStep(Context);
- //
- // Attempt to step over one instruction. Symbols will be helpful here.
- // Without them, this basically does a single step.
- //
- } else {
- //
- // Start with a default value that basically represents a single
- // step.
- //
- RangeStep.BreakRangeMinimum = 0;
- RangeStep.BreakRangeMaximum = MAX_ULONGLONG;
- //
- // If there is a current function symbol, then set the range to
- // break anywhere in this function, unless this is the last
- // instruction in the function.
- //
- if (CurrentFunction != NULL) {
- if ((DebasedInstructionPointer +
- Context->BreakInstructionLength) <
- CurrentFunction->EndAddress) {
- RangeStep.BreakRangeMinimum =
- CurrentFunction->StartAddress + BaseDifference;
- RangeStep.BreakRangeMaximum =
- CurrentFunction->EndAddress + BaseDifference;
- }
- //
- // There's not a function symbol, so check to see if there's at
- // least a source symbol. If there is, set the range to break
- // anywhere in this file.
- //
- } else if (CurrentSource != NULL) {
- if ((DebasedInstructionPointer +
- Context->BreakInstructionLength) <
- CurrentSource->EndAddress) {
- RangeStep.BreakRangeMinimum =
- CurrentSource->StartAddress + BaseDifference;
- RangeStep.BreakRangeMaximum =
- CurrentSource->EndAddress + BaseDifference;
- }
- }
- RangeStep.RangeHoleMinimum = InstructionPointer;
- RangeStep.RangeHoleMaximum = InstructionPointer + 1;
- Result = DbgrpRangeStep(Context, &RangeStep);
- }
- goto StepEnd;
- }
- //
- // Set a "range" breakpoint, which essentially puts the debuggee into single
- // step mode. The debuggee will break when it is inside the break range (ie
- // the current function), but not inside the range hole (ie the current
- // source line). Start by getting the addresses of the beginning and end of
- // the source line.
- //
- if ((CurrentFunction == NULL) || (SourceLine == NULL)) {
- LineEndAddress = 0;
- RangeStep.RangeHoleMinimum = 0;
- RangeStep.RangeHoleMaximum = 0;
- } else {
- LineEndAddress = SourceLine->End + BaseDifference;
- RangeStep.RangeHoleMinimum = SourceLine->Start + BaseDifference;
- RangeStep.RangeHoleMaximum = LineEndAddress;
- }
- //
- // If stepping into the source line or this is the last line of the
- // function (ie it's about to return), just set the break range to be the
- // entire address space.
- //
- if (CurrentFunction != NULL) {
- FunctionEndAddress = CurrentFunction->EndAddress + BaseDifference;
- }
- if ((StepInto != FALSE) ||
- (CurrentFunction == NULL) ||
- (LineEndAddress == FunctionEndAddress)) {
- RangeStep.BreakRangeMinimum = 0;
- RangeStep.BreakRangeMaximum = MAX_ULONGLONG;
- //
- // The command was step over and it's not the last line of the function, so
- // only break anywhere in the function.
- //
- } else {
- RangeStep.BreakRangeMinimum =
- CurrentFunction->StartAddress + BaseDifference;
- RangeStep.BreakRangeMaximum = FunctionEndAddress;
- }
- Result = DbgrpRangeStep(Context, &RangeStep);
- StepEnd:
- return Result;
- }
- INT
- DbgrSetSourceStepping (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine turns source line stepping on or off.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR Argument;
- if (ArgumentCount != 2) {
- DbgOut("Error: Use \"ss on\" or \"ss off\" to enable or disable source "
- "line stepping.\n");
- return EINVAL;
- }
- Argument = Arguments[1];
- if ((strcasecmp(Argument, "on") == 0) ||
- (strcasecmp(Argument, "yes") == 0) ||
- (strcasecmp(Argument, "1") == 0)) {
- Context->Flags |= DEBUGGER_FLAG_SOURCE_LINE_STEPPING;
- }
- if ((strcasecmp(Argument, "off") == 0) ||
- (strcasecmp(Argument, "no") == 0) ||
- (strcasecmp(Argument, "0") == 0)) {
- Context->Flags &= ~DEBUGGER_FLAG_SOURCE_LINE_STEPPING;
- }
- if ((Context->Flags & DEBUGGER_FLAG_SOURCE_LINE_STEPPING) != 0) {
- DbgOut("Stepping by source line is now enabled.\n");
- } else {
- DbgOut("Stepping by source line is now disabled.\n");
- }
- return 0;
- }
- INT
- DbgrSetSourceLinePrinting (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine turns on or off the option to print the source file and line
- next to every text address.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR Argument;
- if (ArgumentCount != 2) {
- DbgOut("Error: Use \"sl on\" or \"sl off\" to enable or disable source "
- "line printing.\n");
- return EINVAL;
- }
- Argument = Arguments[1];
- if ((strcasecmp(Argument, "on") == 0) ||
- (strcasecmp(Argument, "yes") == 0) ||
- (strcasecmp(Argument, "1") == 0)) {
- Context->Flags |= DEBUGGER_FLAG_PRINT_LINE_NUMBERS;
- }
- if ((strcasecmp(Argument, "off") == 0) ||
- (strcasecmp(Argument, "no") == 0) ||
- (strcasecmp(Argument, "0") == 0)) {
- Context->Flags &= ~DEBUGGER_FLAG_PRINT_LINE_NUMBERS;
- }
- if ((Context->Flags & DEBUGGER_FLAG_PRINT_LINE_NUMBERS) != 0) {
- DbgOut("Printing of source line numbers is now enabled.\n");
- } else {
- DbgOut("Printing of source line numbers is now disabled.\n");
- }
- return 0;
- }
- INT
- DbgrReturnToCaller (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine interprets the "go" command from the user.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONG BytesRead;
- ULONG FirstInstruction;
- ULONG FirstInstructionAddress;
- STACK_FRAME Frame;
- ULONG FrameCount;
- ULONGLONG InstructionPointer;
- INT Result;
- ULONGLONG ReturnAddress;
- ReturnAddress = 0;
- assert(Context->CurrentEvent.Type == DebuggerEventBreak);
- InstructionPointer =
- Context->CurrentEvent.BreakNotification.InstructionPointer;
- //
- // For ARM machines, the compiler doesn't generate a stack frame for
- // leaf functions (functions that call no other functions). If this is the
- // case the link register is actually the return value, not the frame.
- // Detect this case by reading the first instruction of the function. If
- // it's not "mov ip, sp", then this is a leaf function.
- //
- if (Context->MachineType == MACHINE_TYPE_ARM) {
- FirstInstructionAddress =
- DbgpGetFunctionStartAddress(Context, InstructionPointer);
- if (FirstInstructionAddress != 0) {
- Result = DbgReadMemory(Context,
- TRUE,
- FirstInstructionAddress,
- ARM_INSTRUCTION_LENGTH,
- &FirstInstruction,
- &BytesRead);
- if ((Result == 0) && (BytesRead == ARM_INSTRUCTION_LENGTH) &&
- ((FirstInstruction != ARM_FUNCTION_PROLOGUE) ||
- (InstructionPointer == FirstInstructionAddress))) {
- ReturnAddress =
- Context->CurrentEvent.BreakNotification.Registers.Arm.R14Lr;
- Result = 0;
- goto ReturnToCallerEnd;
- }
- }
- }
- FrameCount = 1;
- Result = DbgGetCallStack(Context, NULL, &Frame, &FrameCount);
- if ((Result != 0) || (FrameCount == 0)) {
- DbgOut("Error: Unable to get call stack.\n");
- Result = EINVAL;
- goto ReturnToCallerEnd;
- }
- ReturnAddress = Frame.ReturnAddress;
- Result = 0;
- ReturnToCallerEnd:
- //
- // If the return address was successfully retrieved, then send the go
- // command.
- //
- if (Result == 0) {
- Result = DbgrContinue(Context, TRUE, ReturnAddress);
- }
- return Result;
- }
- INT
- DbgrSetSymbolPathCommand (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine sets or updates the symbol search path.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- BOOL Append;
- ULONG ArgumentIndex;
- ULONG PathIndex;
- INT Status;
- INT TotalStatus;
- //
- // The sympath+ command augments the current symbol path.
- //
- if (strcasecmp(Arguments[0], "sympath+") == 0) {
- Append = TRUE;
- //
- // The sympath command command either prints the current symbol path with
- // no arguments or sets a new one.
- //
- } else {
- assert(strcasecmp(Arguments[0], "sympath") == 0);
- Append = FALSE;
- if (ArgumentCount == 1) {
- for (PathIndex = 0;
- PathIndex < Context->SymbolPathCount;
- PathIndex += 1) {
- DbgOut("%s\n", Context->SymbolPath[PathIndex]);
- }
- return 0;
- }
- }
- //
- // Loop adding or replacing the symbol path.
- //
- TotalStatus = 0;
- for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
- Status = DbgrSetSymbolPath(Context, Arguments[ArgumentIndex], Append);
- if (Status != 0) {
- TotalStatus = Status;
- }
- //
- // Assume that even if the user didn't specify sympath+ but did add
- // multiple arguments, they want all the arguments in the search path.
- //
- Append = TRUE;
- }
- Status = TotalStatus;
- return Status;
- }
- INT
- DbgrSetSourcePathCommand (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine sets or updates the source search path.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONG ArgumentIndex;
- PLIST_ENTRY CurrentEntry;
- PDEBUGGER_SOURCE_PATH Entry;
- INT FinalResult;
- INT Result;
- if (strcasecmp(Arguments[0], "srcpath+") != 0) {
- //
- // If it's just srcpath by itself, print the current source path.
- //
- if (ArgumentCount == 1) {
- CurrentEntry = Context->SourcePathList.Next;
- while (CurrentEntry != &(Context->SourcePathList)) {
- Entry = LIST_VALUE(CurrentEntry,
- DEBUGGER_SOURCE_PATH,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Entry->PrefixLength != 0) {
- DbgOut("%s -> %s\n", Entry->Prefix, Entry->Path);
- } else {
- DbgOut("%s\n", Entry->Path);
- }
- }
- } else {
- DbgrpDestroyAllSourcePaths(Context);
- }
- }
- //
- // Add all source paths in the arguments.
- //
- FinalResult = 0;
- for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
- Result = DbgrpAddSourcePath(Context, Arguments[ArgumentIndex]);
- if (Result != 0) {
- DbgOut("Failed to add source path %s: Error %s.\n",
- Arguments[ArgumentIndex],
- strerror(Result));
- FinalResult = Result;
- }
- }
- return FinalResult;
- }
- INT
- DbgrReloadSymbols (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine unloads and reloads all symbols from the search path.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- INT Result;
- DbgrpUnloadAllModules(Context, FALSE);
- Result = DbgrpValidateLoadedModules(
- Context,
- Context->CurrentEvent.BreakNotification.LoadedModuleCount,
- Context->CurrentEvent.BreakNotification.LoadedModuleSignature,
- TRUE);
- return Result;
- }
- INT
- DbgrSetSymbolPath (
- PDEBUGGER_CONTEXT Context,
- PSTR Path,
- BOOL Append
- )
- /*++
- Routine Description:
- This routine sets or updates the symbol search path.
- Arguments:
- Context - Supplies a pointer to the application context.
- Path - Supplies a pointer to the new symbol path. This could contain
- multiple symbol paths if separated by semicolons.
- Append - Supplies a boolean indicating whether the new path should replace
- or append the existing path.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR CurrentString;
- PSTR *NewArray;
- PSTR NewPath;
- ULONG NewPathCount;
- PSTR Next;
- ULONG Offset;
- ULONG PathCount;
- ULONG PathIndex;
- ULONG PathLength;
- INT Status;
- NewArray = NULL;
- //
- // Loop once to count the number of semicolons.
- //
- NewPathCount = 1;
- CurrentString = Path;
- while (TRUE) {
- CurrentString = strchr(CurrentString, ';');
- if (CurrentString == NULL) {
- break;
- }
- NewPathCount += 1;
- CurrentString += 1;
- }
- //
- // Allocate the new array.
- //
- PathCount = NewPathCount;
- if (Append != FALSE) {
- PathCount += Context->SymbolPathCount;
- }
- NewArray = malloc(sizeof(PSTR) * PathCount);
- if (NewArray == NULL) {
- Status = ENOMEM;
- goto SetSymbolPathEnd;
- }
- memset(NewArray, 0, sizeof(PSTR) * PathCount);
- //
- // If copying, move the existing entries over now.
- //
- Offset = 0;
- if (Append != FALSE) {
- for (Offset = 0; Offset < Context->SymbolPathCount; Offset += 1) {
- NewArray[Offset] = Context->SymbolPath[Offset];
- }
- //
- // If not copying, free up the existing entries.
- //
- } else {
- for (PathIndex = 0;
- PathIndex < Context->SymbolPathCount;
- PathIndex += 1) {
- free(Context->SymbolPath[PathIndex]);
- }
- }
- if (Context->SymbolPath != NULL) {
- free(Context->SymbolPath);
- }
- //
- // Now create the new array entries based on the parameter.
- //
- CurrentString = Path;
- for (PathIndex = 0; PathIndex < NewPathCount; PathIndex += 1) {
- Next = strchr(CurrentString, ';');
- if (Next != NULL) {
- PathLength = (UINTN)Next - (UINTN)CurrentString;
- } else {
- PathLength = strlen(CurrentString);
- }
- NewPath = malloc(PathLength + 1);
- if (NewPath == NULL) {
- Status = ENOMEM;
- goto SetSymbolPathEnd;
- }
- memcpy(NewPath, CurrentString, PathLength);
- NewPath[PathLength] = '\0';
- NewArray[PathIndex + Offset] = NewPath;
- CurrentString = Next + 1;
- }
- Context->SymbolPath = NewArray;
- Context->SymbolPathCount = PathCount;
- Status = 0;
- SetSymbolPathEnd:
- if (Status != 0) {
- if (NewArray != NULL) {
- for (PathIndex = 0; PathIndex < NewPathCount; PathIndex += 1) {
- if (NewArray[PathIndex] != NULL) {
- free(NewArray[PathIndex]);
- }
- }
- free(NewArray);
- }
- }
- return Status;
- }
- INT
- DbgrLoadExtension (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine loads or unloads a debugger extension.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONG ArgumentIndex;
- PSTR Name;
- INT Status;
- INT TotalStatus;
- //
- // The load command fires up an extension.
- //
- if (strcasecmp(Arguments[0], "load") == 0) {
- if (ArgumentCount < 2) {
- DbgOut("Usage: load <path>\nLoads a debugger extension at the "
- "given path.\n");
- Status = EINVAL;
- goto LoadExtensionEnd;
- }
- TotalStatus = 0;
- for (ArgumentIndex = 1;
- ArgumentIndex < ArgumentCount;
- ArgumentIndex += 1) {
- Name = Arguments[ArgumentIndex];
- Status = DbgLoadExtension(Context, Name);
- if (Status != 0) {
- DbgOut("Failed to load extension '%s'.\n", Name);
- TotalStatus = Status;
- }
- }
- Status = TotalStatus;
- //
- // Unload an extension, or * for all extensions.
- //
- } else {
- assert(strcasecmp(Arguments[0], "unload") == 0);
- if (ArgumentCount < 2) {
- DbgOut("Usage: unload <path>\nUnloads a debugger extension at the "
- "given path. Use 'unload *' to unload all extensions.\n");
- Status = EINVAL;
- goto LoadExtensionEnd;
- }
- TotalStatus = 0;
- for (ArgumentIndex = 1;
- ArgumentIndex < ArgumentCount;
- ArgumentIndex += 1) {
- Name = Arguments[ArgumentIndex];
- if (strcmp(Name, "*") == 0) {
- DbgOut("Unloading all extensions.\n");
- DbgUnloadAllExtensions(Context);
- Status = 0;
- break;
- } else {
- DbgUnloadExtension(Context, Name);
- }
- }
- Status = TotalStatus;
- }
- LoadExtensionEnd:
- return Status;
- }
- INT
- DbgrSwitchProcessor (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine switches the debugger to another processor in kernel mode or
- thread in user mode.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR AfterScan;
- ULONG Count;
- PULONG Ids;
- ULONG ProcessorNumber;
- PSTR ProcessorNumberString;
- INT Result;
- ULONG ThreadIndex;
- Ids = NULL;
- assert(Arguments[0][0] == '~');
- if (Arguments[0][1] == '\0') {
- ProcessorNumber = -1;
- } else {
- ProcessorNumberString = Arguments[0] + 1;
- ProcessorNumber = strtoul(ProcessorNumberString, &AfterScan, 0);
- if (AfterScan == ProcessorNumberString) {
- DbgOut("Failed to convert '%s' to a number.\n",
- ProcessorNumberString);
- Result = EINVAL;
- goto SwitchProcessorsEnd;
- }
- }
- //
- // If no processor number was supplied, list the processors.
- //
- if (ProcessorNumber == -1) {
- Result = DbgGetThreadList(Context, &Count, &Ids);
- if (Result != 0) {
- DbgOut("Error: Failed to get processor/thread list.\n");
- goto SwitchProcessorsEnd;
- }
- if (Context->ConnectionType == DebugConnectionKernel) {
- if (Count == 1) {
- DbgOut("There is 1 processor in the system.\n");
- } else {
- DbgOut("There are %d processors in the system.\n", Count);
- }
- Result = 0;
- } else if (Context->ConnectionType == DebugConnectionUser) {
- if (Count == 1) {
- DbgOut("There is 1 thread in the process.\n");
- } else {
- DbgOut("There are %d threads in the process:\n", Count);
- for (ThreadIndex = 0; ThreadIndex < Count; ThreadIndex += 1) {
- DbgOut("%x\n", Ids[ThreadIndex]);
- }
- }
- } else {
- DbgOut("Error: Unknown connection type %d.\n",
- Context->ConnectionType);
- Result = EINVAL;
- }
- goto SwitchProcessorsEnd;
- }
- //
- // The user cannot switch to the same processor.
- //
- if (ProcessorNumber ==
- Context->CurrentEvent.BreakNotification.ProcessorOrThreadNumber) {
- Result = 0;
- goto SwitchProcessorsEnd;
- }
- //
- // The user cannot switch to a processor that's out of range.
- //
- Count = Context->CurrentEvent.BreakNotification.ProcessorOrThreadCount;
- if ((Context->ConnectionType == DebugConnectionKernel) &&
- (ProcessorNumber >= Count)) {
- if (Count == 1) {
- DbgOut("Error: There is only one processor in the system.\n");
- } else {
- DbgOut("Error: There are only %d processors in the system!\n",
- Count);
- }
- Result = 0;
- goto SwitchProcessorsEnd;
- }
- //
- // Send the switch command.
- //
- Result = DbgSwitchProcessors(Context, ProcessorNumber);
- if (Result != 0) {
- DbgOut("Error: Failed to switch processors.\n");
- goto SwitchProcessorsEnd;
- }
- //
- // Reset the frame as well.
- //
- DbgrpSetFrame(Context, 0);
- Context->LastMemoryDump.NextAddress =
- Context->CurrentEvent.BreakNotification.InstructionPointer;
- Context->LastMemoryDump.Virtual = TRUE;
- Context->DisassemblyAddress = Context->LastMemoryDump.NextAddress;
- Result = 0;
- SwitchProcessorsEnd:
- if (Ids != NULL) {
- free(Ids);
- }
- return Result;
- }
- INT
- DbgrPrintProcessorBlock (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine prints the contents of the current processor block.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG Address;
- UINTN Size;
- INT Status;
- PSTR TypeString;
- if (ArgumentCount > 1) {
- Size = strlen(Arguments[1]) + strlen("PROCESSOR_BLOCK") + 2;
- TypeString = malloc(Size);
- if (TypeString == NULL) {
- return ENOMEM;
- }
- snprintf(TypeString, Size, "%s.%s", "PROCESSOR_BLOCK", Arguments[1]);
- } else {
- TypeString = "PROCESSOR_BLOCK";
- }
- Address = Context->CurrentEvent.BreakNotification.ProcessorBlock;
- Status = EFAULT;
- if (Address != 0) {
- Status = DbgPrintTypeByName(Context,
- Address,
- TypeString,
- 0,
- DEFAULT_RECURSION_DEPTH);
- DbgOut("\n");
- }
- if (ArgumentCount > 1) {
- free(TypeString);
- }
- return Status;
- }
- VOID
- DbgrRequestBreakIn (
- VOID
- )
- /*++
- Routine Description:
- This routine sends a break-in request to the target.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- if (DbgConsoleContext->ConnectionType == DebugConnectionRemote) {
- DbgrpClientRequestBreakIn(DbgConsoleContext);
- } else {
- DbgRequestBreakIn(DbgConsoleContext);
- }
- return;
- }
- INT
- DbgrDumpPointerSymbols (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine dumps memory at the provided address and attempts to match
- symbols at the dumped memory addresses.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG Address;
- ULONG AddressSize;
- PSTR AddressString;
- PVOID Buffer;
- ULONG BufferSize;
- ULONG BytesRead;
- INT Index;
- INT Result;
- ULONGLONG Value;
- Buffer = NULL;
- AddressString = NULL;
- if (ArgumentCount >= 2) {
- AddressString = Arguments[1];
- Result = DbgEvaluate(Context, AddressString, &Address);
- if (Result != 0) {
- DbgOut("Failed to evaluate address '%s'.\n", AddressString);
- goto DumpPointerSymbolsEnd;
- }
- } else {
- Address = Context->LastMemoryDump.NextAddress;
- }
- AddressSize = DbgGetTargetPointerSize(Context);
- BufferSize = AddressSize * DEFAULT_DUMP_POINTERS_ROWS;
- Buffer = malloc(BufferSize);
- if (Buffer == NULL) {
- Result = ENOMEM;
- goto DumpPointerSymbolsEnd;
- }
- Result = DbgReadMemory(Context,
- TRUE,
- Address,
- BufferSize,
- Buffer,
- &BytesRead);
- if (Result != 0) {
- goto DumpPointerSymbolsEnd;
- }
- for (Index = 0; Index < DEFAULT_DUMP_POINTERS_ROWS; Index += 1) {
- DbgOut("%0*llx ", (int)AddressSize * 2, Address);
- Address += AddressSize;
- if (((Index + 1) * AddressSize) <= BytesRead) {
- Value = 0;
- memcpy(&Value, Buffer + (Index * AddressSize), AddressSize);
- DbgOut("%0*llx ", (int)AddressSize * 2, Value);
- DbgPrintAddressSymbol(Context, Value);
- } else {
- if (AddressSize == 8) {
- DbgOut("????????????????");
- } else {
- DbgOut("????????");
- }
- }
- DbgOut("\n");
- }
- Context->LastMemoryDump.NextAddress = Address;
- Context->LastMemoryDump.Virtual = TRUE;
- Result = 0;
- DumpPointerSymbolsEnd:
- if (Buffer != NULL) {
- free(Buffer);
- }
- return Result;
- }
- INT
- DbgrProfileCommand (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine handles the profile command. It essentially just forwards on
- to the profile handler.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- INT Result;
- Result = DbgrDispatchProfilerCommand(Context,
- Arguments + 1,
- ArgumentCount - 1);
- return Result;
- }
- INT
- DbgrRebootCommand (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine handles the profile command. It essentially just forwards on
- to the profile handler.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- BOOL PrintUsage;
- DEBUG_REBOOT_TYPE RebootType;
- PrintUsage = FALSE;
- RebootType = DebugRebootWarm;
- if (ArgumentCount > 2) {
- PrintUsage = TRUE;
- } else if (ArgumentCount > 1) {
- if (strcasecmp(Arguments[1], "-s") == 0) {
- RebootType = DebugRebootShutdown;
- } else if (strcasecmp(Arguments[1], "-w") == 0) {
- RebootType = DebugRebootWarm;
- } else if (strcasecmp(Arguments[1], "-c") == 0) {
- RebootType = DebugRebootCold;
- } else {
- PrintUsage = TRUE;
- }
- }
- if (PrintUsage != FALSE) {
- DbgOut("Usage: reboot [-s|-w|-c]\n"
- "This command forcefully reboots the target machine. If the \n"
- "target does not support the given option, a cold reboot is \n"
- "performed. Options are:\n"
- " -s -- Shut down the machine.\n"
- " -w -- Warm reset the machine (default).\n"
- " -c -- Cold reset the machine.\n\n");
- return 1;
- }
- return DbgReboot(Context, RebootType);
- }
- INT
- DbgrContinue (
- PDEBUGGER_CONTEXT Context,
- BOOL SetOneTimeBreak,
- ULONGLONG Address
- )
- /*++
- Routine Description:
- This routine sends the "go" command to the target, signaling to continue
- execution.
- Arguments:
- Context - Supplies a pointer to the application context.
- SetOneTimeBreak - Supplies a flag indicating whether to go unconditionally
- (FALSE) or with a one-time breakpoint (TRUE).
- Address - Supplies the address of the one-time breakpoint if one was
- specified.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PDEBUGGER_BREAK_POINT Breakpoint;
- PLIST_ENTRY CurrentEntry;
- INT Result;
- ULONG SignalToDeliver;
- //
- // Look to see if there's already an enabled breakpoint at that address,
- // and do nothing if there is.
- //
- CurrentEntry = Context->BreakpointList.Next;
- while ((SetOneTimeBreak != FALSE) &&
- (CurrentEntry != &(Context->BreakpointList))) {
- Breakpoint = LIST_VALUE(CurrentEntry, DEBUGGER_BREAK_POINT, ListEntry);
- if ((Breakpoint->Enabled != FALSE) &&
- (Breakpoint->Type == BreakpointTypeExecution) &&
- (Breakpoint->Address == Address)) {
- SetOneTimeBreak = FALSE;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Set the one time break point if requested.
- //
- if (SetOneTimeBreak != FALSE) {
- Result = DbgrpSetBreakpointAtAddress(
- Context,
- Address,
- &(Context->OneTimeBreakOriginalValue));
- Context->OneTimeBreakAddress = Address;
- if (Result != 0) {
- DbgOut("Error: Failed to set breakpoint at %I64x.\n", Address);
- return Result;
- }
- Context->OneTimeBreakValid = TRUE;
- }
- //
- // If there's a breakpoint to restore, then do a single step, restore the
- // breakpoint, and then continue.
- //
- if (Context->BreakpointToRestore != NULL) {
- Result = DbgrSingleStep(Context);
- if (Result != 0) {
- DbgOut("Error: Failed to single step.\n");
- return Result;
- }
- Result = DbgWaitForEvent(Context);
- if (Result != 0) {
- DbgOut("Error: Failed to wait for a response after single step.\n");
- return Result;
- }
- if (Context->CurrentEvent.Type != DebuggerEventBreak) {
- DbgOut("Failed to get a break after a single step.\n");
- return EINVAL;
- }
- Result = DbgrpSetBreakpointAtAddress(
- Context,
- Context->BreakpointToRestore->Address,
- &(Context->BreakpointToRestore->OriginalValue));
- if (Result != 0) {
- DbgOut("Failed to restore breakpoint %d at %I64x.\n",
- Context->BreakpointToRestore->Index,
- Context->BreakpointToRestore->Address);
- return Result;
- }
- Context->BreakpointToRestore = NULL;
- }
- SignalToDeliver = DbgGetSignalToDeliver(Context);
- Result = DbgContinue(Context, SignalToDeliver);
- if (Result != 0) {
- return Result;
- }
- Result = 0;
- return Result;
- }
- VOID
- DbgrShowSourceAtAddress (
- PDEBUGGER_CONTEXT Context,
- ULONGLONG Address
- )
- /*++
- Routine Description:
- This routine loads the source file and highlights the source line
- corresponding to the given target address.
- Arguments:
- Context - Supplies a pointer to the application context.
- Address - Supplies the target's executing virtual address.
- Return Value:
- None.
- --*/
- {
- PDEBUGGER_MODULE CurrentModule;
- ULONGLONG DebasedAddress;
- BOOL Result;
- PSOURCE_LINE_SYMBOL SourceLine;
- PSTR SourcePath;
- //
- // Acquire the standard out lock to synchronize with remote threads trying
- // to send updated source information.
- //
- AcquireDebuggerLock(Context->StandardOut.Lock);
- DbgrUnhighlightCurrentLine(Context);
- SourcePath = NULL;
- CurrentModule = DbgpFindModuleFromAddress(Context,
- Address,
- &DebasedAddress);
- if (CurrentModule != NULL) {
- SourceLine = DbgLookupSourceLine(CurrentModule->Symbols,
- DebasedAddress);
- if (SourceLine != NULL) {
- SourcePath = DbgrpCreateFullPath(SourceLine->ParentSource);
- if (SourcePath == NULL) {
- goto ShowSourceAtAddressEnd;
- }
- //
- // If the source file is different than what was previously
- // displayed, load the new source file.
- //
- if ((Context->SourceFile.Path == NULL) ||
- (strcmp(Context->SourceFile.Path, SourcePath) != 0)) {
- if (Context->SourceFile.Path != NULL) {
- free(Context->SourceFile.Path);
- Context->SourceFile.Path = NULL;
- }
- if (Context->SourceFile.ActualPath != NULL) {
- free(Context->SourceFile.ActualPath);
- Context->SourceFile.ActualPath = NULL;
- }
- if (Context->SourceFile.Contents != NULL) {
- free(Context->SourceFile.Contents);
- Context->SourceFile.Contents = 0;
- }
- Context->SourceFile.Path = SourcePath;
- SourcePath = NULL;
- Context->SourceFile.LineNumber = 0;
- Result = DbgrpLoadSourceFile(Context,
- Context->SourceFile.Path,
- &(Context->SourceFile.ActualPath),
- &(Context->SourceFile.Contents),
- &(Context->SourceFile.Size));
- if (Result == 0) {
- Result = UiLoadSourceFile(Context->SourceFile.ActualPath,
- Context->SourceFile.Contents,
- Context->SourceFile.Size);
- if (Result != FALSE) {
- DbgrpHighlightExecutingLine(Context,
- SourceLine->LineNumber);
- }
- //
- // The file load failed. Clear the screen. Do notify the
- // remotes too, maybe they'll have better luck loading the
- // file on their own.
- //
- } else {
- UiLoadSourceFile(NULL, NULL, 0);
- Context->SourceFile.LineNumber = SourceLine->LineNumber;
- DbgrpServerNotifyClients(Context);
- }
- //
- // It's the same file as before, just highlight a different line.
- //
- } else {
- DbgrpHighlightExecutingLine(Context, SourceLine->LineNumber);
- }
- }
- }
- ShowSourceAtAddressEnd:
- ReleaseDebuggerLock(Context->StandardOut.Lock);
- if (SourcePath != NULL) {
- free(SourcePath);
- }
- return;
- }
- INT
- DbgrDumpType (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount,
- PVOID RawDataStream,
- ULONG RawDataStreamSizeInBytes
- )
- /*++
- Routine Description:
- This routine prints information about a type description or value. If only
- a type is specified, the type format will be printed. If an address is
- passed as a second parameter, then the values will be dumped. If a global
- or local variable is passed as the first parameter, the values will also be
- dumped.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies a pointer to an array of argument strings.
- ArgumentCount - Supplies the number of arguments in the argument array.
- RawDataStream - Supplies the actual memory to dump in the given type form.
- If this parameter is non-NULL, then the AddressString parameter is
- ignored. The size of this buffer must be non-zero.
- RawDataStreamSizeInBytes - Supplies the size of the raw data stream buffer,
- in bytes.
- Return Value:
- 0 if the information was printed successfully.
- Returns an error code on failure.
- --*/
- {
- ULONGLONG Address;
- ULONG AddressIndex;
- ULONG AddressStartIndex;
- ULONG BytesRead;
- PDATA_SYMBOL DataResult;
- PVOID DataStream;
- PDATA_SYMBOL Local;
- ULONGLONG Pc;
- INT Result;
- SYMBOL_SEARCH_RESULT SearchResult;
- PDEBUG_SYMBOLS Symbols;
- PSTR SymbolString;
- PTYPE_SYMBOL Type;
- UINTN TypeSize;
- Address = 0;
- AddressStartIndex = 1;
- DataStream = NULL;
- Type = NULL;
- assert((Arguments != NULL) && (ArgumentCount != 0));
- //
- // Test to see if the first argument is a local variable name. Local
- // variables must be tested first because a local variable may match a
- // structure name, at which point the wrong data would be printed. Do not
- // perform this test when raw data is supplied.
- //
- if ((ArgumentCount == 1) &&
- ((RawDataStream == NULL) || (RawDataStreamSizeInBytes == 0))) {
- Result = DbgpFindLocal(Context,
- &(Context->FrameRegisters),
- Arguments[0],
- &Symbols,
- &Local,
- &Pc);
- if (Result == 0) {
- //
- // In order to dump the local variable, the local data symbol must
- // be evaluated for type information.
- //
- Result = DbgGetDataSymbolTypeInformation(Local, &Type, &TypeSize);
- if (Result == FALSE) {
- DbgOut("Error: unable to get type information for the local "
- "variable %s\n",
- Arguments[0]);
- Result = EINVAL;
- goto DumpTypeEnd;
- }
- //
- // Allocate memory to collect the data for the data symbol.
- //
- DataStream = malloc(TypeSize);
- if (DataStream == NULL) {
- DbgOut("Error: unable to allocate %ld bytes of memory\n",
- TypeSize);
- Result = ENOMEM;
- goto DumpTypeEnd;
- }
- //
- // Read the symbol data from the local data symbol.
- //
- Result = DbgGetDataSymbolData(Context,
- Symbols,
- Local,
- Pc,
- DataStream,
- TypeSize,
- NULL,
- 0);
- if (Result == 0) {
- //
- // Resolve the data into something useful to dump.
- //
- Address = 0;
- Result = DbgrpResolveDumpType(Context,
- &Type,
- &DataStream,
- &TypeSize,
- &Address);
- if (Result != 0) {
- DbgOut("Error: could not resolve dump type %s.\n",
- Type->Name);
- goto DumpTypeEnd;
- }
- if (Address != 0) {
- DbgOut("Dumping memory at 0x%08llx\n", Address);
- }
- Result = DbgPrintType(Context,
- Type,
- DataStream,
- TypeSize,
- 0,
- DEFAULT_RECURSION_DEPTH);
- goto DumpTypeEnd;
- //
- // If failed with something other than not found (for not currently
- // active locals), then bail to the end.
- //
- } else if (Result != ENOENT) {
- goto DumpTypeEnd;
- }
- }
- }
- //
- // If a local type was not found, search symbols for the first argument.
- // It should either by a type or a global variable.
- //
- SymbolString = Arguments[0];
- SearchResult.Variety = SymbolResultInvalid;
- Result = DbgpFindSymbol(Context, SymbolString, &SearchResult);
- if (Result == FALSE) {
- DbgOut("Error: Invalid type or global variable %s\n", SymbolString);
- Result = EINVAL;
- goto DumpTypeEnd;
- }
- switch (SearchResult.Variety) {
- case SymbolResultType:
- Type = SearchResult.U.TypeResult;
- AddressStartIndex = 1;
- break;
- case SymbolResultData:
- DataResult = SearchResult.U.DataResult;
- Type = DbgGetType(DataResult->TypeOwner, DataResult->TypeNumber);
- //
- // This argument was an address itself.
- //
- AddressStartIndex = 0;
- break;
- default:
- DbgOut("Error: Invalid symbol type %d for argument 1: %s\n",
- SearchResult.Variety,
- SymbolString);
- break;
- }
- if (Type != NULL) {
- Type = DbgSkipTypedefs(Type);
- }
- //
- // If a type was not found, print the error and exit.
- //
- if (Type == NULL) {
- DbgOut("Error: could not find type %s.\n", SymbolString);
- goto DumpTypeEnd;
- }
- //
- // If a raw data stream was supplied, print the contents of that in terms
- // of the type.
- //
- TypeSize = DbgGetTypeSize(Type, 0);
- if ((RawDataStream != NULL) && (RawDataStreamSizeInBytes != 0)) {
- if (RawDataStreamSizeInBytes < TypeSize) {
- DbgOut("Error: Supplied buffer of size %d is not big enough to "
- "print type of size %ld.\n",
- RawDataStreamSizeInBytes,
- TypeSize);
- Result = EINVAL;
- goto DumpTypeEnd;
- }
- Result = DbgPrintType(Context,
- Type,
- RawDataStream,
- RawDataStreamSizeInBytes,
- 0,
- DEFAULT_RECURSION_DEPTH);
- if (Result != 0) {
- goto DumpTypeEnd;
- }
- //
- // If an address was specified, print the type's contents.
- //
- } else if (ArgumentCount - AddressStartIndex != 0) {
- DataStream = malloc(TypeSize);
- if (DataStream == NULL) {
- Result = ENOMEM;
- goto DumpTypeEnd;
- }
- for (AddressIndex = AddressStartIndex;
- AddressIndex < ArgumentCount;
- AddressIndex += 1) {
- //
- // Evaluate the address. Failure here indicates a syntax error, but
- // is not a fatal error.
- //
- Result = DbgEvaluate(Context, Arguments[AddressIndex], &Address);
- if (Result != 0) {
- DbgOut("Syntax error in address parameter!\n");
- goto DumpTypeEnd;
- }
- Result = DbgReadMemory(Context,
- TRUE,
- Address,
- TypeSize,
- DataStream,
- &BytesRead);
- if (Result != 0) {
- DbgOut("Error reading virtual memory, only read %ld bytes, "
- "type is %d bytes!\n",
- TypeSize,
- BytesRead);
- goto DumpTypeEnd;
- }
- //
- // Resolve the type to something useful to dump.
- //
- Result = DbgrpResolveDumpType(Context,
- &Type,
- &DataStream,
- &TypeSize,
- &Address);
- if (Result != 0) {
- DbgOut("Error: could not resolve dump type %s.\n", Type->Name);
- goto DumpTypeEnd;
- }
- //
- // Print the values.
- //
- DbgOut("Dumping memory at 0x%08llx\n", Address);
- Result = DbgPrintType(Context,
- Type,
- DataStream,
- TypeSize,
- 0,
- DEFAULT_RECURSION_DEPTH);
- if (AddressIndex != ArgumentCount - 1) {
- DbgOut("\n");
- }
- if (Result != 0) {
- goto DumpTypeEnd;
- }
- }
- //
- // No address was specified, so print the type description.
- //
- } else {
- DbgPrintTypeName(Type);
- DbgOut(" = ");
- DbgPrintTypeDescription(Type, 0, DEFAULT_RECURSION_DEPTH);
- }
- Result = 0;
- DumpTypeEnd:
- if (DataStream != NULL) {
- free(DataStream);
- }
- return Result;
- }
- INT
- DbgrpHighlightExecutingLine (
- PDEBUGGER_CONTEXT Context,
- ULONGLONG LineNumber
- )
- /*++
- Routine Description:
- This routine highlights the currently executing source line and scrolls to
- it, or removes the highlight.
- Arguments:
- Context - Supplies the application context.
- LineNumber - Supplies the one-based line number to highlight, or 0 to
- disable highlighting.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- BOOL Result;
- if (Context->SourceFile.LineNumber == LineNumber) {
- return 0;
- }
- //
- // Unhighlight the current line first.
- //
- if (Context->SourceFile.LineNumber != 0) {
- UiHighlightExecutingLine(Context->SourceFile.LineNumber, FALSE);
- }
- //
- // Set the new line number and notify the connected clients.
- //
- Context->SourceFile.LineNumber = LineNumber;
- DbgrpServerNotifyClients(Context);
- //
- // If a new line is being highlighted, set it in the UI.
- //
- if (LineNumber != 0) {
- Result = UiHighlightExecutingLine(Context->SourceFile.LineNumber, TRUE);
- if (Result == FALSE) {
- return -1;
- }
- }
- return 0;
- }
- INT
- DbgrpLoadSourceFile (
- PDEBUGGER_CONTEXT Context,
- PSTR Path,
- PSTR *FoundPath,
- PVOID *Contents,
- PULONGLONG Size
- )
- /*++
- Routine Description:
- This routine loads a source file into memory.
- Arguments:
- Context - Supplies a pointer to the application context.
- Path - Supplies a pointer to the path to load.
- FoundPath - Supplies a pointer where a pointer to the path of the actual
- file loaded will be returned. The path may be modified by the source
- path list, so this represents the final found path.
- Contents - Supplies a pointer where a pointer to the loaded file will be
- returned on success. The caller is responsible for freeing this memory.
- Size - Supplies a pointer where the size of the file will be returned on
- success.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PDEBUGGER_SOURCE_PATH Entry;
- size_t PathLength;
- PSTR Potential;
- size_t PotentialSize;
- INT Result;
- *FoundPath = NULL;
- *Contents = NULL;
- *Size = 0;
- PathLength = strlen(Path);
- Potential = NULL;
- PotentialSize = 0;
- //
- // Loop over all the source paths trying to find a file path that
- // exists.
- //
- CurrentEntry = Context->SourcePathList.Next;
- while (CurrentEntry != &(Context->SourcePathList)) {
- Entry = LIST_VALUE(CurrentEntry, DEBUGGER_SOURCE_PATH, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // If the prefix is empty or matches this path, chop the prefix off,
- // replace it with the path, and try to load that file.
- //
- if ((Entry->PrefixLength == 0) ||
- (strncmp(Path, Entry->Prefix, Entry->PrefixLength) == 0)) {
- PotentialSize = Entry->PathLength +
- (PathLength - Entry->PrefixLength) + 1;
- Potential = malloc(PotentialSize);
- if (Potential == NULL) {
- continue;
- }
- memcpy(Potential, Entry->Path, Entry->PathLength);
- memcpy(Potential + Entry->PathLength,
- Path + Entry->PrefixLength,
- PathLength - Entry->PrefixLength);
- Potential[PotentialSize - 1] = '\0';
- Result = DbgrpLoadFile(Potential, Contents, Size);
- if ((Context->Flags & DEBUGGER_FLAG_PRINT_SOURCE_LOADS) != 0) {
- //
- // Use printf directly here and not DbgOut as the standard out
- // lock is held already.
- //
- printf("Load %s: %s\n", Potential, strerror(Result));
- }
- if (Result == 0) {
- *FoundPath = Potential;
- return 0;
- }
- free(Potential);
- }
- }
- //
- // Finally, try the source by itself.
- //
- PotentialSize = PathLength + 1;
- Potential = strdup(Path);
- if (Potential == NULL) {
- return ENOMEM;
- }
- Result = DbgrpLoadFile(Potential, Contents, Size);
- if ((Context->Flags & DEBUGGER_FLAG_PRINT_SOURCE_LOADS) != 0) {
- //
- // Use printf directly here and not DbgOut as the standard out lock is
- // held already.
- //
- printf("Load %s: %s\n", Potential, strerror(Result));
- }
- if (Result == 0) {
- *FoundPath = Potential;
- return 0;
- }
- return Result;
- }
- INT
- DbgrpAddSourcePath (
- PDEBUGGER_CONTEXT Context,
- PSTR PathString
- )
- /*++
- Routine Description:
- This routine adds a source path entry to the given application context.
- Arguments:
- Context - Supplies a pointer to the application context.
- PathString - Supplies a pointer to the path string, which takes the form
- prefix=path. If there is no equals sign, then the prefix is assumed to
- be empty.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PDEBUGGER_SOURCE_PATH Entry;
- PSTR Equals;
- PSTR Path;
- UINTN PathLength;
- PSTR Prefix;
- UINTN PrefixLength;
- INT Status;
- if (*PathString == '\0') {
- return 0;
- }
- Entry = NULL;
- Prefix = NULL;
- PrefixLength = 0;
- Path = NULL;
- PathLength = 0;
- //
- // Split on the equals.
- //
- Equals = strchr(PathString, '=');
- if (Equals != NULL) {
- if (Equals != PathString) {
- PrefixLength = (UINTN)Equals - (UINTN)PathString;
- Prefix = malloc(PrefixLength + 1);
- if (Prefix == NULL) {
- Status = ENOMEM;
- goto AddSourcePathEnd;
- }
- memcpy(Prefix, PathString, PrefixLength);
- Prefix[PrefixLength] = '\0';
- }
- PathLength = strlen(Equals + 1);
- Path = strdup(Equals + 1);
- } else {
- PathLength = strlen(PathString);
- Path = strdup(PathString);
- }
- if (Path == NULL) {
- Status = ENOMEM;
- goto AddSourcePathEnd;
- }
- //
- // Don't bother adding dumb entries.
- //
- if ((PathLength == 0) && (PrefixLength == 0)) {
- Status = 0;
- goto AddSourcePathEnd;
- }
- //
- // Create the entry and add it to the end.
- //
- Entry = malloc(sizeof(DEBUGGER_SOURCE_PATH));
- if (Entry == NULL) {
- Status = ENOMEM;
- goto AddSourcePathEnd;
- }
- Entry->Prefix = Prefix;
- Entry->PrefixLength = PrefixLength;
- Entry->Path = Path;
- Entry->PathLength = PathLength;
- Path = NULL;
- Prefix = NULL;
- INSERT_BEFORE(&(Entry->ListEntry), &(Context->SourcePathList));
- Status = 0;
- AddSourcePathEnd:
- if (Path != NULL) {
- free(Path);
- }
- if (Prefix != NULL) {
- free(Prefix);
- }
- return Status;
- }
- VOID
- DbgrpDestroyAllSourcePaths (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine destroys all source path entries in the given application
- context.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PDEBUGGER_SOURCE_PATH SourcePathEntry;
- while (LIST_EMPTY(&(Context->SourcePathList)) == FALSE) {
- SourcePathEntry = LIST_VALUE(Context->SourcePathList.Next,
- DEBUGGER_SOURCE_PATH,
- ListEntry);
- LIST_REMOVE(&(SourcePathEntry->ListEntry));
- DbgrpDestroySourcePath(SourcePathEntry);
- }
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- INT
- DbgrpSetBreakpointAtAddress (
- PDEBUGGER_CONTEXT Context,
- ULONGLONG Address,
- PULONG OriginalValue
- )
- /*++
- Routine Description:
- This routine modifies the instruction stream to set a breakpoint at the
- given address.
- Arguments:
- Context - Supplies a pointer to the application context.
- Address - Supplies the target address to change to a breakpoint instruction.
- OriginalValue - Supplies a pointer that receives the original contents
- of memory that the breakpoint instruction replaced.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONG BreakInstruction;
- ULONG BytesComplete;
- ULONGLONG MemoryAddress;
- INT Result;
- ULONG Size;
- MemoryAddress = Address;
- if ((Context->MachineType == MACHINE_TYPE_X86) ||
- (Context->MachineType == MACHINE_TYPE_X64)) {
- BreakInstruction = X86_BREAK_INSTRUCTION;
- Size = X86_BREAK_INSTRUCTION_LENGTH;
- } else if (Context->MachineType == MACHINE_TYPE_ARM) {
- if ((Address & ARM_THUMB_BIT) != 0) {
- BreakInstruction = THUMB_BREAK_INSTRUCTION;
- Size = THUMB_BREAK_INSTRUCTION_LENGTH;
- MemoryAddress = Address & ~ARM_THUMB_BIT;
- } else {
- BreakInstruction = ARM_BREAK_INSTRUCTION;
- Size = ARM_BREAK_INSTRUCTION_LENGTH;
- }
- } else {
- DbgOut("Unknown machine type %d.\n", Context->MachineType);
- return EINVAL;
- }
- //
- // Read the original contents.
- //
- *OriginalValue = 0;
- Result = DbgReadMemory(Context,
- TRUE,
- MemoryAddress,
- Size,
- OriginalValue,
- &BytesComplete);
- if ((Result != 0) || (BytesComplete != Size)) {
- if (Result == 0) {
- Result = EINVAL;
- }
- return Result;
- }
- //
- // Write out the breakpoint instruction.
- //
- Result = DbgWriteMemory(Context,
- TRUE,
- MemoryAddress,
- Size,
- &BreakInstruction,
- &BytesComplete);
- if ((Result != 0) || (BytesComplete != Size)) {
- if (Result == 0) {
- Result = EINVAL;
- }
- //
- // Attempt to restore the original value.
- //
- DbgrpClearBreakpointAtAddress(Context, Address, *OriginalValue);
- return Result;
- }
- return 0;
- }
- INT
- DbgrpClearBreakpointAtAddress (
- PDEBUGGER_CONTEXT Context,
- ULONGLONG Address,
- ULONG OriginalValue
- )
- /*++
- Routine Description:
- This routine restores an instruction stream to its original form before a
- breakpoint was inserted in it.
- Arguments:
- Context - Supplies a pointer to the application context.
- Address - Supplies the target address to change to a breakpoint instruction.
- OriginalValue - Supplies the original value returned when the breakpoint
- was set.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONG BreakInstruction;
- ULONG BytesComplete;
- ULONG CurrentValue;
- ULONGLONG MemoryAddress;
- INT Result;
- ULONG Size;
- MemoryAddress = Address;
- if ((Context->MachineType == MACHINE_TYPE_X86) ||
- (Context->MachineType == MACHINE_TYPE_X64)) {
- BreakInstruction = X86_BREAK_INSTRUCTION;
- Size = X86_BREAK_INSTRUCTION_LENGTH;
- } else if (Context->MachineType == MACHINE_TYPE_ARM) {
- if ((Address & ARM_THUMB_BIT) != 0) {
- BreakInstruction = THUMB_BREAK_INSTRUCTION;
- Size = THUMB_BREAK_INSTRUCTION_LENGTH;
- MemoryAddress = Address & ~ARM_THUMB_BIT;
- } else {
- BreakInstruction = ARM_BREAK_INSTRUCTION;
- Size = ARM_BREAK_INSTRUCTION_LENGTH;
- }
- } else {
- DbgOut("Unknown machine type %d.\n", Context->MachineType);
- return EINVAL;
- }
- //
- // Read what's there. If it's not a break instruction, warn the user that
- // perhaps something's wrong.
- //
- CurrentValue = 0;
- Result = DbgReadMemory(Context,
- TRUE,
- MemoryAddress,
- Size,
- &CurrentValue,
- &BytesComplete);
- if ((Result != 0) || (BytesComplete != Size)) {
- if (Result == 0) {
- Result = EINVAL;
- }
- goto ClearBreakpointAtAddressEnd;
- }
- if (CurrentValue == OriginalValue) {
- goto ClearBreakpointAtAddressEnd;
- }
- //
- // Write out the original instruction.
- //
- Result = DbgWriteMemory(Context,
- TRUE,
- MemoryAddress,
- Size,
- &OriginalValue,
- &BytesComplete);
- if ((Result != 0) || (BytesComplete != Size)) {
- if (Result == 0) {
- Result = EINVAL;
- }
- goto ClearBreakpointAtAddressEnd;
- }
- ClearBreakpointAtAddressEnd:
- if ((Result != 0) &&
- (CurrentValue != BreakInstruction) &&
- (CurrentValue != OriginalValue)) {
- DbgOut("Warning: Clearing a breakpoint at address %I64x, but instead "
- "of finding the breakpoint instruction %x at that address, %x "
- "was found instead.\n",
- Address,
- BreakInstruction,
- CurrentValue);
- }
- return Result;
- }
- ULONG
- DbgrpHandleBreakpoints (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine is called when a new break notification comes in. It looks to
- see if any breakpoints were hit, and if they were, backs up the instruction
- pointer and fixes the instruction.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- Returns the breakpoint number of the breakpoint that was hit, or -1 if no
- breakpoint was hit.
- --*/
- {
- PDEBUGGER_BREAK_POINT Breakpoint;
- ULONG BreakpointNumber;
- PLIST_ENTRY CurrentEntry;
- BOOL Result;
- ULONG Size;
- BreakpointNumber = -1;
- //
- // If there's a breakpoint to restore, do it. This code may restore the
- // breakpoint (as opposed to the code in Continue) if the user requests a
- // single step.
- //
- if (Context->BreakpointToRestore != NULL) {
- Result = DbgrpSetBreakpointAtAddress(
- Context,
- Context->BreakpointToRestore->Address,
- &(Context->BreakpointToRestore->OriginalValue));
- if (Result != 0) {
- DbgOut("Failed to restore breakpoint %d at %I64x.\n",
- Context->BreakpointToRestore->Index,
- Context->BreakpointToRestore->Address);
- return -1;
- }
- Context->BreakpointToRestore = NULL;
- }
- //
- // Check the breakpoint list to see if that's the cause of the break, and
- // clean up after it if it is.
- //
- CurrentEntry = Context->BreakpointList.Next;
- while (CurrentEntry != &(Context->BreakpointList)) {
- Breakpoint = LIST_VALUE(CurrentEntry,
- DEBUGGER_BREAK_POINT,
- ListEntry);
- if ((Context->MachineType == MACHINE_TYPE_X86) ||
- (Context->MachineType == MACHINE_TYPE_X64)) {
- Size = X86_BREAK_INSTRUCTION_LENGTH;
- } else if (Context->MachineType == MACHINE_TYPE_ARM) {
- if ((Breakpoint->Address & ARM_THUMB_BIT) != 0) {
- Size = THUMB_BREAK_INSTRUCTION_LENGTH;
- } else {
- Size = ARM_BREAK_INSTRUCTION_LENGTH;
- }
- } else {
- DbgOut("Unknown machine type %d.\n", Context->MachineType);
- return -1;
- }
- //
- // If the instruction pointer is exactly after the breakpoint address,
- // then it must have stopped for the breakpoint. Hide the breakpoint
- // from the user.
- //
- if ((Breakpoint->Enabled != FALSE) &&
- (Breakpoint->Type == BreakpointTypeExecution) &&
- (Context->CurrentEvent.BreakNotification.InstructionPointer ==
- Breakpoint->Address + Size)) {
- BreakpointNumber = Breakpoint->Index;
- Result = DbgrpAdjustInstructionPointerForBreakpoint(
- Context,
- Breakpoint->OriginalValue);
- if (Result != 0) {
- DbgOut("Unable to adjust instruction pointer for breakpoint "
- "%d.\n",
- Breakpoint->Index);
- goto HandleBreakpointsEnd;
- }
- //
- // Put the right instruction back in memory.
- //
- Result = DbgrpClearBreakpointAtAddress(Context,
- Breakpoint->Address,
- Breakpoint->OriginalValue);
- if (Result != 0) {
- DbgOut("Error: Unable to temporarily clear breakpoint at "
- "%08x.\n",
- Breakpoint->Address);
- goto HandleBreakpointsEnd;
- }
- //
- // Mark this breakpoint as needing to be restored.
- //
- Context->BreakpointToRestore = Breakpoint;
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Check the one-time break point.
- //
- if (Context->OneTimeBreakValid != FALSE) {
- if ((Context->MachineType == MACHINE_TYPE_X86) ||
- (Context->MachineType == MACHINE_TYPE_X64)) {
- Size = X86_BREAK_INSTRUCTION_LENGTH;
- } else if (Context->MachineType == MACHINE_TYPE_ARM) {
- if ((Context->OneTimeBreakAddress & ARM_THUMB_BIT) != 0) {
- Size = THUMB_BREAK_INSTRUCTION_LENGTH;
- } else {
- Size = ARM_BREAK_INSTRUCTION_LENGTH;
- }
- } else {
- DbgOut("Unknown machine type %d.\n", Context->MachineType);
- return -1;
- }
- if (Context->CurrentEvent.BreakNotification.InstructionPointer ==
- Context->OneTimeBreakAddress + Size) {
- Result = DbgrpAdjustInstructionPointerForBreakpoint(
- Context,
- Context->OneTimeBreakOriginalValue);
- if (Result != 0) {
- DbgOut("Error: Failed to adjust instruction pointer for one "
- "time break.");
- goto HandleBreakpointsEnd;
- }
- }
- //
- // Remove the one time breakpoint.
- //
- Result = DbgrpClearBreakpointAtAddress(
- Context,
- Context->OneTimeBreakAddress,
- Context->OneTimeBreakOriginalValue);
- if (Result != 0) {
- DbgOut("Error: Failed to clear one time break point.\n");
- goto HandleBreakpointsEnd;
- }
- Context->OneTimeBreakValid = FALSE;
- }
- HandleBreakpointsEnd:
- return BreakpointNumber;
- }
- INT
- DbgrpAdjustInstructionPointerForBreakpoint (
- PDEBUGGER_CONTEXT Context,
- ULONG OriginalValue
- )
- /*++
- Routine Description:
- This routine potentially moves the instruction pointer back and hides a
- breakpoint instruction.
- Arguments:
- Context - Supplies a pointer to the application context.
- OriginalValue - Supplies the original instruction stream contents at that
- address.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PBREAK_NOTIFICATION BreakNotification;
- ULONG ByteIndex;
- PUSHORT Pointer16;
- PULONG Pointer32;
- BOOL Result;
- ULONG Size;
- assert(Context->CurrentEvent.Type == DebuggerEventBreak);
- BreakNotification = &(Context->CurrentEvent.BreakNotification);
- if (Context->MachineType == MACHINE_TYPE_X86) {
- Size = X86_BREAK_INSTRUCTION_LENGTH;
- //
- // On x86, debug breaks are traps, meaning the instruction pointer
- // points to the next instruction. Move the instruction pointer back
- // and replace the original value in the first position.
- //
- BreakNotification->InstructionPointer -= Size;
- BreakNotification->Registers.X86.Eip -= Size;
- for (ByteIndex = sizeof(BreakNotification->InstructionStream) - 1;
- ByteIndex > 0;
- ByteIndex -= 1) {
- BreakNotification->InstructionStream[ByteIndex] =
- BreakNotification->InstructionStream[ByteIndex - 1];
- }
- BreakNotification->InstructionStream[0] = (UCHAR)OriginalValue;
- } else if (Context->MachineType == MACHINE_TYPE_X64) {
- Size = X86_BREAK_INSTRUCTION_LENGTH;
- //
- // x64 is just like x86.
- //
- BreakNotification->InstructionPointer -= Size;
- BreakNotification->Registers.X64.Rip -= Size;
- for (ByteIndex = sizeof(BreakNotification->InstructionStream) - 1;
- ByteIndex > 0;
- ByteIndex -= 1) {
- BreakNotification->InstructionStream[ByteIndex] =
- BreakNotification->InstructionStream[ByteIndex - 1];
- }
- BreakNotification->InstructionStream[0] = (UCHAR)OriginalValue;
- } else if (Context->MachineType == MACHINE_TYPE_ARM) {
- Size = ARM_BREAK_INSTRUCTION_LENGTH;
- if ((BreakNotification->Registers.Arm.Cpsr & PSR_FLAG_THUMB) != 0) {
- Size = THUMB_BREAK_INSTRUCTION_LENGTH;
- Pointer16 = (PUSHORT)(&(BreakNotification->InstructionStream[0]));
- Pointer16[1] = Pointer16[0];
- Pointer16[0] = OriginalValue;
- } else {
- Pointer32 = (PULONG)(&(BreakNotification->InstructionStream[0]));
- *Pointer32 = OriginalValue;
- }
- //
- // On ARM, the break instruction also points to the next one. In this
- // case though the instruction size is known, so there's no need to
- // carefully shift the whole instruction stream buffer.
- //
- BreakNotification->InstructionPointer -= Size;
- BreakNotification->Registers.Arm.R15Pc -= Size;
- } else {
- DbgOut("Unknown machine type %d.\n", Context->MachineType);
- return FALSE;
- }
- //
- // Reflect the register change in the target as well.
- //
- Result = DbgSetRegisters(Context, &(BreakNotification->Registers));
- if (Result != 0) {
- DbgOut("Error adjusting EIP on breakpoint instruction.\n");
- return Result;
- }
- return 0;
- }
- INT
- DbgrpProcessBreakNotification (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine is called when a new break notification comes in.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONG BreakpointNumber;
- PBREAK_NOTIFICATION CurrentBreak;
- BOOL ForceModuleUpdate;
- BOOL InRange;
- ULONGLONG InstructionPointer;
- INT Result;
- Context->TargetFlags &= ~DEBUGGER_TARGET_RUNNING;
- //
- // Synchronize symbols with the target.
- //
- CurrentBreak = &(Context->CurrentEvent.BreakNotification);
- ForceModuleUpdate = FALSE;
- if (Context->PreviousProcess != CurrentBreak->Process) {
- ForceModuleUpdate = TRUE;
- }
- Context->PreviousProcess = CurrentBreak->Process;
- Result = DbgrpValidateLoadedModules(Context,
- CurrentBreak->LoadedModuleCount,
- CurrentBreak->LoadedModuleSignature,
- ForceModuleUpdate);
- if (Result != 0) {
- DbgOut("Failed to validate loaded modules.\n");
- }
- //
- // Handle any breakpoint stuff.
- //
- BreakpointNumber = DbgrpHandleBreakpoints(Context);
- InstructionPointer = CurrentBreak->InstructionPointer;
- //
- // Print the exception.
- //
- switch (CurrentBreak->Exception) {
- case ExceptionDebugBreak:
- case ExceptionSingleStep:
- case ExceptionSignal:
- if (CurrentBreak->Exception == ExceptionSignal) {
- if (Context->CurrentEvent.SignalParameters.SignalNumber !=
- SIGNAL_TRAP) {
- DbgOut("Caught signal %d.\n",
- Context->CurrentEvent.SignalParameters.SignalNumber);
- }
- }
- if (BreakpointNumber != -1) {
- DbgOut("Breakpoint %d hit!\n", BreakpointNumber);
- //
- // If the range step is valid, then only break if the address qualifies.
- //
- } else if (Context->RangeStepValid != FALSE) {
- InRange = FALSE;
- if ((InstructionPointer >=
- Context->RangeStepParameters.BreakRangeMinimum) &&
- (InstructionPointer <
- Context->RangeStepParameters.BreakRangeMaximum)) {
- InRange = TRUE;
- if ((InstructionPointer >=
- Context->RangeStepParameters.RangeHoleMinimum) &&
- (InstructionPointer <
- Context->RangeStepParameters.RangeHoleMaximum)) {
- InRange = FALSE;
- }
- }
- if (InRange == FALSE) {
- Result = DbgrSingleStep(Context);
- if (Result != 0) {
- DbgOut("Failed to single step over %I64x.\n",
- InstructionPointer);
- goto ProcessBreakNotificationEnd;
- }
- Context->TargetFlags |= DEBUGGER_TARGET_RUNNING;
- goto ProcessBreakNotificationEnd;
- }
- }
- break;
- case ExceptionAssertionFailure:
- break;
- case ExceptionAccessViolation:
- DbgOut("\n *** Access violation: Error code 0x%08x ***\n",
- CurrentBreak->ErrorCode);
- break;
- case ExceptionDoubleFault:
- DbgOut("\n *** Double Fault ***\n");
- break;
- case ExceptionInvalid:
- DbgOut("Error: Invalid exception received!\n");
- break;
- case ExceptionIllegalInstruction:
- DbgOut("\n *** Illegal Instruction ***\n");
- break;
- case ExceptionUnknown:
- DbgOut("Error: Unknown exception received!\n");
- break;
- default:
- DbgOut("Error: Unknown exception %d received!\n",
- CurrentBreak->Exception);
- break;
- }
- //
- // This break is really going to the user. Turn off any range stepping.
- //
- Context->RangeStepValid = FALSE;
- //
- // Set the globals indicating where to disassemble from and where
- // the current frame is.
- //
- Context->DisassemblyAddress = InstructionPointer;
- RtlCopyMemory(&(Context->FrameRegisters),
- &(Context->CurrentEvent.BreakNotification.Registers),
- sizeof(REGISTERS_UNION));
- Context->CurrentFrame = 0;
- Context->LastMemoryDump.Virtual = TRUE;
- Context->LastMemoryDump.NextAddress = InstructionPointer;
- Context->LastMemoryDump.Columns = 0;
- Context->LastMemoryDump.TotalValues = 0;
- Context->LastMemoryDump.PrintCharacters = TRUE;
- //
- // Load up the source file in the source window.
- //
- DbgrShowSourceAtAddress(Context, InstructionPointer);
- //
- // Print the instruction that's about to execute.
- //
- DbgrpPrintDisassembly(Context,
- CurrentBreak->InstructionStream,
- InstructionPointer,
- 1,
- &(Context->BreakInstructionLength));
- Result = 0;
- ProcessBreakNotificationEnd:
- return Result;
- }
- INT
- DbgrpRangeStep (
- PDEBUGGER_CONTEXT Context,
- PRANGE_STEP RangeStep
- )
- /*++
- Routine Description:
- This routine continues execution until a range of execution addresses is
- reached.
- Arguments:
- Context - Supplies a pointer to the application context.
- RangeStep - Supplies a pointer to the range to go to.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- BOOL Result;
- ULONG SignalToDeliver;
- //
- // First attempt to use the direct API method. The kernel debugger for
- // instance has support for doing range stepping on its own so it doesn't
- // have to send break notifications back and forth for every singls step.
- //
- SignalToDeliver = DbgGetSignalToDeliver(Context);
- Result = DbgRangeStep(Context, RangeStep, SignalToDeliver);
- if (Result == 0) {
- return 0;
- }
- //
- // The API is unavailable, so it's going to have to be done the old
- // fashioned way.
- //
- RtlCopyMemory(&(Context->RangeStepParameters),
- RangeStep,
- sizeof(RANGE_STEP));
- Context->RangeStepValid = TRUE;
- return DbgrSingleStep(Context);
- }
- INT
- DbgrpValidateLoadedModules (
- PDEBUGGER_CONTEXT Context,
- ULONG ModuleCount,
- ULONGLONG Signature,
- BOOL ForceReload
- )
- /*++
- Routine Description:
- This routine validates that the debugger's list of loaded modules is in sync
- with the target. This routine may load or unload symbols.
- Arguments:
- Context - Supplies a pointer to the application context.
- ModuleCount - Supplies the number of modules loaded in the target.
- Signature - Supplies the total of the timestamps and loaded addresses of
- all loaded modules. This is used esseentially as a quick way to
- determine whether or not the list is in sync without transmitting much
- data.
- ForceReload - Supplies a boolean indicating if the module list should be
- reloaded no matter what.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- BOOL AlreadyPrinted;
- ULONG BinaryNameLength;
- PLIST_ENTRY CurrentEntry;
- PLOADED_MODULE_ENTRY CurrentTargetModule;
- PDEBUGGER_MODULE ExistingModule;
- PSTR FriendlyName;
- ULONG FriendlyNameLength;
- PSTR FriendlyNameStart;
- PMODULE_LIST_HEADER ModuleListHeader;
- ULONG RemoteModuleCount;
- INT Result;
- AlreadyPrinted = FALSE;
- ModuleListHeader = NULL;
- //
- // If the two checksum totals match, then the debugger symbols are in sync.
- // No action is required.
- //
- if ((Signature == Context->ModuleList.Signature) &&
- (ModuleCount == Context->ModuleList.ModuleCount) &&
- (ForceReload == FALSE)) {
- Result = 0;
- goto ValidateLoadedModulesEnd;
- }
- //
- // If the signature hasn't changed since the last time it wasn't in sync,
- // don't bother going through all that again.
- //
- if ((Signature == Context->RemoteModuleListSignature) &&
- (ForceReload == FALSE)) {
- AlreadyPrinted = TRUE;
- Result = 0;
- goto ValidateLoadedModulesEnd;
- }
- //
- // Request the loaded modules list header to determine how many modules
- // are loaded in the target.
- //
- Result = DbgGetLoadedModuleList(Context, &ModuleListHeader);
- if (Result != 0) {
- DbgOut("Error: Failed to get loaded module list.\n");
- goto ValidateLoadedModulesEnd;
- }
- Signature = ModuleListHeader->Signature;
- RemoteModuleCount = ModuleListHeader->ModuleCount;
- CurrentTargetModule = (PLOADED_MODULE_ENTRY)(ModuleListHeader + 1);
- //
- // Mark all modules as unloaded.
- //
- CurrentEntry = Context->ModuleList.ModulesHead.Next;
- while (CurrentEntry != &(Context->ModuleList.ModulesHead)) {
- ExistingModule = LIST_VALUE(CurrentEntry,
- DEBUGGER_MODULE,
- ListEntry);
- ExistingModule->Loaded = FALSE;
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Get all modules. For each module, attempt to match it to an existing
- // loaded module. If none is found, attempt to load the module.
- //
- while (RemoteModuleCount != 0) {
- //
- // Create a friendly name from the binary name by chopping off the
- // extension and any path stuff at the beginning.
- //
- assert(CurrentTargetModule->StructureSize >=
- sizeof(LOADED_MODULE_ENTRY));
- BinaryNameLength = CurrentTargetModule->StructureSize -
- sizeof(LOADED_MODULE_ENTRY) +
- (ANYSIZE_ARRAY * sizeof(CHAR));
- DbgpGetFriendlyName(CurrentTargetModule->BinaryName,
- BinaryNameLength,
- &FriendlyNameStart,
- &FriendlyNameLength);
- FriendlyName = malloc(FriendlyNameLength + 1);
- if (FriendlyName == NULL) {
- DbgOut("Error: Failed to allocate %d bytes for friendly name.\n",
- FriendlyNameLength + 1);
- Result = ENOMEM;
- goto ValidateLoadedModulesEnd;
- }
- RtlStringCopy(FriendlyName, FriendlyNameStart, FriendlyNameLength + 1);
- FriendlyName[FriendlyNameLength] = '\0';
- ExistingModule = DbgpFindModuleFromEntry(Context, CurrentTargetModule);
- if (ExistingModule != NULL) {
- ExistingModule->Loaded = TRUE;
- } else {
- DbgpLoadModule(Context,
- CurrentTargetModule->BinaryName,
- FriendlyName,
- CurrentTargetModule->Size,
- CurrentTargetModule->LowestAddress,
- CurrentTargetModule->Timestamp,
- CurrentTargetModule->Process);
- }
- free(FriendlyName);
- RemoteModuleCount -= 1;
- CurrentTargetModule =
- (PLOADED_MODULE_ENTRY)((PUCHAR)CurrentTargetModule +
- CurrentTargetModule->StructureSize);
- }
- //
- // Unload any modules no longer in the list.
- //
- CurrentEntry = Context->ModuleList.ModulesHead.Next;
- while (CurrentEntry != &(Context->ModuleList.ModulesHead)) {
- ExistingModule = LIST_VALUE(CurrentEntry,
- DEBUGGER_MODULE,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (ExistingModule->Loaded == FALSE) {
- DbgrpUnloadModule(Context, ExistingModule, TRUE);
- }
- }
- Context->RemoteModuleListSignature = Signature;
- Result = 0;
- ValidateLoadedModulesEnd:
- if (Result == 0) {
- if ((Context->ModuleList.Signature != Signature) &&
- (AlreadyPrinted == FALSE)) {
- DbgOut("*** Module signatures don't match after synchronization. "
- "***\nDebugger: 0x%I64x, Target: 0x%I64x\n",
- Context->ModuleList.Signature,
- Signature);
- }
- }
- if (ModuleListHeader != NULL) {
- free(ModuleListHeader);
- }
- return Result;
- }
- VOID
- DbgrpUnloadModule (
- PDEBUGGER_CONTEXT Context,
- PDEBUGGER_MODULE Module,
- BOOL Verbose
- )
- /*++
- Routine Description:
- This routine unloads a module, removing its binary and symbol information.
- Arguments:
- Context - Supplies a pointer to the application context.
- Module - Supplies a pointer to the loaded module to unload. Once this
- function is called, this pointer will no longer be valid.
- Verbose - Supplies a flag indicating whether or not this unload should be
- printed to the user.
- Return Value:
- None.
- --*/
- {
- //
- // Subtract the checksum out of the checksum total, and remove the module
- // from the list.
- //
- Context->ModuleList.Signature -= Module->Timestamp + Module->LowestAddress;
- Context->ModuleList.ModuleCount -= 1;
- LIST_REMOVE(&(Module->ListEntry));
- if (Verbose != FALSE) {
- DbgOut("Module unloaded: %s.\n", Module->ModuleName);
- }
- //
- // Free all the symbols.
- //
- if (Module->Symbols != NULL) {
- DbgUnloadSymbols(Module->Symbols);
- Module->Symbols = NULL;
- }
- if (Module->Filename != NULL) {
- free(Module->Filename);
- }
- if (Module->ModuleName != NULL) {
- free(Module->ModuleName);
- }
- free(Module);
- return;
- }
- VOID
- DbgrpUnloadAllModules (
- PDEBUGGER_CONTEXT Context,
- BOOL Verbose
- )
- /*++
- Routine Description:
- This routine unloads all modules and symbols from the debugger.
- Arguments:
- Context - Supplies a pointer to the application context.
- Verbose - Supplies a flag indicating whether or not this unload should be
- printed to the user.
- Return Value:
- Returns TRUE if information was printed, or FALSE if module information
- could not be found for the address.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PDEBUGGER_MODULE CurrentModule;
- if (Context->ModuleList.ModuleCount == 0) {
- assert(Context->ModuleList.Signature == 0);
- assert(Context->RemoteModuleListSignature == 0);
- return;
- }
- CurrentEntry = Context->ModuleList.ModulesHead.Next;
- while (CurrentEntry != &(Context->ModuleList.ModulesHead)) {
- CurrentModule = LIST_VALUE(CurrentEntry, DEBUGGER_MODULE, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- DbgrpUnloadModule(Context, CurrentModule, Verbose);
- }
- assert(Context->ModuleList.ModuleCount == 0);
- assert(Context->ModuleList.Signature == 0);
- Context->RemoteModuleListSignature = 0;
- return;
- }
- INT
- DbgrpPrintDisassembly (
- PDEBUGGER_CONTEXT Context,
- PBYTE InstructionStream,
- ULONGLONG InstructionPointer,
- ULONG InstructionCount,
- PULONG BytesDecoded
- )
- /*++
- Routine Description:
- This routine prints the disassembly of one or more instructions.
- Arguments:
- Context - Supplies a pointer to the application context.
- InstructionStream - Supplies a pointer to the binary instruction stream to
- disassemble. It is assumed that this buffer contains enough bytes to
- completely disassemble the specified number of instructions.
- InstructionPointer - Supplies the location in the target's memory where
- these instructions reside.
- InstructionCount - Supplies the number of instructions to disassemble.
- BytesDecoded - Supplies a pointer where the number of bytes decoded from the
- instruction stream is returned.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONG CurrentInstructionByte;
- DISASSEMBLED_INSTRUCTION Disassembly;
- PSTR DisassemblyBuffer;
- MACHINE_LANGUAGE Language;
- ULONGLONG OperandAddress;
- INT Result;
- if (BytesDecoded != NULL) {
- *BytesDecoded = 0;
- }
- DisassemblyBuffer = malloc(200);
- if (DisassemblyBuffer == NULL) {
- Result = ENOMEM;
- goto PrintDisassemblyEnd;
- }
- switch (Context->MachineType) {
- case MACHINE_TYPE_X86:
- Language = MachineLanguageX86;
- break;
- case MACHINE_TYPE_ARM:
- Language = MachineLanguageArm;
- if ((InstructionPointer & ARM_THUMB_BIT) != 0) {
- Language = MachineLanguageThumb2;
- }
- break;
- case MACHINE_TYPE_X64:
- Language = MachineLanguageX64;
- break;
- default:
- DbgOut("Error: Unknown machine type %d.\n", Context->MachineType);
- Result = EINVAL;
- goto PrintDisassemblyEnd;
- }
- Result = DbgPrintAddressSymbol(Context, InstructionPointer);
- if (Result == 0) {
- DbgOut(":\n");
- }
- while (InstructionCount > 0) {
- //
- // Print the instruction pointer and attempt to decode the instruction.
- //
- DbgOut("%08I64x ", InstructionPointer);
- Result = DbgDisassemble(InstructionPointer,
- InstructionStream,
- DisassemblyBuffer,
- 200,
- &Disassembly,
- Language);
- if (Result == FALSE) {
- DbgOut("*** Error decoding instruction ***\n");
- Result = EINVAL;
- goto PrintDisassemblyEnd;
- }
- if ((Language == MachineLanguageArm) ||
- (Language == MachineLanguageThumb2)) {
- if (Disassembly.BinaryLength == 2) {
- DbgOut("%04x ", *((PUSHORT)InstructionStream));
- } else {
- assert(Disassembly.BinaryLength == 4);
- if (Language == MachineLanguageThumb2) {
- DbgOut("%04x %04x ",
- *((PUSHORT)InstructionStream),
- *((PUSHORT)InstructionStream + 1));
- } else {
- DbgOut("%08x ", *((PULONG)InstructionStream));
- }
- }
- }
- DbgOut("%s\t", Disassembly.Mnemonic);
- //
- // Print the first (destination) operand if one exists.
- //
- if (Disassembly.DestinationOperand != NULL) {
- if ((Disassembly.AddressIsDestination != FALSE) &&
- (Disassembly.AddressIsValid != FALSE)) {
- OperandAddress = Disassembly.OperandAddress;
- Result = DbgPrintAddressSymbol(Context, OperandAddress);
- if (Result == 0) {
- DbgOut(" ");
- }
- if (Disassembly.DestinationOperand[0] == '[') {
- DbgOut("%s", Disassembly.DestinationOperand);
- } else {
- DbgOut("%s (0x%08I64x)",
- Disassembly.DestinationOperand,
- OperandAddress);
- }
- } else {
- DbgOut("%s", Disassembly.DestinationOperand);
- }
- }
- //
- // Print the second (source) operand if one exists.
- //
- if (Disassembly.SourceOperand != NULL) {
- DbgOut(", ");
- if ((Disassembly.AddressIsDestination == FALSE) &&
- (Disassembly.AddressIsValid != FALSE)) {
- OperandAddress = Disassembly.OperandAddress;
- Result = DbgPrintAddressSymbol(Context, OperandAddress);
- if (Result == 0) {
- DbgOut(" ");
- }
- if (Disassembly.SourceOperand[0] == '[') {
- DbgOut("%s", Disassembly.SourceOperand);
- } else {
- DbgOut("%s (0x%08I64x)",
- Disassembly.SourceOperand,
- OperandAddress);
- }
- } else {
- DbgOut("%s", Disassembly.SourceOperand);
- }
- }
- //
- // Print the third operand if one exists. This operand will not have a
- // symbol associated with it.
- //
- if (Disassembly.ThirdOperand != NULL) {
- DbgOut(", %s", Disassembly.ThirdOperand);
- }
- //
- // Print the fourth operand if one exists. This one also will not have
- // a symbol associated with it.
- //
- if (Disassembly.FourthOperand != NULL) {
- DbgOut(", %s", Disassembly.FourthOperand);
- }
- //
- // For x86 disassembly, print out the bytes of the actual instruction.
- //
- if ((Language == MachineLanguageX86) ||
- (Language == MachineLanguageX64)) {
- DbgOut("\t; ");
- for (CurrentInstructionByte = 0;
- CurrentInstructionByte < Disassembly.BinaryLength;
- CurrentInstructionByte += 1) {
- DbgOut("%02x", *InstructionStream);
- InstructionStream += 1;
- }
- } else {
- InstructionStream += Disassembly.BinaryLength;
- }
- DbgOut("\n");
- //
- // Update the variables and loop.
- //
- if (BytesDecoded != NULL) {
- *BytesDecoded += Disassembly.BinaryLength;
- }
- InstructionPointer += Disassembly.BinaryLength;
- InstructionCount -= 1;
- }
- Result = 0;
- PrintDisassemblyEnd:
- if (DisassemblyBuffer != NULL) {
- free(DisassemblyBuffer);
- }
- return Result;
- }
- PSTR
- DbgrpCreateFullPath (
- PSOURCE_FILE_SYMBOL Source
- )
- /*++
- Routine Description:
- This routine makes a full source file path from the given source file. The
- caller must remember to free memory allocated here.
- Arguments:
- Source - Supplies a pointer to the source line symbol.
- Return Value:
- Returns a pointer to string containing the full path, or NULL if there was
- an error. This memory has been allocated in the function, and must be freed
- by the caller.
- --*/
- {
- UINTN DirectoryLength;
- UINTN FileLength;
- ULONG Index;
- CHAR LastCharacter;
- BOOL NeedsSlash;
- PSTR Path;
- ULONG PathLength;
- //
- // Validate parameters.
- //
- if ((Source == NULL) || (Source->SourceFile == NULL)) {
- return NULL;
- }
- DirectoryLength = 0;
- FileLength = strlen(Source->SourceFile);
- PathLength = FileLength;
- NeedsSlash = FALSE;
- //
- // Get the length of the full path, depending on whether or not a directory
- // was specified.
- //
- if (Source->SourceDirectory != NULL) {
- DirectoryLength = strlen(Source->SourceDirectory);
- PathLength += DirectoryLength;
- if (DirectoryLength != 0) {
- LastCharacter = Source->SourceDirectory[DirectoryLength - 1];
- if ((LastCharacter != '/') && (LastCharacter != '\\')) {
- NeedsSlash = TRUE;
- PathLength += 1;
- }
- }
- }
- //
- // Allocate the buffer.
- //
- Path = malloc(PathLength + 1);
- if (Path == NULL) {
- return NULL;
- }
- if (Source->SourceDirectory != NULL) {
- memcpy(Path, Source->SourceDirectory, DirectoryLength);
- if (NeedsSlash != FALSE) {
- Path[DirectoryLength] = '/';
- DirectoryLength += 1;
- }
- }
- memcpy(Path + DirectoryLength, Source->SourceFile, FileLength + 1);
- //
- // Change any backslashes to forward slashes.
- //
- for (Index = 0; Index < PathLength; Index += 1) {
- if (Path[Index] == '\\') {
- Path[Index] = '/';
- }
- }
- return Path;
- }
- INT
- DbgrpPrintMemory (
- PDEBUGGER_CONTEXT Context,
- ULONGLONG Address,
- BOOL VirtualAddress,
- ULONG TypeSize,
- ULONG Columns,
- ULONG TotalValues,
- BOOL PrintCharacters
- )
- /*++
- Routine Description:
- This routine prints the contents of memory in a formatted way.
- Arguments:
- Context - Supplies a pointer to the application context.
- Address - Supplies the address of the memory in the debuggee to print.
- VirtualAddress - Supplies a flag indicating whether or not Address is a
- virtual address (TRUE) or physical address (FALSE).
- TypeSize - Supplies the unit of integers to print, in bytes. Valid values
- are 1, 2, 4, and 8.
- Columns - Supplies the number of columns to print for each line. To use a
- default value, set this parameter to 0.
- TotalValues - Supplies the total number of integers to print (the total
- amount of memory will depend on the type size as well). To use a default
- value, set this parameter to 0.
- PrintCharacters - Supplies a flag indicating whether or not to print
- characters alongside the integers.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PUCHAR Buffer;
- PUCHAR CharacterPointer;
- ULONG ColumnIndex;
- ULONGLONG CurrentAddress;
- PUCHAR CurrentByte;
- PUCHAR InvalidBytes;
- ULONG ItemsPrinted;
- INT Result;
- ULONG ValidBytes;
- Buffer = NULL;
- ItemsPrinted = 0;
- //
- // If the number of columns was 0, then pick a default number of columns to
- // print.
- //
- if (Columns == 0) {
- Columns = 2;
- if (TypeSize == 4) {
- Columns *= 2;
- }
- if (TypeSize == 2) {
- Columns *= 4;
- }
- if (TypeSize == 1) {
- Columns *= 8;
- }
- }
- //
- // If the number of items was 0, then pick a default number of items to
- // print.
- //
- if (TotalValues == 0) {
- TotalValues = Columns * DEFAULT_MEMORY_PRINT_ROWS;
- }
- //
- // Allocate a buffer big enough to hold all the values.
- //
- Buffer = malloc(TotalValues * TypeSize);
- if (Buffer == NULL) {
- Result = ENOMEM;
- goto PrintMemoryEnd;
- }
- //
- // Read the memory in from the debuggee.
- //
- Result = DbgReadMemory(Context,
- VirtualAddress,
- Address,
- TotalValues * TypeSize,
- Buffer,
- &ValidBytes);
- if (Result != 0) {
- DbgOut("Error retrieving memory!\n");
- goto PrintMemoryEnd;
- }
- InvalidBytes = Buffer + ValidBytes;
- //
- // Print every value.
- //
- ColumnIndex = 0;
- CurrentAddress = Address;
- CurrentByte = Buffer;
- CharacterPointer = Buffer;
- for (ItemsPrinted = 0; ItemsPrinted < TotalValues; ItemsPrinted += 1) {
- //
- // If this is the beginning of a new column, print the address.
- //
- if (ColumnIndex == 0) {
- DbgOut("%08I64x: ", CurrentAddress);
- }
- //
- // Depending on the size, print the value.
- //
- if (TypeSize == 8) {
- if (CurrentByte + 7 >= InvalidBytes) {
- DbgOut("????????`???????? ");
- } else {
- DbgOut("%08x`%08x ",
- *((PULONG)CurrentByte + 1),
- *((PULONG)CurrentByte));
- }
- } else if (TypeSize == 4) {
- if (CurrentByte + 3 >= InvalidBytes) {
- DbgOut("???????? ");
- } else {
- DbgOut("%08x ", *((PULONG)CurrentByte));
- }
- } else if (TypeSize == 2) {
- if (CurrentByte + 1 >= InvalidBytes) {
- DbgOut("???? ");
- } else {
- DbgOut("%04x ", *((PUSHORT)CurrentByte));
- }
- } else if (TypeSize == 1) {
- if (ColumnIndex == 7) {
- if (CurrentByte >= InvalidBytes) {
- DbgOut("?""?-");
- } else {
- DbgOut("%02x-", *CurrentByte);
- }
- } else {
- if (CurrentByte >= InvalidBytes) {
- DbgOut("?? ");
- } else {
- DbgOut("%02x ", *CurrentByte);
- }
- }
- }
- //
- // Advance all the pointers and whatnot.
- //
- CurrentByte += TypeSize;
- ColumnIndex += 1;
- CurrentAddress += TypeSize;
- //
- // If this is the last column in the row, and characters are to be
- // printed, print them.
- //
- if (ColumnIndex == Columns) {
- if (PrintCharacters != FALSE) {
- DbgOut(" ");
- for (ColumnIndex = 0;
- ColumnIndex < (Columns * TypeSize);
- ColumnIndex += 1) {
- //
- // If the character is printable, print it. Otherwise, print
- // a dot. If the memory doesn't exist, print a question
- // mark.
- //
- if (CharacterPointer >= InvalidBytes) {
- DbgOut("?");
- } else if (*CharacterPointer < 0x20) {
- DbgOut(".");
- } else {
- DbgOut("%c", *CharacterPointer);
- }
- CharacterPointer += 1;
- }
- assert(CharacterPointer == CurrentByte);
- }
- ColumnIndex = 0;
- DbgOut("\n");
- }
- }
- //
- // Print one more newline if a column was not complete.
- //
- if (ColumnIndex != 0) {
- DbgOut("\n");
- }
- Result = 0;
- PrintMemoryEnd:
- if (Buffer != NULL) {
- free(Buffer);
- }
- return Result;
- }
- VOID
- DbgrpProcessShutdown (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine processes a shutdown event coming from the debuggee.
- Arguments:
- Context - Supplies a pointer to the application context.
- Return Value:
- None.
- --*/
- {
- assert(Context->CurrentEvent.Type == DebuggerEventShutdown);
- switch (Context->CurrentEvent.ShutdownNotification.ShutdownType) {
- case ShutdownTypeTransition:
- DbgOut("Target disconnected.\n");
- DbgrConnect(Context);
- break;
- case ShutdownTypeExit:
- DbgOut("Process %x exited with status %d.\n",
- Context->CurrentEvent.ShutdownNotification.Process,
- Context->CurrentEvent.ShutdownNotification.ExitStatus);
- break;
- case ShutdownTypeSynchronizationLost:
- DbgOut("Resynchronizing...\n");
- DbgrConnect(Context);
- break;
- default:
- DbgOut("Shutdown occurred, unknown reason %d.\n",
- Context->CurrentEvent.ShutdownNotification.ShutdownType);
- break;
- }
- if (Context->CurrentEvent.ShutdownNotification.UnloadAllSymbols != FALSE) {
- DbgrpUnloadAllModules(Context, TRUE);
- }
- return;
- }
- PDEBUGGER_MODULE
- DbgpLoadModule (
- PDEBUGGER_CONTEXT Context,
- PSTR BinaryName,
- PSTR FriendlyName,
- ULONGLONG Size,
- ULONGLONG LowestAddress,
- ULONGLONG Timestamp,
- ULONG Process
- )
- /*++
- Routine Description:
- This routine loads a new module and adds it to the debugger's loaded module
- list.
- Arguments:
- Context - Supplies a pointer to the application context.
- BinaryName - Supplies the name of the binary to load. This routine will use
- the known symbol path to try to find this binary.
- FriendlyName - Supplies the friendly name of the module.
- Size - Supplies the size of the module.
- LowestAddress - Supplies the lowest address of the module in memory.
- Timestamp - Supplies the timestamp of the module.
- Checksum - Supplies the required checksum of the module.
- Process - Supplies the ID of the process this module is specific to.
- Return Value:
- Returns a pointer to the loaded module on success.
- NULL on failure.
- --*/
- {
- PSTR BackupPotential;
- ULONGLONG BackupPotentialTimestamp;
- PSTR CurrentPath;
- ULONG CurrentPathLength;
- ULONGLONG Delta;
- IMAGE_MACHINE_TYPE ImageMachineType;
- UINTN LastIndex;
- ULONG NameIndex;
- ULONG NameLength;
- PDEBUGGER_MODULE NewModule;
- PSTR OriginalBinaryName;
- ULONG PathCount;
- ULONG PathIndex;
- PSTR PotentialBinary;
- ULONGLONG PotentialTimestamp;
- BOOL Result;
- struct stat Stat;
- INT Status;
- time_t Time;
- char *TimeString;
- struct tm *TimeStructure;
- OriginalBinaryName = BinaryName;
- BackupPotential = NULL;
- BackupPotentialTimestamp = 0;
- //
- // Determine the image machine type.
- //
- switch (Context->MachineType) {
- case MACHINE_TYPE_X86:
- ImageMachineType = ImageMachineTypeX86;
- break;
- case MACHINE_TYPE_ARM:
- ImageMachineType = ImageMachineTypeArm32;
- break;
- case MACHINE_TYPE_X64:
- ImageMachineType = ImageMachineTypeX64;
- break;
- default:
- ImageMachineType = ImageMachineTypeUnknown;
- break;
- }
- //
- // Create an entry for the module.
- //
- NewModule = malloc(sizeof(DEBUGGER_MODULE));
- if (NewModule == NULL) {
- Result = FALSE;
- goto LoadModuleEnd;
- }
- memset(NewModule, 0, sizeof(DEBUGGER_MODULE));
- NameLength = strlen(BinaryName);
- if (NameLength == 0) {
- Result = FALSE;
- goto LoadModuleEnd;
- }
- PathCount = Context->SymbolPathCount;
- //
- // Find the base name to stick on the path.
- //
- NameIndex = NameLength - 1;
- while ((NameIndex != 0) && (BinaryName[NameIndex - 1] != '/') &&
- (BinaryName[NameIndex - 1] != '\\')) {
- NameIndex -= 1;
- }
- BinaryName += NameIndex;
- NameLength -= NameIndex;
- //
- // Attempt to load the binary using each path in the symbol path.
- //
- for (PathIndex = 0; PathIndex < PathCount; PathIndex += 1) {
- CurrentPath = Context->SymbolPath[PathIndex];
- CurrentPathLength = strlen(CurrentPath);
- //
- // Create the full binary path.
- //
- PotentialBinary = malloc(CurrentPathLength + NameLength + 2);
- if (PotentialBinary == NULL) {
- DbgOut("Error: Could not allocate memory for potential binary.\n");
- Result = FALSE;
- goto LoadModuleEnd;
- }
- if (CurrentPathLength != 0) {
- memcpy(PotentialBinary, CurrentPath, CurrentPathLength);
- PotentialBinary[CurrentPathLength] = '/';
- CurrentPathLength += 1;
- }
- strcpy(PotentialBinary + CurrentPathLength, BinaryName);
- Status = stat(PotentialBinary, &Stat);
- if (Status == 0) {
- //
- // Compare the timestamps. Allow for a difference of one because
- // some file systems like FAT only store modification date to
- // two second granules.
- //
- PotentialTimestamp = Stat.st_mtime - SYSTEM_TIME_TO_EPOCH_DELTA;
- if ((Timestamp == 0) ||
- (PotentialTimestamp == Timestamp) ||
- (PotentialTimestamp + 1 == Timestamp) ||
- (PotentialTimestamp - 1 == Timestamp)) {
- //
- // The file name and timestamps match, try to load symbols in
- // this file.
- //
- Status = DbgLoadSymbols(PotentialBinary,
- ImageMachineType,
- Context,
- &(NewModule->Symbols));
- if (Status == 0) {
- NewModule->Timestamp = Timestamp;
- NewModule->Filename = PotentialBinary;
- break;
- }
- //
- // The name matches, but the timestamp doesn't. If nothing better
- // is found keep this around to try at the end.
- //
- } else if (BackupPotential == NULL) {
- BackupPotential = PotentialBinary;
- BackupPotentialTimestamp = Stat.st_mtime -
- SYSTEM_TIME_TO_EPOCH_DELTA;
- PotentialBinary = NULL;
- }
- }
- if (PotentialBinary != NULL) {
- free(PotentialBinary);
- }
- }
- //
- // Attempt to load the binary without any symbol path.
- //
- if (NewModule->Symbols == NULL) {
- Status = stat(OriginalBinaryName, &Stat);
- if (Status == 0) {
- PotentialTimestamp = Stat.st_mtime - SYSTEM_TIME_TO_EPOCH_DELTA;
- NewModule->Filename = strdup(OriginalBinaryName);
- if (NewModule->Filename == NULL) {
- DbgOut("Error: Unable to allocate space for filename.\n");
- Result = FALSE;
- goto LoadModuleEnd;
- }
- //
- // Attempt to load symbols if the timestamps match.
- //
- if ((Timestamp == 0) ||
- (PotentialTimestamp == Timestamp) ||
- (PotentialTimestamp + 1 == Timestamp) ||
- (PotentialTimestamp - 1 == Timestamp)) {
- Status = DbgLoadSymbols(NewModule->Filename,
- ImageMachineType,
- Context,
- &(NewModule->Symbols));
- if (Status == 0) {
- //
- // A module was successfully loaded this way, so skip the
- // symbol path searching.
- //
- PathCount = 0;
- NewModule->Timestamp = Timestamp;
- } else {
- free(NewModule->Filename);
- NewModule->Filename = NULL;
- }
- //
- // The timestamps don't match but the name does, save this as a
- // backup if there's nothing better.
- //
- } else if (BackupPotential == NULL) {
- BackupPotential = NewModule->Filename;
- BackupPotentialTimestamp = PotentialTimestamp;
- NewModule->Filename = NULL;
- }
- }
- }
- //
- // If nothing was found but there's a backup, try the backup.
- //
- if ((NewModule->Symbols == NULL) && (BackupPotential != NULL)) {
- Status = DbgLoadSymbols(BackupPotential,
- ImageMachineType,
- Context,
- &(NewModule->Symbols));
- if (Status == 0) {
- //
- // Warn the user that a module with a different timestamp is being
- // loaded, as it could easily mean the symbols are out of sync.
- // Don't bother warning them for timestamps that are different by 2
- // seconds or less, as some file systems (FAT) and compression
- // formats (ZIP) only have 2-second resolution.
- //
- Delta = BackupPotentialTimestamp - Timestamp;
- if (Timestamp > BackupPotentialTimestamp) {
- Delta = Timestamp - BackupPotentialTimestamp;
- }
- if (Delta > 2) {
- Time = Timestamp + SYSTEM_TIME_TO_EPOCH_DELTA;
- TimeStructure = localtime(&Time);
- TimeString = asctime(TimeStructure);
- LastIndex = strlen(TimeString);
- if (LastIndex != 0) {
- if (TimeString[LastIndex - 1] == '\n') {
- TimeString[LastIndex - 1] = '\0';
- }
- }
- DbgOut("Warning: Target timestamp for %s is %s\n",
- FriendlyName,
- TimeString);
- Time = BackupPotentialTimestamp + SYSTEM_TIME_TO_EPOCH_DELTA;
- TimeStructure = localtime(&Time);
- TimeString = asctime(TimeStructure);
- LastIndex = strlen(TimeString);
- if (LastIndex != 0) {
- if (TimeString[LastIndex - 1] == '\n') {
- TimeString[LastIndex - 1] = '\0';
- }
- }
- DbgOut("but file '%s' has timestamp %s.\n",
- BackupPotential,
- TimeString);
- }
- NewModule->Filename = BackupPotential;
- NewModule->Timestamp = Timestamp;
- BackupPotential = NULL;
- }
- }
- //
- // Populate the other fields of the module.
- //
- NameLength = strlen(FriendlyName);
- if (NameLength == 0) {
- Result = FALSE;
- goto LoadModuleEnd;
- }
- NewModule->ModuleName = malloc(NameLength + 1);
- if (NewModule->ModuleName == NULL) {
- Result = FALSE;
- goto LoadModuleEnd;
- }
- strcpy(NewModule->ModuleName, FriendlyName);
- NewModule->LowestAddress = LowestAddress;
- NewModule->Size = Size;
- NewModule->Process = Process;
- NewModule->Loaded = TRUE;
- INSERT_BEFORE(&(NewModule->ListEntry), &(Context->ModuleList.ModulesHead));
- NewModule->BaseDifference = LowestAddress;
- if (NewModule->Symbols != NULL) {
- NewModule->BaseDifference = LowestAddress -
- NewModule->Symbols->ImageBase;
- }
- DbgOut("Module loaded 0x%08I64x: %s -> ",
- NewModule->BaseDifference,
- NewModule->ModuleName);
- if (NewModule->Symbols == NULL) {
- DbgOut(" *** Error: Symbols could not be loaded. ***\n");
- } else {
- DbgOut("%s\n", NewModule->Filename);
- }
- //
- // Update the total checksum.
- //
- Context->ModuleList.Signature += NewModule->Timestamp +
- NewModule->LowestAddress;
- Context->ModuleList.ModuleCount += 1;
- Result = TRUE;
- LoadModuleEnd:
- if (BackupPotential != NULL) {
- free(BackupPotential);
- }
- if (Result == FALSE) {
- if (NewModule != NULL) {
- if (NewModule->Filename != NULL) {
- free(NewModule->Filename);
- }
- if (NewModule->ModuleName != NULL) {
- free(NewModule->ModuleName);
- }
- if (NewModule->Symbols != NULL) {
- DbgUnloadSymbols(NewModule->Symbols);
- NewModule->Symbols = NULL;
- }
- free(NewModule);
- NewModule = NULL;
- }
- }
- return NewModule;
- }
- INT
- DbgrpResolveDumpType (
- PDEBUGGER_CONTEXT Context,
- PTYPE_SYMBOL *Type,
- PVOID *Data,
- PUINTN DataSize,
- PULONGLONG Address
- )
- /*++
- Routine Description:
- This routine resolves a dump type and data to something valuable that can
- be dumped. For example, it will follow pointers until a structure type and
- data is found.
- Arguments:
- Context - Supplies a pointer to the applicaton context.
- Type - Supplies a pointer that receives the resolved type. It also supplies
- thie initial type.
- Data - Supplies a pointer that receives the data to be dumped. It also
- supplies the dump data for the given type.
- DataSize - Supplies a pointer that on input contains the size of the
- existing data buffer. This will be updated on output.
- Address - Supplies a pointer that receives the address of the final
- data if pointers are followed.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- ULONG BytesRead;
- PVOID CurrentData;
- ULONG CurrentSize;
- PTYPE_SYMBOL CurrentType;
- ULONGLONG PointerValue;
- PDATA_TYPE_RELATION RelationData;
- ULONG RelativeSize;
- PTYPE_SYMBOL RelativeType;
- INT Result;
- SYMBOL_SEARCH_RESULT SearchResult;
- CurrentData = *Data;
- CurrentSize = *DataSize;
- CurrentType = *Type;
- while (TRUE) {
- Result = FALSE;
- //
- // Resolve the current type until a void, pointer, array, function, or
- // non-relation type is found.
- //
- CurrentType = DbgSkipTypedefs(CurrentType);
- if (CurrentType == NULL) {
- Result = EINVAL;
- goto ResolveDumpTypeEnd;
- }
- //
- // If the type resolved to a non-relation type, then exit successfully.
- //
- if (CurrentType->Type != DataTypeRelation) {
- break;
- }
- RelationData = &(CurrentType->U.Relation);
- RelativeType = DbgGetType(RelationData->OwningFile,
- RelationData->TypeNumber);
- //
- // If the resolved type is a void, an array, or a function, then there
- // is nothing more to resolve.
- //
- if ((RelativeType == CurrentType) ||
- (RelationData->Array.Minimum != RelationData->Array.Maximum) ||
- (RelationData->Function != FALSE)) {
- break;
- }
- //
- // If the relative type is a structure with zero size, search for a
- // structure with the same name and a non-zero size.
- //
- RelativeSize = DbgGetTypeSize(RelativeType, 0);
- if ((RelativeType->Type == DataTypeStructure) && (RelativeSize == 0)) {
- SearchResult.Variety = SymbolResultType;
- Result = DbgpFindSymbol(Context,
- RelativeType->Name,
- &SearchResult);
- if (Result != FALSE) {
- RelativeType = SearchResult.U.TypeResult;
- RelativeSize = DbgGetTypeSize(RelativeType, 0);
- }
- }
- //
- // Follow pointers, reading the relative type data from the pointer.
- // The pointer value is stored in the current data and the size of the
- // current data should not be bigger than a pointer size.
- //
- assert(RelationData->Pointer != 0);
- CurrentSize = DbgGetTypeSize(CurrentType, 0);
- if (CurrentSize > sizeof(ULONGLONG)) {
- DbgOut("Pointer for type %s is of size %d.\n",
- CurrentType->Name,
- CurrentSize);
- Result = EINVAL;
- goto ResolveDumpTypeEnd;
- }
- assert((CurrentData != *Data) || (*DataSize == CurrentSize));
- //
- // Make sure to not follow a NULL pointer.
- //
- PointerValue = 0;
- memcpy(&PointerValue, CurrentData, CurrentSize);
- if (PointerValue == 0) {
- DbgOut("Pointer is NULL.\n", CurrentType->Name);
- Result = FALSE;
- goto ResolveDumpTypeEnd;
- }
- //
- // Allocate a new buffer and read the type data.
- //
- free(CurrentData);
- CurrentSize = RelativeSize;
- CurrentData = malloc(CurrentSize);
- if (CurrentData == NULL) {
- DbgOut("Error unable to allocate %d bytes of memory.\n",
- RelativeSize);
- Result = ENOMEM;
- goto ResolveDumpTypeEnd;
- }
- *Address = PointerValue;
- Result = DbgReadMemory(Context,
- TRUE,
- PointerValue,
- RelativeSize,
- CurrentData,
- &BytesRead);
- if ((Result != 0) || (BytesRead != RelativeSize)) {
- if (Result == 0) {
- Result = EINVAL;
- }
- DbgOut("Error reading memory at 0x%I64x. Expected %d bytes and "
- "read %d bytes\n",
- PointerValue,
- RelativeSize,
- BytesRead);
- goto ResolveDumpTypeEnd;
- }
- CurrentType = RelativeType;
- }
- Result = 0;
- ResolveDumpTypeEnd:
- if (Result != 0) {
- if (CurrentData != NULL) {
- free(CurrentData);
- CurrentData = NULL;
- }
- CurrentSize = 0;
- }
- *Type = CurrentType;
- *Data = CurrentData;
- *DataSize = CurrentSize;
- return Result;
- }
- INT
- DbgrpSetFrame (
- PDEBUGGER_CONTEXT Context,
- ULONG FrameNumber
- )
- /*++
- Routine Description:
- This routine changes the current frame, so that local variables may come
- from a different function in the call stack.
- Arguments:
- Context - Supplies a pointer to the application context.
- FrameNumber - Supplies the frame number. Zero represents the currently
- executing function, 1 represents 0's caller, 2 represents 1's caller,
- etc.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- STACK_FRAME Frame;
- ULONG FrameIndex;
- REGISTERS_UNION Registers;
- INT Status;
- BOOL Unwind;
- assert(Context->CurrentEvent.Type == DebuggerEventBreak);
- Status = 0;
- //
- // Attempt to unwind to the given frame.
- //
- RtlCopyMemory(&Registers,
- &(Context->CurrentEvent.BreakNotification.Registers),
- sizeof(REGISTERS_UNION));
- //
- // Set the return address to the current PC so that if it's frame 0, the
- // highlighted line returns to the PC.
- //
- Frame.ReturnAddress = DbgGetPc(Context, &Registers);
- //
- // Unwind the desired number of frames.
- //
- Unwind = TRUE;
- for (FrameIndex = 0; FrameIndex < FrameNumber; FrameIndex += 1) {
- Status = DbgStackUnwind(Context, &Registers, &Unwind, &Frame);
- if (Status == EOF) {
- DbgOut("Error: Only %d frames on the stack.\n", FrameIndex);
- break;
- } else if (Status != 0) {
- DbgOut("Error: Failed to unwind stack: %s.\n",
- strerror(Status));
- break;
- }
- }
- //
- // If the stack was successfully unwound to the given frame, set that
- // as the current information.
- //
- if (Status == 0) {
- RtlCopyMemory(&(Context->FrameRegisters),
- &Registers,
- sizeof(REGISTERS_UNION));
- Context->CurrentFrame = FrameNumber;
- //
- // Load and highlight the source line of the new frame.
- //
- DbgrShowSourceAtAddress(Context, Frame.ReturnAddress);
- }
- return Status;
- }
- INT
- DbgrpEnableBreakPoint (
- PDEBUGGER_CONTEXT Context,
- LONG BreakPointIndex,
- BOOL Enable
- )
- /*++
- Routine Description:
- This routine enables or disables a breakpoint identified by its zero-based
- index.
- Arguments:
- Context - Supplies a pointer to the application context.
- BreakPointIndex - Supplies the zero-based index of the breakpoint to enable
- or disable. To specify all breakpoints, set Index to -1.
- Enable - Supplies a flag indicating whether or not to enable (TRUE) or
- disable (FALSE) this breakpoint.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PDEBUGGER_BREAK_POINT Breakpoint;
- PLIST_ENTRY CurrentEntry;
- INT Status;
- //
- // Loop through looking for the breakpoint in the list.
- //
- CurrentEntry = Context->BreakpointList.Next;
- while (CurrentEntry != &(Context->BreakpointList)) {
- Breakpoint = LIST_VALUE(CurrentEntry, DEBUGGER_BREAK_POINT, ListEntry);
- if ((Breakpoint->Index == BreakPointIndex) || (BreakPointIndex == -1)) {
- //
- // Attempt to enable the breakpoint if it's not already enabled.
- //
- if (Enable != FALSE) {
- if (Breakpoint->Enabled == FALSE) {
- Status = DbgrpSetBreakpointAtAddress(
- Context,
- Breakpoint->Address,
- &(Breakpoint->OriginalValue));
- if (Status != 0) {
- goto EnableBreakPointEnd;
- }
- Breakpoint->Enabled = TRUE;
- }
- //
- // Disable the breakpoint if it's not already disabled.
- //
- } else {
- if (Breakpoint->Enabled != FALSE) {
- if (Context->BreakpointToRestore == Breakpoint) {
- Context->BreakpointToRestore = NULL;
- }
- Status = DbgrpClearBreakpointAtAddress(
- Context,
- Breakpoint->Address,
- Breakpoint->OriginalValue);
- if (Status != 0) {
- goto EnableBreakPointEnd;
- }
- Breakpoint->Enabled = FALSE;
- }
- }
- if (BreakPointIndex != -1) {
- break;
- }
- }
- CurrentEntry = CurrentEntry->Next;
- }
- if ((CurrentEntry == &(Context->BreakpointList)) &&
- (BreakPointIndex != -1)) {
- DbgOut("Breakpoint %d not found.\n", BreakPointIndex);
- Status = EINVAL;
- goto EnableBreakPointEnd;
- }
- Status = 0;
- EnableBreakPointEnd:
- return Status;
- }
- VOID
- DbgrpDestroySourcePath (
- PDEBUGGER_SOURCE_PATH SourcePath
- )
- /*++
- Routine Description:
- This routine destroys a source path entry. It is assumed the entry is
- already removed from its list.
- Arguments:
- SourcePath - Supplies a pointer to the source path to destroy.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- if (SourcePath->Prefix != NULL) {
- free(SourcePath->Prefix);
- }
- if (SourcePath->Path != NULL) {
- free(SourcePath->Path);
- }
- free(SourcePath);
- return;
- }
- INT
- DbgrpLoadFile (
- PSTR Path,
- PVOID *Contents,
- PULONGLONG Size
- )
- /*++
- Routine Description:
- This routine loads a file into memory.
- Arguments:
- Path - Supplies a pointer to the path to load.
- Contents - Supplies a pointer where a pointer to the loaded file will be
- returned on success. The caller is responsible for freeing this memory.
- Size - Supplies a pointer where the size of the file will be returned on
- success.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PVOID Buffer;
- FILE *File;
- size_t Read;
- INT Result;
- struct stat Stat;
- *Contents = NULL;
- *Size = 0;
- Result = stat(Path, &Stat);
- if (Result != 0) {
- return errno;
- }
- Buffer = malloc(Stat.st_size);
- if (Buffer == NULL) {
- return ENOMEM;
- }
- File = fopen(Path, "rb");
- if (File == NULL) {
- Result = errno;
- goto LoadFileEnd;
- }
- Read = fread(Buffer, 1, Stat.st_size, File);
- fclose(File);
- if (Read != Stat.st_size) {
- Result = errno;
- goto LoadFileEnd;
- }
- Result = 0;
- LoadFileEnd:
- if (Result != 0) {
- if (Buffer != NULL) {
- free(Buffer);
- Buffer = NULL;
- }
- }
- *Contents = Buffer;
- *Size = Stat.st_size;
- return Result;
- }
- VOID
- DbgrpPrintEflags (
- ULONGLONG Eflags
- )
- /*++
- Routine Description:
- This routine prints the broken down x86 eflags register.
- Arguments:
- Eflags - Supplies the eflags value.
- Return Value:
- None.
- --*/
- {
- ULONG Iopl;
- Iopl = (Eflags & IA32_EFLAG_IOPL_MASK) >> IA32_EFLAG_IOPL_SHIFT;
- DbgOut("Iopl: %d Flags: ", Iopl);
- if (((Eflags & IA32_EFLAG_ALWAYS_0) != 0) ||
- ((Eflags & IA32_EFLAG_ALWAYS_1) != IA32_EFLAG_ALWAYS_1)) {
- DbgOut("*** WARNING: Invalid Flags!! ***");
- }
- if ((Eflags & IA32_EFLAG_CF) != 0) {
- DbgOut("cf ");
- }
- if ((Eflags & IA32_EFLAG_PF) != 0) {
- DbgOut("pf ");
- }
- if ((Eflags & IA32_EFLAG_AF) != 0) {
- DbgOut("af ");
- }
- if ((Eflags & IA32_EFLAG_ZF) != 0) {
- DbgOut("zf ");
- }
- if ((Eflags & IA32_EFLAG_SF) != 0) {
- DbgOut("sf ");
- }
- if ((Eflags & IA32_EFLAG_TF) != 0) {
- DbgOut("tf ");
- }
- if ((Eflags & IA32_EFLAG_IF) != 0) {
- DbgOut("if ");
- }
- if ((Eflags & IA32_EFLAG_DF) != 0) {
- DbgOut("df ");
- }
- if ((Eflags & IA32_EFLAG_OF) != 0) {
- DbgOut("of ");
- }
- if ((Eflags & IA32_EFLAG_NT) != 0) {
- DbgOut("nt ");
- }
- if ((Eflags & IA32_EFLAG_RF) != 0) {
- DbgOut("rf ");
- }
- if ((Eflags & IA32_EFLAG_VM) != 0) {
- DbgOut("vm ");
- }
- if ((Eflags & IA32_EFLAG_AC) != 0) {
- DbgOut("ac ");
- }
- if ((Eflags & IA32_EFLAG_VIF) != 0) {
- DbgOut("vif ");
- }
- if ((Eflags & IA32_EFLAG_VIP) != 0) {
- DbgOut("vip ");
- }
- if ((Eflags & IA32_EFLAG_ID) != 0) {
- DbgOut("id ");
- }
- return;
- }
|