1 /*
2 * Copyright (c) 2019-2022 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file     mos_util_debug_specific.cpp
24 //! \brief    This module implments Linux MOS debug functionalities
25 //!
26 
27 #include "mos_util_debug.h"
28 #include "mos_util_debug_specific.h"
29 #include "mos_oca_rtlog_mgr_defs.h"
30 #include "mos_interface.h"
31 #include <stdlib.h>
32 
33 #if MOS_MESSAGES_ENABLED
34 
35 #include "mos_utilities_specific.h"
36 #include "media_user_setting.h"
37 #include "string.h"
38 #include <time.h>      //get_clocktime
39 #include <unistd.h>    //read, lseek
40 #include <fcntl.h>     //open
41 
42 #ifdef ANDROID
43 #include <android/log.h>
44 #else
45 #include <signal.h>
46 #endif // ANDROID
47 
48 #define MOS_ULT_LOG_PATH_PREFIX     "./"
49 
50 //!
51 //! \brief HLT log file prefix
52 //!
53 #define MOS_LOG_PATH_PREFIX     "/etc/log"
54 
55 #define HLT_COPY_BUFFER_LENGTH 200
56 
MosHltpCopyFile(PFILE pFile,const PCCHAR szFileName)57 MOS_STATUS MosUtilDebug::MosHltpCopyFile(PFILE pFile, const PCCHAR szFileName)
58 {
59     PFILE   pFileSrc;
60     char    szBuffer[HLT_COPY_BUFFER_LENGTH];
61     int32_t nRead;
62 
63     nRead = 0;
64     if( (pFileSrc = fopen(szFileName , "r" )) == nullptr)
65     {
66         printf("open file %s failed", szFileName);
67         return MOS_STATUS_FILE_OPEN_FAILED;
68     }
69     do
70     {
71         nRead = fread(szBuffer, 1, HLT_COPY_BUFFER_LENGTH, pFileSrc);
72         if( ( nRead > 0 ) && (nRead <= HLT_COPY_BUFFER_LENGTH) )
73         {
74             fwrite(szBuffer, 1, nRead, pFile);
75         }
76     } while( nRead > 0 );
77 
78     fclose(pFileSrc);
79 
80     return MOS_STATUS_SUCCESS;
81 }
82 
MosHltpPreface(PFILE pFile)83 void MosUtilDebug::MosHltpPreface(PFILE pFile)
84 {
85     time_t      rawtime;
86     struct tm*  timeinfo;
87 
88     time(&rawtime);
89     timeinfo = localtime(&rawtime);
90     if (timeinfo == nullptr)
91     {
92         printf("fail to call localtime in MosHltpPreface\n");
93         return;
94     }
95 
96     fprintf(pFile, "//\n"
97                    "// HLT log file: version1.0\n"
98                    "// Logtime %d-%d-%d %d:%d:%d; Machine=",
99                    timeinfo->tm_year,timeinfo->tm_mon, timeinfo->tm_yday,
100                    timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec);
101 
102     fwrite("\n", 1, 1, pFile);
103     MosHltpCopyFile(pFile, "/etc/hosts");
104 
105     // This section has been temporarily commented out because it's printing a non standard character to the logfile and corrupting it.
106     /*
107     fprintf(pFile, "\n"
108                    "// PID=%d; Process name=",
109                    getpid());
110 
111     MosHltpCopyFile(pFile, "/proc/self/cmdline");
112     */
113 
114     fwrite("\n", 1, 1, pFile);
115 
116     MosHltpCopyFile(pFile, "/proc/version");
117     // Linux version 2.6.35-22-generic (buildd@rothera) (gcc version 4.4.5 (Ubuntu/Linaro // 4.4.4-14ubuntu4) ) #33-Ubuntu SMP Sun Sep 19 20:34:50 UTC 2010
118 
119     if (m_mosMsgParams.bEnableMaps)
120     {
121         fwrite("\n// Loaded modules:\n", 20, 1, pFile);
122 
123         MosHltpCopyFile(pFile, "/proc/self/maps");
124         fwrite("\n", 1, 1, pFile);
125     }
126 
127     fflush(pFile);
128 }
129 
MosLogFileNamePrefix(char * fileNamePrefix,MediaUserSettingSharedPtr userSettingPtr)130 MOS_STATUS MosUtilDebug::MosLogFileNamePrefix(char *fileNamePrefix, MediaUserSettingSharedPtr userSettingPtr)
131 {
132     int32_t                             iRet = 0;
133     MOS_STATUS                          eStatus = MOS_STATUS_UNKNOWN;
134     MediaUserSetting::Value             outValue;
135 
136     if (MosUtilities::m_mosUltFlag && (*MosUtilities::m_mosUltFlag))
137     {
138         iRet =  MosUtilities::MosSecureStringPrint(
139                      fileNamePrefix,
140                      MOS_MAX_HLT_FILENAME_LEN,
141                      MOS_MAX_HLT_FILENAME_LEN,
142                      MOS_ULT_LOG_PATH_PREFIX);
143 
144         if (iRet > 0)
145         {
146             eStatus = MOS_STATUS_SUCCESS;
147         }
148 
149         return eStatus;
150     }
151 
152     eStatus = ReadUserSetting(
153         userSettingPtr,
154         outValue,
155         __MOS_USER_FEATURE_KEY_MESSAGE_HLT_OUTPUT_DIRECTORY,
156         MediaUserSetting::Group::Device);
157 
158     if(outValue.ConstString().size() > 0 && outValue.ConstString().size() < MOS_MAX_HLT_FILENAME_LEN)
159     {
160         MosUtilities::MosSecureStrcpy(fileNamePrefix, MOS_MAX_HLT_FILENAME_LEN, outValue.ConstString().c_str());
161     }
162     else     // If the user feature key was not found or not valid, create it with the default value.
163     {
164         MOS_OS_NORMALMESSAGE("eStatus = %x, outValue.size = %x", eStatus, outValue.ConstString().size());
165 
166         iRet = MosUtilities::MosSecureStringPrint(
167                      fileNamePrefix,
168                      MOS_MAX_HLT_FILENAME_LEN,
169                      MOS_MAX_HLT_FILENAME_LEN,
170                      MOS_LOG_PATH_PREFIX);
171 
172         if (iRet > 0)
173         {
174             eStatus = ReportUserSetting(
175                 userSettingPtr,
176                 __MOS_USER_FEATURE_KEY_MESSAGE_HLT_OUTPUT_DIRECTORY,
177                 fileNamePrefix,
178                 MediaUserSetting::Group::Device);
179         }
180         else
181         {
182             return MOS_STATUS_UNKNOWN;
183         }
184     }
185 
186     return eStatus;
187 }
188 
MosMessageInternal(MOS_MESSAGE_LEVEL level,MOS_COMPONENT_ID compID,uint8_t subCompID,const PCCHAR functionName,int32_t lineNum,const PCCHAR message,va_list var_args)189 void MosUtilDebug::MosMessageInternal(
190     MOS_MESSAGE_LEVEL level,
191     MOS_COMPONENT_ID  compID,
192     uint8_t           subCompID,
193     const PCCHAR      functionName,
194     int32_t           lineNum,
195     const PCCHAR      message,
196     va_list           var_args)
197 {
198     uint32_t nLen = 0;
199     PCCHAR func = functionName;
200     static MOS_MUTEX mosMsgMutex = PTHREAD_MUTEX_INITIALIZER;
201 
202     if (MosShouldPrintMessage(level, compID, subCompID, message) == false)
203     {
204         return;
205     }
206     if (level == MOS_MESSAGE_LVL_CRITICAL)
207     {
208         OcaOnMosCriticalMessage(functionName, lineNum);
209     }
210 
211     MosUtilities::MosLockMutex(&mosMsgMutex);
212     // Proceed to print the message
213     if (functionName == nullptr)
214     {
215         MosUtilities::MosSecureStringPrint(m_mosMsgParams.g_MosMsgBuffer,
216                 MOS_MAX_MSG_BUF_SIZE,
217                 (MOS_MAX_MSG_BUF_SIZE-1),
218                 "%s%s - ",
219                 m_mosComponentName[compID],
220                 m_mosLogLevelName[level]);
221         nLen = strlen(m_mosMsgParams.g_MosMsgBuffer);
222     }
223     else
224     {
225 #if USE_PRETTY_FUNCTION
226         // call MosGetClassMethod to convert pretty function to class::function
227         // return string locate in static memory, mutex should be hold.
228         func = MosGetClassMethod(functionName);
229 #endif //USE_PRETTY_FUNCTION
230         if (lineNum < 0)
231         {
232             // no line number output
233             MosUtilities::MosSecureStringPrint(m_mosMsgParams.g_MosMsgBuffer,
234                 MOS_MAX_MSG_BUF_SIZE,
235                 (MOS_MAX_MSG_BUF_SIZE-1),
236                 "%s%s - %s",
237                 m_mosComponentName[compID],
238                 m_mosLogLevelName[level],
239                 func);
240             nLen = strlen(m_mosMsgParams.g_MosMsgBuffer);
241         }
242         else
243         {
244             MosUtilities::MosSecureStringPrint(m_mosMsgParams.g_MosMsgBuffer,
245                     MOS_MAX_MSG_BUF_SIZE,
246                     (MOS_MAX_MSG_BUF_SIZE-1),
247                     "%s%s - %s:%d: ",
248                     m_mosComponentName[compID],
249                     m_mosLogLevelName[level],
250                     func,
251                     lineNum);
252             nLen = strlen(m_mosMsgParams.g_MosMsgBuffer);
253         }
254     }
255     MosUtilities::MosSecureVStringPrint(m_mosMsgParams.g_MosMsgBuffer + nLen,
256                 MOS_MAX_MSG_BUF_SIZE - nLen,
257                 (MOS_MAX_MSG_BUF_SIZE - 1 - nLen),
258                 message,
259                 var_args);
260 
261     // Dump message to debugger if print to output window enabled
262     if (m_mosMsgParams.bUseOutputDebugString)
263     {
264         printf("%s\n", m_mosMsgParams.g_MosMsgBuffer);
265     }
266 
267     // Write to log file if HLT enabled. File already open to add preface information
268     if (m_mosMsgParams.bUseHybridLogTrace)
269     {
270         if (m_mosMsgParams.pLogFile != nullptr)
271         {
272             nLen = strlen(m_mosMsgParams.g_MosMsgBuffer);
273             fwrite(m_mosMsgParams.g_MosMsgBuffer, nLen, 1, m_mosMsgParams.pLogFile);
274             fprintf(m_mosMsgParams.pLogFile, "\n");
275         }
276         else
277         {
278             printf("ERROR: m_mosMsgParams.pLogFile is NULL!\n");
279         }
280     }
281     MosUtilities::MosUnlockMutex(&mosMsgMutex);
282 
283     return;
284 }
285 
286 //!
287 //! When printing from a C++ class, we'd like the class and function to be printed.
288 //! With our current Linux compiler, __FUNCTION__ does not include the class name.
289 //! So we use __PRETTY_FUNCTION__ and call MosGetClassMethod(__PRETTY_FUNCTION__) to remove extra data.
290 //! This is not needed for prints from C files so they will usually use __FUNCTION__.
291 //!
292 #if USE_PRETTY_FUNCTION
293 
294 //!
295 //! functionName is used to temporarily store the concatinated __PRETTY_FUNCTION__,
296 //! when calling MosGetClassMethod().
297 //!
298 
MosGetClassMethod(PCCHAR pcPrettyFunction)299 PCCHAR MosUtilDebug::MosGetClassMethod(PCCHAR pcPrettyFunction)
300 {
301     PCCHAR end  = nullptr;
302     uint32_t len  = 0;
303     static char functionName[256] = {}; // 256 is an arbitrary long enough size.
304 
305     memset(functionName, '\0', sizeof(functionName));
306 
307     // Find the first '(', if it exists.
308     end = strchr(pcPrettyFunction, '(');
309 
310     // We want to copy pcPrettyFunction into gFunction, only up to the first '('.
311     len = end ? (uint32_t)(end - pcPrettyFunction) : strlen(pcPrettyFunction);
312 
313     MosUtilities::MosSecureMemcpy(functionName, sizeof(functionName), pcPrettyFunction, len);
314 
315     // dismiss anything before the last ' '.
316     return strrchr(functionName, ' ') ? strrchr(functionName, ' ') + 1 : functionName;
317 }
318 
319 #endif // USE_PRETTY_FUNCTION
320 
321 #if MOS_ASSERT_ENABLED
322 
MosAssert(MOS_COMPONENT_ID compID,uint8_t subCompID)323 void MosUtilDebug::MosAssert(MOS_COMPONENT_ID compID, uint8_t subCompID)
324 {
325     if (MosShouldAssert(compID, subCompID) == false)
326     {
327         return;
328     }
329 
330     //! NOTE:
331     //! If you hit asserts here and do not want to, you can cancel them by updating user feature keys under __MEDIA_USER_FEATURE_SUBKEY_INTERNAL.
332     //! These keys can be found in USER_FEATURE_FILE (currently "/etc/igfx_user_feature.txt").
333     //! First figure out what component is asserting (check element number compID in MOS_COMPONENT_ID).
334     //! Then in the user feature key "<component> Message Tags", set the forth bit to zero.
335     raise(SIGTRAP);
336 }
337 
338 #endif // MOS_ASSERT_ENABLED
339 
340 #endif // MOS_MESSAGES_ENABLED
341