1/*
2 * Copyright (C) 2005 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 <binder/Debug.h>
18#include <binder/ProcessState.h>
19
20#include <utils/misc.h>
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <ctype.h>
25
26namespace android {
27
28// ---------------------------------------------------------------------
29
30static const char indentStr[] =
31"                                                                            "
32"                                                                            ";
33
34const char* stringForIndent(int32_t indentLevel)
35{
36    ssize_t off = sizeof(indentStr)-1-(indentLevel*2);
37    return indentStr + (off < 0 ? 0 : off);
38}
39
40// ---------------------------------------------------------------------
41
42static void defaultPrintFunc(void* /*cookie*/, const char* txt)
43{
44    printf("%s", txt);
45}
46
47// ---------------------------------------------------------------------
48
49static inline int isident(int c)
50{
51    return isalnum(c) || c == '_';
52}
53
54static inline bool isasciitype(char c)
55{
56    if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true;
57    return false;
58}
59
60static inline char makehexdigit(uint32_t val)
61{
62    return "0123456789abcdef"[val&0xF];
63}
64
65static char* appendhexnum(uint32_t val, char* out)
66{
67    for( int32_t i=28; i>=0; i-=4 ) {
68        *out++ = makehexdigit( val>>i );
69    }
70    *out = 0;
71    return out;
72}
73
74static char* appendcharornum(char c, char* out, bool skipzero = true)
75{
76    if (skipzero && c == 0) return out;
77
78    if (isasciitype(c)) {
79        *out++ = c;
80        return out;
81    }
82
83    *out++ = '\\';
84    *out++ = 'x';
85    *out++ = makehexdigit(c>>4);
86    *out++ = makehexdigit(c);
87    return out;
88}
89
90static char* typetostring(uint32_t type, char* out,
91                          bool fullContext = true,
92                          bool strict = false)
93{
94    char* pos = out;
95    char c[4];
96    c[0] = (char)((type>>24)&0xFF);
97    c[1] = (char)((type>>16)&0xFF);
98    c[2] = (char)((type>>8)&0xFF);
99    c[3] = (char)(type&0xFF);
100    bool valid;
101    if( !strict ) {
102        // now even less strict!
103        // valid = isasciitype(c[3]);
104        valid = true;
105        int32_t i = 0;
106        bool zero = true;
107        while (valid && i<3) {
108            if (c[i] == 0) {
109                if (!zero) valid = false;
110            } else {
111                zero = false;
112                //if (!isasciitype(c[i])) valid = false;
113            }
114            i++;
115        }
116        // if all zeros, not a valid type code.
117        if (zero) valid = false;
118    } else {
119        valid = isident(c[3]) ? true : false;
120        int32_t i = 0;
121        bool zero = true;
122        while (valid && i<3) {
123            if (c[i] == 0) {
124                if (!zero) valid = false;
125            } else {
126                zero = false;
127                if (!isident(c[i])) valid = false;
128            }
129            i++;
130        }
131    }
132    if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) {
133        if( fullContext ) *pos++ = '\'';
134        pos = appendcharornum(c[0], pos);
135        pos = appendcharornum(c[1], pos);
136        pos = appendcharornum(c[2], pos);
137        pos = appendcharornum(c[3], pos);
138        if( fullContext ) *pos++ = '\'';
139        *pos = 0;
140        return pos;
141    }
142
143    if( fullContext ) {
144        *pos++ = '0';
145        *pos++ = 'x';
146    }
147    return appendhexnum(type, pos);
148}
149
150void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie)
151{
152    char buffer[32];
153    char* end = typetostring(typeCode, buffer);
154    *end = 0;
155    func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer);
156}
157
158void printHexData(int32_t indent, const void *buf, size_t length,
159    size_t bytesPerLine, int32_t singleLineBytesCutoff,
160    size_t alignment, bool cStyle,
161    debugPrintFunc func, void* cookie)
162{
163    if (alignment == 0) {
164        if (bytesPerLine >= 16) alignment = 4;
165        else if (bytesPerLine >= 8) alignment = 2;
166        else alignment = 1;
167    }
168    if (func == NULL) func = defaultPrintFunc;
169
170    size_t offset;
171
172    unsigned char *pos = (unsigned char *)buf;
173
174    if (pos == NULL) {
175        if (singleLineBytesCutoff < 0) func(cookie, "\n");
176        func(cookie, "(NULL)");
177        return;
178    }
179
180    if (length == 0) {
181        if (singleLineBytesCutoff < 0) func(cookie, "\n");
182        func(cookie, "(empty)");
183        return;
184    }
185
186    if ((int32_t)length < 0) {
187        if (singleLineBytesCutoff < 0) func(cookie, "\n");
188        char buf[64];
189        sprintf(buf, "(bad length: %zu)", length);
190        func(cookie, buf);
191        return;
192    }
193
194    char buffer[256];
195    static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1);
196
197    if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine;
198
199    const bool oneLine = (int32_t)length <= singleLineBytesCutoff;
200    bool newLine = false;
201    if (cStyle) {
202        indent++;
203        func(cookie, "{\n");
204        newLine = true;
205    } else if (!oneLine) {
206        func(cookie, "\n");
207        newLine = true;
208    }
209
210    for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
211        long remain = length;
212
213        char* c = buffer;
214        if (!oneLine && !cStyle) {
215            sprintf(c, "0x%08x: ", (int)offset);
216            c += 12;
217        }
218
219        size_t index;
220        size_t word;
221
222        for (word = 0; word < bytesPerLine; ) {
223
224            const size_t startIndex = word+(alignment-(alignment?1:0));
225
226            for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
227
228                if (!cStyle) {
229                    if (index == 0 && word > 0 && alignment > 0) {
230                        *c++ = ' ';
231                    }
232
233                    if (remain-- > 0) {
234                        const unsigned char val = *(pos+startIndex-index);
235                        *c++ = makehexdigit(val>>4);
236                        *c++ = makehexdigit(val);
237                    } else if (!oneLine) {
238                        *c++ = ' ';
239                        *c++ = ' ';
240                    }
241                } else {
242                    if (remain > 0) {
243                        if (index == 0 && word > 0) {
244                            *c++ = ',';
245                            *c++ = ' ';
246                        }
247                        if (index == 0) {
248                            *c++ = '0';
249                            *c++ = 'x';
250                        }
251                        const unsigned char val = *(pos+startIndex-index);
252                        *c++ = makehexdigit(val>>4);
253                        *c++ = makehexdigit(val);
254                        remain--;
255                    }
256                }
257            }
258
259            word += index;
260        }
261
262        if (!cStyle) {
263            remain = length;
264            *c++ = ' ';
265            *c++ = '\'';
266            for (index = 0; index < bytesPerLine; index++) {
267
268                if (remain-- > 0) {
269                    const unsigned char val = pos[index];
270                    *c++ = (val >= ' ' && val < 127) ? val : '.';
271                } else if (!oneLine) {
272                    *c++ = ' ';
273                }
274            }
275
276            *c++ = '\'';
277            if (length > bytesPerLine) *c++ = '\n';
278        } else {
279            if (remain > 0) *c++ = ',';
280            *c++ = '\n';
281        }
282
283        if (newLine && indent) func(cookie, stringForIndent(indent));
284        *c = 0;
285        func(cookie, buffer);
286        newLine = true;
287
288        if (length <= bytesPerLine) break;
289        length -= bytesPerLine;
290    }
291
292    if (cStyle) {
293        if (indent > 0) func(cookie, stringForIndent(indent-1));
294        func(cookie, "};");
295    }
296}
297
298ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf) {
299    sp<ProcessState> proc = ProcessState::selfOrNull();
300    if (proc.get() == NULL) {
301        return 0;
302    }
303
304    return proc->getKernelReferences(count, buf);
305}
306
307}; // namespace android
308
309