1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "chre/util/system/debug_dump.h"
18 
19 #include <cstdio>
20 
21 #include "chre/platform/log.h"
22 
23 namespace chre {
24 
print(const char * formatStr,...)25 void DebugDumpWrapper::print(const char *formatStr, ...) {
26   va_list argList;
27   va_start(argList, formatStr);
28   printVaList(formatStr, argList);
29   va_end(argList);
30 }
31 
printVaList(const char * formatStr,va_list argList)32 void DebugDumpWrapper::printVaList(const char *formatStr, va_list argList) {
33   va_list argListCopy;
34   va_copy(argListCopy, argList);
35 
36   if (mCurrBuff != nullptr || allocNewBuffer()) {
37     bool sizeValid;
38     size_t sizeOfStr;
39     if (!insertString(formatStr, argList, &sizeValid, &sizeOfStr)) {
40       if (!sizeValid) {
41         LOGE("Error inserting string into buffer in debug dump");
42       } else if (sizeOfStr >= kBuffSize) {
43         LOGE(
44             "String was too large to fit in a single buffer for debug dump "
45             "print");
46       } else if (allocNewBuffer()) {
47         // Insufficient space left in buffer, allocate a new one and it's
48         // guaranteed to succeed.
49         bool success =
50             insertString(formatStr, argListCopy, &sizeValid, &sizeOfStr);
51         CHRE_ASSERT(success);
52       }
53     }
54   }
55   va_end(argListCopy);
56 }
57 
allocNewBuffer()58 bool DebugDumpWrapper::allocNewBuffer() {
59   mCurrBuff = static_cast<char *>(memoryAlloc(kBuffSize));
60   if (mCurrBuff == nullptr) {
61     LOG_OOM();
62   } else {
63     mBuffers.emplace_back(mCurrBuff);
64     mBuffPos = 0;
65     mCurrBuff[0] = '\0';
66   }
67   return mCurrBuff != nullptr;
68 }
69 
insertString(const char * formatStr,va_list argList,bool * sizeValid,size_t * sizeOfStr)70 bool DebugDumpWrapper::insertString(const char *formatStr, va_list argList,
71                                     bool *sizeValid, size_t *sizeOfStr) {
72   CHRE_ASSERT(mCurrBuff != nullptr);
73   CHRE_ASSERT(mBuffPos <= kBuffSize);
74 
75   // Buffer space left
76   size_t spaceLeft = kBuffSize - mBuffPos;
77 
78   // Note strLen doesn't count the terminating null character.
79   int strLen = vsnprintf(&mCurrBuff[mBuffPos], spaceLeft, formatStr, argList);
80   size_t strSize = static_cast<size_t>(strLen);
81 
82   bool success = false;
83   *sizeValid = false;
84   if (strLen >= 0) {
85     *sizeValid = true;
86 
87     if (strSize >= spaceLeft) {
88       // Chop off the incomplete string.
89       mCurrBuff[mBuffPos] = '\0';
90     } else {
91       success = true;
92       mBuffPos += strSize;
93     }
94   }
95 
96   *sizeOfStr = strSize;
97   return success;
98 }
99 
100 }  // namespace chre
101