1/*
2 Copyright (c) 2001, 2011, Oracle and/or its affiliates
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17#include <my_global.h>
18#include <my_stacktrace.h>
19
20#ifndef __WIN__
21#include <signal.h>
22#include <my_pthread.h>
23#include <m_string.h>
24#ifdef HAVE_STACKTRACE
25#include <unistd.h>
26#include <strings.h>
27
28#ifdef __linux__
29#include <ctype.h> /* isprint */
30#include <sys/syscall.h> /* SYS_gettid */
31#endif
32
33#if HAVE_EXECINFO_H
34#include <execinfo.h>
35#endif
36
37#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
38
39static char *heap_start;
40
41#if(defined HAVE_BSS_START) && !(defined __linux__)
42extern char *__bss_start;
43#endif
44
45void my_init_stacktrace()
46{
47#if(defined HAVE_BSS_START) && !(defined __linux__)
48 heap_start = (char*) &__bss_start;
49#endif
50}
51
52#ifdef __linux__
53
54static void print_buffer(char *buffer, size_t count)
55{
56 const char s[]= " ";
57 for (; count && *buffer; --count)
58 {
59 my_write_stderr(isprint(*buffer) ? buffer : s, 1);
60 ++buffer;
61 }
62}
63
64/**
65 Access the pages of this process through /proc/self/task/<tid>/mem
66 in order to safely print the contents of a memory address range.
67
68 @param addr The address at the start of the memory region.
69 @param max_len The length of the memory region.
70
71 @return Zero on success.
72*/
73static int safe_print_str(const char *addr, size_t max_len)
74{
75 int fd;
76 pid_t tid;
77 off_t offset;
78 ssize_t nbytes= 0;
79 size_t total, count;
80 char buf[256];
81
82 tid= (pid_t) syscall(SYS_gettid);
83
84 sprintf(buf, "/proc/self/task/%d/mem", tid);
85
86 if ((fd= open(buf, O_RDONLY)) < 0)
87 return -1;
88
89 /* Ensure that off_t can hold a pointer. */
90 compile_time_assert(sizeof(off_t) >= sizeof(intptr));
91
92 total= max_len;
93 offset= (intptr) addr;
94
95 /* Read up to the maximum number of bytes. */
96 while (total)
97 {
98 count= MY_MIN(sizeof(buf), total);
99
100 if ((nbytes= pread(fd, buf, count, offset)) < 0)
101 {
102 /* Just in case... */
103 if (errno == EINTR)
104 continue;
105 else
106 break;
107 }
108
109 /* Advance offset into memory. */
110 total-= nbytes;
111 offset+= nbytes;
112 addr+= nbytes;
113
114 /* Output the printable characters. */
115 print_buffer(buf, nbytes);
116
117 /* Break if less than requested... */
118 if ((count - nbytes))
119 break;
120 }
121
122 if (nbytes == -1)
123 my_safe_printf_stderr("Can't read from address %p", addr);
124
125 close(fd);
126
127 return 0;
128}
129
130#endif
131
132/*
133 Attempt to print a char * pointer as a string.
134
135 SYNOPSIS
136 Prints either until the end of string ('\0'), or max_len characters have
137 been printed.
138
139 RETURN VALUE
140 0 Pointer was within the heap address space.
141 The string was printed fully, or until the end of the heap address space.
142 1 Pointer is outside the heap address space. Printed as invalid.
143
144 NOTE
145 On some systems, we can have valid pointers outside the heap address space.
146 This is through the use of mmap inside malloc calls. When this function
147 returns 1, it does not mean 100% that the pointer is corrupted.
148*/
149
150int my_safe_print_str(const char* val, size_t max_len)
151{
152 char *heap_end;
153
154#ifdef __linux__
155 // Try and make use of /proc filesystem to safely print memory contents.
156 if (!safe_print_str(val, max_len))
157 return 0;
158#endif
159
160 heap_end= (char*) sbrk(0);
161
162 if (!PTR_SANE(val))
163 {
164 my_safe_printf_stderr("%s", "is an invalid pointer");
165 return 1;
166 }
167
168 for (; max_len && PTR_SANE(val) && *val; --max_len)
169 my_write_stderr((val++), 1);
170 my_safe_printf_stderr("%s", "\n");
171
172 return 0;
173}
174
175#if defined(HAVE_PRINTSTACK)
176
177/* Use Solaris' symbolic stack trace routine. */
178#include <ucontext.h>
179
180void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)),
181 ulong thread_stack __attribute__((unused)),
182 my_bool silent)
183{
184 if (printstack(fileno(stderr)) == -1)
185 my_safe_printf_stderr("%s",
186 "Error when traversing the stack, stack appears corrupt.\n");
187 else if (!silent)
188 my_safe_printf_stderr("%s",
189 "Please read "
190 "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
191 "and follow instructions on how to resolve the stack trace.\n"
192 "Resolved stack trace is much more helpful in diagnosing the\n"
193 "problem, so please do resolve it\n");
194}
195
196#elif HAVE_BACKTRACE && (HAVE_BACKTRACE_SYMBOLS || HAVE_BACKTRACE_SYMBOLS_FD)
197
198#if BACKTRACE_DEMANGLE
199
200char __attribute__ ((weak)) *
201my_demangle(const char *mangled_name __attribute__((unused)),
202 int *status __attribute__((unused)))
203{
204 return NULL;
205}
206
207static void my_demangle_symbols(char **addrs, int n)
208{
209 int status, i;
210 char *begin, *end, *demangled;
211
212 for (i= 0; i < n; i++)
213 {
214 demangled= NULL;
215 begin= strchr(addrs[i], '(');
216 end= begin ? strchr(begin, '+') : NULL;
217
218 if (begin && end)
219 {
220 *begin++= *end++= '\0';
221 demangled= my_demangle(begin, &status);
222 if (!demangled || status)
223 {
224 demangled= NULL;
225 begin[-1]= '(';
226 end[-1]= '+';
227 }
228 }
229
230 if (demangled)
231 my_safe_printf_stderr("%s(%s+%s\n", addrs[i], demangled, end);
232 else
233 my_safe_printf_stderr("%s\n", addrs[i]);
234 }
235}
236
237#endif /* BACKTRACE_DEMANGLE */
238
239#if HAVE_MY_ADDR_RESOLVE
240static int print_with_addr_resolve(void **addrs, int n)
241{
242 int i;
243 const char *err;
244
245 if ((err= my_addr_resolve_init()))
246 {
247 my_safe_printf_stderr("(my_addr_resolve failure: %s)\n", err);
248 return 0;
249 }
250
251 for (i= 0; i < n; i++)
252 {
253 my_addr_loc loc;
254 if (my_addr_resolve(addrs[i], &loc))
255 backtrace_symbols_fd(addrs+i, 1, fileno(stderr));
256 else
257 my_safe_printf_stderr("%s:%u(%s)[%p]\n",
258 loc.file, loc.line, loc.func, addrs[i]);
259 }
260 return 1;
261}
262#endif
263
264void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack,
265 my_bool silent __attribute__((unused)))
266{
267 void *addrs[128];
268 char **strings __attribute__((unused)) = NULL;
269 int n = backtrace(addrs, array_elements(addrs));
270 my_safe_printf_stderr("stack_bottom = %p thread_stack 0x%lx\n",
271 stack_bottom, thread_stack);
272#if HAVE_MY_ADDR_RESOLVE
273 if (print_with_addr_resolve(addrs, n))
274 return;
275#endif
276#if BACKTRACE_DEMANGLE
277 if ((strings= backtrace_symbols(addrs, n)))
278 {
279 my_demangle_symbols(strings, n);
280 free(strings);
281 return;
282 }
283#endif
284#if HAVE_BACKTRACE_SYMBOLS_FD
285 backtrace_symbols_fd(addrs, n, fileno(stderr));
286#endif
287}
288
289#elif defined(TARGET_OS_LINUX)
290
291#ifdef __i386__
292#define SIGRETURN_FRAME_OFFSET 17
293#endif
294
295#ifdef __x86_64__
296#define SIGRETURN_FRAME_OFFSET 23
297#endif
298
299#if defined(__alpha__) && defined(__GNUC__)
300/*
301 The only way to backtrace without a symbol table on alpha
302 is to find stq fp,N(sp), and the first byte
303 of the instruction opcode will give us the value of N. From this
304 we can find where the old value of fp is stored
305*/
306
307#define MAX_INSTR_IN_FUNC 10000
308
309inline uchar** find_prev_fp(uint32* pc, uchar** fp)
310{
311 int i;
312 for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
313 {
314 uchar* p = (uchar*)pc;
315 if (p[2] == 222 && p[3] == 35)
316 {
317 return (uchar**)((uchar*)fp - *(short int*)p);
318 }
319 }
320 return 0;
321}
322
323inline uint32* find_prev_pc(uint32* pc, uchar** fp)
324{
325 int i;
326 for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
327 {
328 char* p = (char*)pc;
329 if (p[1] == 0 && p[2] == 94 && p[3] == -73)
330 {
331 uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp)));
332 return prev_pc;
333 }
334 }
335 return 0;
336}
337#endif /* defined(__alpha__) && defined(__GNUC__) */
338
339void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack,
340 my_bool silent)
341{
342 uchar** UNINIT_VAR(fp);
343 uint frame_count = 0, sigreturn_frame_count;
344#if defined(__alpha__) && defined(__GNUC__)
345 uint32* pc;
346#endif
347
348
349#ifdef __i386__
350 __asm __volatile__ ("movl %%ebp,%0"
351 :"=r"(fp)
352 :"r"(fp));
353#endif
354#ifdef __x86_64__
355 __asm __volatile__ ("movq %%rbp,%0"
356 :"=r"(fp)
357 :"r"(fp));
358#endif
359#if defined(__alpha__) && defined(__GNUC__)
360 __asm __volatile__ ("mov $30,%0"
361 :"=r"(fp)
362 :"r"(fp));
363#endif
364 if (!fp)
365 {
366 my_safe_printf_stderr("%s",
367 "frame pointer is NULL, did you compile with\n"
368 "-fomit-frame-pointer? Aborting backtrace!\n");
369 return;
370 }
371
372 if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp)
373 {
374 ulong tmp= MY_MIN(0x10000,thread_stack);
375 /* Assume that the stack starts at the previous even 65K */
376 stack_bottom= (uchar*) (((ulong) &fp + tmp) & ~(ulong) 0xFFFF);
377 my_safe_printf_stderr("Cannot determine thread, fp=%p, "
378 "backtrace may not be correct.\n", fp);
379 }
380 if (fp > (uchar**) stack_bottom ||
381 fp < (uchar**) stack_bottom - thread_stack)
382 {
383 my_safe_printf_stderr("Bogus stack limit or frame pointer, "
384 "fp=%p, stack_bottom=%p, thread_stack=%ld, "
385 "aborting backtrace.\n",
386 fp, stack_bottom, thread_stack);
387 return;
388 }
389
390 my_safe_printf_stderr("%s",
391 "Stack range sanity check OK, backtrace follows:\n");
392#if defined(__alpha__) && defined(__GNUC__)
393 my_safe_printf_stderr("%s",
394 "Warning: Alpha stacks are difficult -"
395 "will be taking some wild guesses, stack trace may be incorrect or "
396 "terminate abruptly\n");
397
398 /* On Alpha, we need to get pc */
399 __asm __volatile__ ("bsr %0, do_next; do_next: "
400 :"=r"(pc)
401 :"r"(pc));
402#endif /* __alpha__ */
403
404 /* We are 1 frame above signal frame with NPTL and 2 frames above with LT */
405 sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
406
407 while (fp < (uchar**) stack_bottom)
408 {
409#if defined(__i386__) || defined(__x86_64__)
410 uchar** new_fp = (uchar**)*fp;
411 my_safe_printf_stderr("%p\n",
412 frame_count == sigreturn_frame_count ?
413 *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
414#endif /* defined(__386__) || defined(__x86_64__) */
415
416#if defined(__alpha__) && defined(__GNUC__)
417 uchar** new_fp = find_prev_fp(pc, fp);
418 if (frame_count == sigreturn_frame_count - 1)
419 {
420 new_fp += 90;
421 }
422
423 if (fp && pc)
424 {
425 pc = find_prev_pc(pc, fp);
426 if (pc)
427 my_safe_printf_stderr("%p\n", pc);
428 else
429 {
430 my_safe_printf_stderr("%s",
431 "Not smart enough to deal with the rest of this stack\n");
432 goto end;
433 }
434 }
435 else
436 {
437 my_safe_printf_stderr("%s",
438 "Not smart enough to deal with the rest of this stack\n");
439 goto end;
440 }
441#endif /* defined(__alpha__) && defined(__GNUC__) */
442 if (new_fp <= fp )
443 {
444 my_safe_printf_stderr("New value of fp=%p failed sanity check, "
445 "terminating stack trace!\n", new_fp);
446 goto end;
447 }
448 fp = new_fp;
449 ++frame_count;
450 }
451 my_safe_printf_stderr("%s",
452 "Stack trace seems successful - bottom reached\n");
453
454end:
455 if (!silent)
456 my_safe_printf_stderr("%s",
457 "Please read "
458 "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
459 "and follow instructions on how to resolve the stack trace.\n"
460 "Resolved stack trace is much more helpful in diagnosing the\n"
461 "problem, so please do resolve it\n");
462}
463#endif /* TARGET_OS_LINUX */
464#endif /* HAVE_STACKTRACE */
465
466/* Produce a core for the thread */
467void my_write_core(int sig)
468{
469#ifdef HAVE_gcov
470 extern void __gcov_flush(void);
471#endif
472 signal(sig, SIG_DFL);
473#ifdef HAVE_gcov
474 /*
475 For GCOV build, crashing will prevent the writing of code coverage
476 information from this process, causing gcov output to be incomplete.
477 So we force the writing of coverage information here before terminating.
478 */
479 __gcov_flush();
480#endif
481 pthread_kill(pthread_self(), sig);
482#if defined(P_MYID) && !defined(SCO)
483 /* On Solaris, the above kill is not enough */
484 sigsend(P_PID,P_MYID,sig);
485#endif
486}
487
488#else /* __WIN__*/
489
490#ifdef _MSC_VER
491/* Silence warning in OS header dbghelp.h */
492#pragma warning(push)
493#pragma warning(disable : 4091)
494#endif
495
496#include <dbghelp.h>
497
498#ifdef _MSC_VER
499#pragma warning(pop)
500#endif
501
502#include <tlhelp32.h>
503#include <my_sys.h>
504#if _MSC_VER
505#pragma comment(lib, "dbghelp")
506#endif
507
508static EXCEPTION_POINTERS *exception_ptrs;
509
510#define MODULE64_SIZE_WINXP 576
511#define STACKWALK_MAX_FRAMES 64
512
513void my_init_stacktrace()
514{
515}
516
517
518void my_set_exception_pointers(EXCEPTION_POINTERS *ep)
519{
520 exception_ptrs = ep;
521}
522
523/*
524 Appends directory to symbol path.
525*/
526static void add_to_symbol_path(char *path, size_t path_buffer_size,
527 char *dir, size_t dir_buffer_size)
528{
529 strcat_s(dir, dir_buffer_size, ";");
530 if (!strstr(path, dir))
531 {
532 strcat_s(path, path_buffer_size, dir);
533 }
534}
535
536/*
537 Get symbol path - semicolon-separated list of directories to search
538 for debug symbols. We expect PDB in the same directory as
539 corresponding exe or dll, so the path is build from directories of
540 the loaded modules. If environment variable _NT_SYMBOL_PATH is set,
541 it's value appended to the symbol search path
542*/
543static void get_symbol_path(char *path, size_t size)
544{
545 HANDLE hSnap;
546 char *envvar;
547 char *p;
548#ifndef DBUG_OFF
549 static char pdb_debug_dir[MAX_PATH + 7];
550#endif
551
552 path[0]= '\0';
553
554#ifndef DBUG_OFF
555 /*
556 Add "debug" subdirectory of the application directory, sometimes PDB will
557 placed here by installation.
558 */
559 GetModuleFileName(NULL, pdb_debug_dir, MAX_PATH);
560 p= strrchr(pdb_debug_dir, '\\');
561 if(p)
562 {
563 *p= 0;
564 strcat_s(pdb_debug_dir, sizeof(pdb_debug_dir), "\\debug;");
565 add_to_symbol_path(path, size, pdb_debug_dir, sizeof(pdb_debug_dir));
566 }
567#endif
568
569 /*
570 Enumerate all modules, and add their directories to the path.
571 Avoid duplicate entries.
572 */
573 hSnap= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
574 if (hSnap != INVALID_HANDLE_VALUE)
575 {
576 BOOL ret;
577 MODULEENTRY32 mod;
578 mod.dwSize= sizeof(MODULEENTRY32);
579 for (ret= Module32First(hSnap, &mod); ret; ret= Module32Next(hSnap, &mod))
580 {
581 char *module_dir= mod.szExePath;
582 p= strrchr(module_dir,'\\');
583 if (!p)
584 {
585 /*
586 Path separator was not found. Not known to happen, if ever happens,
587 will indicate current directory.
588 */
589 module_dir[0]= '.';
590 module_dir[1]= '\0';
591 }
592 else
593 {
594 *p= '\0';
595 }
596 add_to_symbol_path(path, size, module_dir,sizeof(mod.szExePath));
597 }
598 CloseHandle(hSnap);
599 }
600
601
602 /* Add _NT_SYMBOL_PATH, if present. */
603 envvar= getenv("_NT_SYMBOL_PATH");
604 if(envvar)
605 {
606 strcat_s(path, size, envvar);
607 }
608}
609
610#define MAX_SYMBOL_PATH 32768
611
612/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/
613#ifndef SYMOPT_NO_PROMPTS
614#define SYMOPT_NO_PROMPTS 0
615#endif
616
617void my_print_stacktrace(uchar* unused1, ulong unused2, my_bool silent)
618{
619 HANDLE hProcess= GetCurrentProcess();
620 HANDLE hThread= GetCurrentThread();
621 static IMAGEHLP_MODULE64 module= {sizeof(module)};
622 static IMAGEHLP_SYMBOL64_PACKAGE package;
623 DWORD64 addr;
624 DWORD machine;
625 int i;
626 CONTEXT context;
627 STACKFRAME64 frame={0};
628 static char symbol_path[MAX_SYMBOL_PATH];
629
630 if(!exception_ptrs)
631 return;
632
633 /* Copy context, as stackwalking on original will unwind the stack */
634 context = *(exception_ptrs->ContextRecord);
635 /*Initialize symbols.*/
636 SymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);
637 get_symbol_path(symbol_path, sizeof(symbol_path));
638 SymInitialize(hProcess, symbol_path, TRUE);
639
640 /*Prepare stackframe for the first StackWalk64 call*/
641 frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat;
642#if (defined _M_IX86)
643 machine= IMAGE_FILE_MACHINE_I386;
644 frame.AddrFrame.Offset= context.Ebp;
645 frame.AddrPC.Offset= context.Eip;
646 frame.AddrStack.Offset= context.Esp;
647#elif (defined _M_X64)
648 machine = IMAGE_FILE_MACHINE_AMD64;
649 frame.AddrFrame.Offset= context.Rbp;
650 frame.AddrPC.Offset= context.Rip;
651 frame.AddrStack.Offset= context.Rsp;
652#else
653 /*There is currently no need to support IA64*/
654#pragma error ("unsupported architecture")
655#endif
656
657 package.sym.SizeOfStruct= sizeof(package.sym);
658 package.sym.MaxNameLength= sizeof(package.name);
659
660 /*Walk the stack, output useful information*/
661 for(i= 0; i< STACKWALK_MAX_FRAMES;i++)
662 {
663 DWORD64 function_offset= 0;
664 DWORD line_offset= 0;
665 IMAGEHLP_LINE64 line= {sizeof(line)};
666 BOOL have_module= FALSE;
667 BOOL have_symbol= FALSE;
668 BOOL have_source= FALSE;
669
670 if(!StackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0))
671 break;
672 addr= frame.AddrPC.Offset;
673
674 have_module= SymGetModuleInfo64(hProcess,addr,&module);
675#ifdef _M_IX86
676 if(!have_module)
677 {
678 /*
679 ModuleInfo structure has been "compatibly" extended in
680 releases after XP, and its size was increased. To make XP
681 dbghelp.dll function happy, pretend passing the old structure.
682 */
683 module.SizeOfStruct= MODULE64_SIZE_WINXP;
684 have_module= SymGetModuleInfo64(hProcess, addr, &module);
685 }
686#endif
687
688 have_symbol= SymGetSymFromAddr64(hProcess, addr, &function_offset,
689 &(package.sym));
690 have_source= SymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
691
692 if(have_module)
693 {
694 const char *base_image_name= my_basename(module.ImageName);
695 my_safe_printf_stderr("%s!", base_image_name);
696 }
697 if(have_symbol)
698 my_safe_printf_stderr("%s()", package.sym.Name);
699
700 else if(have_module)
701 my_safe_printf_stderr("%s", "???");
702
703 if(have_source)
704 {
705 const char *base_file_name= my_basename(line.FileName);
706 my_safe_printf_stderr("[%s:%lu]",
707 base_file_name, line.LineNumber);
708 }
709 my_safe_printf_stderr("%s", "\n");
710 }
711}
712
713
714/*
715 Write dump. The dump is created in current directory,
716 file name is constructed from executable name plus
717 ".dmp" extension
718*/
719void my_write_core(int unused)
720{
721 char path[MAX_PATH];
722 char dump_fname[MAX_PATH]= "core.dmp";
723 MINIDUMP_EXCEPTION_INFORMATION info;
724 HANDLE hFile;
725
726 if(!exception_ptrs)
727 return;
728
729 info.ExceptionPointers= exception_ptrs;
730 info.ClientPointers= FALSE;
731 info.ThreadId= GetCurrentThreadId();
732
733 if(GetModuleFileName(NULL, path, sizeof(path)))
734 {
735 _splitpath(path, NULL, NULL,dump_fname,NULL);
736 strcat_s(dump_fname, sizeof(dump_fname), ".dmp");
737 }
738
739 hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
740 FILE_ATTRIBUTE_NORMAL, 0);
741 if(hFile)
742 {
743 /* Create minidump */
744 if(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
745 hFile, MiniDumpNormal, &info, 0, 0))
746 {
747 my_safe_printf_stderr("Minidump written to %s\n",
748 _fullpath(path, dump_fname, sizeof(path)) ?
749 path : dump_fname);
750 }
751 else
752 {
753 my_safe_printf_stderr("MiniDumpWriteDump() failed, last error %u\n",
754 (uint) GetLastError());
755 }
756 CloseHandle(hFile);
757 }
758 else
759 {
760 my_safe_printf_stderr("CreateFile(%s) failed, last error %u\n",
761 dump_fname, (uint) GetLastError());
762 }
763}
764
765
766int my_safe_print_str(const char *val, size_t len)
767{
768 __try
769 {
770 my_write_stderr(val, len);
771 }
772 __except(EXCEPTION_EXECUTE_HANDLER)
773 {
774 my_safe_printf_stderr("%s", "is an invalid string pointer");
775 }
776 return 0;
777}
778#endif /*__WIN__*/
779
780
781size_t my_write_stderr(const void *buf, size_t count)
782{
783 return (size_t) write(fileno(stderr), buf, (uint)count);
784}
785
786
787size_t my_safe_printf_stderr(const char* fmt, ...)
788{
789 char to[512];
790 size_t result;
791 va_list args;
792 va_start(args,fmt);
793 result= my_vsnprintf(to, sizeof(to), fmt, args);
794 va_end(args);
795 my_write_stderr(to, result);
796 return result;
797}
798