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 <cinttypes>
20 #include <cstdio>
21
22 #include "chre/platform/log.h"
23
24 namespace chre {
25
print(const char * formatStr,...)26 void DebugDumpWrapper::print(const char *formatStr, ...) {
27 va_list argList;
28 va_start(argList, formatStr);
29 printVaList(formatStr, argList);
30 va_end(argList);
31 }
32
printVaList(const char * formatStr,va_list argList)33 void DebugDumpWrapper::printVaList(const char *formatStr, va_list argList) {
34 va_list argListCopy;
35 va_copy(argListCopy, argList);
36
37 if (mCurrBuff != nullptr || allocNewBuffer()) {
38 bool sizeValid;
39 size_t sizeOfStr;
40 if (!insertString(formatStr, argList, &sizeValid, &sizeOfStr)) {
41 if (!sizeValid) {
42 LOGE("Error inserting string into buffer in debug dump");
43 } else if (sizeOfStr >= kBuffSize) {
44 LOGE(
45 "String was too large to fit in a single buffer for debug dump "
46 "print");
47 } else if (allocNewBuffer()) {
48 // Insufficient space left in buffer, allocate a new one and it's
49 // guaranteed to succeed.
50 bool success =
51 insertString(formatStr, argListCopy, &sizeValid, &sizeOfStr);
52 CHRE_ASSERT(success);
53 }
54 }
55 }
56 va_end(argListCopy);
57 }
58
allocNewBuffer()59 bool DebugDumpWrapper::allocNewBuffer() {
60 mCurrBuff = static_cast<char *>(memoryAlloc(kBuffSize));
61 if (mCurrBuff == nullptr) {
62 LOG_OOM();
63 } else {
64 mBuffers.emplace_back(mCurrBuff);
65 mBuffPos = 0;
66 mCurrBuff[0] = '\0';
67 }
68 return mCurrBuff != nullptr;
69 }
70
insertString(const char * formatStr,va_list argList,bool * sizeValid,size_t * sizeOfStr)71 bool DebugDumpWrapper::insertString(const char *formatStr, va_list argList,
72 bool *sizeValid, size_t *sizeOfStr) {
73 CHRE_ASSERT(mCurrBuff != nullptr);
74 CHRE_ASSERT(mBuffPos <= kBuffSize);
75
76 // Buffer space left
77 size_t spaceLeft = kBuffSize - mBuffPos;
78
79 // Note strLen doesn't count the terminating null character.
80 int strLen = vsnprintf(&mCurrBuff[mBuffPos], spaceLeft, formatStr, argList);
81 size_t strSize = static_cast<size_t>(strLen);
82
83 bool success = false;
84 *sizeValid = false;
85 if (strLen >= 0) {
86 *sizeValid = true;
87
88 if (strSize >= spaceLeft) {
89 // Chop off the incomplete string.
90 mCurrBuff[mBuffPos] = '\0';
91 } else {
92 success = true;
93 mBuffPos += strSize;
94 }
95 }
96
97 *sizeOfStr = strSize;
98 return success;
99 }
100
logErrorHistogram(const uint32_t * histogram,uint8_t histogramLength)101 void DebugDumpWrapper::logErrorHistogram(const uint32_t *histogram,
102 uint8_t histogramLength) {
103 print(" [");
104 for (int i = 0; i < histogramLength; i++) {
105 print("%" PRIu32, histogram[i]);
106 if (i < histogramLength - 1) {
107 print(",");
108 }
109 }
110 print("]\n");
111 }
112
113 } // namespace chre
114