]>
Commit | Line | Data |
---|---|---|
fbd26352 | 1 | /* Copyright (C) 2012-2019 Free Software Foundation, Inc. |
b710ec85 | 2 | |
3 | This file is part of GCC. | |
4 | ||
5 | GCC is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3, or (at your option) | |
8 | any later version. | |
9 | ||
10 | GCC is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | Under Section 7 of GPL version 3, you are granted additional | |
16 | permissions described in the GCC Runtime Library Exception, version | |
17 | 3.1, as published by the Free Software Foundation. | |
18 | ||
19 | You should have received a copy of the GNU General Public License and | |
20 | a copy of the GCC Runtime Library Exception along with this program; | |
21 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
22 | <http://www.gnu.org/licenses/>. */ | |
23 | ||
24 | /* This file is part of the vtable verication runtime library (see | |
25 | comments in vtv_rts.cc for more information about vtable | |
26 | verification). This file contains log file utilities. */ | |
27 | ||
28 | #include <sys/types.h> | |
29 | #include <sys/stat.h> | |
30 | #include <fcntl.h> | |
31 | #include <stdarg.h> | |
32 | #include <stdio.h> | |
83628c60 | 33 | #include <stdlib.h> |
b710ec85 | 34 | #include <string.h> |
5be42fa9 | 35 | #if defined (__CYGWIN__) || defined (__MINGW32__) |
36 | #include <windows.h> | |
37 | #else | |
b710ec85 | 38 | #include <execinfo.h> |
5be42fa9 | 39 | #endif |
40 | ||
b710ec85 | 41 | #include <unistd.h> |
42 | #include <errno.h> | |
43 | ||
44 | #include "vtv_utils.h" | |
45 | ||
83628c60 | 46 | #ifndef HAVE_SECURE_GETENV |
47 | # ifdef HAVE___SECURE_GETENV | |
48 | # define secure_getenv __secure_getenv | |
49 | # else | |
50 | # define secure_getenv getenv | |
51 | # endif | |
52 | #endif | |
b710ec85 | 53 | |
83628c60 | 54 | static int vtv_failures_log_fd = -1; |
b710ec85 | 55 | |
56 | /* This function takes the NAME of a log file to open, attempts to | |
57 | open it in the logs_dir directory, and returns the resulting file | |
83628c60 | 58 | descriptor. |
59 | ||
60 | This function first checks to see if the user has specifed (via | |
61 | the environment variable VTV_LOGS_DIR) a directory to use for the | |
62 | vtable verification logs. If that fails, the function will open | |
63 | the logs in the current directory. | |
64 | */ | |
b710ec85 | 65 | |
66 | int | |
67 | __vtv_open_log (const char *name) | |
68 | { | |
83628c60 | 69 | char log_name[1024]; |
70 | char log_dir[512]; | |
5be42fa9 | 71 | #if defined (__CYGWIN__) || defined (__MINGW32__) |
72 | pid_t process_id = GetCurrentProcessId (); | |
73 | #else | |
83628c60 | 74 | uid_t user_id = getuid (); |
75 | pid_t process_id = getpid (); | |
5be42fa9 | 76 | #endif |
83628c60 | 77 | char *logs_prefix; |
78 | bool logs_dir_specified = false; | |
79 | int fd = -1; | |
80 | ||
81 | logs_prefix = secure_getenv ("VTV_LOGS_DIR"); | |
82 | if (logs_prefix && strlen (logs_prefix) > 0) | |
83 | { | |
84 | logs_dir_specified = true; | |
5be42fa9 | 85 | #ifdef __MINGW32__ |
86 | mkdir (logs_prefix); | |
87 | #else | |
83628c60 | 88 | mkdir (logs_prefix, S_IRWXU); |
5be42fa9 | 89 | #endif |
90 | ||
83628c60 | 91 | snprintf (log_dir, sizeof (log_dir), "%s/vtv_logs", logs_prefix); |
83628c60 | 92 | |
5be42fa9 | 93 | #ifdef __MINGW32__ |
94 | mkdir (log_dir); | |
95 | #else | |
96 | mkdir (log_dir, S_IRWXU); | |
97 | #endif | |
98 | #if defined (__CYGWIN__) || defined (__MINGW32__) | |
99 | snprintf (log_name, sizeof (log_name), "%s_%d_%s", log_dir, | |
100 | (unsigned) process_id, name); | |
101 | fd = open (log_name, O_WRONLY | O_APPEND | O_CREAT, S_IRWXU); | |
102 | #else | |
83628c60 | 103 | snprintf (log_name, sizeof (log_name), "%s/%d_%d_%s", log_dir, |
104 | (unsigned) user_id, (unsigned) process_id, name); | |
105 | fd = open (log_name, O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW, | |
106 | S_IRWXU); | |
5be42fa9 | 107 | #endif |
83628c60 | 108 | } |
109 | else | |
110 | fd = dup (2); | |
111 | ||
b710ec85 | 112 | if (fd == -1) |
113 | __vtv_add_to_log (2, "Cannot open log file %s %s\n", name, | |
114 | strerror (errno)); | |
115 | return fd; | |
116 | } | |
117 | ||
118 | /* This function takes a file descriptor (FD) and a string (STR) and | |
119 | tries to write the string to the file. */ | |
120 | ||
121 | static int | |
122 | vtv_log_write (int fd, const char *str) | |
123 | { | |
124 | if (write (fd, str, strlen (str)) != -1) | |
125 | return 0; | |
126 | ||
127 | if (fd != 2) /* Make sure we dont get in a loop. */ | |
128 | __vtv_add_to_log (2, "Error writing to log: %s\n", strerror (errno)); | |
129 | return -1; | |
130 | } | |
131 | ||
132 | ||
133 | /* This function takes a file decriptor (LOG_FILE) and an output | |
134 | format string (FORMAT), followed by zero or more print format | |
135 | arguments (the same as fprintf, for example). It gets the current | |
136 | process ID and PPID, pre-pends them to the formatted message, and | |
137 | writes write it out to the log file referenced by LOG_FILE via calles | |
138 | to vtv_log_write. */ | |
139 | ||
140 | int | |
141 | __vtv_add_to_log (int log_file, const char * format, ...) | |
142 | { | |
143 | /* We dont want to dynamically allocate this buffer. This should be | |
144 | more than enough in most cases. It if isn't we are careful not to | |
145 | do a buffer overflow. */ | |
146 | char output[1024]; | |
147 | ||
148 | va_list ap; | |
149 | va_start (ap, format); | |
150 | ||
5be42fa9 | 151 | #if defined (__CYGWIN__) || defined (__MINGW32__) |
152 | snprintf (output, sizeof (output), "VTV: PID=%ld ", GetCurrentProcessId ()); | |
153 | #else | |
b710ec85 | 154 | snprintf (output, sizeof (output), "VTV: PID=%d PPID=%d ", getpid (), |
155 | getppid ()); | |
5be42fa9 | 156 | #endif |
b710ec85 | 157 | vtv_log_write (log_file, output); |
158 | vsnprintf (output, sizeof (output), format, ap); | |
159 | vtv_log_write (log_file, output); | |
160 | va_end (ap); | |
161 | ||
162 | return 0; | |
163 | } | |
164 | ||
165 | /* Open error logging file, if not already open, and write vtable | |
166 | verification failure messages (LOG_MSG) to the log file. Also | |
167 | generate a backtrace in the log file, if GENERATE_BACKTRACE is | |
168 | set. */ | |
169 | ||
170 | void | |
171 | __vtv_log_verification_failure (const char *log_msg, bool generate_backtrace) | |
172 | { | |
173 | if (vtv_failures_log_fd == -1) | |
174 | vtv_failures_log_fd = __vtv_open_log ("vtable_verification_failures.log"); | |
175 | ||
176 | if (vtv_failures_log_fd == -1) | |
177 | return; | |
178 | ||
179 | __vtv_add_to_log (vtv_failures_log_fd, "%s", log_msg); | |
180 | ||
5be42fa9 | 181 | #if !defined (__CYGWIN__) && !defined (__MINGW32__) |
b710ec85 | 182 | if (generate_backtrace) |
183 | { | |
184 | #define STACK_DEPTH 20 | |
185 | void *callers[STACK_DEPTH]; | |
186 | int actual_depth = backtrace (callers, STACK_DEPTH); | |
187 | backtrace_symbols_fd (callers, actual_depth, vtv_failures_log_fd); | |
188 | } | |
5be42fa9 | 189 | #endif |
b710ec85 | 190 | } |