| /* | |
| * Copyright (C) 2005 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <binder/Debug.h> | |
| #include <binder/ProcessState.h> | |
| #include <utils/misc.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <ctype.h> | |
| namespace android { | |
| // --------------------------------------------------------------------- | |
| static const char indentStr[] = | |
| " " | |
| " "; | |
| const char* stringForIndent(int32_t indentLevel) | |
| { | |
| ssize_t off = sizeof(indentStr)-1-(indentLevel*2); | |
| return indentStr + (off < 0 ? 0 : off); | |
| } | |
| // --------------------------------------------------------------------- | |
| static void defaultPrintFunc(void* /*cookie*/, const char* txt) | |
| { | |
| printf("%s", txt); | |
| } | |
| // --------------------------------------------------------------------- | |
| static inline int isident(int c) | |
| { | |
| return isalnum(c) || c == '_'; | |
| } | |
| static inline bool isasciitype(char c) | |
| { | |
| if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true; | |
| return false; | |
| } | |
| static inline char makehexdigit(uint32_t val) | |
| { | |
| return "0123456789abcdef"[val&0xF]; | |
| } | |
| static char* appendhexnum(uint32_t val, char* out) | |
| { | |
| for( int32_t i=28; i>=0; i-=4 ) { | |
| *out++ = makehexdigit( val>>i ); | |
| } | |
| *out = 0; | |
| return out; | |
| } | |
| static char* appendcharornum(char c, char* out, bool skipzero = true) | |
| { | |
| if (skipzero && c == 0) return out; | |
| if (isasciitype(c)) { | |
| *out++ = c; | |
| return out; | |
| } | |
| *out++ = '\\'; | |
| *out++ = 'x'; | |
| *out++ = makehexdigit(c>>4); | |
| *out++ = makehexdigit(c); | |
| return out; | |
| } | |
| static char* typetostring(uint32_t type, char* out, | |
| bool fullContext = true, | |
| bool strict = false) | |
| { | |
| char* pos = out; | |
| char c[4]; | |
| c[0] = (char)((type>>24)&0xFF); | |
| c[1] = (char)((type>>16)&0xFF); | |
| c[2] = (char)((type>>8)&0xFF); | |
| c[3] = (char)(type&0xFF); | |
| bool valid; | |
| if( !strict ) { | |
| // now even less strict! | |
| // valid = isasciitype(c[3]); | |
| valid = true; | |
| int32_t i = 0; | |
| bool zero = true; | |
| while (valid && i<3) { | |
| if (c[i] == 0) { | |
| if (!zero) valid = false; | |
| } else { | |
| zero = false; | |
| //if (!isasciitype(c[i])) valid = false; | |
| } | |
| i++; | |
| } | |
| // if all zeros, not a valid type code. | |
| if (zero) valid = false; | |
| } else { | |
| valid = isident(c[3]) ? true : false; | |
| int32_t i = 0; | |
| bool zero = true; | |
| while (valid && i<3) { | |
| if (c[i] == 0) { | |
| if (!zero) valid = false; | |
| } else { | |
| zero = false; | |
| if (!isident(c[i])) valid = false; | |
| } | |
| i++; | |
| } | |
| } | |
| if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) { | |
| if( fullContext ) *pos++ = '\''; | |
| pos = appendcharornum(c[0], pos); | |
| pos = appendcharornum(c[1], pos); | |
| pos = appendcharornum(c[2], pos); | |
| pos = appendcharornum(c[3], pos); | |
| if( fullContext ) *pos++ = '\''; | |
| *pos = 0; | |
| return pos; | |
| } | |
| if( fullContext ) { | |
| *pos++ = '0'; | |
| *pos++ = 'x'; | |
| } | |
| return appendhexnum(type, pos); | |
| } | |
| void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie) | |
| { | |
| char buffer[32]; | |
| char* end = typetostring(typeCode, buffer); | |
| *end = 0; | |
| func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer); | |
| } | |
| void printHexData(int32_t indent, const void *buf, size_t length, | |
| size_t bytesPerLine, int32_t singleLineBytesCutoff, | |
| size_t alignment, bool cStyle, | |
| debugPrintFunc func, void* cookie) | |
| { | |
| if (alignment == 0) { | |
| if (bytesPerLine >= 16) alignment = 4; | |
| else if (bytesPerLine >= 8) alignment = 2; | |
| else alignment = 1; | |
| } | |
| if (func == NULL) func = defaultPrintFunc; | |
| size_t offset; | |
| unsigned char *pos = (unsigned char *)buf; | |
| if (pos == NULL) { | |
| if (singleLineBytesCutoff < 0) func(cookie, "\n"); | |
| func(cookie, "(NULL)"); | |
| return; | |
| } | |
| if (length == 0) { | |
| if (singleLineBytesCutoff < 0) func(cookie, "\n"); | |
| func(cookie, "(empty)"); | |
| return; | |
| } | |
| if ((int32_t)length < 0) { | |
| if (singleLineBytesCutoff < 0) func(cookie, "\n"); | |
| char buf[64]; | |
| sprintf(buf, "(bad length: %zu)", length); | |
| func(cookie, buf); | |
| return; | |
| } | |
| char buffer[256]; | |
| static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1); | |
| if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine; | |
| const bool oneLine = (int32_t)length <= singleLineBytesCutoff; | |
| bool newLine = false; | |
| if (cStyle) { | |
| indent++; | |
| func(cookie, "{\n"); | |
| newLine = true; | |
| } else if (!oneLine) { | |
| func(cookie, "\n"); | |
| newLine = true; | |
| } | |
| for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) { | |
| long remain = length; | |
| char* c = buffer; | |
| if (!oneLine && !cStyle) { | |
| sprintf(c, "0x%08x: ", (int)offset); | |
| c += 12; | |
| } | |
| size_t index; | |
| size_t word; | |
| for (word = 0; word < bytesPerLine; ) { | |
| const size_t startIndex = word+(alignment-(alignment?1:0)); | |
| for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { | |
| if (!cStyle) { | |
| if (index == 0 && word > 0 && alignment > 0) { | |
| *c++ = ' '; | |
| } | |
| if (remain-- > 0) { | |
| const unsigned char val = *(pos+startIndex-index); | |
| *c++ = makehexdigit(val>>4); | |
| *c++ = makehexdigit(val); | |
| } else if (!oneLine) { | |
| *c++ = ' '; | |
| *c++ = ' '; | |
| } | |
| } else { | |
| if (remain > 0) { | |
| if (index == 0 && word > 0) { | |
| *c++ = ','; | |
| *c++ = ' '; | |
| } | |
| if (index == 0) { | |
| *c++ = '0'; | |
| *c++ = 'x'; | |
| } | |
| const unsigned char val = *(pos+startIndex-index); | |
| *c++ = makehexdigit(val>>4); | |
| *c++ = makehexdigit(val); | |
| remain--; | |
| } | |
| } | |
| } | |
| word += index; | |
| } | |
| if (!cStyle) { | |
| remain = length; | |
| *c++ = ' '; | |
| *c++ = '\''; | |
| for (index = 0; index < bytesPerLine; index++) { | |
| if (remain-- > 0) { | |
| const unsigned char val = pos[index]; | |
| *c++ = (val >= ' ' && val < 127) ? val : '.'; | |
| } else if (!oneLine) { | |
| *c++ = ' '; | |
| } | |
| } | |
| *c++ = '\''; | |
| if (length > bytesPerLine) *c++ = '\n'; | |
| } else { | |
| if (remain > 0) *c++ = ','; | |
| *c++ = '\n'; | |
| } | |
| if (newLine && indent) func(cookie, stringForIndent(indent)); | |
| *c = 0; | |
| func(cookie, buffer); | |
| newLine = true; | |
| if (length <= bytesPerLine) break; | |
| length -= bytesPerLine; | |
| } | |
| if (cStyle) { | |
| if (indent > 0) func(cookie, stringForIndent(indent-1)); | |
| func(cookie, "};"); | |
| } | |
| } | |
| ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf) { | |
| sp<ProcessState> proc = ProcessState::selfOrNull(); | |
| if (proc.get() == NULL) { | |
| return 0; | |
| } | |
| return proc->getKernelReferences(count, buf); | |
| } | |
| }; // namespace android | |