/* * Recursively convert binary log data to printable form. * * This needs to be recursive because you can have lists of lists. * * If we run out of room, we stop processing immediately. It's important * for us to check for space on every output element to avoid producing * garbled output. * * Returns 0 on success, 1 on buffer full, -1 on failure. */ static int android_log_printBinaryEvent(const unsigned char** pEventData, size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen) { const unsigned char* eventData = *pEventData; size_t eventDataLen = *pEventDataLen; char* outBuf = *pOutBuf; size_t outBufLen = *pOutBufLen; unsigned char type; size_t outCount; int result = 0; if (eventDataLen < 1) return -1; type = *eventData++; eventDataLen--; //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen); switch (type) { case EVENT_TYPE_INT: /* 32-bit signed int */ { int ival; if (eventDataLen < 4) return -1; ival = get4LE(eventData); eventData += 4; eventDataLen -= 4; outCount = snprintf(outBuf, outBufLen, "%d", ival); if (outCount < outBufLen) { outBuf += outCount; outBufLen -= outCount; } else { /* halt output */ goto no_room; } } break; case EVENT_TYPE_LONG: /* 64-bit signed long */ { long long lval; if (eventDataLen < 8) return -1; lval = get8LE(eventData); eventData += 8; eventDataLen -= 8; outCount = snprintf(outBuf, outBufLen, "%lld", lval); if (outCount < outBufLen) { outBuf += outCount; outBufLen -= outCount; } else { /* halt output */ goto no_room; } } break; case EVENT_TYPE_STRING: /* UTF-8 chars, not NULL-terminated */ { unsigned int strLen; if (eventDataLen < 4) return -1; strLen = get4LE(eventData); eventData += 4; eventDataLen -= 4; if (eventDataLen < strLen) return -1; if (strLen < outBufLen) { memcpy(outBuf, eventData, strLen); outBuf += strLen; outBufLen -= strLen; } else if (outBufLen > 0) { /* copy what we can */ memcpy(outBuf, eventData, outBufLen); outBuf += outBufLen; outBufLen -= outBufLen; goto no_room; } eventData += strLen; eventDataLen -= strLen; break; } case EVENT_TYPE_LIST: /* N items, all different types */ { unsigned char count; int i; if (eventDataLen < 1) return -1; count = *eventData++; eventDataLen--; if (outBufLen > 0) { *outBuf++ = '['; outBufLen--; } else { goto no_room; } for (i = 0; i < count; i++) { result = android_log_printBinaryEvent(&eventData, &eventDataLen, &outBuf, &outBufLen); if (result != 0) goto bail; if (i < count-1) { if (outBufLen > 0) { *outBuf++ = ','; outBufLen--; } else { goto no_room; } } } if (outBufLen > 0) { *outBuf++ = ']'; outBufLen--; } else { goto no_room; } } break; default: fprintf(stderr, "Unknown binary event type %d\n", type); return -1; } bail: *pEventData = eventData; *pEventDataLen = eventDataLen; *pOutBuf = outBuf; *pOutBufLen = outBufLen; return result; no_room: result = 1; goto bail; }
/** * Convert a binary log entry to ASCII form. * * For convenience we mimic the processLogBuffer API. There is no * pre-defined output length for the binary data, since we're free to format * it however we choose, which means we can't really use a fixed-size buffer * here. */ int android_log_processBinaryLogBuffer(struct logger_entry *buf, AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf, int messageBufLen) { size_t inCount; unsigned int tagIndex; const unsigned char* eventData; entry->tv_sec = buf->sec; entry->tv_nsec = buf->nsec; entry->priority = ANDROID_LOG_INFO; entry->pid = buf->pid; entry->tid = buf->tid; /* * Pull the tag out. */ eventData = (const unsigned char*) buf->msg; inCount = buf->len; if (inCount < 4) return -1; tagIndex = get4LE(eventData); eventData += 4; inCount -= 4; if (map != NULL) { entry->tag = android_lookupEventTag(map, tagIndex); } else { entry->tag = NULL; } /* * If we don't have a map, or didn't find the tag number in the map, * stuff a generated tag value into the start of the output buffer and * shift the buffer pointers down. */ if (entry->tag == NULL) { int tagLen; tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex); entry->tag = messageBuf; messageBuf += tagLen+1; messageBufLen -= tagLen+1; } /* * Format the event log data into the buffer. */ char* outBuf = messageBuf; size_t outRemaining = messageBufLen-1; /* leave one for nul byte */ int result; result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf, &outRemaining); if (result < 0) { fprintf(stderr, "Binary log entry conversion failed\n"); return -1; } else if (result == 1) { if (outBuf > messageBuf) { /* leave an indicator */ *(outBuf-1) = '!'; } else { /* no room to output anything at all */ *outBuf++ = '!'; outRemaining--; } /* pretend we ate all the data */ inCount = 0; } /* eat the silly terminating '\n' */ if (inCount == 1 && *eventData == '\n') { eventData++; inCount--; } if (inCount != 0) { fprintf(stderr, "Warning: leftover binary log data (%zu bytes)\n", inCount); } /* * Terminate the buffer. The NUL byte does not count as part of * entry->messageLen. */ *outBuf = '\0'; entry->messageLen = outBuf - messageBuf; assert(entry->messageLen == (messageBufLen-1) - outRemaining); entry->message = messageBuf; return 0; }
/** * Convert a binary log entry to ASCII form. * * For convenience we mimic the processLogBuffer API. There is no * pre-defined output length for the binary data, since we're free to format * it however we choose, which means we can't really use a fixed-size buffer * here. */ LIBLOG_ABI_PUBLIC int android_log_processBinaryLogBuffer( struct logger_entry *buf, AndroidLogEntry *entry, const EventTagMap *map, char *messageBuf, int messageBufLen) { size_t inCount; unsigned int tagIndex; const unsigned char* eventData; entry->tv_sec = buf->sec; entry->tv_nsec = buf->nsec; entry->priority = ANDROID_LOG_INFO; entry->uid = -1; entry->pid = buf->pid; entry->tid = buf->tid; /* * Pull the tag out, fill in some additional details based on incoming * buffer version (v3 adds lid, v4 adds uid). */ eventData = (const unsigned char*) buf->msg; struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf; if (buf2->hdr_size) { if ((buf2->hdr_size < sizeof(((struct log_msg *)NULL)->entry_v1)) || (buf2->hdr_size > sizeof(((struct log_msg *)NULL)->entry))) { fprintf(stderr, "+++ LOG: entry illegal hdr_size\n"); return -1; } eventData = ((unsigned char *)buf2) + buf2->hdr_size; if ((buf2->hdr_size >= sizeof(struct logger_entry_v3)) && (((struct logger_entry_v3 *)buf)->lid == LOG_ID_SECURITY)) { entry->priority = ANDROID_LOG_WARN; } if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) { entry->uid = ((struct logger_entry_v4 *)buf)->uid; } } inCount = buf->len; if (inCount < 4) return -1; tagIndex = get4LE(eventData); eventData += 4; inCount -= 4; entry->tagLen = 0; if (map != NULL) { entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex); } else { entry->tag = NULL; } /* * If we don't have a map, or didn't find the tag number in the map, * stuff a generated tag value into the start of the output buffer and * shift the buffer pointers down. */ if (entry->tag == NULL) { size_t tagLen; tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex); if (tagLen >= (size_t)messageBufLen) { tagLen = messageBufLen - 1; } entry->tag = messageBuf; entry->tagLen = tagLen; messageBuf += tagLen + 1; messageBufLen -= tagLen + 1; } /* * Format the event log data into the buffer. */ char* outBuf = messageBuf; size_t outRemaining = messageBufLen-1; /* leave one for nul byte */ int result; result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf, &outRemaining); if (result < 0) { fprintf(stderr, "Binary log entry conversion failed\n"); return -1; } else if (result == 1) { if (outBuf > messageBuf) { /* leave an indicator */ *(outBuf-1) = '!'; } else { /* no room to output anything at all */ *outBuf++ = '!'; outRemaining--; } /* pretend we ate all the data */ inCount = 0; } /* eat the silly terminating '\n' */ if (inCount == 1 && *eventData == '\n') { eventData++; inCount--; } if (inCount != 0) { fprintf(stderr, "Warning: leftover binary log data (%zu bytes)\n", inCount); } /* * Terminate the buffer. The NUL byte does not count as part of * entry->messageLen. */ *outBuf = '\0'; entry->messageLen = outBuf - messageBuf; assert(entry->messageLen == (messageBufLen-1) - outRemaining); entry->message = messageBuf; return 0; }