| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <ctype.h> | |
| #include "debugtools.h" | |
| #include "thread.h" | |
| #include "winbase.h" | |
| #include "winnt.h" | |
| #include "wtypes.h" | |
| /* ---------------------------------------------------------------------- */ | |
| struct debug_info | |
| { | |
| char *str_pos; /* current position in strings buffer */ | |
| char *out_pos; /* current position in output buffer */ | |
| char strings[500]; /* buffer for temporary strings */ | |
| char output[500]; /* current output line */ | |
| }; | |
| static struct debug_info tmp; | |
| static inline struct debug_info *get_info(void) | |
| { | |
| struct debug_info *info = NtCurrentTeb()->debug_info; | |
| if (!info) | |
| { | |
| /* setup the temp structure in case HeapAlloc wants to print something */ | |
| NtCurrentTeb()->debug_info = &tmp; | |
| tmp.str_pos = tmp.strings; | |
| tmp.out_pos = tmp.output; | |
| info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) ); | |
| info->str_pos = info->strings; | |
| info->out_pos = info->output; | |
| NtCurrentTeb()->debug_info = info; | |
| } | |
| return info; | |
| } | |
| /* ---------------------------------------------------------------------- */ | |
| static void * | |
| gimme1 (int n) | |
| { | |
| struct debug_info *info = get_info(); | |
| char *res = info->str_pos; | |
| if (res + n >= &info->strings[sizeof(info->strings)]) res = info->strings; | |
| info->str_pos = res + n; | |
| return res; | |
| } | |
| /* ---------------------------------------------------------------------- */ | |
| /* release extra space that we requested in gimme1() */ | |
| static inline void release( void *ptr ) | |
| { | |
| struct debug_info *info = NtCurrentTeb()->debug_info; | |
| info->str_pos = ptr; | |
| } | |
| /* ---------------------------------------------------------------------- */ | |
| LPCSTR debugstr_an (LPCSTR src, int n) | |
| { | |
| LPSTR dst, res; | |
| if (!src) return "(null)"; | |
| if (n < 0) n = 0; | |
| dst = res = gimme1 (n * 4 + 6); | |
| *dst++ = '"'; | |
| while (n-- > 0 && *src) | |
| { | |
| BYTE c = *src++; | |
| switch (c) | |
| { | |
| case '\n': *dst++ = '\\'; *dst++ = 'n'; break; | |
| case '\r': *dst++ = '\\'; *dst++ = 'r'; break; | |
| case '\t': *dst++ = '\\'; *dst++ = 't'; break; | |
| case '"': *dst++ = '\\'; *dst++ = '"'; break; | |
| case '\\': *dst++ = '\\'; *dst++ = '\\'; break; | |
| default: | |
| if (c >= ' ' && c <= 126) | |
| *dst++ = c; | |
| else | |
| { | |
| *dst++ = '\\'; | |
| *dst++ = '0' + ((c >> 6) & 7); | |
| *dst++ = '0' + ((c >> 3) & 7); | |
| *dst++ = '0' + ((c >> 0) & 7); | |
| } | |
| } | |
| } | |
| *dst++ = '"'; | |
| if (*src) | |
| { | |
| *dst++ = '.'; | |
| *dst++ = '.'; | |
| *dst++ = '.'; | |
| } | |
| *dst++ = '\0'; | |
| release( dst ); | |
| return res; | |
| } | |
| /* ---------------------------------------------------------------------- */ | |
| LPCSTR debugstr_wn (LPCWSTR src, int n) | |
| { | |
| LPSTR dst, res; | |
| if (!src) return "(null)"; | |
| if (n < 0) n = 0; | |
| dst = res = gimme1 (n * 5 + 7); | |
| *dst++ = 'L'; | |
| *dst++ = '"'; | |
| while (n-- > 0 && *src) | |
| { | |
| WORD c = *src++; | |
| switch (c) | |
| { | |
| case '\n': *dst++ = '\\'; *dst++ = 'n'; break; | |
| case '\r': *dst++ = '\\'; *dst++ = 'r'; break; | |
| case '\t': *dst++ = '\\'; *dst++ = 't'; break; | |
| case '"': *dst++ = '\\'; *dst++ = '"'; break; | |
| case '\\': *dst++ = '\\'; *dst++ = '\\'; break; | |
| default: | |
| if (c >= ' ' && c <= 126) | |
| *dst++ = c; | |
| else | |
| { | |
| *dst++ = '\\'; | |
| sprintf(dst,"%04x",c); | |
| dst+=4; | |
| } | |
| } | |
| } | |
| *dst++ = '"'; | |
| if (*src) | |
| { | |
| *dst++ = '.'; | |
| *dst++ = '.'; | |
| *dst++ = '.'; | |
| } | |
| *dst++ = '\0'; | |
| release( dst ); | |
| return res; | |
| } | |
| /* ---------------------------------------------------------------------- */ | |
| /* This routine returns a nicely formated name of the resource res | |
| If the resource name is a string, it will return '<res-name>' | |
| If it is a number, it will return #<4-digit-hex-number> */ | |
| LPCSTR debugres_a( LPCSTR res ) | |
| { | |
| char *resname; | |
| if (HIWORD(res)) return debugstr_a(res); | |
| resname = gimme1(6); | |
| sprintf(resname, "#%04x", LOWORD(res) ); | |
| return resname; | |
| } | |
| LPCSTR debugres_w( LPCWSTR res ) | |
| { | |
| char *resname; | |
| if (HIWORD(res)) return debugstr_w(res); | |
| resname = gimme1(6); | |
| sprintf( resname, "#%04x", LOWORD(res) ); | |
| return resname; | |
| } | |
| /* ---------------------------------------------------------------------- */ | |
| LPCSTR debugstr_guid( const GUID *id ) | |
| { | |
| LPSTR str; | |
| if (!id) return "(null)"; | |
| if (!HIWORD(id)) | |
| { | |
| str = gimme1(12); | |
| sprintf( str, "<guid-0x%04x>", LOWORD(id) ); | |
| } | |
| else | |
| { | |
| str = gimme1(40); | |
| sprintf( str, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", | |
| id->Data1, id->Data2, id->Data3, | |
| id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], | |
| id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); | |
| } | |
| return str; | |
| } | |
| /* ---------------------------------------------------------------------- */ | |
| int dbg_vprintf( const char *format, va_list args ) | |
| { | |
| struct debug_info *info = get_info(); | |
| int ret = vsprintf( info->out_pos, format, args ); | |
| char *p = strrchr( info->out_pos, '\n' ); | |
| if (!p) info->out_pos += ret; | |
| else | |
| { | |
| char *pos = info->output; | |
| p++; | |
| write( 2, pos, p - pos ); | |
| /* move beginning of next line to start of buffer */ | |
| while ((*pos = *p++)) pos++; | |
| info->out_pos = pos; | |
| } | |
| return ret; | |
| } | |
| /* ---------------------------------------------------------------------- */ | |
| int dbg_printf(const char *format, ...) | |
| { | |
| int ret; | |
| va_list valist; | |
| va_start(valist, format); | |
| ret = dbg_vprintf( format, valist); | |
| va_end(valist); | |
| return ret; | |
| } | |
| /*--< Function >--------------------------------------------------------- | |
| ** | |
| ** debugstr_hex_dump | |
| ** | |
| ** Description: | |
| ** This function creates a hex dump, with a readable ascii | |
| ** section, for displaying memory. | |
| ** | |
| ** Parameters: | |
| ** 1. ptr Pointer to memory | |
| ** 2. len How much to dump. | |
| ** | |
| ** Returns: | |
| ** Temporarily allocated buffer, with the hex dump in it. | |
| ** Don't rely on this pointer being around for very long, just | |
| ** long enough to use it in a TRACE statement; e.g.: | |
| ** TRACE("struct dump is \n%s", debugstr_hex_dump(&x, sizeof(x))); | |
| ** | |
| **-------------------------------------------------------------------------*/ | |
| LPCSTR debugstr_hex_dump (const void *ptr, int len) | |
| { | |
| /* Locals */ | |
| char dumpbuf[59]; | |
| char charbuf[20]; | |
| char tempbuf[8]; | |
| const char *p; | |
| int i; | |
| unsigned int nosign; | |
| LPSTR dst; | |
| LPSTR outptr; | |
| /* Begin function dbg_hex_dump */ | |
| /*----------------------------------------------------------------------- | |
| ** Allocate an output buffer | |
| ** A reasonable value is one line overhand (80 chars), and | |
| ** then one line (80) for every 16 bytes. | |
| **---------------------------------------------------------------------*/ | |
| outptr = dst = gimme1 ((len * (80 / 16)) + 80); | |
| /*----------------------------------------------------------------------- | |
| ** Loop throught the input buffer, one character at a time | |
| **---------------------------------------------------------------------*/ | |
| for (i = 0, p = ptr; (i < len); i++, p++) | |
| { | |
| /*------------------------------------------------------------------- | |
| ** If we're just starting a line, | |
| ** we need to possibly flush the old line, and then | |
| ** intialize the line buffer. | |
| **-----------------------------------------------------------------*/ | |
| if ((i % 16) == 0) | |
| { | |
| if (i) | |
| { | |
| sprintf(outptr, " %-43.43s %-16.16s\n", dumpbuf, charbuf); | |
| outptr += strlen(outptr); | |
| } | |
| sprintf (dumpbuf, "%04x: ", i); | |
| strcpy (charbuf, ""); | |
| } | |
| /*------------------------------------------------------------------- | |
| ** Add the current data byte to the dump section. | |
| **-----------------------------------------------------------------*/ | |
| nosign = (unsigned char) *p; | |
| sprintf (tempbuf, "%02X", nosign); | |
| /*------------------------------------------------------------------- | |
| ** If we're two DWORDS through, add a hyphen for readability, | |
| ** if it's a DWORD boundary, add a space for more | |
| ** readability. | |
| **-----------------------------------------------------------------*/ | |
| if ((i % 16) == 7) | |
| strcat(tempbuf, " - "); | |
| else if ( (i % 4) == 3) | |
| strcat(tempbuf, " "); | |
| strcat (dumpbuf, tempbuf); | |
| /*------------------------------------------------------------------- | |
| ** Add the current byte to the character display part of the | |
| ** hex dump | |
| **-----------------------------------------------------------------*/ | |
| sprintf (tempbuf, "%c", isprint(*p) ? *p : '.'); | |
| strcat (charbuf, tempbuf); | |
| } | |
| /*----------------------------------------------------------------------- | |
| ** Flush the last line, if any | |
| **---------------------------------------------------------------------*/ | |
| if (i > 0) | |
| { | |
| sprintf(outptr, " %-43.43s %-16.16s\n", dumpbuf, charbuf); | |
| outptr += strlen(outptr); | |
| } | |
| return(dst); | |
| } /* End function dbg_hex_dump */ | |