/* * Copyright (C) 2018-2021 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "print_formatter.h" #include "shared/source/helpers/string.h" #include namespace NEO { PrintFormatter::PrintFormatter(const uint8_t *printfOutputBuffer, uint32_t printfOutputBufferMaxSize, bool using32BitPointers, const StringMap *stringLiteralMap) : printfOutputBuffer(printfOutputBuffer), printfOutputBufferSize(printfOutputBufferMaxSize), using32BitPointers(using32BitPointers), usesStringMap(stringLiteralMap != nullptr), stringLiteralMap(stringLiteralMap) { output.reset(new char[maxSinglePrintStringLength]); } void PrintFormatter::printKernelOutput(const std::function &print) { currentOffset = 0; // first 4 bytes of the buffer store the actual size of data that was written by printf from within EUs uint32_t printfOutputBufferSizeRead = 0; read(&printfOutputBufferSizeRead); printfOutputBufferSize = std::min(printfOutputBufferSizeRead, printfOutputBufferSize); if (usesStringMap) { uint32_t stringIndex = 0; while (currentOffset + 4 <= printfOutputBufferSize) { read(&stringIndex); const char *formatString = queryPrintfString(stringIndex); if (formatString != nullptr) { printString(formatString, print); } } } else { while (currentOffset + sizeof(char *) <= printfOutputBufferSize) { char *formatString = nullptr; read(&formatString); printString(formatString, print); } } } void PrintFormatter::printString(const char *formatString, const std::function &print) { size_t length = strnlen_s(formatString, maxSinglePrintStringLength - 1); size_t cursor = 0; std::unique_ptr dataFormat(new char[length + 1]); for (size_t i = 0; i <= length; i++) { if (formatString[i] == '\\') output[cursor++] = escapeChar(formatString[++i]); else if (formatString[i] == '%') { size_t end = i; if (end + 1 <= length && formatString[end + 1] == '%') { output[cursor++] = '%'; continue; } while (isConversionSpecifier(formatString[end++]) == false && end < length) ; memcpy_s(dataFormat.get(), length, formatString + i, end - i); dataFormat[end - i] = '\0'; if (formatString[end - 1] == 's') cursor += printStringToken(output.get() + cursor, maxSinglePrintStringLength - cursor, dataFormat.get()); else cursor += printToken(output.get() + cursor, maxSinglePrintStringLength - cursor, dataFormat.get()); i = end - 1; } else { output[cursor++] = formatString[i]; } } output[maxSinglePrintStringLength - 1] = '\0'; print(output.get()); } void PrintFormatter::stripVectorFormat(const char *format, char *stripped) { while (*format != '\0') { if (*format != 'v') { *stripped = *format; } else if (*(format + 1) != '1') { format += 2; continue; } else { format += 3; continue; } stripped++; format++; } *stripped = '\0'; } void PrintFormatter::stripVectorTypeConversion(char *format) { size_t len = strlen(format); if (len > 3 && format[len - 3] == 'h' && format[len - 2] == 'l') { format[len - 3] = format[len - 1]; format[len - 2] = '\0'; } } size_t PrintFormatter::printToken(char *output, size_t size, const char *formatString) { PRINTF_DATA_TYPE type(PRINTF_DATA_TYPE::INVALID); read(&type); switch (type) { case PRINTF_DATA_TYPE::BYTE: return typedPrintToken(output, size, formatString); case PRINTF_DATA_TYPE::SHORT: return typedPrintToken(output, size, formatString); case PRINTF_DATA_TYPE::INT: return typedPrintToken(output, size, formatString); case PRINTF_DATA_TYPE::FLOAT: return typedPrintToken(output, size, formatString); case PRINTF_DATA_TYPE::LONG: return typedPrintToken(output, size, formatString); case PRINTF_DATA_TYPE::POINTER: return printPointerToken(output, size, formatString); case PRINTF_DATA_TYPE::DOUBLE: return typedPrintToken(output, size, formatString); case PRINTF_DATA_TYPE::VECTOR_BYTE: return typedPrintVectorToken(output, size, formatString); case PRINTF_DATA_TYPE::VECTOR_SHORT: return typedPrintVectorToken(output, size, formatString); case PRINTF_DATA_TYPE::VECTOR_INT: return typedPrintVectorToken(output, size, formatString); case PRINTF_DATA_TYPE::VECTOR_LONG: return typedPrintVectorToken(output, size, formatString); case PRINTF_DATA_TYPE::VECTOR_FLOAT: return typedPrintVectorToken(output, size, formatString); case PRINTF_DATA_TYPE::VECTOR_DOUBLE: return typedPrintVectorToken(output, size, formatString); default: return 0; } } size_t PrintFormatter::printStringToken(char *output, size_t size, const char *formatString) { int type = 0; read(&type); const char *string = nullptr; if (usesStringMap) { int index = 0; read(&index); string = queryPrintfString(index); } else { char *str = nullptr; read(&str); string = str; } if (type == static_cast(PRINTF_DATA_TYPE::STRING)) { return simple_sprintf(output, size, formatString, string); } else { return simple_sprintf(output, size, formatString, 0); } return 0; } size_t PrintFormatter::printPointerToken(char *output, size_t size, const char *formatString) { uint64_t value = {0}; read(&value); if (using32BitPointers) { value &= 0x00000000FFFFFFFF; } return simple_sprintf(output, size, formatString, value); } const char *PrintFormatter::queryPrintfString(uint32_t index) const { auto stringEntry = stringLiteralMap->find(index); return stringEntry == stringLiteralMap->end() ? nullptr : stringEntry->second.c_str(); } char PrintFormatter::escapeChar(char escape) { switch (escape) { case 'n': return '\n'; default: return escape; } } bool PrintFormatter::isConversionSpecifier(char c) { switch (c) { case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 's': case 'c': case 'p': return true; default: return false; } } } // namespace NEO