123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- kdebug.c
- Abstract:
- This module implements the kernel debugging functionality.
- Author:
- Evan Green 3-Jul-2012
- Environment:
- Kernel mode
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include <minoca/kernel/bootload.h>
- #include <minoca/debug/dbgproto.h>
- #include "kdp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the increment to stall for in microseconds when waiting for a packet.
- //
- #define DEBUG_STALL_INCREMENT 1000
- //
- // Define the amount of time to wait if just waiting a little bit, not the full
- // stall increment yet.
- //
- #define DEBUG_SMALL_STALL 100
- //
- // Define the maximum size of the kernel module name.
- //
- #define MAX_KERNEL_MODULE_NAME 16
- //
- // Define the number of microseconds to wait for all other processors before
- // declaring them lost and entering the debugger anyway.
- //
- #define DEBUG_PROCESSOR_WAIT_TIME (10 * MICROSECONDS_PER_SECOND)
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure defines a "range" breakpoint. This type of breakpoint will
- break on a range of addresses, with an optional "hole" within the range that
- will not cause a break. This type of breakpoint is very slow, as it puts
- the processor into single step mode and manually checks the range on every
- trap.
- Members:
- Enabled - Stores a flag indicating whether or not the range breakpoint is
- current enabled. If disabled (FALSE), none of the other fields are
- guaranteed to be initialized.
- BreakRangeStart - Stores a pointer to the first byte of memory that
- qualifies as being in the break range.
- BreakRangeEnd - Stores a pointer to the first byte of memory that does not
- qualify as being in the break range.
- RangeHoleStart - Stores a pointer to the first byte within the range that
- does not generate a break (a "hole" in the break range).
- RangeHoleEnd - Stores a pointer to the first byte within the range that does
- not fall in the range hole (the first byte that again qualifies as
- within the break range).
- --*/
- typedef struct _BREAK_RANGE {
- BOOL Enabled;
- PVOID BreakRangeStart;
- PVOID BreakRangeEnd;
- PVOID RangeHoleStart;
- PVOID RangeHoleEnd;
- } BREAK_RANGE, *PBREAK_RANGE;
- /*++
- Structure Description:
- This structure stores the set of parameters needed for a kernel debug print
- operation.
- Members:
- FormatString - Stores a pointer to the printf format string to print.
- Arguments - Stores the list of arguments needed by the format string.
- --*/
- typedef struct _PRINT_PARAMETERS {
- PSTR FormatString;
- va_list Arguments;
- } PRINT_PARAMETERS, *PPRINT_PARAMETERS;
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Define globals indicating the initialization and connection state of Kd.
- //
- BOOL KdDebuggerConnected;
- BOOL KdDebuggingEnabled = TRUE;
- BOOL KdInitialized = FALSE;
- volatile ULONG KdLockAcquired = -1;
- volatile ULONG KdProcessorsFrozen = 0;
- volatile ULONG KdFreezeOwner = MAX_ULONG;
- BOOL KdNmiBroadcastAllowed = FALSE;
- //
- // Store a pointer to the debugger transport.
- //
- PDEBUG_DEVICE_DESCRIPTION KdDebugDevice;
- DEBUG_HANDOFF_DATA KdHandoffData;
- //
- // Set this flag to allow notable user mode exceptions to bubble up into the
- // kernel mode debugger.
- //
- BOOL KdEnableUserModeExceptions = TRUE;
- //
- // Set this flag to debug the time counter itself or situations where the time
- // counter may not be accessible or reliable.
- //
- BOOL KdAvoidTimeCounter = FALSE;
- //
- // Set this flag to enable encoding of certain characters that might not fly
- // across the wire well directly (like XON/XOFF).
- //
- BOOL KdEncodeBytes = FALSE;
- //
- // Variable used for one-time assertions.
- //
- BOOL KdAsserted = FALSE;
- //
- // Carve off some memory for sending and receiving debug packets, and storing
- // the currently loaded modules.
- //
- DEBUG_PACKET KdTxPacket;
- DEBUG_PACKET KdRxPacket;
- DEBUG_MODULE_LIST KdLoadedModules;
- BOOL KdLoadedModulesInitialized;
- //
- // Carve off memory to store the kernel module, including its string.
- //
- UCHAR KdKernelModuleBuffer[sizeof(DEBUG_MODULE) + MAX_KERNEL_MODULE_NAME];
- //
- // Store information about whether or not the user asked for a single step.
- //
- BOOL KdUserRequestedSingleStep;
- BREAK_RANGE KdBreakRange;
- UINTN KdPeriodicBreakInCheck;
- //
- // Variable used to determine whether or not memory validation should be
- // skipped.
- //
- BOOL KdSkipMemoryValidation = FALSE;
- //
- // Define the amount of time to wait in microseconds to wait for a connection
- // before moving on. Set to -1 to avoid using the stall function and wait
- // indefinitely.
- //
- ULONG KdConnectionTimeout = DEBUG_CONNECTION_TIMEOUT;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- KdpSendPacket (
- PDEBUG_PACKET Packet,
- PBOOL BreakInRequested
- );
- KSTATUS
- KdpReceivePacket (
- PDEBUG_PACKET Packet,
- ULONG Timeout
- );
- KSTATUS
- KdpReceivePacketHeader (
- PDEBUG_PACKET_HEADER Packet,
- PULONG Timeout
- );
- KSTATUS
- KdpProcessCommand (
- PDEBUG_PACKET Packet,
- ULONG Exception,
- PTRAP_FRAME TrapFrame,
- PBOOL ContinueExecution
- );
- KSTATUS
- KdpPrint (
- PPRINT_PARAMETERS PrintParameters,
- PBOOL BreakInRequested
- );
- KSTATUS
- KdpSendProfilingData (
- PBOOL BreakInRequested
- );
- USHORT
- KdpCalculateChecksum (
- PVOID Data,
- ULONG DataLength
- );
- KSTATUS
- KdpSendModuleList (
- BOOL SendHeaderOnly
- );
- KSTATUS
- KdpHandleMemoryAccess (
- VOID
- );
- VOID
- KdpInitializeBreakNotification (
- ULONG Exception,
- PTRAP_FRAME TrapFrame,
- PDEBUG_PACKET Packet
- );
- VOID
- KdpReboot (
- DEBUG_REBOOT_TYPE RebootType,
- ULONG Exception,
- PTRAP_FRAME TrapFrame
- );
- VOID
- KdpDisconnect (
- VOID
- );
- KSTATUS
- KdpConnect (
- PBOOL BreakInRequested
- );
- VOID
- KdpSynchronize (
- VOID
- );
- KSTATUS
- KdpSendConnectionResponse (
- PCONNECTION_REQUEST ConnectionRequest,
- PBOOL BreakInRequested
- );
- VOID
- KdpInternalPrint (
- PSTR Format,
- ...
- );
- VOID
- KdpAcquireDebuggerLock (
- PTRAP_FRAME TrapFrame
- );
- VOID
- KdpReleaseDebuggerLock (
- VOID
- );
- KSTATUS
- KdpTransmitBytes (
- PVOID Data,
- ULONG Size
- );
- KSTATUS
- KdpReceiveBuffer (
- PVOID Data,
- PULONG Size,
- PULONG Timeout
- );
- KSTATUS
- KdpDeviceReceiveBuffer (
- PVOID Data,
- PULONG Size,
- PULONG Timeout
- );
- KSTATUS
- KdpDeviceReset (
- ULONG BaudRate
- );
- KSTATUS
- KdpDeviceTransmit (
- PVOID Data,
- ULONG Size
- );
- KSTATUS
- KdpDeviceReceive (
- PVOID Data,
- PULONG Size
- );
- KSTATUS
- KdpDeviceGetStatus (
- PBOOL ReceiveDataAvailable
- );
- VOID
- KdpDeviceDisconnect (
- VOID
- );
- VOID
- KdpFreezeProcessors (
- VOID
- );
- //
- // ------------------------------------------------------------------ Functions
- //
- KERNEL_API
- VOID
- KdConnect (
- VOID
- )
- /*++
- Routine Description:
- This routine connects to the kernel debugger.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- if ((KdInitialized == FALSE) || (KdDebuggingEnabled == FALSE)) {
- return;
- }
- RtlDebugService(EXCEPTION_DEBUGGER_CONNECT, NULL);
- return;
- }
- KERNEL_API
- VOID
- KdDisconnect (
- VOID
- )
- /*++
- Routine Description:
- This routine disconnects from the kernel debugger.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- if ((KdInitialized == FALSE) ||
- (KdDebuggingEnabled == FALSE) ||
- (KdDebuggerConnected == FALSE)) {
- return;
- }
- RtlDebugService(EXCEPTION_DEBUGGER_DISCONNECT, NULL);
- return;
- }
- KERNEL_API
- KSTATUS
- KdGetDeviceInformation (
- PDEBUG_HANDOFF_DATA *Information
- )
- /*++
- Routine Description:
- This routine returns information about the debug device in use. This
- includes information identifying the device, OEM-specific data, and
- transport-specific data that may be needed to coordinate shared control
- between runtime drivers and the kernel debug subsystem.
- Arguments:
- Information - Supplies a pointer where a pointer to the debug information
- will be returned on success. The caller must not modify or free this
- data.
- Return Value:
- STATUS_SUCCESS if information was successfully returned.
- STATUS_NO_ELIGIBLE_DEVICES if no debug devices were found or used.
- Other status codes on other errors.
- --*/
- {
- KSTATUS Status;
- if (Information != NULL) {
- *Information = NULL;
- }
- if (KdDebugDevice == NULL) {
- return STATUS_NO_ELIGIBLE_DEVICES;
- }
- KdHandoffData.PortType = KdDebugDevice->PortType;
- KdHandoffData.PortSubType = KdDebugDevice->PortSubType;
- KdHandoffData.Identifier = KdDebugDevice->Identifier;
- if (KdHandoffData.PortType == DEBUG_PORT_TYPE_USB) {
- Status = KdpUsbGetHandoffData(&KdHandoffData);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- }
- if (Information != NULL) {
- *Information = &KdHandoffData;
- }
- return STATUS_SUCCESS;
- }
- VOID
- KdPrint (
- PSTR Format,
- ...
- )
- /*++
- Routine Description:
- This routine prints a string to the debugger. Currently the maximum length
- string is a little less than one debug packet.
- Arguments:
- Format - Supplies a pointer to the printf-like format string.
- ... - Supplies any needed arguments for the format string.
- Return Value:
- None.
- --*/
- {
- va_list ArgumentList;
- va_start(ArgumentList, Format);
- KdPrintWithArgumentList(Format, ArgumentList);
- va_end(ArgumentList);
- return;
- }
- VOID
- KdPrintWithArgumentList (
- PSTR Format,
- va_list ArgumentList
- )
- /*++
- Routine Description:
- This routine prints a string to the debugger. Currently the maximum length
- string is a little less than one debug packet.
- Arguments:
- Format - Supplies a pointer to the printf-like format string.
- ArgumentList - Supplies a pointer to the initialized list of arguments
- required for the format string.
- Return Value:
- None.
- --*/
- {
- PRINT_PARAMETERS PrintParameters;
- if ((KdDebuggingEnabled != FALSE) &&
- (KdDebuggerConnected != FALSE) &&
- (KdInitialized != FALSE)) {
- PrintParameters.FormatString = Format;
- PrintParameters.Arguments = ArgumentList;
- RtlDebugService(EXCEPTION_PRINT, &PrintParameters);
- }
- return;
- }
- KSTATUS
- KdInitialize (
- PDEBUG_DEVICE_DESCRIPTION DebugDevice,
- PDEBUG_MODULE CurrentModule
- )
- /*++
- Routine Description:
- This routine initializes the debugger subsystem and connects to the target
- if debugging is enabled.
- Arguments:
- DebugDevice - Supplies a pointer to the debug device to communicate on.
- CurrentModule - Supplies the details of the initial running program.
- Return Value:
- Kernel status code.
- --*/
- {
- PSTR KernelBinaryName;
- PDEBUG_MODULE KernelModule;
- ULONG NameSize;
- KSTATUS Status;
- Status = STATUS_SUCCESS;
- if (DebugDevice != NULL) {
- KdDebugDevice = DebugDevice;
- }
- //
- // Set up the loaded modules list now if it has not been done.
- //
- if (KdLoadedModulesInitialized == FALSE) {
- KernelModule = (PDEBUG_MODULE)KdKernelModuleBuffer;
- KernelBinaryName = CurrentModule->BinaryName;
- //
- // Copy the name string into the kernel module structure.
- //
- NameSize = CurrentModule->StructureSize - sizeof(DEBUG_MODULE) +
- (ANYSIZE_ARRAY * sizeof(CHAR));
- if (NameSize > MAX_KERNEL_MODULE_NAME) {
- NameSize = MAX_KERNEL_MODULE_NAME;
- }
- RtlStringCopy(KernelModule->BinaryName, KernelBinaryName, NameSize);
- KernelModule->StructureSize = CurrentModule->StructureSize;
- //
- // Fill out the rest of the kernel module information.
- //
- KernelModule->BaseAddress = CurrentModule->BaseAddress;
- KernelModule->LowestAddress = CurrentModule->LowestAddress;
- KernelModule->Size = CurrentModule->Size;
- KernelModule->Timestamp = CurrentModule->Timestamp;
- KernelModule->Process = 0;
- //
- // Initialize the loaded modules list, inserting the kernel as the first
- // entry.
- //
- KdLoadedModules.ModuleCount = 1;
- KdLoadedModules.Signature = KernelModule->Timestamp +
- (UINTN)(KernelModule->LowestAddress);
- INITIALIZE_LIST_HEAD(&(KdLoadedModules.ModulesHead));
- INSERT_AFTER(&(KernelModule->ListEntry),
- &(KdLoadedModules.ModulesHead));
- KdLoadedModulesInitialized = TRUE;
- }
- //
- // Initialize debugging hardware state.
- //
- KdpInitializeDebuggingHardware();
- //
- // Initialize other runtime globals.
- //
- KdBreakRange.Enabled = FALSE;
- KdUserRequestedSingleStep = FALSE;
- KdInitialized = TRUE;
- //
- // If debugging is not enabled, then initialization is finished.
- //
- if (KdDebuggingEnabled == FALSE) {
- Status = STATUS_SUCCESS;
- goto InitializeEnd;
- }
- //
- // Fire up a connection with the host.
- //
- KdConnect();
- InitializeEnd:
- return Status;
- }
- VOID
- KdBreak (
- VOID
- )
- /*++
- Routine Description:
- This routine breaks into the debugger if one is connected.
- Arguments:
- None.
- Return Value:
- Kernel status code.
- --*/
- {
- if ((KdDebuggingEnabled != FALSE) && (KdInitialized != FALSE)) {
- KdpBreak();
- }
- return;
- }
- VOID
- KdReportModuleChange (
- PDEBUG_MODULE Module,
- BOOL Loading
- )
- /*++
- Routine Description:
- This routine informs the debugger of an image being loaded or unloaded.
- Arguments:
- Module - Supplies a pointer to the module being loaded or unloaded. The
- caller is responsible for managing this memory. The memory should
- not be freed until after reporting that the module has unloaded. This
- memory must not be pagable.
- Loading - Supplies a flag indicating whether the module is being loaded or
- unloaded.
- Return Value:
- None.
- --*/
- {
- MODULE_CHANGE_NOTIFICATION Notification;
- Notification.Module = Module;
- Notification.Loading = Loading;
- RtlDebugService(EXCEPTION_MODULE_CHANGE, &Notification);
- return;
- }
- VOID
- KdPollForBreakRequest (
- VOID
- )
- /*++
- Routine Description:
- This routine polls the debugger connection to determine if the debugger
- has requested to break in.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- //
- // If debugging is not enabled, then this shouldn't execute. This does
- // run even if the debugger is disconnected in case the debugger is trying
- // to connect.
- //
- if ((KdInitialized == FALSE) || (KdDebuggingEnabled == FALSE)) {
- return;
- }
- RtlDebugService(EXCEPTION_POLL_DEBUGGER, NULL);
- return;
- }
- BOOL
- KdIsDebuggerConnected (
- VOID
- )
- /*++
- Routine Description:
- This routine indicates whether or not a kernel debugger is currently
- connected to the system.
- Arguments:
- None.
- Return Value:
- TRUE if the debugger is enabled and connected.
- FALSE otherwise.
- --*/
- {
- return KdDebuggerConnected;
- }
- BOOL
- KdAreUserModeExceptionsEnabled (
- VOID
- )
- /*++
- Routine Description:
- This routine indicates whether or not noteworthy exceptions caused in
- applications should bubble up to kernel mode debugger breaks.
- Arguments:
- None.
- Return Value:
- TRUE if user mode exceptions should bubble up to kernel mode.
- FALSE otherwise.
- --*/
- {
- return KdEnableUserModeExceptions;
- }
- ULONG
- KdSetConnectionTimeout (
- ULONG Timeout
- )
- /*++
- Routine Description:
- This routine sets the debugger connection timeout.
- Arguments:
- Timeout - Supplies the new timeout in microseconds. Supply MAX_ULONG to
- cause the debugger to not call the stall function and never time out
- the connection.
- Return Value:
- Returns the original timeout.
- --*/
- {
- return RtlAtomicExchange32(&KdConnectionTimeout, Timeout);
- }
- VOID
- KdSendProfilingData (
- VOID
- )
- /*++
- Routine Description:
- This routine polls the system profiler to determine if there is profiling
- data to be sent to the debugger.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- ULONG Flags;
- //
- // If debugging is not enabled, then this shouldn't execute.
- //
- if ((KdInitialized == FALSE) || (KdDebuggingEnabled == FALSE)) {
- return;
- }
- //
- // If the debugger's not actually connected, just poll for a connection
- // request.
- //
- Flags = 0;
- if (KdDebuggerConnected != FALSE) {
- Flags = SpGetProfilerDataStatus();
- }
- if (Flags == 0) {
- KdPollForBreakRequest();
- } else {
- RtlDebugService(EXCEPTION_PROFILER, NULL);
- }
- return;
- }
- VOID
- KdEnableNmiBroadcast (
- BOOL Enable
- )
- /*++
- Routine Description:
- This routine enables or disables the use of NMI broadcasts by the debugger.
- Arguments:
- Enable - Supplies TRUE if NMI broadcast is being enabled, or FALSE if NMI
- broadcast is being disabled.
- Return Value:
- None.
- --*/
- {
- KdNmiBroadcastAllowed = Enable;
- return;
- }
- VOID
- KdDebugExceptionHandler (
- ULONG Exception,
- PVOID Parameter,
- PTRAP_FRAME TrapFrame
- )
- /*++
- Routine Description:
- This routine handles the debug break exception. It is usually called by an
- assembly routine responding to an exception.
- Arguments:
- Exception - Supplies the type of exception that this function is handling.
- See EXCEPTION_* definitions for valid values.
- Parameter - Supplies a pointer to a parameter supplying additional
- context in the case of a debug service request.
- TrapFrame - Supplies a pointer to the state of the machine immediately
- before the debug exception occurred. Also returns the possibly modified
- machine state.
- Return Value:
- None.
- --*/
- {
- BOOL BreakInRequested;
- BOOL ContinueExecution;
- ULONG FreezeOwner;
- BOOL FunctionReturning;
- BOOL InsideRange;
- ULONGLONG InstructionPointer;
- PMODULE_CHANGE_NOTIFICATION Notification;
- BOOL OutsideHole;
- PVOID PreviousSingleStepAddress;
- PPROCESSOR_BLOCK ProcessorBlock;
- BOOL ReceiveDataAvailable;
- BOOL SingleStepHandled;
- KSTATUS Status;
- BreakInRequested = FALSE;
- PreviousSingleStepAddress = NULL;
- ProcessorBlock = NULL;
- SingleStepHandled = FALSE;
- KD_TRACE(KdTraceInExceptionHandler);
- //
- // If debugging is not enabled, then this shouldn't execute.
- //
- if ((KdInitialized == FALSE) || (KdDebuggingEnabled == FALSE)) {
- return;
- }
- KD_TRACE(KdTraceDebuggingEnabled);
- //
- // If the exception is a user mode trap, use the trap frame provided by the
- // parameter and treat it as a single step.
- //
- if (Exception == EXCEPTION_USER_MODE) {
- TrapFrame = (PTRAP_FRAME)Parameter;
- Exception = EXCEPTION_BREAK;
- }
- //
- // Disable interrupts. They will get re-enabled by popping flags on the
- // return from this exception. Also acquire the lock so that two processors
- // aren't using the debug port at once.
- //
- KdpDisableInterrupts();
- KdpAcquireDebuggerLock(TrapFrame);
- KdpAtomicAdd32(&KdProcessorsFrozen, 1);
- KD_TRACE(KdTraceLockAcquired);
- //
- // If this is just a poll, check for received bytes before bothering to
- // freeze everyone. Chances are there's nothing.
- //
- if (Exception == EXCEPTION_POLL_DEBUGGER) {
- Status = KdpDeviceGetStatus(&ReceiveDataAvailable);
- if ((!KSUCCESS(Status)) || (ReceiveDataAvailable == FALSE)) {
- KD_TRACE(KdTracePollBailing);
- goto DebugExceptionHandlerEnd;
- }
- }
- //
- // Clear single step mode super early to minimize the chance of infinite
- // breakpoints if using a software-based single step mechanism. Remember to
- // put it back if this routine shortcuts to the exit.
- //
- KdpClearSingleStepMode(&Exception, TrapFrame, &PreviousSingleStepAddress);
- KD_TRACE(KdTraceClearedSingleStep);
- if (KeActiveProcessorCount > 1) {
- ProcessorBlock = KeGetCurrentProcessorBlockForDebugger();
- if (KdNmiBroadcastAllowed != FALSE) {
- FreezeOwner = KdpAtomicCompareExchange32(
- &KdFreezeOwner,
- ProcessorBlock->ProcessorNumber,
- MAX_ULONG);
- if (FreezeOwner != MAX_ULONG) {
- KdpReleaseDebuggerLock();
- KD_ASSERT_ONCE(FALSE);
- KdpAcquireDebuggerLock(TrapFrame);
- }
- //
- // Send an NMI to freeze all other processors, and wait until all
- // processors are frozen. Skip this when sending profiling data to
- // allow higher throughput.
- //
- if (Exception != EXCEPTION_PROFILER) {
- KdpFreezeProcessors();
- }
- //
- // There are more than one processors, but for whatever reason the
- // debugger should not be trying to freeze them. Set the freeze owner
- // to the current processor so it acts like the owner.
- //
- } else {
- KdFreezeOwner = ProcessorBlock->ProcessorNumber;
- }
- //
- // If there's only one processor, don't even get the processor block
- // (as it may not be there), just set the freeze owner.
- //
- } else {
- KdFreezeOwner = 0;
- }
- KD_TRACE(KdTraceProcessorsFrozen);
- //
- // If the exception is a result of polling, find out what's being sent.
- // Process this possible exception first because it's super common.
- //
- if (Exception == EXCEPTION_POLL_DEBUGGER) {
- while (TRUE) {
- Status = KdpDeviceGetStatus(&ReceiveDataAvailable);
- if ((!KSUCCESS(Status)) || (ReceiveDataAvailable == FALSE)) {
- KD_TRACE(KdTracePollBailing);
- break;
- }
- Status = KdpReceivePacket(&KdRxPacket, KdConnectionTimeout);
- if (!KSUCCESS(Status)) {
- KD_TRACE(KdTraceReceiveFailure);
- if (Status == STATUS_CONNECTION_RESET) {
- Exception = EXCEPTION_DEBUGGER_CONNECT;
- }
- break;
- }
- KD_TRACE(KdTraceProcessingCommand);
- if (KdRxPacket.Header.Command == DbgBreakRequest) {
- Exception = EXCEPTION_BREAK;
- KdDebuggerConnected = TRUE;
- } else {
- ContinueExecution = FALSE;
- Status = KdpProcessCommand(&KdRxPacket,
- Exception,
- TrapFrame,
- &ContinueExecution);
- if (!KSUCCESS(Status)) {
- break;
- }
- if (ContinueExecution == FALSE) {
- Exception = EXCEPTION_BREAK;
- }
- }
- }
- if (Exception == EXCEPTION_POLL_DEBUGGER) {
- goto DebugExceptionHandlerEnd;
- }
- //
- // If the exception was a disconnect request, do the disconnect and return.
- //
- } else if (Exception == EXCEPTION_DEBUGGER_DISCONNECT) {
- KdpDisconnect();
- goto DebugExceptionHandlerEnd;
- //
- // If the exception was just a print, do the print and return.
- //
- } else if (Exception == EXCEPTION_PRINT) {
- KD_TRACE(KdTracePrinting);
- KdpPrint((PPRINT_PARAMETERS)Parameter, &BreakInRequested);
- if (BreakInRequested == FALSE) {
- goto DebugExceptionHandlerEnd;
- }
- Exception = EXCEPTION_BREAK;
- //
- // If the exception is just to send profiling data, send the data and
- // return.
- //
- } else if (Exception == EXCEPTION_PROFILER) {
- KD_TRACE(KdTraceSendingProfilingData);
- KdpSendProfilingData(&BreakInRequested);
- if (BreakInRequested == FALSE) {
- goto DebugExceptionHandlerEnd;
- }
- //
- // The other cores were not frozen above. Attempt to freeze them now
- // that the debugger needs break in.
- //
- KdpFreezeProcessors();
- Exception = EXCEPTION_BREAK;
- //
- // If the exception was a module state change, update the module
- // information and return.
- //
- } else if (Exception == EXCEPTION_MODULE_CHANGE) {
- KD_TRACE(KdTraceModuleChange);
- Notification = (PMODULE_CHANGE_NOTIFICATION)Parameter;
- if (Notification->Loading == FALSE) {
- KdLoadedModules.ModuleCount -= 1;
- KdLoadedModules.Signature -=
- Notification->Module->Timestamp +
- (UINTN)(Notification->Module->LowestAddress);
- LIST_REMOVE(&(Notification->Module->ListEntry));
- } else {
- KdLoadedModules.ModuleCount += 1;
- KdLoadedModules.Signature +=
- Notification->Module->Timestamp +
- (UINTN)(Notification->Module->LowestAddress);
- INSERT_AFTER(&(Notification->Module->ListEntry),
- &(KdLoadedModules.ModulesHead));
- }
- goto DebugExceptionHandlerEnd;
- }
- //
- // If the exception is a connection request or one of the above exceptions
- // noticed that the host needed to be reconnected, run through the
- // connection process.
- //
- if (Exception == EXCEPTION_DEBUGGER_CONNECT) {
- KD_TRACE(KdTraceConnecting);
- Status = KdpConnect(&BreakInRequested);
- if ((KSUCCESS(Status)) && (BreakInRequested != FALSE)) {
- Exception = EXCEPTION_BREAK;
- } else {
- KD_TRACE(KdTraceConnectBailing);
- goto DebugExceptionHandlerEnd;
- }
- }
- KD_TRACE(KdTraceCheckSingleStep);
- //
- // There are no more shortcuts out of this function, this is going to make
- // it to the user. Don't feel responsible for restoring the cleared single
- // step, as the remainder of the routine will decide whether or not to set
- // a new one.
- //
- PreviousSingleStepAddress = NULL;
- //
- // If the user requested this single step or this is not a single step,
- // cancel the range breakpoint.
- //
- if ((KdUserRequestedSingleStep != FALSE) ||
- (Exception != EXCEPTION_SINGLE_STEP)) {
- KdBreakRange.Enabled = FALSE;
- }
- //
- // If the range breakpoint is active and the user didn't request a single
- // step, then the only purpose of this step is to validate the break range.
- //
- InstructionPointer = (UINTN)KdpGetInstructionPointer(TrapFrame);
- if ((KdBreakRange.Enabled != FALSE) &&
- (Exception == EXCEPTION_SINGLE_STEP)) {
- InsideRange =
- (InstructionPointer >= (ULONG)KdBreakRange.BreakRangeStart) &&
- (InstructionPointer < (ULONG)KdBreakRange.BreakRangeEnd);
- OutsideHole =
- (InstructionPointer < (ULONG)KdBreakRange.RangeHoleStart) ||
- (InstructionPointer >= (ULONG)KdBreakRange.RangeHoleEnd);
- if ((OutsideHole != FALSE) && (InsideRange != FALSE)) {
- //
- // This instruction fits the range description. Change the exception
- // to a break and turn off the trap flag. This turns it into a real
- // exception that will notify the debugger.
- //
- Exception = EXCEPTION_BREAK;
- //
- // This instruction does not fit the range. Continue single stepping.
- //
- } else {
- KdpSetSingleStepMode(Exception, TrapFrame, NULL);
- SingleStepHandled = TRUE;
- KdPeriodicBreakInCheck += 1;
- if ((KdPeriodicBreakInCheck &
- DEBUG_PERIODIC_BREAK_CHECK_MASK) == 0) {
- Status = KdpDeviceGetStatus(&ReceiveDataAvailable);
- if ((KSUCCESS(Status)) || (ReceiveDataAvailable != FALSE)) {
- SingleStepHandled = FALSE;
- }
- }
- //
- // If this instruction is a function return, check to see if it
- // matches the range (but is in the hole). If so, expand the range
- // to the whole address range so the next step won't miss the fact
- // that the function just returned.
- //
- FunctionReturning = KdpIsFunctionReturning(TrapFrame);
- if ((InsideRange != FALSE) && (FunctionReturning != FALSE)) {
- KdBreakRange.BreakRangeStart = 0;
- KdBreakRange.BreakRangeEnd = (PVOID)MAX_ULONG;
- }
- }
- }
- //
- // If the user did not request a single step exception, and it was handled
- // above, then there is no reason to communicate with the debugger.
- //
- if ((Exception == EXCEPTION_SINGLE_STEP) &&
- (SingleStepHandled != FALSE)) {
- goto DebugExceptionHandlerEnd;
- }
- KD_TRACE(KdTraceCommittingToBreak);
- //
- // Unless it isn't connected, this break is going to make it to the
- // debugger. Turn off the break range.
- //
- KdBreakRange.Enabled = FALSE;
- //
- // Now that essential business is taken care of, check to see if there's a
- // debugger to talk to. If not, return.
- //
- if (KdDebuggerConnected == FALSE) {
- KD_TRACE(KdTraceBailingUnconnected);
- goto DebugExceptionHandlerEnd;
- }
- while (TRUE) {
- if (KdFreezeOwner == MAX_ULONG) {
- break;
- }
- if ((KeActiveProcessorCount > 1) &&
- (KdFreezeOwner != ProcessorBlock->ProcessorNumber)) {
- continue;
- }
- //
- // Loop processing commands and handling connection resets. Also send a
- // break request the first time around the loop and if the connection
- // was reset.
- //
- BreakInRequested = TRUE;
- KD_TRACE(KdTraceProcessingCommand);
- ContinueExecution = FALSE;
- do {
- if (BreakInRequested != FALSE) {
- KdpInitializeBreakNotification(Exception,
- TrapFrame,
- &KdTxPacket);
- Status = KdpSendPacket(&KdTxPacket, NULL);
- if (!KSUCCESS(Status)) {
- KD_TRACE(KdTraceTransmitFailure);
- goto DebugExceptionHandlerEnd;
- }
- BreakInRequested = FALSE;
- }
- Status = KdpReceivePacket(&KdRxPacket, MAX_ULONG);
- if (!KSUCCESS(Status)) {
- continue;
- }
- Status = KdpProcessCommand(&KdRxPacket,
- Exception,
- TrapFrame,
- &ContinueExecution);
- if (!KSUCCESS(Status)) {
- break;
- }
- } while (ContinueExecution == FALSE);
- }
- DebugExceptionHandlerEnd:
- KD_TRACE(KdTraceThawingProcessors);
- if (PreviousSingleStepAddress != NULL) {
- KdpSetSingleStepMode(Exception, TrapFrame, PreviousSingleStepAddress);
- }
- KdpAtomicCompareExchange32(&KdFreezeOwner, MAX_ULONG, KdFreezeOwner);
- //
- // Wait until all processors are ready to go, then go.
- //
- KdpAtomicAdd32(&KdProcessorsFrozen, -1);
- while (KdProcessorsFrozen != 0) {
- NOTHING;
- }
- KdpReleaseDebuggerLock();
- KD_TRACE(KdTraceExit);
- return;
- }
- VOID
- KdNmiHandler (
- PTRAP_FRAME TrapFrame
- )
- /*++
- Routine Description:
- This routine handles NMI interrupts.
- Arguments:
- TrapFrame - Supplies a pointer to the state of the machine immediately
- before the NMI occurred. Also returns the possibly modified
- machine state.
- Return Value:
- None.
- --*/
- {
- BOOL ContinueExecution;
- PPROCESSOR_BLOCK ProcessorBlock;
- KSTATUS Status;
- KdpDisableInterrupts();
- ProcessorBlock = KeGetCurrentProcessorBlockForDebugger();
- //
- // If there is no freeze owner or no processors are frozen, this may be a
- // real NMI. Crash here unless NMIs are maskable.
- //
- if ((KdFreezeOwner == MAX_ULONG) ||
- (KdProcessorsFrozen == 0) ||
- (KdProcessorsFrozen >= KeActiveProcessorCount)) {
- ASSERT(KdFreezesAreMaskable != FALSE);
- return;
- }
- //
- // Let the freeze owner know that this processor is frozen and listening.
- //
- KdpAtomicAdd32(&KdProcessorsFrozen, 1);
- //
- // Spin waiting for the freeze owner to become this processor or signal to
- // continue execution.
- //
- while (TRUE) {
- //
- // If the freeze owner becomes -1, break out and continue execution.
- //
- if (KdFreezeOwner == MAX_ULONG) {
- break;
- }
- //
- // If the freeze owner becomes this processor, take over and start
- // processing commands. Report this as a regular break exception to
- // distinguish between actual NMIs and debug IPIs.
- //
- if (KdFreezeOwner == ProcessorBlock->ProcessorNumber) {
- KdpInitializeBreakNotification(EXCEPTION_BREAK,
- TrapFrame,
- &KdTxPacket);
- Status = KdpSendPacket(&KdTxPacket, NULL);
- if (!KSUCCESS(Status)) {
- continue;
- }
- //
- // Loop processing commands.
- //
- ContinueExecution = FALSE;
- do {
- Status = KdpReceivePacket(&KdRxPacket, MAX_ULONG);
- if (!KSUCCESS(Status)) {
- continue;
- }
- Status = KdpProcessCommand(&KdRxPacket,
- EXCEPTION_NMI,
- TrapFrame,
- &ContinueExecution);
- if (!KSUCCESS(Status)) {
- break;
- }
- } while (ContinueExecution == FALSE);
- }
- }
- KdpInvalidateInstructionCache();
- //
- // Indicate that this processor is back on its way, and go.
- //
- KdpAtomicAdd32(&KdProcessorsFrozen, -1);
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- KdpSendPacket (
- PDEBUG_PACKET Packet,
- PBOOL BreakInRequested
- )
- /*++
- Routine Description:
- This routine sends a packet across the wire to the debugging client.
- Arguments:
- Packet - Supplies a pointer to the debug packet. The checksum field will be
- calculated in this function.
- BreakInRequested - Supplies an optional pointer where a boolean will be
- returned indicating if the debugger would like to break in.
- Return Value:
- Status code.
- --*/
- {
- DEBUG_PACKET_ACKNOWLEDGE Acknowledge;
- USHORT Checksum;
- DEBUG_PACKET_HEADER Header;
- ULONG HeaderSize;
- ULONG PayloadSize;
- ULONG Retries;
- KSTATUS Status;
- ULONG Timeout;
- HeaderSize = sizeof(DEBUG_PACKET_HEADER);
- if (BreakInRequested != NULL) {
- *BreakInRequested = FALSE;
- }
- if ((KdInitialized == FALSE) || (KdDebuggingEnabled == FALSE)) {
- return STATUS_NOT_INITIALIZED;
- }
- if (Packet->Header.PayloadSize > DEBUG_PACKET_SIZE - HeaderSize) {
- return STATUS_INVALID_PARAMETER;
- }
- Packet->Header.Magic = DEBUG_PACKET_MAGIC;
- Packet->Header.PayloadSizeComplement = ~(Packet->Header.PayloadSize);
- Packet->Header.Checksum = 0;
- Checksum = KdpCalculateChecksum(Packet,
- Packet->Header.PayloadSize + HeaderSize);
- Packet->Header.Checksum = Checksum;
- //
- // Loop sending the data until an ackowledgement or rejection is received.
- //
- Timeout = KdConnectionTimeout;
- Retries = 10;
- while (Retries > 0) {
- Status = KdpTransmitBytes(Packet,
- HeaderSize + Packet->Header.PayloadSize);
- if (!KSUCCESS(Status)) {
- Retries -= 1;
- continue;
- }
- Status = KdpReceivePacketHeader(&Header, &Timeout);
- if ((Status == STATUS_TIMEOUT) || (Status == STATUS_CONNECTION_RESET)) {
- break;
- }
- if (!KSUCCESS(Status)) {
- Retries -= 1;
- continue;
- }
- if (Header.Command == DbgPacketAcknowledge) {
- //
- // Attempt to read the payload, which says whether or not the
- // debugger would like to break in.
- //
- if (Header.PayloadSize == sizeof(DEBUG_PACKET_ACKNOWLEDGE)) {
- PayloadSize = sizeof(DEBUG_PACKET_ACKNOWLEDGE);
- Status = KdpReceiveBuffer(&Acknowledge, &PayloadSize, &Timeout);
- if ((KSUCCESS(Status)) && (BreakInRequested != NULL)) {
- *BreakInRequested = Acknowledge.BreakInRequested;
- }
- }
- Status = STATUS_SUCCESS;
- break;
- } else if (Header.Command != DbgPacketResend) {
- Status = STATUS_CONNECTION_RESET;
- break;
- }
- Retries -= 1;
- }
- //
- // If the receive timed out or the connection was reset, mark the
- // connection terminated. Don't send sync bytes if not connected, as that's
- // counterproductive during connect.
- //
- if ((Status == STATUS_TIMEOUT) || (Status == STATUS_CONNECTION_RESET)) {
- if (KdDebuggerConnected != FALSE) {
- KdpSynchronize();
- KdDebuggerConnected = FALSE;
- }
- }
- return Status;
- }
- KSTATUS
- KdpReceivePacket (
- PDEBUG_PACKET Packet,
- ULONG Timeout
- )
- /*++
- Routine Description:
- This routine receives a packet across the wire from the debugger.
- Arguments:
- Packet - Supplies a pointer to the buffer that will receive the debug
- packet.
- Timeout - Supplies the timeout in microseconds that this function should
- give up in.
- Return Value:
- Status code.
- --*/
- {
- DEBUG_PACKET_HEADER Acknowledge;
- USHORT CalculatedChecksum;
- USHORT Checksum;
- USHORT HeaderChecksum;
- ULONG HeaderSize;
- ULONG PayloadSize;
- ULONG Retries;
- KSTATUS Status;
- HeaderSize = sizeof(DEBUG_PACKET_HEADER);
- Retries = 10;
- while (TRUE) {
- Status = KdpReceivePacketHeader(&(Packet->Header), &Timeout);
- if ((Status == STATUS_TIMEOUT) || (Status == STATUS_CONNECTION_RESET)) {
- break;
- }
- if (!KSUCCESS(Status)) {
- goto ReceivePacketRetry;
- }
- //
- // If the packet has a payload, get that as well.
- //
- if (Packet->Header.PayloadSize != 0) {
- PayloadSize = Packet->Header.PayloadSize;
- Status = KdpReceiveBuffer(&(Packet->Payload),
- &PayloadSize,
- &Timeout);
- if (!KSUCCESS(Status)) {
- if (Status == STATUS_TIMEOUT) {
- break;
- }
- goto ReceivePacketRetry;
- }
- }
- //
- // Ensure that the packet came across okay. The checksum field is not
- // included in the checksum calculation, so zero it out while
- // calculating.
- //
- HeaderChecksum = Packet->Header.Checksum;
- Packet->Header.Checksum = 0;
- CalculatedChecksum = KdpCalculateChecksum(
- Packet,
- HeaderSize + Packet->Header.PayloadSize);
- Packet->Header.Checksum = HeaderChecksum;
- if (HeaderChecksum != CalculatedChecksum) {
- Status = STATUS_CHECKSUM_MISMATCH;
- goto ReceivePacketRetry;
- }
- //
- // Send the acknowledge and break.
- //
- RtlZeroMemory(&Acknowledge, sizeof(DEBUG_PACKET_HEADER));
- Acknowledge.Magic = DEBUG_PACKET_MAGIC;
- Acknowledge.Command = DbgPacketAcknowledge;
- Acknowledge.PayloadSizeComplement = ~(Acknowledge.PayloadSize);
- Checksum = KdpCalculateChecksum(&Acknowledge,
- sizeof(DEBUG_PACKET_HEADER));
- Acknowledge.Checksum = Checksum;
- Status = KdpTransmitBytes(&Acknowledge, sizeof(DEBUG_PACKET_HEADER));
- if (!KSUCCESS(Status)) {
- goto ReceivePacketRetry;
- }
- Status = STATUS_SUCCESS;
- break;
- ReceivePacketRetry:
- if (Retries == 0) {
- break;
- }
- //
- // Ask the host to resend and loop.
- //
- RtlZeroMemory(&Acknowledge, sizeof(DEBUG_PACKET_HEADER));
- Acknowledge.Command = DbgPacketResend;
- Acknowledge.PayloadSizeComplement = ~(Acknowledge.PayloadSize);
- Checksum = KdpCalculateChecksum(&Acknowledge,
- sizeof(DEBUG_PACKET_HEADER));
- Acknowledge.Checksum = Checksum;
- Status = KdpTransmitBytes(&Acknowledge, sizeof(DEBUG_PACKET_HEADER));
- if (!KSUCCESS(Status)) {
- break;
- }
- Retries -= 1;
- }
- //
- // If the receive timed out or the connection was reset, mark the
- // connection terminated. Don't send sync bytes if not connected, as that's
- // counterproductive during connect.
- //
- if ((Status == STATUS_TIMEOUT) || (Status == STATUS_CONNECTION_RESET)) {
- if (KdDebuggerConnected != FALSE) {
- KdpSynchronize();
- KdDebuggerConnected = FALSE;
- }
- }
- return Status;
- }
- KSTATUS
- KdpReceivePacketHeader (
- PDEBUG_PACKET_HEADER Packet,
- PULONG Timeout
- )
- /*++
- Routine Description:
- This routine receives a packet header across the wire from the debugger.
- Arguments:
- Packet - Supplies a pointer to the buffer that will receive the debug
- packet header.
- Timeout - Supplies a pointer that on input contains the number of
- microseconds to wait before timing out. On output, will contain the
- remainder of that wait.
- Return Value:
- Status code.
- --*/
- {
- DEBUG_PACKET_HEADER Acknowledge;
- USHORT Checksum;
- ULONG HeaderSize;
- BYTE Magic;
- PBYTE ReceiveBuffer;
- ULONG ReceiveSize;
- ULONG Retries;
- KSTATUS Status;
- HeaderSize = sizeof(DEBUG_PACKET_HEADER);
- Retries = 10;
- Status = STATUS_SUCCESS;
- while (TRUE) {
- //
- // Attempt to synchronize on the magic field.
- //
- Magic = 0;
- ReceiveSize = sizeof(BYTE);
- Status = KdpReceiveBuffer(&Magic, &ReceiveSize, Timeout);
- if (Status == STATUS_TIMEOUT) {
- break;
- }
- if (!KSUCCESS(Status)) {
- goto ReceivePacketRetry;
- }
- if (Magic != DEBUG_PACKET_MAGIC_BYTE1) {
- //
- // If this was a resync byte from the host, then report the
- // connection as reset.
- //
- if (Magic == DEBUG_SYNCHRONIZE_HOST) {
- Status = STATUS_CONNECTION_RESET;
- break;
- }
- continue;
- }
- Magic = 0;
- ReceiveSize = sizeof(BYTE);
- Status = KdpReceiveBuffer(&Magic, &ReceiveSize, Timeout);
- if (Status == STATUS_TIMEOUT) {
- break;
- }
- if (!KSUCCESS(Status)) {
- goto ReceivePacketRetry;
- }
- if (Magic != DEBUG_PACKET_MAGIC_BYTE2) {
- continue;
- }
- //
- // Get the packet header. Sometimes this is all that's required.
- //
- Packet->Magic = DEBUG_PACKET_MAGIC;
- ReceiveSize = HeaderSize - DEBUG_PACKET_MAGIC_SIZE;
- ReceiveBuffer = (PBYTE)Packet + DEBUG_PACKET_MAGIC_SIZE;
- Status = KdpReceiveBuffer(ReceiveBuffer, &ReceiveSize, Timeout);
- if (!KSUCCESS(Status)) {
- goto ReceivePacketRetry;
- }
- //
- // Validate that the payload size is reasonable by checking its
- // complement against the header.
- //
- if ((USHORT)~(Packet->PayloadSize) != Packet->PayloadSizeComplement) {
- continue;
- }
- if (Packet->PayloadSize > DEBUG_PACKET_SIZE - HeaderSize) {
- Status = STATUS_INVALID_PARAMETER;
- goto ReceivePacketRetry;
- }
- Status = STATUS_SUCCESS;
- break;
- ReceivePacketRetry:
- if (Retries == 0) {
- break;
- }
- //
- // Ask the host to resend and loop.
- //
- RtlZeroMemory(&Acknowledge, sizeof(DEBUG_PACKET_HEADER));
- Acknowledge.Command = DbgPacketResend;
- Acknowledge.PayloadSizeComplement = ~(Acknowledge.PayloadSize);
- Checksum = KdpCalculateChecksum(&Acknowledge,
- sizeof(DEBUG_PACKET_HEADER));
- Acknowledge.Checksum = Checksum;
- Status = KdpTransmitBytes(&Acknowledge, sizeof(DEBUG_PACKET_HEADER));
- if (!KSUCCESS(Status)) {
- break;
- }
- Retries -= 1;
- }
- return Status;
- }
- KSTATUS
- KdpProcessCommand (
- PDEBUG_PACKET Packet,
- ULONG Exception,
- PTRAP_FRAME TrapFrame,
- PBOOL ContinueExecution
- )
- /*++
- Routine Description:
- This routine processes a received debug packet.
- Arguments:
- Packet - Supplies a pointer to the complete packet.
- Exception - Supplies the exception that caused the break.
- TrapFrame - Supplies a pointer to the machine's current context.
- ContinueExecution - Supplies a pointer that receives whether or not the
- debugger should continue execution or process more packets.
- Return Value:
- Status code.
- --*/
- {
- BOOL BreakInRequested;
- PRANGE_STEP RangeStep;
- PDEBUG_REBOOT_REQUEST RebootRequest;
- PSET_SPECIAL_REGISTERS SetSpecialRegisters;
- KSTATUS Status;
- PSWITCH_PROCESSOR_REQUEST SwitchProcessorRequest;
- Status = STATUS_SUCCESS;
- //
- // By default, most commands don't result in continued execution.
- //
- *ContinueExecution = FALSE;
- switch (KdRxPacket.Header.Command) {
- //
- // Re-send the break notification if needed.
- //
- case DbgBreakRequest:
- KdpInitializeBreakNotification(Exception,
- TrapFrame,
- &KdTxPacket);
- Status = KdpSendPacket(&KdTxPacket, NULL);
- break;
- //
- // The "go" command continues execution. Turn single stepping off in this
- // case.
- //
- case DbgCommandGo:
- KdUserRequestedSingleStep = FALSE;
- //
- // Signal to the caller to break out of the command processing loop,
- // and signal to all other processors to continue execution.
- //
- *ContinueExecution = TRUE;
- KdFreezeOwner = MAX_ULONG;
- break;
- //
- // The single step command is like "go", but turns on the trap flag so that
- // the next instruction to execute will also break into the debugger.
- //
- case DbgCommandSingleStep:
- KdpSetSingleStepMode(Exception, TrapFrame, NULL);
- KdUserRequestedSingleStep = TRUE;
- *ContinueExecution = TRUE;
- KdFreezeOwner = MAX_ULONG;
- break;
- //
- // The range step command puts the machine into single step mode. At every
- // single step, it checks to see if the instruction pointer is within a
- // certain range, and breaks if so.
- //
- case DbgCommandRangeStep:
- RangeStep = (PRANGE_STEP)Packet->Payload;
- KdBreakRange.BreakRangeStart =
- (PVOID)(ULONG)RangeStep->BreakRangeMinimum;
- KdBreakRange.BreakRangeEnd = (PVOID)(ULONG)RangeStep->BreakRangeMaximum;
- KdBreakRange.RangeHoleStart = (PVOID)(ULONG)RangeStep->RangeHoleMinimum;
- KdBreakRange.RangeHoleEnd = (PVOID)(ULONG)RangeStep->RangeHoleMaximum;
- KdBreakRange.Enabled = TRUE;
- KdUserRequestedSingleStep = FALSE;
- KdpSetSingleStepMode(Exception, TrapFrame, NULL);
- *ContinueExecution = TRUE;
- KdFreezeOwner = MAX_ULONG;
- break;
- //
- // The set registers command replaces all the general registers in the trap
- // frame with the ones provided by the debugger.
- //
- case DbgCommandSetRegisters:
- KdpSetRegisters(TrapFrame, Packet->Payload);
- break;
- //
- // The module list header request causes the debugger to send information
- // about all the loaded modules in the system so the debugger can determine
- // if it's in sync.
- //
- case DbgModuleListHeaderRequest:
- KdpSendModuleList(TRUE);
- break;
- //
- // The module list entries request causes the debugger to send a complete
- // list of all loaded modules. This is a much slower operation than just
- // sending the header.
- //
- case DbgModuleListEntriesRequest:
- KdpSendModuleList(FALSE);
- break;
- //
- // The read or write virtual memory request sends or edits host memory.
- //
- case DbgMemoryReadVirtual:
- case DbgMemoryWriteVirtual:
- KdpHandleMemoryAccess();
- break;
- //
- // The switch processor command switches the view to another processor.
- //
- case DbgCommandSwitchProcessor:
- SwitchProcessorRequest = (PSWITCH_PROCESSOR_REQUEST)KdRxPacket.Payload;
- KdFreezeOwner = SwitchProcessorRequest->ProcessorNumber;
- *ContinueExecution = TRUE;
- break;
- //
- // Handle commands for getting and setting special registers.
- //
- case DbgCommandGetSpecialRegisters:
- KdpGetSpecialRegisters((PSPECIAL_REGISTERS_UNION)(KdTxPacket.Payload));
- KdTxPacket.Header.Command = DbgCommandReturnSpecialRegisters;
- KdTxPacket.Header.PayloadSize = sizeof(SPECIAL_REGISTERS_UNION);
- Status = KdpSendPacket(&KdTxPacket, NULL);
- break;
- case DbgCommandSetSpecialRegisters:
- SetSpecialRegisters = (PSET_SPECIAL_REGISTERS)(KdRxPacket.Payload);
- KdpSetSpecialRegisters(&(SetSpecialRegisters->Original),
- &(SetSpecialRegisters->New));
- break;
- //
- // Reboot the system.
- //
- case DbgCommandReboot:
- RebootRequest = (PDEBUG_REBOOT_REQUEST)(KdRxPacket.Payload);
- KdpReboot(RebootRequest->ResetType, Exception, TrapFrame);
- break;
- //
- // If a connection request is found, then the host is out of sync with the
- // target. Resend the connection parameters and break notification.
- //
- case DbgConnectionRequest:
- KdpSendConnectionResponse((PCONNECTION_REQUEST)(KdRxPacket.Payload),
- &BreakInRequested);
- if (Exception == EXCEPTION_POLL_DEBUGGER) {
- //
- // If it's just polling and the caller didn't want a break, then
- // continue. Otherwise, turn the poll into a break.
- //
- if (BreakInRequested == FALSE) {
- *ContinueExecution = TRUE;
- KdFreezeOwner = MAX_ULONG;
- }
- } else {
- //
- // If a break is requested, send the notification.
- //
- if (BreakInRequested != FALSE) {
- KdpInitializeBreakNotification(Exception,
- TrapFrame,
- &KdTxPacket);
- Status = KdpSendPacket(&KdTxPacket, NULL);
- }
- }
- break;
- //
- // Ignore spurious acknowledge commands.
- //
- case DbgPacketAcknowledge:
- break;
- //
- // The command is not recognized. Send the invalid command response.
- //
- default:
- KdTxPacket.Header.Command = DbgConnectionInvalidRequest;
- KdTxPacket.Header.PayloadSize = sizeof(DEBUG_PACKET_HEADER);
- RtlCopyMemory(&KdTxPacket.Payload,
- &KdRxPacket.Header,
- sizeof(DEBUG_PACKET_HEADER));
- Status = KdpSendPacket(&KdTxPacket, NULL);
- break;
- }
- return Status;
- }
- KSTATUS
- KdpPrint (
- PPRINT_PARAMETERS PrintParameters,
- PBOOL BreakInRequested
- )
- /*++
- Routine Description:
- This routine prints a string to the debugger. Currently the maximum length
- string is a little less than one debug packet. This routine MUST be called
- from within the debugger path (not outside kernel code), as it writes to
- the global transmit/receive packets.
- Arguments:
- PrintParameters - Supplies a pointer to the required print parameters.
- BreakInRequested - Supplies an optional pointer where a boolean will be
- returned indicating if the debugger would like to break in.
- Return Value:
- Status code.
- --*/
- {
- ULONG MaxStringLength;
- ULONG StringLength;
- KdTxPacket.Header.Command = DbgPrintString;
- //
- // Print the format string, with the packet as the destination buffer.
- //
- MaxStringLength = DEBUG_PACKET_SIZE - sizeof(DEBUG_PACKET_HEADER);
- StringLength = RtlFormatString((PSTR)(&(KdTxPacket.Payload)),
- MaxStringLength,
- CharacterEncodingDefault,
- PrintParameters->FormatString,
- PrintParameters->Arguments);
- //
- // Print strings cannot be bigger than the packet size. If they are,
- // print out a warning. Otherwise, print the string.
- //
- if (StringLength > MaxStringLength) {
- StringLength = MaxStringLength;
- }
- KdTxPacket.Header.PayloadSize = StringLength;
- return KdpSendPacket(&KdTxPacket, BreakInRequested);
- }
- KSTATUS
- KdpSendProfilingData (
- PBOOL BreakInRequested
- )
- /*++
- Routine Description:
- This routine calls the system profiler for data and sends it to the
- debugger.
- Arguments:
- BreakInRequested - Supplies a pointer where a boolean will be returned
- indicating if the debugger would like to break in.
- Return Value:
- Status code.
- --*/
- {
- ULONG DataSize;
- ULONG Flags;
- BOOL LocalBreakInRequested;
- PPROCESSOR_BLOCK ProcessorBlock;
- PPROFILER_NOTIFICATION ProfilerNotification;
- KSTATUS Status;
- *BreakInRequested = FALSE;
- //
- // Check to see if there is any data to send. Another core may have
- // collected and sent the data since the flags were checked before the
- // debug exception.
- //
- Flags = SpGetProfilerDataStatus();
- if (Flags == 0) {
- Status = STATUS_SUCCESS;
- goto SendProfilingDataEnd;
- }
- ProcessorBlock = KeGetCurrentProcessorBlockForDebugger();
- DataSize = DEBUG_PAYLOAD_SIZE - sizeof(PROFILER_NOTIFICATION_HEADER);
- ProfilerNotification = (PPROFILER_NOTIFICATION)KdTxPacket.Payload;
- KdTxPacket.Header.Command = DbgProfilerNotification;
- //
- // Loop as long as there is more profiling data to send.
- //
- while (Flags != 0) {
- //
- // Initialize the debugger packet for a profiler notification message.
- //
- ASSERT(KdTxPacket.Header.Command == DbgProfilerNotification);
- KdTxPacket.Header.PayloadSize = DEBUG_PAYLOAD_SIZE;
- //
- // Collect the pending profiler data. Exit if something went wrong.
- //
- ProfilerNotification->Header.DataSize = DataSize;
- Status = SpGetProfilerData(ProfilerNotification, &Flags);
- if (!KSUCCESS(Status)) {
- goto SendProfilingDataEnd;
- }
- //
- // Don't bother sending an empty packet. Skip to the next one.
- //
- if (ProfilerNotification->Header.DataSize == 0) {
- continue;
- }
- //
- // Send the profiler notification packet.
- //
- Status = KdpSendPacket(&KdTxPacket, &LocalBreakInRequested);
- if (!KSUCCESS(Status)) {
- goto SendProfilingDataEnd;
- }
- if (LocalBreakInRequested != FALSE) {
- *BreakInRequested = TRUE;
- }
- }
- //
- // Send a final packet to the debugger notifying that this round of sending
- // profiling data is complete.
- //
- ASSERT(KdTxPacket.Header.Command == DbgProfilerNotification);
- KdTxPacket.Header.PayloadSize = sizeof(PROFILER_NOTIFICATION_HEADER);
- ProfilerNotification->Header.DataSize = 0;
- ProfilerNotification->Header.Type = ProfilerDataTypeMax;
- ProfilerNotification->Header.Processor = 0;
- if (ProcessorBlock != NULL) {
- ProfilerNotification->Header.Processor =
- ProcessorBlock->ProcessorNumber;
- }
- Status = KdpSendPacket(&KdTxPacket, &LocalBreakInRequested);
- if (!KSUCCESS(Status)) {
- goto SendProfilingDataEnd;
- }
- if (LocalBreakInRequested != FALSE) {
- *BreakInRequested = TRUE;
- }
- SendProfilingDataEnd:
- return Status;
- }
- ULONG
- KdpValidateMemoryAccess (
- PVOID Address,
- ULONG Length,
- PBOOL Writable
- )
- /*++
- Routine Description:
- This routine validates that access to a specified location in memory will
- not cause a page fault.
- Arguments:
- Address - Supplies the virtual address of the memory that will be read or
- written.
- Length - Supplies how many bytes at that location the caller would like to
- read or write.
- Writable - Supplies an optional pointer that receives a boolean indicating
- whether or not the memory range is mapped writable.
- Return Value:
- Returns the number of bytes from the beginning of the address that are
- accessible. If the memory is completely available, the return value will be
- equal to the Length parameter. If the memory is completely paged out, 0
- will be returned.
- --*/
- {
- if (KdSkipMemoryValidation != FALSE) {
- if (Writable != NULL) {
- *Writable = TRUE;
- }
- return Length;
- }
- return MmValidateMemoryAccessForDebugger(Address, Length, Writable);
- }
- VOID
- KdpModifyAddressMapping (
- PVOID Address,
- BOOL Writable,
- PBOOL WasWritable
- )
- /*++
- Routine Description:
- This routine modifies the mapping properties for the page that contains the
- given address.
- Arguments:
- Address - Supplies the virtual address of the memory whose mapping
- properties are to be changed.
- Writable - Supplies a boolean indicating whether or not to make the page
- containing the address writable (TRUE) or read-only (FALSE).
- WasWritable - Supplies a pointer that receives a boolean indicating whether
- or not the page was writable (TRUE) or read-only (FALSE) before any
- modifications.
- Return Value:
- None.
- --*/
- {
- if (KdSkipMemoryValidation != FALSE) {
- *WasWritable = TRUE;
- return;
- }
- return MmModifyAddressMappingForDebugger(Address, Writable, WasWritable);
- }
- USHORT
- KdpCalculateChecksum (
- PVOID Data,
- ULONG DataLength
- )
- /*++
- Routine Description:
- This routine computes a checksum over a given length. It can handle both odd
- and even length data.
- Arguments:
- Data - Supplies a pointer to the data that is to be checksummed.
- DataLength - Supplies the length of the data buffer, in bytes.
- Return Value:
- Returns the checksum.
- --*/
- {
- USHORT Checksum;
- PUSHORT CurrentData;
- ULONG Index;
- ULONG ShortLength;
- Checksum = 0;
- Index = 0;
- //
- // Checksums are calculated by adding up a series of two-byte values.
- // Convert the pointer to a short pointer and divide bytes by 2 to get size
- // in shorts.
- //
- ShortLength = DataLength / 2;
- CurrentData = (PUSHORT)Data;
- while (Index < ShortLength) {
- Checksum += *CurrentData;
- CurrentData += 1;
- Index += 1;
- }
- //
- // If the data was an odd length, then there's one byte left to be added.
- // Add only that byte.
- //
- if ((ShortLength * 2) != DataLength) {
- Checksum += *((PUCHAR)CurrentData);
- }
- return Checksum;
- }
- KSTATUS
- KdpSendModuleList (
- BOOL SendHeaderOnly
- )
- /*++
- Routine Description:
- This routine sends information to the debugger client about the binaries
- currently loaded in the system.
- Arguments:
- SendHeaderOnly - Supplies a flag indicating that the debugger requested only
- the module list header.
- Return Value:
- Status code.
- --*/
- {
- PDEBUG_MODULE CurrentModule;
- PLIST_ENTRY CurrentModuleListEntry;
- ULONG MaxNameLength;
- PLOADED_MODULE_ENTRY ModuleEntry;
- PMODULE_LIST_HEADER ModuleListHeader;
- PCHAR NameDestination;
- ULONG NameLength;
- PCHAR NameSource;
- ULONG PacketMaxNameLength;
- KSTATUS Status;
- PacketMaxNameLength = sizeof(KdTxPacket.Payload) -
- sizeof(LOADED_MODULE_ENTRY) +
- (sizeof(CHAR) * ANYSIZE_ARRAY);
- //
- // If the loaded modules list has not been initialized, send an error, and
- // return as successful.
- //
- if (KdLoadedModulesInitialized == FALSE) {
- KdTxPacket.Header.Command = DbgModuleListError;
- KdTxPacket.Header.PayloadSize = 0;
- Status = KdpSendPacket(&KdTxPacket, NULL);
- goto SendModuleListEnd;
- }
- //
- // Send the module list header.
- //
- KdTxPacket.Header.Command = DbgModuleListHeader;
- KdTxPacket.Header.PayloadSize = sizeof(MODULE_LIST_HEADER);
- ModuleListHeader = (PMODULE_LIST_HEADER)KdTxPacket.Payload;
- ModuleListHeader->ModuleCount = KdLoadedModules.ModuleCount;
- ModuleListHeader->Signature = KdLoadedModules.Signature;
- Status = KdpSendPacket(&KdTxPacket, NULL);
- if ((!KSUCCESS(Status)) || (SendHeaderOnly != FALSE)) {
- goto SendModuleListEnd;
- }
- //
- // Send all modules.
- //
- KdTxPacket.Header.Command = DbgModuleListEntry;
- ModuleEntry = (PLOADED_MODULE_ENTRY)KdTxPacket.Payload;
- CurrentModuleListEntry = KdLoadedModules.ModulesHead.Next;
- while (CurrentModuleListEntry != &(KdLoadedModules.ModulesHead)) {
- CurrentModule = LIST_VALUE(CurrentModuleListEntry,
- DEBUG_MODULE,
- ListEntry);
- //
- // Copy the name.
- //
- NameSource = CurrentModule->BinaryName;
- NameDestination = ModuleEntry->BinaryName;
- MaxNameLength = CurrentModule->StructureSize - sizeof(DEBUG_MODULE) +
- (ANYSIZE_ARRAY * sizeof(CHAR));
- if (MaxNameLength > PacketMaxNameLength) {
- MaxNameLength = PacketMaxNameLength;
- }
- NameLength = RtlStringCopy(NameDestination, NameSource, MaxNameLength);
- //
- // Copy the rest of the module information, and send the packet.
- //
- ModuleEntry->StructureSize = sizeof(LOADED_MODULE_ENTRY) +
- ((NameLength - ANYSIZE_ARRAY) *
- sizeof(CHAR));
- ModuleEntry->Timestamp = CurrentModule->Timestamp;
- ModuleEntry->BaseAddress = (UINTN)CurrentModule->BaseAddress;
- if (ModuleEntry->BaseAddress == (UINTN)-1ULL) {
- ModuleEntry->BaseAddress = -1ULL;
- }
- ModuleEntry->LowestAddress = (UINTN)CurrentModule->LowestAddress;
- ModuleEntry->Size = CurrentModule->Size;
- ModuleEntry->Process = CurrentModule->Process;
- KdTxPacket.Header.PayloadSize = ModuleEntry->StructureSize;
- Status = KdpSendPacket(&KdTxPacket, NULL);
- if (!KSUCCESS(Status)) {
- goto SendModuleListEnd;
- }
- //
- // Get the next module.
- //
- CurrentModuleListEntry = CurrentModuleListEntry->Next;
- }
- SendModuleListEnd:
- return Status;
- }
- KSTATUS
- KdpHandleMemoryAccess (
- VOID
- )
- /*++
- Routine Description:
- This routine handles memory read and write commands from the debugger.
- Arguments:
- None.
- Return Value:
- Status code.
- --*/
- {
- PBYTE AddressByte;
- PUINTN AddressNatural;
- PVOID Buffer;
- ULONG ByteCount;
- ULONG MaxSize;
- PVOID PageAddress;
- ULONG PageSize;
- BOOL PageWritable;
- PBYTE ReadDestinationByte;
- PUINTN ReadDestinationNatural;
- BOOL RegionWritable;
- PMEMORY_REQUEST Request;
- PMEMORY_CONTENTS Response;
- KSTATUS Status;
- ULONG ValidSize;
- PWRITE_REQUEST_ACKNOWLEDGEMENT WriteAcknowledgement;
- PBYTE WriteSourceByte;
- PUINTN WriteSourceNatural;
- Request = (PMEMORY_REQUEST)KdRxPacket.Payload;
- //
- // Determine that maximum size that could legally be requested and still fit
- // inside a debug packet.
- //
- if (KdRxPacket.Header.Command == DbgMemoryReadVirtual) {
- MaxSize = DEBUG_PACKET_SIZE - sizeof(DEBUG_PACKET_HEADER) -
- sizeof(MEMORY_CONTENTS);
- } else if (KdRxPacket.Header.Command == DbgMemoryWriteVirtual) {
- MaxSize = DEBUG_PACKET_SIZE - sizeof(DEBUG_PACKET_HEADER) -
- sizeof(MEMORY_REQUEST);
- } else {
- MaxSize = 0;
- }
- //
- // If the request is invalid, send back an invalid command packet.
- //
- if (Request->Size > MaxSize) {
- KdTxPacket.Header.Command = DbgInvalidCommand;
- KdTxPacket.Header.PayloadSize = 0;
- }
- //
- // Validate the memory access to make sure the debugger does not cause an
- // access violation.
- //
- AddressByte = (PVOID)(ULONG)Request->Address;
- AddressNatural = (PUINTN)AddressByte;
- ValidSize = KdpValidateMemoryAccess(AddressByte,
- Request->Size,
- &RegionWritable);
- //
- // For reads, copy the contents from memory into the packet.
- //
- if (KdRxPacket.Header.Command == DbgMemoryReadVirtual) {
- KdTxPacket.Header.Command = DbgMemoryContents;
- KdTxPacket.Header.PayloadSize = sizeof(MEMORY_CONTENTS) + ValidSize;
- Response = (PMEMORY_CONTENTS)KdTxPacket.Payload;
- Response->Address = (ULONGLONG)(ULONG)AddressByte;
- Response->Size = ValidSize;
- Buffer = (PVOID)KdTxPacket.Payload + sizeof(MEMORY_CONTENTS);
- //
- // Copy in natural word size chunks if possible.
- //
- if ((ValidSize & (sizeof(UINTN) - 1)) == 0) {
- ReadDestinationNatural = Buffer;
- for (ByteCount = 0;
- ByteCount < ValidSize;
- ByteCount += sizeof(UINTN)) {
- *ReadDestinationNatural = *AddressNatural;
- AddressNatural += 1;
- ReadDestinationNatural += 1;
- }
- //
- // Copy byte for byte.
- //
- } else {
- ReadDestinationByte = Buffer;
- for (ByteCount = 0; ByteCount < ValidSize; ByteCount += 1) {
- *ReadDestinationByte = *AddressByte;
- AddressByte += 1;
- ReadDestinationByte += 1;
- }
- }
- //
- // For writes, copy the contents of the packet into memory.
- //
- } else if (KdRxPacket.Header.Command == DbgMemoryWriteVirtual) {
- KdTxPacket.Header.Command = DbgMemoryWriteAcknowledgement;
- KdTxPacket.Header.PayloadSize = sizeof(WRITE_REQUEST_ACKNOWLEDGEMENT);
- WriteAcknowledgement =
- (PWRITE_REQUEST_ACKNOWLEDGEMENT)KdTxPacket.Payload;
- WriteAcknowledgement->Address = (ULONGLONG)(ULONG)AddressByte;
- WriteAcknowledgement->BytesWritten = ValidSize;
- WriteSourceByte = (PBYTE)KdRxPacket.Payload + sizeof(MEMORY_REQUEST);
- WriteSourceNatural = (PUINTN)WriteSourceByte;
- //
- // Copy in natural word size chunks if possible.
- //
- PageAddress = NULL;
- PageSize = MmPageSize();
- PageWritable = FALSE;
- if ((ValidSize & (sizeof(UINTN) - 1)) == 0) {
- for (ByteCount = 0;
- ByteCount < ValidSize;
- ByteCount += sizeof(UINTN)) {
- //
- // Make sure the current page is mapped writable if the entire
- // region was determined to not be writable.
- //
- if ((RegionWritable == FALSE) && (PageAddress == NULL)) {
- PageAddress = ALIGN_POINTER_DOWN(AddressNatural, PageSize);
- KdpModifyAddressMapping(PageAddress, TRUE, &PageWritable);
- }
- *AddressNatural = *WriteSourceNatural;
- KdpCleanMemory(AddressNatural);
- WriteSourceNatural += 1;
- AddressNatural += 1;
- //
- // If the entire region was not writable and a new page is up
- // next, then set the last page back to read-only if it was not
- // originally writable.
- //
- if ((RegionWritable == FALSE) &&
- (PageAddress !=
- ALIGN_POINTER_DOWN(AddressNatural, PageSize))) {
- ASSERT(PageAddress != NULL);
- if (PageWritable == FALSE) {
- KdpModifyAddressMapping(PageAddress,
- FALSE,
- &PageWritable);
- }
- PageAddress = NULL;
- }
- }
- //
- // Copy byte for byte.
- //
- } else {
- for (ByteCount = 0; ByteCount < ValidSize; ByteCount += 1) {
- //
- // Make sure the current page is mapped writable if the entire
- // region was determined to not be writable.
- //
- if ((RegionWritable == FALSE) && (PageAddress == NULL)) {
- PageAddress = ALIGN_POINTER_DOWN(AddressByte, PageSize);
- KdpModifyAddressMapping(PageAddress, TRUE, &PageWritable);
- }
- *AddressByte = *WriteSourceByte;
- KdpCleanMemory(AddressByte);
- AddressByte += 1;
- WriteSourceByte += 1;
- //
- // If the entire region was not writable and a new page is up
- // next, then set the last page back to read-only if it was not
- // originally writable.
- //
- if ((RegionWritable == FALSE) &&
- (PageAddress !=
- ALIGN_POINTER_DOWN(AddressByte, PageSize))) {
- ASSERT(PageAddress != NULL);
- if (PageWritable == FALSE) {
- KdpModifyAddressMapping(PageAddress,
- FALSE,
- &PageWritable);
- }
- PageAddress = NULL;
- }
- }
- }
- //
- // If the entire region was not writable, then the last page might have
- // been left in the incorrect state. If the page address is valid and
- // it was not writable, then modify it to read-only.
- //
- if ((RegionWritable == FALSE) &&
- (PageWritable == FALSE) &&
- (PageAddress != NULL)) {
- KdpModifyAddressMapping(PageAddress, FALSE, &PageWritable);
- }
- //
- // For unknown requests, the response will be an invalid request packet.
- //
- } else {
- KdTxPacket.Header.Command = DbgInvalidCommand;
- KdTxPacket.Header.PayloadSize = 0;
- }
- //
- // Send the response.
- //
- Status = KdpSendPacket(&KdTxPacket, NULL);
- return Status;
- }
- VOID
- KdpInitializeBreakNotification (
- ULONG Exception,
- PTRAP_FRAME TrapFrame,
- PDEBUG_PACKET Packet
- )
- /*++
- Routine Description:
- This routine initializes a break notification structure to be sent to the
- debugger.
- Arguments:
- Exception - Supplies the type of exception to notify the debugger about.
- TrapFrame - Supplies a pointer to the current trap frame.
- Packet - Supplies a pointer to receive the debug packet to send to the
- debugger.
- Return Value:
- None.
- --*/
- {
- PBREAK_NOTIFICATION BreakNotification;
- PVOID InstructionPointer;
- PVOID InstructionPointerAddress;
- PBYTE InstructionStream;
- ULONG InstructionStreamBytes;
- PKPROCESS Process;
- PPROCESSOR_BLOCK ProcessorBlock;
- ULONG StreamIndex;
- //
- // Begin to initialize the break notification that will be sent to the
- // debugger.
- //
- BreakNotification = (PBREAK_NOTIFICATION)Packet->Payload;
- BreakNotification->LoadedModuleCount = KdLoadedModules.ModuleCount;
- BreakNotification->LoadedModuleSignature = KdLoadedModules.Signature;
- //
- // Initialize the processor number, but be careful about reaching through
- // the processor block as it will be NULL in the loader or very early
- // kernel init.
- //
- BreakNotification->ProcessorOrThreadCount = 1;
- BreakNotification->ProcessorOrThreadNumber = 0;
- BreakNotification->Process = 0;
- BreakNotification->ProcessorBlock = (UINTN)NULL;
- if (KeActiveProcessorCount != 0) {
- ProcessorBlock = KeGetCurrentProcessorBlockForDebugger();
- if (ProcessorBlock != NULL) {
- BreakNotification->ProcessorOrThreadCount = KeActiveProcessorCount;
- BreakNotification->ProcessorOrThreadNumber =
- ProcessorBlock->ProcessorNumber;
- BreakNotification->ProcessorBlock = (UINTN)ProcessorBlock;
- //
- // Reach out to get the current process ID. It would be safer (but
- // also slower) if each of these pointer reach-throughs was
- // validated first. Doing the validation would really only save
- // cases where the current thread or process structure was severely
- // corrupted.
- //
- if ((ProcessorBlock->RunningThread != NULL) &&
- (ProcessorBlock->RunningThread->OwningProcess != NULL)) {
- Process = ProcessorBlock->RunningThread->OwningProcess;
- BreakNotification->Process = Process->Identifiers.ProcessId;
- }
- }
- }
- InstructionPointer = KdpGetInstructionPointer(TrapFrame);
- InstructionPointerAddress = KdpGetInstructionPointerAddress(TrapFrame);
- BreakNotification->InstructionPointer = (UINTN)InstructionPointer;
- BreakNotification->ErrorCode = 0;
- //
- // If this was a break exception, set the exception type based on whether or
- // not this was an official breakpoint or some random int3.
- //
- if (Exception == EXCEPTION_BREAK) {
- BreakNotification->Exception = ExceptionDebugBreak;
- } else if (Exception == EXCEPTION_SINGLE_STEP) {
- BreakNotification->Exception = ExceptionSingleStep;
- } else if (Exception == EXCEPTION_ASSERTION_FAILURE) {
- BreakNotification->Exception = ExceptionAssertionFailure;
- } else if (Exception == EXCEPTION_ACCESS_VIOLATION) {
- BreakNotification->Exception = ExceptionAccessViolation;
- BreakNotification->ErrorCode = KdpGetErrorCode(Exception, TrapFrame);
- } else if (Exception == EXCEPTION_DOUBLE_FAULT) {
- BreakNotification->Exception = ExceptionDoubleFault;
- BreakNotification->ErrorCode = 0;
- } else if (Exception == EXCEPTION_UNDEFINED_INSTRUCTION) {
- BreakNotification->Exception = ExceptionIllegalInstruction;
- } else if (Exception == EXCEPTION_DEBUGGER_CONNECT) {
- BreakNotification->Exception = ExceptionDebugBreak;
- //
- // This was an unknown exception.
- //
- } else {
- BreakNotification->Exception = ExceptionUnknown;
- }
- //
- // Read in the instruction stream, validating access. As a safety, don't
- // read from instruction pointers that are NULL.
- //
- InstructionStreamBytes = KdpValidateMemoryAccess(
- InstructionPointerAddress,
- BREAK_NOTIFICATION_STREAM_SIZE,
- NULL);
- RtlZeroMemory(BreakNotification->InstructionStream,
- BREAK_NOTIFICATION_STREAM_SIZE);
- if ((TrapFrame != NULL) && (InstructionPointer != NULL)) {
- InstructionStream = InstructionPointerAddress;
- for (StreamIndex = 0;
- StreamIndex < InstructionStreamBytes;
- StreamIndex += 1) {
- BreakNotification->InstructionStream[StreamIndex] =
- *InstructionStream;
- InstructionStream += 1;
- }
- }
- //
- // Copy in the trap frame registers.
- //
- KdpGetRegisters(TrapFrame, &(BreakNotification->Registers));
- //
- // Send the break notification to the debugger.
- //
- Packet->Header.Command = DbgBreakNotification;
- Packet->Header.PayloadSize = sizeof(BREAK_NOTIFICATION);
- return;
- }
- VOID
- KdpReboot (
- DEBUG_REBOOT_TYPE RebootType,
- ULONG Exception,
- PTRAP_FRAME TrapFrame
- )
- /*++
- Routine Description:
- This routine attempts to reboot the target machine.
- Arguments:
- RebootType - Supplies the reboot type.
- Exception - Supplies the original exception code.
- TrapFrame - Supplies a pointer to the trap frame, used to reinitialize the
- debugger connection after a failed reboot attempt.
- Return Value:
- None.
- --*/
- {
- SYSTEM_RESET_TYPE ResetType;
- KSTATUS Status;
- ResetType = SystemResetWarm;
- switch (RebootType) {
- case DebugRebootShutdown:
- ResetType = SystemResetShutdown;
- break;
- case DebugRebootWarm:
- ResetType = SystemResetWarm;
- break;
- case DebugRebootCold:
- ResetType = SystemResetCold;
- break;
- default:
- break;
- }
- KdpDisconnect();
- Status = HlResetSystem(ResetType);
- KdpConnect(NULL);
- KdpInternalPrint("Reset system failed with status %x\n", Status);
- KdpInitializeBreakNotification(Exception, TrapFrame, &KdTxPacket);
- KdpSendPacket(&KdTxPacket, NULL);
- return;
- }
- VOID
- KdpDisconnect (
- VOID
- )
- /*++
- Routine Description:
- This routine disconnects the target from the host.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PSHUTDOWN_NOTIFICATION Notification;
- if (KdDebuggerConnected == FALSE) {
- return;
- }
- Notification = (PSHUTDOWN_NOTIFICATION)KdTxPacket.Payload;
- Notification->UnloadAllSymbols = TRUE;
- Notification->ShutdownType = ShutdownTypeTransition;
- Notification->Process = 0;
- Notification->ExitStatus = 0;
- KdTxPacket.Header.Command = DbgShutdownNotification;
- KdTxPacket.Header.PayloadSize = sizeof(SHUTDOWN_NOTIFICATION);
- KdpSendPacket(&KdTxPacket, NULL);
- KdpDeviceDisconnect();
- KdDebuggerConnected = FALSE;
- return;
- }
- KSTATUS
- KdpConnect (
- PBOOL BreakInRequested
- )
- /*++
- Routine Description:
- This routine attempts to connect to the kernel debugger.
- Arguments:
- BreakInRequested - Supplies a pointer where a boolean will be returned
- indicating if an initial break is requested.
- Return Value:
- Status code. If the status is failing, the debugger connected global will
- be set to FALSE.
- --*/
- {
- PCONNECTION_REQUEST ConnectionRequest;
- KSTATUS Status;
- if (KdDebuggerConnected != FALSE) {
- return STATUS_SUCCESS;
- }
- //
- // Initialize the serial port for use.
- //
- Status = KdpDeviceReset(DEBUG_DEFAULT_BAUD_RATE);
- if (!KSUCCESS(Status)) {
- goto ConnectEnd;
- }
- if (BreakInRequested != NULL) {
- *BreakInRequested = FALSE;
- }
- //
- // Let the host know a new connection is present.
- //
- KdpSynchronize();
- //
- // Attempt to receive the connection request packet.
- //
- while (TRUE) {
- Status = KdpReceivePacket(&KdRxPacket, KdConnectionTimeout);
- //
- // If a synchronize byte was found, reply to it and try again.
- //
- if (Status == STATUS_CONNECTION_RESET) {
- KdpSynchronize();
- continue;
- }
- if (!KSUCCESS(Status)) {
- goto ConnectEnd;
- }
- if (KdRxPacket.Header.Command != DbgConnectionRequest) {
- KdTxPacket.Header.Command = DbgConnectionUninitialized;
- KdTxPacket.Header.PayloadSize = 0;
- KdpSendPacket(&KdTxPacket, NULL);
- } else {
- break;
- }
- }
- ConnectionRequest = (PCONNECTION_REQUEST)(KdRxPacket.Payload);
- Status = KdpSendConnectionResponse(ConnectionRequest, BreakInRequested);
- if (!KSUCCESS(Status)) {
- goto ConnectEnd;
- }
- ConnectEnd:
- return Status;
- }
- VOID
- KdpSynchronize (
- VOID
- )
- /*++
- Routine Description:
- This routine synchronizes with the kernel debugger in preparation for
- receiving the connection request packet. The synchornization process is a
- simply exchange of bytes where both sides must send a SYN, ACK the other
- side's SYN, and receive an ACK.
- Arguments:
- None.
- Return Value:
- None. Failure is considered non-fatal.
- --*/
- {
- UCHAR SynchronizeByte;
- SynchronizeByte = DEBUG_SYNCHRONIZE_TARGET;
- KdpTransmitBytes(&SynchronizeByte, 1);
- return;
- }
- KSTATUS
- KdpSendConnectionResponse (
- PCONNECTION_REQUEST ConnectionRequest,
- PBOOL BreakInRequested
- )
- /*++
- Routine Description:
- This routine attempts to connect to the kernel debugger.
- Arguments:
- ConnectionRequest - Supplies a pointer to the connection request.
- BreakInRequested - Supplies an optional pointer where a boolean will be
- returned indicating if an initial break is requested.
- Return Value:
- Status code. If the status is failing, the debugger connected global will
- be set to FALSE.
- --*/
- {
- BOOL AcknowledgeBreakRequested;
- PCONNECTION_RESPONSE ConnectionResponse;
- KSTATUS OverallStatus;
- KSTATUS Status;
- ULONG StringSize;
- SYSTEM_VERSION_INFORMATION SystemVersion;
- OverallStatus = STATUS_SUCCESS;
- //
- // Compare protocol version numbers.
- //
- if (ConnectionRequest->ProtocolMajorVersion <
- DEBUG_PROTOCOL_MAJOR_VERSION) {
- //
- // Protocols do not match. Send back the kernel's debugger
- // protocol information, and return. Consider the debugger to be
- // disconnected at this point.
- //
- KdTxPacket.Header.Command = DbgConnectionWrongVersion;
- OverallStatus = STATUS_VERSION_MISMATCH;
- } else {
- KdTxPacket.Header.Command = DbgConnectionAcknowledge;
- }
- if (BreakInRequested != NULL) {
- *BreakInRequested = ConnectionRequest->BreakRequested;
- }
- //
- // Fill out and send the connection response.
- //
- ConnectionResponse = (PCONNECTION_RESPONSE)(KdTxPacket.Payload);
- RtlZeroMemory(ConnectionResponse, sizeof(CONNECTION_RESPONSE));
- ConnectionResponse->ProtocolMajorVersion = DEBUG_PROTOCOL_MAJOR_VERSION;
- ConnectionResponse->ProtocolRevision = DEBUG_PROTOCOL_REVISION;
- StringSize = DEBUG_PAYLOAD_SIZE - sizeof(CONNECTION_RESPONSE);
- Status = KeGetSystemVersion(&SystemVersion,
- ConnectionResponse + 1,
- &StringSize);
- if (KSUCCESS(Status)) {
- ConnectionResponse->SystemMajorVersion = SystemVersion.MajorVersion;
- ConnectionResponse->SystemMinorVersion = SystemVersion.MinorVersion;
- ConnectionResponse->SystemRevision = SystemVersion.Revision;
- ConnectionResponse->SystemSerialVersion = SystemVersion.SerialVersion;
- ConnectionResponse->SystemReleaseLevel = SystemVersion.ReleaseLevel;
- ConnectionResponse->SystemBuildDebugLevel = SystemVersion.DebugLevel;
- ConnectionResponse->SystemBuildTime = SystemVersion.BuildTime.Seconds;
- ConnectionResponse->ProductNameOffset =
- (UINTN)(SystemVersion.ProductName) -
- (UINTN)(KdTxPacket.Payload);
- if (SystemVersion.BuildString != NULL) {
- ConnectionResponse->BuildStringOffset =
- (UINTN)(SystemVersion.BuildString) -
- (UINTN)(KdTxPacket.Payload);
- }
- }
- ConnectionResponse->Machine = KdMachineType;
- KdTxPacket.Header.PayloadSize = sizeof(CONNECTION_RESPONSE) + StringSize;
- Status = KdpSendPacket(&KdTxPacket, &AcknowledgeBreakRequested);
- if (!KSUCCESS(Status)) {
- OverallStatus = Status;
- goto SendConnectionResponseEnd;
- }
- if ((BreakInRequested != NULL) && (AcknowledgeBreakRequested != FALSE)) {
- *BreakInRequested = TRUE;
- }
- if (KdTxPacket.Header.Command == DbgConnectionAcknowledge) {
- KdDebuggerConnected = TRUE;
- }
- SendConnectionResponseEnd:
- return OverallStatus;
- }
- VOID
- KdpInternalPrint (
- PSTR Format,
- ...
- )
- /*++
- Routine Description:
- This routine prints to the debug client window. This routine can only be
- called from *inside* the debug exception handler.
- Arguments:
- Format - Supplies the printf-style format string.
- ... - Supplies additional values as dictated by the format.
- Return Value:
- None.
- --*/
- {
- PRINT_PARAMETERS PrintParameters;
- PrintParameters.FormatString = Format;
- va_start(PrintParameters.Arguments, Format);
- KdpPrint(&PrintParameters, NULL);
- va_end(PrintParameters.Arguments);
- return;
- }
- VOID
- KdpAcquireDebuggerLock (
- PTRAP_FRAME TrapFrame
- )
- /*++
- Routine Description:
- This routine acquires the master debugger lock, ensuring that only one
- processor is speaking out the debugger port at a time.
- Arguments:
- TrapFrame - Supplies a pointer to the trap frame, which is used in case
- this processor needs to respond to a freeze request and become a
- subordinate processor.
- Return Value:
- None.
- --*/
- {
- ULONG LockValue;
- PPROCESSOR_BLOCK ProcessorBlock;
- ULONG ProcessorNumber;
- ProcessorNumber = 0;
- ProcessorBlock = KeGetCurrentProcessorBlockForDebugger();
- if (ProcessorBlock != NULL) {
- ProcessorNumber = ProcessorBlock->ProcessorNumber;
- }
- do {
- LockValue = KdpAtomicCompareExchange32(&KdLockAcquired,
- ProcessorNumber,
- -1);
- //
- // If the lock was not acquired and freeze requests are maskable,
- // look to see if another processor got the lock and is trying to
- // send a freeze request. If this is the case, there's a freeze
- // interrupt pending, which this processor will never get in this loop
- // as interrupts are disabled. Manually freeze, then mark that the
- // freeze, when it does come in, is expected.
- //
- if ((LockValue != -1) &&
- (KeActiveProcessorCount > 1) &&
- (KdFreezesAreMaskable != FALSE) &&
- (KdFreezeOwner != MAX_ULONG) &&
- (KdNmiBroadcastAllowed != FALSE)) {
- KdNmiHandler(TrapFrame);
- }
- } while (LockValue != ProcessorNumber);
- return;
- }
- VOID
- KdpReleaseDebuggerLock (
- VOID
- )
- /*++
- Routine Description:
- This routine releases the master debugging lock.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- ULONG LockValue;
- PPROCESSOR_BLOCK ProcessorBlock;
- ULONG ProcessorNumber;
- ProcessorNumber = 0;
- ProcessorBlock = KeGetCurrentProcessorBlockForDebugger();
- if (ProcessorBlock != NULL) {
- ProcessorNumber = ProcessorBlock->ProcessorNumber;
- }
- LockValue = KdpAtomicCompareExchange32(&KdLockAcquired,
- -1,
- ProcessorNumber);
- ASSERT(LockValue == ProcessorNumber);
- return;
- }
- KSTATUS
- KdpTransmitBytes (
- PVOID Data,
- ULONG Size
- )
- /*++
- Routine Description:
- This routine sends bytes down the transmit to the debug host.
- Arguments:
- Data - Supplies the data to transmit.
- Size - Supplies the number of bytes to transmit.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_TIMEOUT if the desired number of bytes could not be retrieved in a
- timely fashion.
- STATUS_DEVICE_IO_ERROR if a device error occurred.
- --*/
- {
- PUCHAR Bytes;
- UCHAR EncodedByte[2];
- ULONG SendSize;
- KSTATUS Status;
- Bytes = Data;
- Status = STATUS_SUCCESS;
- while (Size != 0) {
- if (KdEncodeBytes != FALSE) {
- //
- // Gather bytes until one is found that needs escaping.
- //
- SendSize = 0;
- while ((SendSize < Size) &&
- (Bytes[SendSize] != DEBUG_XON) &&
- (Bytes[SendSize] != DEBUG_XOFF) &&
- (Bytes[SendSize] != DEBUG_ESCAPE)) {
- SendSize += 1;
- }
- //
- // If not encoding bytes, just send everything.
- //
- } else {
- SendSize = Size;
- }
- //
- // Send off the buffer so far.
- //
- if (SendSize != 0) {
- Status = KdpDeviceTransmit(Bytes, SendSize);
- if (!KSUCCESS(Status)) {
- break;
- }
- }
- Bytes += SendSize;
- Size -= SendSize;
- //
- // Send an encoded byte.
- //
- if (Size != 0) {
- EncodedByte[0] = DEBUG_ESCAPE;
- EncodedByte[1] = *Bytes + DEBUG_ESCAPE;
- Status = KdpDeviceTransmit(EncodedByte, 2);
- if (!KSUCCESS(Status)) {
- break;
- }
- Size -= 1;
- Bytes += 1;
- }
- }
- return Status;
- }
- KSTATUS
- KdpReceiveBuffer (
- PVOID Data,
- PULONG Size,
- PULONG Timeout
- )
- /*++
- Routine Description:
- This routine receives incoming data from the debug device.
- Arguments:
- Data - Supplies a pointer where the read data will be returned on success.
- Size - Supplies a pointer that on input contains the size of the receive
- buffer. On output, returns the number of bytes read.
- Timeout - Supplies a pointer that on input contains the number of
- microseconds to wait before timing out. On output, will contain the
- remainder of that wait.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_TIMEOUT if the desired number of bytes could not be retrieved in a
- timely fashion.
- STATUS_DEVICE_IO_ERROR if a device error occurred.
- --*/
- {
- PUCHAR Bytes;
- ULONG BytesCompleted;
- ULONG BytesRemaining;
- ULONG Count;
- ULONG Index;
- ULONG MoveIndex;
- BOOL NextEscaped;
- KSTATUS Status;
- NextEscaped = FALSE;
- Status = STATUS_SUCCESS;
- Bytes = Data;
- BytesRemaining = *Size;
- while (BytesRemaining != 0) {
- BytesCompleted = BytesRemaining;
- Status = KdpDeviceReceiveBuffer(Bytes, &BytesCompleted, Timeout);
- if (!KSUCCESS(Status)) {
- break;
- }
- //
- // If escaping is on, then remove any escape bytes found, and fix up
- // the escaped byte.
- //
- Count = 0;
- if (KdEncodeBytes != FALSE) {
- //
- // If the last byte received was an escape, then unescape this
- // first byte.
- //
- if (NextEscaped != FALSE) {
- NextEscaped = FALSE;
- Bytes[0] -= DEBUG_ESCAPE;
- Bytes += 1;
- BytesRemaining -= 1;
- BytesCompleted -= 1;
- if (BytesRemaining == 0) {
- break;
- }
- }
- for (Index = 0; Index < BytesCompleted - 1; Index += 1) {
- if (Bytes[Index] == DEBUG_ESCAPE) {
- for (MoveIndex = Index;
- MoveIndex < BytesCompleted - 1;
- MoveIndex += 1) {
- Bytes[MoveIndex] = Bytes[MoveIndex + 1];
- }
- Count += 1;
- Bytes[Index] -= DEBUG_ESCAPE;
- }
- }
- //
- // If the last byte received is an escape, remember to unescape the
- // next byte.
- //
- if (Bytes[Index] == DEBUG_ESCAPE) {
- Count += 1;
- NextEscaped = TRUE;
- }
- }
- BytesCompleted -= Count;
- Bytes += BytesCompleted;
- //
- // If the count is non-zero, fewer real bytes were received than
- // expected, so go get the extra ones.
- //
- BytesRemaining -= BytesCompleted;
- }
- *Size -= BytesRemaining;
- return Status;
- }
- KSTATUS
- KdpDeviceReceiveBuffer (
- PVOID Data,
- PULONG Size,
- PULONG Timeout
- )
- /*++
- Routine Description:
- This routine receives incoming data from the debug device.
- Arguments:
- Data - Supplies a pointer where the read data will be returned on success.
- Size - Supplies a pointer that on input contains the size of the receive
- buffer. On output, returns the number of bytes read.
- Timeout - Supplies a pointer that on input contains the number of
- microseconds to wait before timing out. On output, will contain the
- remainder of that wait.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_TIMEOUT if the desired number of bytes could not be retrieved in a
- timely fashion.
- STATUS_DEVICE_IO_ERROR if a device error occurred.
- --*/
- {
- ULONG BytesCompleted;
- ULONG BytesRemaining;
- ULONG StallDuration;
- KSTATUS Status;
- //
- // Loop until all data has been received. The first time around, do a
- // smaller delay. This way if a stream is being sent reliably but not
- // back to back, the larger delay doesn't get stuck in between each byte.
- //
- BytesRemaining = *Size;
- StallDuration = DEBUG_SMALL_STALL;
- Status = STATUS_SUCCESS;
- while (BytesRemaining != 0) {
- BytesCompleted = BytesRemaining;
- Status = KdpDeviceReceive(Data, &BytesCompleted);
- BytesRemaining -= BytesCompleted;
- if (Status == STATUS_NO_DATA_AVAILABLE) {
- //
- // Avoid both the time counter and stalls if the boolean is set.
- //
- if (KdAvoidTimeCounter != FALSE) {
- continue;
- }
- //
- // Keep the time counter fresh.
- //
- HlQueryTimeCounter();
- if (*Timeout == MAX_ULONG) {
- continue;
- } else if (*Timeout == 0) {
- Status = STATUS_TIMEOUT;
- break;
- } else if (*Timeout < StallDuration) {
- *Timeout = StallDuration;
- }
- //
- // Stall to count time towards the timeout.
- //
- HlBusySpin(StallDuration);
- *Timeout -= StallDuration;
- StallDuration = DEBUG_STALL_INCREMENT;
- continue;
- } else if (!KSUCCESS(Status)) {
- break;
- }
- Data += BytesCompleted;
- StallDuration = DEBUG_SMALL_STALL;
- }
- *Size -= BytesRemaining;
- return Status;
- }
- KSTATUS
- KdpDeviceReset (
- ULONG BaudRate
- )
- /*++
- Routine Description:
- This routine initializes and resets a debug device, preparing it to send
- and receive data.
- Arguments:
- BaudRate - Supplies the baud rate to set.
- Return Value:
- STATUS_SUCCESS on success.
- Other status codes on failure. The device will not be used if a failure
- status code is returned.
- --*/
- {
- KSTATUS Status;
- KD_DEVICE_TRACE(KdDeviceTraceResetting);
- if (KdDebugDevice == NULL) {
- Status = STATUS_NO_SUCH_DEVICE;
- goto DeviceResetEnd;
- }
- Status = KdDebugDevice->FunctionTable.Reset(KdDebugDevice->Context,
- BaudRate);
- DeviceResetEnd:
- if (!KSUCCESS(Status)) {
- KD_DEVICE_TRACE(KdDeviceTraceResetFailed);
- } else {
- KD_DEVICE_TRACE(KdDeviceTraceResetComplete);
- }
- return Status;
- }
- KSTATUS
- KdpDeviceTransmit (
- PVOID Data,
- ULONG Size
- )
- /*++
- Routine Description:
- This routine transmits data from the host out through the debug device.
- Arguments:
- Data - Supplies a pointer to the data to write.
- Size - Supplies the size to write, in bytes.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_DEVICE_IO_ERROR if a device error occurred.
- --*/
- {
- KSTATUS Status;
- KD_DEVICE_TRACE(KdDeviceTraceTransmitting);
- if (KdDebugDevice == NULL) {
- Status = STATUS_NO_SUCH_DEVICE;
- goto DeviceTransmitEnd;
- }
- Status = KdDebugDevice->FunctionTable.Transmit(KdDebugDevice->Context,
- Data,
- Size);
- DeviceTransmitEnd:
- if (!KSUCCESS(Status)) {
- KD_DEVICE_TRACE(KdDeviceTraceTransmitFailed);
- } else {
- KD_DEVICE_TRACE(KdDeviceTraceTransmitComplete);
- }
- return Status;
- }
- KSTATUS
- KdpDeviceReceive (
- PVOID Data,
- PULONG Size
- )
- /*++
- Routine Description:
- This routine receives incoming data from the debug device.
- Arguments:
- Data - Supplies a pointer where the read data will be returned on success.
- Size - Supplies a pointer that on input contains the size of the receive
- buffer. On output, returns the number of bytes read.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_NO_DATA_AVAILABLE if there was no data to be read at the current
- time.
- STATUS_DEVICE_IO_ERROR if a device error occurred.
- --*/
- {
- KSTATUS Status;
- KD_DEVICE_TRACE(KdDeviceTraceReceiving);
- if (KdDebugDevice == NULL) {
- Status = STATUS_NO_SUCH_DEVICE;
- goto DeviceReceiveEnd;
- }
- Status = KdDebugDevice->FunctionTable.Receive(KdDebugDevice->Context,
- Data,
- Size);
- DeviceReceiveEnd:
- if (!KSUCCESS(Status)) {
- KD_DEVICE_TRACE(KdDeviceTraceReceiveFailed);
- } else {
- KD_DEVICE_TRACE(KdDeviceTraceReceiveComplete);
- }
- return Status;
- }
- KSTATUS
- KdpDeviceGetStatus (
- PBOOL ReceiveDataAvailable
- )
- /*++
- Routine Description:
- This routine returns the current device status.
- Arguments:
- ReceiveDataAvailable - Supplies a pointer where a boolean will be returned
- indicating whether or not receive data is available.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- KD_DEVICE_TRACE(KdDeviceTraceGettingStatus);
- if (KdDebugDevice == NULL) {
- Status = STATUS_NO_SUCH_DEVICE;
- goto DeviceGetStatusEnd;
- }
- Status = KdDebugDevice->FunctionTable.GetStatus(KdDebugDevice->Context,
- ReceiveDataAvailable);
- DeviceGetStatusEnd:
- if (!KSUCCESS(Status)) {
- KD_DEVICE_TRACE(KdDeviceTraceGetStatusFailed);
- } else {
- if (*ReceiveDataAvailable != FALSE) {
- KD_DEVICE_TRACE(KdDeviceTraceGetStatusHasData);
- } else {
- KD_DEVICE_TRACE(KdDeviceTraceGetStatusEmpty);
- }
- }
- return Status;
- }
- VOID
- KdpDeviceDisconnect (
- VOID
- )
- /*++
- Routine Description:
- This routine disconnects a device, taking it offline.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- KD_DEVICE_TRACE(KdDeviceTraceDisconnecting);
- if (KdDebugDevice == NULL) {
- goto DeviceDisconnectEnd;
- }
- KdDebugDevice->FunctionTable.Disconnect(KdDebugDevice->Context);
- DeviceDisconnectEnd:
- KD_DEVICE_TRACE(KdDeviceTraceDisconnected);
- return;
- }
- VOID
- KdpFreezeProcessors (
- VOID
- )
- /*++
- Routine Description:
- This routine attempts to freeze all of the processors, assuming that the
- current processor is the freeze owner. It sends an NMI IPI to all of the
- other processors and waits for them to be marked frozen.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PROCESSOR_SET ProcessorSet;
- KSTATUS Status;
- ULONG Timeout;
- ProcessorSet.Target = ProcessorTargetAllExcludingSelf;
- Status = HlSendIpi(IpiTypeNmi, &ProcessorSet);
- if (!KSUCCESS(Status)) {
- goto FreezeProcessorsEnd;
- }
- Timeout = DEBUG_PROCESSOR_WAIT_TIME;
- //
- // Wait until all processors are frozen, or it's time to give
- // up. Keep the time counter fresh too during this period.
- //
- KD_TRACE(KdTraceWaitingForFrozenProcessors);
- while (KdProcessorsFrozen != KeActiveProcessorCount) {
- if ((KdConnectionTimeout != MAX_ULONG) &&
- (KdAvoidTimeCounter == FALSE)) {
- if (Timeout == 0) {
- break;
- } else if (Timeout < DEBUG_STALL_INCREMENT) {
- Timeout = DEBUG_STALL_INCREMENT;
- }
- HlBusySpin(DEBUG_STALL_INCREMENT);
- Timeout -= DEBUG_STALL_INCREMENT;
- }
- if (KdAvoidTimeCounter == FALSE) {
- HlQueryTimeCounter();
- }
- }
- FreezeProcessorsEnd:
- return;
- }
|