Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #if defined (UNX) || defined (__GNUC__)
21 : #include <unistd.h>
22 : #else
23 : #include <direct.h>
24 : #endif
25 :
26 : #include <errno.h>
27 : #include <time.h>
28 : #include <cstdarg>
29 : #include <stdlib.h>
30 : #include <string.h>
31 : #include <stdio.h>
32 :
33 : #if defined ( WNT )
34 : #include <windows.h>
35 : #endif
36 :
37 : #include "com/sun/star/task/ErrorCodeIOException.hpp"
38 : #include <tools/debug.hxx>
39 : #include <rtl/string.h>
40 : #include <sal/log.hxx>
41 : #include <sal/macros.h>
42 :
43 : #include <vector>
44 :
45 : #include <osl/diagnose.h>
46 : #include <tools/diagnose_ex.h>
47 :
48 : #ifdef DBG_UTIL
49 :
50 : struct DebugData
51 : {
52 : DbgData aDbgData;
53 : bool bInit;
54 : DbgTestSolarMutexProc pDbgTestSolarMutex;
55 :
56 : DebugData()
57 : :bInit( false )
58 : ,pDbgTestSolarMutex( NULL )
59 : {
60 : aDbgData.nTestFlags = DBG_TEST_RESOURCE;
61 : aDbgData.aDbgWinState[0] = 0;
62 : }
63 : };
64 :
65 : static DebugData aDebugData;
66 :
67 : #define FILE_LINEEND "\n"
68 :
69 : typedef FILE* FILETYPE;
70 : #define FileOpen fopen
71 : #define FileRead fread
72 : #define FilePrintF fprintf
73 : #define FileClose fclose
74 :
75 : namespace
76 : {
77 : enum ConfigSection
78 : {
79 : eGUI,
80 : eTest,
81 :
82 : eUnknown
83 : };
84 :
85 : void lcl_lineFeed( FILETYPE _pFile )
86 : {
87 : FilePrintF( _pFile, "%s", FILE_LINEEND );
88 : }
89 :
90 : const sal_Char* lcl_getSectionName( ConfigSection _eSection )
91 : {
92 : const sal_Char* pSectionName = NULL;
93 : switch ( _eSection )
94 : {
95 : case eGUI : pSectionName = "gui"; break;
96 : case eTest : pSectionName = "test"; break;
97 : case eUnknown:
98 : OSL_ASSERT(false);
99 : break;
100 : }
101 : return pSectionName;
102 : }
103 :
104 : ConfigSection lcl_getSectionFromName( const sal_Char* _pSectionName, size_t _nSectionNameLength )
105 : {
106 : if ( strncmp( _pSectionName, "gui", _nSectionNameLength < 3 ? _nSectionNameLength : 3 ) == 0 )
107 : return eGUI;
108 : if ( strncmp( _pSectionName, "test", _nSectionNameLength < 4 ? _nSectionNameLength : 4 ) == 0 )
109 : return eTest;
110 : return eUnknown;
111 : }
112 :
113 : void lcl_startSection( FILETYPE _pFile, ConfigSection _eSection )
114 : {
115 : FilePrintF( _pFile, "[%s]%s", lcl_getSectionName( _eSection ), FILE_LINEEND );
116 : }
117 :
118 : void lcl_writeConfigString( FILETYPE _pFile, const sal_Char* _pKeyName, const sal_Char* _pValue )
119 : {
120 : FilePrintF( _pFile, "%s=%s%s", _pKeyName, _pValue, FILE_LINEEND );
121 : }
122 :
123 : void lcl_writeConfigBoolean( FILETYPE _pFile, const sal_Char* _pKeyName, bool _bValue )
124 : {
125 : lcl_writeConfigString( _pFile, _pKeyName, _bValue ? "1" : "0" );
126 : }
127 :
128 : void lcl_writeConfigFlag( FILETYPE _pFile, const sal_Char* _pKeyName, sal_uIntPtr _nAllFlags, sal_uIntPtr _nCheckFlag )
129 : {
130 : lcl_writeConfigBoolean( _pFile, _pKeyName, ( _nAllFlags & _nCheckFlag ) != 0 );
131 : }
132 :
133 : bool lcl_isConfigSection( const sal_Char* _pLine, size_t _nLineLen )
134 : {
135 : if ( _nLineLen < 2 )
136 : // not even enough space for '[' and ']'
137 : return false;
138 : if ( ( _pLine[0] == '[' ) && ( _pLine[ _nLineLen - 1 ] == ']' ) )
139 : return true;
140 : return false;
141 : }
142 :
143 : bool lcl_isConfigKey( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName )
144 : {
145 : size_t nKeyLength = strlen( _pKeyName );
146 : if ( nKeyLength + 1 >= _nLineLen )
147 : // not even long enough for the key name plus "=" plus a one-character value
148 : return false;
149 : if ( ( strncmp( _pLine, _pKeyName, nKeyLength ) == 0 ) && ( _pLine[ nKeyLength ] == '=' ) )
150 : return true;
151 : return false;
152 : }
153 :
154 : sal_Int32 lcl_tryReadConfigString( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_Char* _pValue, size_t _nValueLen )
155 : {
156 : if ( !lcl_isConfigKey( _pLine, _nLineLen, _pKeyName ) )
157 : return 0;
158 : size_t nValuePos = strlen( _pKeyName ) + 1;
159 : size_t nValueLen = _nLineLen - nValuePos;
160 : const sal_Char* pValue = _pLine + nValuePos;
161 : strncpy( _pValue, pValue, ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen );
162 : _pValue[ ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen - 1 ] = 0;
163 : return strlen( _pValue );
164 : }
165 :
166 : void lcl_tryReadConfigFlag( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uIntPtr* _out_pnAllFlags, sal_uIntPtr _nCheckFlag )
167 : {
168 : sal_Char aBuf[2];
169 : size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
170 : if ( nValueLen )
171 : {
172 : if ( strcmp( aBuf, "1" ) == 0 )
173 : *_out_pnAllFlags |= _nCheckFlag;
174 : else
175 : *_out_pnAllFlags &= ~_nCheckFlag;
176 : }
177 : }
178 : }
179 :
180 : static void DbgGetDbgFileName( sal_Char* pStr, sal_Int32 nMaxLen )
181 : {
182 : #if defined( UNX )
183 : const sal_Char* pName = getenv("DBGSV_INIT");
184 : if ( !pName )
185 : pName = ".dbgsv.init";
186 : strncpy( pStr, pName, nMaxLen );
187 : #elif defined( WNT )
188 : const sal_Char* pName = getenv("DBGSV_INIT");
189 : if ( pName )
190 : strncpy( pStr, pName, nMaxLen );
191 : else
192 : GetProfileStringA( "sv", "dbgsv", "dbgsv.ini", pStr, nMaxLen );
193 : #else
194 : strncpy( pStr, "dbgsv.ini", nMaxLen );
195 : #endif
196 : pStr[ nMaxLen - 1 ] = 0;
197 : }
198 :
199 : static DebugData* GetDebugData()
200 : {
201 : if ( !aDebugData.bInit )
202 : {
203 : aDebugData.bInit = true;
204 :
205 : // DEBUG.INI-File
206 : sal_Char aBuf[ 4096 ];
207 : DbgGetDbgFileName( aBuf, sizeof( aBuf ) );
208 : FILETYPE pIniFile = FileOpen( aBuf, "r" );
209 : if ( pIniFile != NULL )
210 : {
211 : ConfigSection eCurrentSection = eUnknown;
212 :
213 : // no sophisticated algorithm here, assume that the whole file fits into aBuf ...
214 : sal_uIntPtr nReallyRead = FileRead( aBuf, 1, sizeof( aBuf ) / sizeof( sal_Char ) - 1, pIniFile );
215 : aBuf[ nReallyRead ] = 0;
216 : const sal_Char* pLine = aBuf;
217 : while ( const sal_Char* pNextLine = strstr( pLine, FILE_LINEEND ) )
218 : {
219 : size_t nLineLength = pNextLine - pLine;
220 :
221 : if ( lcl_isConfigSection( pLine, nLineLength ) )
222 : eCurrentSection = lcl_getSectionFromName( pLine + 1, nLineLength - 2 );
223 :
224 : // elements of the [gui] section
225 : if ( eCurrentSection == eGUI )
226 : {
227 : lcl_tryReadConfigString( pLine, nLineLength, "debug_window_state", aDebugData.aDbgData.aDbgWinState, sizeof( aDebugData.aDbgData.aDbgWinState ) );
228 : }
229 :
230 : // elements of the [test] section
231 : if ( eCurrentSection == eTest )
232 : {
233 : lcl_tryReadConfigFlag( pLine, nLineLength, "resources", &aDebugData.aDbgData.nTestFlags, DBG_TEST_RESOURCE );
234 : lcl_tryReadConfigFlag( pLine, nLineLength, "dialog", &aDebugData.aDbgData.nTestFlags, DBG_TEST_DIALOG );
235 : lcl_tryReadConfigFlag( pLine, nLineLength, "bold_app_font", &aDebugData.aDbgData.nTestFlags, DBG_TEST_BOLDAPPFONT );
236 : }
237 :
238 : pLine = pNextLine + strlen( FILE_LINEEND );
239 : }
240 :
241 : FileClose( pIniFile );
242 : }
243 : }
244 :
245 : return &aDebugData;
246 : }
247 :
248 : inline DebugData* ImplGetDebugData()
249 : {
250 : if ( !aDebugData.bInit )
251 : return GetDebugData();
252 : else
253 : return &aDebugData;
254 : }
255 :
256 : void* DbgFunc( sal_uInt16 nAction, void* pParam )
257 : {
258 : DebugData* pDebugData = ImplGetDebugData();
259 :
260 : if ( nAction == DBG_FUNC_GETDATA )
261 : return (void*)&(pDebugData->aDbgData);
262 : else
263 : {
264 : switch ( nAction )
265 : {
266 : case DBG_FUNC_SAVEDATA:
267 : {
268 : const DbgData* pData = static_cast< const DbgData* >( pParam );
269 :
270 : sal_Char aBuf[ 4096 ];
271 : DbgGetDbgFileName( aBuf, sizeof( aBuf ) );
272 : FILETYPE pIniFile = FileOpen( aBuf, "w" );
273 : if ( pIniFile == NULL )
274 : break;
275 :
276 : lcl_lineFeed( pIniFile );
277 : lcl_startSection( pIniFile, eGUI );
278 : lcl_writeConfigString( pIniFile, "debug_window_state", pData->aDbgWinState );
279 :
280 : lcl_lineFeed( pIniFile );
281 : lcl_startSection( pIniFile, eTest );
282 : lcl_writeConfigFlag( pIniFile, "resources", pData->nTestFlags, DBG_TEST_RESOURCE );
283 : lcl_writeConfigFlag( pIniFile, "dialog", pData->nTestFlags, DBG_TEST_DIALOG );
284 : lcl_writeConfigFlag( pIniFile, "bold_app_font", pData->nTestFlags, DBG_TEST_BOLDAPPFONT );
285 :
286 : FileClose( pIniFile );
287 : }
288 : break;
289 :
290 : case DBG_FUNC_SETTESTSOLARMUTEX:
291 : pDebugData->pDbgTestSolarMutex = (DbgTestSolarMutexProc)(long)pParam;
292 : break;
293 :
294 : case DBG_FUNC_TESTSOLARMUTEX:
295 : SAL_WARN_IF(
296 : pDebugData->pDbgTestSolarMutex == 0, "tools.debug",
297 : "no DbgTestSolarMutex function set");
298 : if ( pDebugData->pDbgTestSolarMutex )
299 : pDebugData->pDbgTestSolarMutex();
300 : break;
301 : }
302 :
303 : return NULL;
304 : }
305 : }
306 :
307 : #else
308 :
309 0 : void* DbgFunc( sal_uInt16, void* ) { return NULL; }
310 :
311 : #endif
312 :
313 :
314 0 : TOOLS_DLLPUBLIC void DbgUnhandledException(const css::uno::Any & caught, const char* currentFunction, const char* fileAndLineNo)
315 : {
316 : #if OSL_DEBUG_LEVEL == 0
317 : (void) caught;
318 : (void) currentFunction;
319 : (void) fileAndLineNo;
320 : #else
321 : OString sMessage( "caught an exception!" );
322 : sMessage += "\nin function:";
323 : sMessage += currentFunction;
324 : sMessage += "\ntype: ";
325 : sMessage += OUStringToOString( caught.getValueTypeName(), osl_getThreadTextEncoding() );
326 : ::com::sun::star::uno::Exception exception;
327 : caught >>= exception;
328 : if ( !exception.Message.isEmpty() )
329 : {
330 : sMessage += "\nmessage: ";
331 : sMessage += OUStringToOString( exception.Message, osl_getThreadTextEncoding() );
332 : }
333 : if ( exception.Context.is() )
334 : {
335 : const char* pContext = typeid( *exception.Context.get() ).name();
336 : sMessage += "\ncontext: ";
337 : sMessage += pContext;
338 : }
339 : {
340 : ::com::sun::star::configuration::CorruptedConfigurationException
341 : specialized;
342 : if ( caught >>= specialized )
343 : {
344 : sMessage += "\ndetails: ";
345 : sMessage += OUStringToOString(
346 : specialized.Details, osl_getThreadTextEncoding() );
347 : }
348 : }
349 : {
350 : ::com::sun::star::task::ErrorCodeIOException specialized;
351 : if ( caught >>= specialized )
352 : {
353 : sMessage += "\ndetails: ";
354 : sMessage += OString::number( specialized.ErrCode );
355 : }
356 : }
357 : sMessage += "\n";
358 :
359 : SAL_DETAIL_LOG_FORMAT(
360 : SAL_DETAIL_ENABLE_LOG_WARN, SAL_DETAIL_LOG_LEVEL_WARN,
361 : "legacy.osl", fileAndLineNo, "%s", sMessage.getStr());
362 : #endif
363 0 : }
364 :
365 :
366 :
367 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|