/*++ Copyright (c) 1991 Microsoft Corporation Module Name: debug.c Abstract: This component of netbios runs in the user process and can ( when built in a debug kernel) will log to either the console or through the kernel debugger. Author: Colin Watson (ColinW) 24-Jun-91 Revision History: --*/ #if DBG #include #include #include ULONG NbDllDebug = 0x0; #define NB_DLL_DEBUG_NCB 0x00000001 // print all NCB's submitted #define NB_DLL_DEBUG_NCB_BUFF 0x00000002 // print buffers for NCB's submitted BOOL UseConsole = FALSE; BOOL UseLogFile = TRUE; HANDLE LogFile = INVALID_HANDLE_VALUE; #define LOGNAME (LPTSTR) TEXT("netbios.log") LONG NbMaxDump = 128; // Macro used in DisplayNcb #define DISPLAY_COMMAND( cmd ) \ case cmd: NbPrintf(( #cmd )); break; VOID FormattedDump( PCHAR far_p, LONG len ); VOID HexDumpLine( PCHAR pch, ULONG len, PCHAR s, PCHAR t ); VOID DisplayNcb( IN PNCBI pncbi ) /*++ Routine Description: This routine displays on the standard output stream the contents of the Ncb. Arguments: IN PNCBI - Supplies the NCB to be displayed. Return Value: none. --*/ { if ( (NbDllDebug & NB_DLL_DEBUG_NCB) == 0 ) { return; } NbPrintf(( "PNCB %#010lx\n", pncbi)); NbPrintf(( "ncb_command %#04x ", pncbi->ncb_command)); switch ( pncbi->ncb_command & ~ASYNCH ) { DISPLAY_COMMAND( NCBCALL ); DISPLAY_COMMAND( NCBLISTEN ); DISPLAY_COMMAND( NCBHANGUP ); DISPLAY_COMMAND( NCBSEND ); DISPLAY_COMMAND( NCBRECV ); DISPLAY_COMMAND( NCBRECVANY ); DISPLAY_COMMAND( NCBCHAINSEND ); DISPLAY_COMMAND( NCBDGSEND ); DISPLAY_COMMAND( NCBDGRECV ); DISPLAY_COMMAND( NCBDGSENDBC ); DISPLAY_COMMAND( NCBDGRECVBC ); DISPLAY_COMMAND( NCBADDNAME ); DISPLAY_COMMAND( NCBDELNAME ); DISPLAY_COMMAND( NCBRESET ); DISPLAY_COMMAND( NCBASTAT ); DISPLAY_COMMAND( NCBSSTAT ); DISPLAY_COMMAND( NCBCANCEL ); DISPLAY_COMMAND( NCBADDGRNAME ); DISPLAY_COMMAND( NCBENUM ); DISPLAY_COMMAND( NCBUNLINK ); DISPLAY_COMMAND( NCBSENDNA ); DISPLAY_COMMAND( NCBCHAINSENDNA ); DISPLAY_COMMAND( NCBLANSTALERT ); DISPLAY_COMMAND( NCBFINDNAME ); // Extensions DISPLAY_COMMAND( NCALLNIU ); DISPLAY_COMMAND( NCBQUICKADDNAME ); DISPLAY_COMMAND( NCBQUICKADDGRNAME ); DISPLAY_COMMAND( NCBACTION ); default: NbPrintf(( " Unknown type")); break; } if ( pncbi->ncb_command & ASYNCH ) { NbPrintf(( " | ASYNCH")); } NbPrintf(( "\nncb_retcode %#04x\n", pncbi->ncb_retcode)); NbPrintf(( "ncb_lsn %#04x\n", pncbi->ncb_lsn)); NbPrintf(( "ncb_num %#04x\n", pncbi->ncb_num)); NbPrintf(( "ncb_buffer %#010lx\n",pncbi->ncb_buffer)); NbPrintf(( "ncb_length %#06x\n", pncbi->ncb_length)); NbPrintf(( "\nncb_callname and ncb->name\n")); FormattedDump( pncbi->cu.ncb_callname, NCBNAMSZ ); FormattedDump( pncbi->ncb_name, NCBNAMSZ ); if (((pncbi->ncb_command & ~ASYNCH) == NCBCHAINSEND) || ((pncbi->ncb_command & ~ASYNCH) == NCBCHAINSENDNA)) { NbPrintf(( "ncb_length2 %#06x\n", pncbi->cu.ncb_chain.ncb_length2)); NbPrintf(( "ncb_buffer2 %#010lx\n",pncbi->cu.ncb_chain.ncb_buffer2)); } NbPrintf(( "ncb_rto %#04x\n", pncbi->ncb_rto)); NbPrintf(( "ncb_sto %#04x\n", pncbi->ncb_sto)); NbPrintf(( "ncb_post %lx\n", pncbi->ncb_post)); NbPrintf(( "ncb_lana_num %#04x\n", pncbi->ncb_lana_num)); NbPrintf(( "ncb_cmd_cplt %#04x\n", pncbi->ncb_cmd_cplt)); NbPrintf(( "ncb_reserve\n")); FormattedDump( ((PNCB)pncbi)->ncb_reserve, 14 ); NbPrintf(( "ncb_next\n")); FormattedDump( (PCHAR)&pncbi->u.ncb_next, sizeof( LIST_ENTRY) ); NbPrintf(( "ncb_iosb\n")); FormattedDump( (PCHAR)&pncbi->u.ncb_iosb, sizeof( IO_STATUS_BLOCK ) ); NbPrintf(( "ncb_event %#04x\n", pncbi->ncb_event)); if ( (NbDllDebug & NB_DLL_DEBUG_NCB_BUFF) == 0 ) { NbPrintf(( "\n\n" )); return; } switch ( pncbi->ncb_command & ~ASYNCH ) { case NCBSEND: case NCBCHAINSEND: case NCBDGSEND: case NCBSENDNA: case NCBCHAINSENDNA: if ( pncbi->ncb_retcode == NRC_PENDING ) { // // If pending then presumably we have not displayed the ncb // before. After its been sent there isn't much point in displaying // the buffer again. // NbPrintf(( "ncb_buffer contents:\n")); FormattedDump( pncbi->ncb_buffer, pncbi->ncb_length ); } break; case NCBRECV: case NCBRECVANY: case NCBDGRECV: case NCBDGSENDBC: case NCBDGRECVBC: case NCBENUM: case NCBASTAT: case NCBSSTAT: case NCBFINDNAME: if ( pncbi->ncb_retcode != NRC_PENDING ) { // Buffer has been loaded with data NbPrintf(( "ncb_buffer contents:\n")); FormattedDump( pncbi->ncb_buffer, pncbi->ncb_length ); } break; case NCBCANCEL: // Buffer has been loaded with the NCB to be cancelled NbPrintf(( "ncb_buffer contents:\n")); FormattedDump( pncbi->ncb_buffer, sizeof(NCB)); break; } NbPrintf(( "\n\n" )); } VOID NbPrint( char *Format, ... ) /*++ Routine Description: This routine is equivalent to printf with the output being directed to stdout. Arguments: IN char *Format - Supplies string to be output and describes following (optional) parameters. Return Value: none. --*/ { va_list arglist; char OutputBuffer[1024]; ULONG length; if ( NbDllDebug == 0 ) { return; } va_start( arglist, Format ); vsprintf( OutputBuffer, Format, arglist ); va_end( arglist ); if ( UseConsole ) { DbgPrint( "%s", OutputBuffer ); } else { length = strlen( OutputBuffer ); if ( LogFile == INVALID_HANDLE_VALUE ) { if ( UseLogFile ) { LogFile = CreateFile( LOGNAME, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if ( LogFile == INVALID_HANDLE_VALUE ) { // Could not access logfile so use stdout instead UseLogFile = FALSE; LogFile = GetStdHandle(STD_OUTPUT_HANDLE); } } else { // Use the applications stdout file. LogFile = GetStdHandle(STD_OUTPUT_HANDLE); } } WriteFile( LogFile , (LPVOID )OutputBuffer, length, &length, NULL ); } } // NbPrint void FormattedDump( PCHAR far_p, LONG len ) /*++ Routine Description: This routine outputs a buffer in lines of text containing hex and printable characters. Arguments: IN far_p - Supplies buffer to be displayed. IN len - Supplies the length of the buffer in bytes. Return Value: none. --*/ { ULONG l; char s[80], t[80]; if ( len > NbMaxDump ) { len = NbMaxDump; } while (len) { l = len < 16 ? len : 16; NbPrintf (("%lx ", far_p)); HexDumpLine (far_p, l, s, t); NbPrintf (("%s%.*s%s\n", s, 1 + ((16 - l) * 3), "", t)); len -= l; far_p += l; } } VOID HexDumpLine( PCHAR pch, ULONG len, PCHAR s, PCHAR t ) /*++ Routine Description: This routine builds a line of text containing hex and printable characters. Arguments: IN pch - Supplies buffer to be displayed. IN len - Supplies the length of the buffer in bytes. IN s - Supplies the start of the buffer to be loaded with the string of hex characters. IN t - Supplies the start of the buffer to be loaded with the string of printable ascii characters. Return Value: none. --*/ { static UCHAR rghex[] = "0123456789ABCDEF"; UCHAR c; UCHAR *hex, *asc; hex = s; asc = t; *(asc++) = '*'; while (len--) { c = *(pch++); *(hex++) = rghex [c >> 4] ; *(hex++) = rghex [c & 0x0F]; *(hex++) = ' '; *(asc++) = (c < ' ' || c > '~') ? (CHAR )'.' : c; } *(asc++) = '*'; *asc = 0; *hex = 0; } #endif