1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Run-Time Library 4 * FILE: lib/rtl/debug.c 5 * PURPOSE: Debug Print and Prompt routines 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Royce Mitchel III 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <rtl.h> 13 14 #include <ndk/kdfuncs.h> 15 16 #define NDEBUG 17 #include <debug.h> 18 19 /* PRIVATE FUNCTIONS ********************************************************/ 20 21 ULONG 22 NTAPI 23 DebugPrint(IN PSTRING DebugString, 24 IN ULONG ComponentId, 25 IN ULONG Level) 26 { 27 /* Call the Debug Service */ 28 return DebugService(BREAKPOINT_PRINT, 29 DebugString->Buffer, 30 UlongToPtr(DebugString->Length), 31 UlongToPtr(ComponentId), 32 UlongToPtr(Level)); 33 } 34 35 ULONG 36 NTAPI 37 DebugPrompt(IN PSTRING Output, 38 IN PSTRING Input) 39 { 40 /* Call the Debug Service */ 41 return DebugService(BREAKPOINT_PROMPT, 42 Output->Buffer, 43 UlongToPtr(Output->Length), 44 Input->Buffer, 45 UlongToPtr(Input->MaximumLength)); 46 } 47 48 /* FUNCTIONS ****************************************************************/ 49 50 ULONG 51 NTAPI 52 vDbgPrintExWithPrefixInternal(IN PCCH Prefix, 53 IN ULONG ComponentId, 54 IN ULONG Level, 55 IN PCCH Format, 56 IN va_list ap, 57 IN BOOLEAN HandleBreakpoint) 58 { 59 NTSTATUS Status; 60 STRING DebugString; 61 CHAR Buffer[512]; 62 SIZE_T Length, PrefixLength; 63 EXCEPTION_RECORD ExceptionRecord; 64 65 /* Check if we should print it or not */ 66 if ((ComponentId != MAXULONG) && 67 (NtQueryDebugFilterState(ComponentId, Level)) != (NTSTATUS)TRUE) 68 { 69 /* This message is masked */ 70 return STATUS_SUCCESS; 71 } 72 73 /* For user mode, don't recursively DbgPrint */ 74 if (RtlpSetInDbgPrint()) return STATUS_SUCCESS; 75 76 /* Guard against incorrect pointers */ 77 _SEH2_TRY 78 { 79 /* Get the length and normalize it */ 80 PrefixLength = strlen(Prefix); 81 if (PrefixLength > sizeof(Buffer)) PrefixLength = sizeof(Buffer); 82 83 /* Copy it */ 84 strncpy(Buffer, Prefix, PrefixLength); 85 86 /* Do the printf */ 87 Length = _vsnprintf(Buffer + PrefixLength, 88 sizeof(Buffer) - PrefixLength, 89 Format, 90 ap); 91 } 92 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 93 { 94 /* In user-mode, clear the InDbgPrint Flag */ 95 RtlpClearInDbgPrint(); 96 /* Fail */ 97 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 98 } 99 _SEH2_END; 100 101 /* Check if we went past the buffer */ 102 if (Length == MAXULONG) 103 { 104 /* Terminate it if we went over-board */ 105 Buffer[sizeof(Buffer) - 1] = '\n'; 106 107 /* Put maximum */ 108 Length = sizeof(Buffer); 109 } 110 else 111 { 112 /* Add the prefix */ 113 Length += PrefixLength; 114 } 115 116 /* Build the string */ 117 DebugString.Length = (USHORT)Length; 118 DebugString.Buffer = Buffer; 119 120 /* First, let the debugger know as well */ 121 if (RtlpCheckForActiveDebugger()) 122 { 123 /* Fill out an exception record */ 124 ExceptionRecord.ExceptionCode = DBG_PRINTEXCEPTION_C; 125 ExceptionRecord.ExceptionRecord = NULL; 126 ExceptionRecord.NumberParameters = 2; 127 ExceptionRecord.ExceptionFlags = 0; 128 ExceptionRecord.ExceptionInformation[0] = DebugString.Length + 1; 129 ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR)DebugString.Buffer; 130 131 /* Raise the exception */ 132 RtlRaiseException(&ExceptionRecord); 133 134 /* In user-mode, clear the InDbgPrint Flag */ 135 RtlpClearInDbgPrint(); 136 return STATUS_SUCCESS; 137 } 138 139 /* Call the Debug Print routine */ 140 Status = DebugPrint(&DebugString, ComponentId, Level); 141 142 /* Check if this was with Control-C */ 143 if (HandleBreakpoint) 144 { 145 /* Check if we got a breakpoint */ 146 if (Status == STATUS_BREAKPOINT) 147 { 148 /* Breakpoint */ 149 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); 150 Status = STATUS_SUCCESS; 151 } 152 } 153 154 /* In user-mode, clear the InDbgPrint Flag */ 155 RtlpClearInDbgPrint(); 156 157 /* Return */ 158 return Status; 159 } 160 161 /* 162 * @implemented 163 */ 164 ULONG 165 NTAPI 166 vDbgPrintExWithPrefix(IN PCCH Prefix, 167 IN ULONG ComponentId, 168 IN ULONG Level, 169 IN PCCH Format, 170 IN va_list ap) 171 { 172 /* Call the internal routine that also handles ControlC */ 173 return vDbgPrintExWithPrefixInternal(Prefix, 174 ComponentId, 175 Level, 176 Format, 177 ap, 178 TRUE); 179 } 180 181 /* 182 * @implemented 183 */ 184 ULONG 185 NTAPI 186 vDbgPrintEx(IN ULONG ComponentId, 187 IN ULONG Level, 188 IN PCCH Format, 189 IN va_list ap) 190 { 191 /* Call the internal routine that also handles ControlC */ 192 return vDbgPrintExWithPrefixInternal("", 193 ComponentId, 194 Level, 195 Format, 196 ap, 197 TRUE); 198 } 199 200 /* 201 * @implemented 202 */ 203 ULONG 204 __cdecl 205 DbgPrint(PCCH Format, 206 ...) 207 { 208 ULONG Status; 209 va_list ap; 210 211 /* Call the internal routine that also handles ControlC */ 212 va_start(ap, Format); 213 Status = vDbgPrintExWithPrefixInternal("", 214 -1, 215 DPFLTR_ERROR_LEVEL, 216 Format, 217 ap, 218 TRUE); 219 va_end(ap); 220 return Status; 221 } 222 223 /* 224 * @implemented 225 */ 226 ULONG 227 __cdecl 228 DbgPrintEx(IN ULONG ComponentId, 229 IN ULONG Level, 230 IN PCCH Format, 231 ...) 232 { 233 ULONG Status; 234 va_list ap; 235 236 /* Call the internal routine that also handles ControlC */ 237 va_start(ap, Format); 238 Status = vDbgPrintExWithPrefixInternal("", 239 ComponentId, 240 Level, 241 Format, 242 ap, 243 TRUE); 244 va_end(ap); 245 return Status; 246 } 247 248 /* 249 * @implemented 250 */ 251 ULONG 252 __cdecl 253 DbgPrintReturnControlC(PCCH Format, 254 ...) 255 { 256 ULONG Status; 257 va_list ap; 258 259 /* Call the internal routine that also handles ControlC */ 260 va_start(ap, Format); 261 Status = vDbgPrintExWithPrefixInternal("", 262 -1, 263 DPFLTR_ERROR_LEVEL, 264 Format, 265 ap, 266 FALSE); 267 va_end(ap); 268 return Status; 269 } 270 271 /* 272 * @implemented 273 */ 274 ULONG 275 NTAPI 276 DbgPrompt(IN PCCH Prompt, 277 OUT PCH Response, 278 IN ULONG MaximumResponseLength) 279 { 280 STRING Output; 281 STRING Input; 282 283 /* Setup the input string */ 284 Input.MaximumLength = (USHORT)MaximumResponseLength; 285 Input.Buffer = Response; 286 287 /* Setup the output string */ 288 Output.Length = (USHORT)strlen(Prompt); 289 Output.Buffer = (PCHAR)Prompt; 290 291 /* Call the system service */ 292 return DebugPrompt(&Output, &Input); 293 } 294 295 /* 296 * @implemented 297 */ 298 NTSTATUS 299 NTAPI 300 DbgQueryDebugFilterState(IN ULONG ComponentId, 301 IN ULONG Level) 302 { 303 /* Call the Nt routine */ 304 return NtQueryDebugFilterState(ComponentId, Level); 305 } 306 307 /* 308 * @implemented 309 */ 310 NTSTATUS 311 NTAPI 312 DbgSetDebugFilterState(IN ULONG ComponentId, 313 IN ULONG Level, 314 IN BOOLEAN State) 315 { 316 /* Call the Nt routine */ 317 return NtSetDebugFilterState(ComponentId, Level, State); 318 } 319 320 /* 321 * @implemented 322 */ 323 VOID 324 NTAPI 325 DbgLoadImageSymbols(IN PSTRING Name, 326 IN PVOID Base, 327 IN ULONG_PTR ProcessId) 328 { 329 PIMAGE_NT_HEADERS NtHeader; 330 KD_SYMBOLS_INFO SymbolInfo; 331 332 /* Setup the symbol data */ 333 SymbolInfo.BaseOfDll = Base; 334 SymbolInfo.ProcessId = ProcessId; 335 336 /* Get NT Headers */ 337 NtHeader = RtlImageNtHeader(Base); 338 if (NtHeader) 339 { 340 /* Get the rest of the data */ 341 SymbolInfo.CheckSum = NtHeader->OptionalHeader.CheckSum; 342 SymbolInfo.SizeOfImage = NtHeader->OptionalHeader.SizeOfImage; 343 } 344 else 345 { 346 /* No data available */ 347 SymbolInfo.CheckSum = 348 SymbolInfo.SizeOfImage = 0; 349 } 350 351 /* Load the symbols */ 352 DebugService2(Name, &SymbolInfo, BREAKPOINT_LOAD_SYMBOLS); 353 } 354 355 /* 356 * @implemented 357 */ 358 VOID 359 NTAPI 360 DbgUnLoadImageSymbols(IN PSTRING Name, 361 IN PVOID Base, 362 IN ULONG_PTR ProcessId) 363 { 364 KD_SYMBOLS_INFO SymbolInfo; 365 366 /* Setup the symbol data */ 367 SymbolInfo.BaseOfDll = Base; 368 SymbolInfo.ProcessId = ProcessId; 369 SymbolInfo.CheckSum = SymbolInfo.SizeOfImage = 0; 370 371 /* Load the symbols */ 372 DebugService2(Name, &SymbolInfo, BREAKPOINT_UNLOAD_SYMBOLS); 373 } 374 375 /* 376 * @implemented 377 */ 378 VOID 379 NTAPI 380 DbgCommandString(IN PCCH Name, 381 IN PCCH Command) 382 { 383 STRING NameString, CommandString; 384 385 /* Setup the strings */ 386 NameString.Buffer = (PCHAR)Name; 387 NameString.Length = (USHORT)strlen(Name); 388 CommandString.Buffer = (PCHAR)Command; 389 CommandString.Length = (USHORT)strlen(Command); 390 391 /* Send them to the debugger */ 392 DebugService2(&NameString, &CommandString, BREAKPOINT_COMMAND_STRING); 393 } 394 395 /* 396 * @implemented 397 */ 398 VOID 399 NTAPI 400 RtlPopFrame(IN PTEB_ACTIVE_FRAME Frame) 401 { 402 /* Restore the previous frame as the active one */ 403 NtCurrentTeb()->ActiveFrame = Frame->Previous; 404 } 405 406 /* 407 * @implemented 408 */ 409 VOID 410 NTAPI 411 RtlPushFrame(IN PTEB_ACTIVE_FRAME Frame) 412 { 413 /* Save the current frame and set the new one as active */ 414 Frame->Previous = NtCurrentTeb()->ActiveFrame; 415 NtCurrentTeb()->ActiveFrame = Frame; 416 } 417 418 PTEB_ACTIVE_FRAME 419 NTAPI 420 RtlGetFrame(VOID) 421 { 422 /* Return the frame that's currently active */ 423 return NtCurrentTeb()->ActiveFrame; 424 } 425