blob: c3560169857c77f07e7dbbdb493527bc86700ec8 [file] [log] [blame]
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "kern/linux/printk.hh"
#include <sys/types.h>
#include <algorithm>
#include <iostream>
#include <sstream>
#include "base/compiler.hh"
#include "cpu/thread_context.hh"
#include "mem/port_proxy.hh"
#include "mem/translating_port_proxy.hh"
namespace gem5
{
GEM5_DEPRECATED_NAMESPACE(Linux, linux);
namespace linux
{
int
printk(std::string &str, ThreadContext *tc, Addr format_ptr,
PrintkVarArgs args)
{
std::string format;
std::ostringstream out;
TranslatingPortProxy proxy(tc);
proxy.readString(format, format_ptr);
const char *p = format.c_str();
while (*p) {
switch (*p) {
case '%': {
bool more = true;
bool islong = false;
bool leftjustify = false;
bool format = false;
bool zero = false;
int width = 0;
while (more && *++p) {
switch (*p) {
case 'l':
case 'L':
islong = true;
break;
case '-':
leftjustify = true;
break;
case '#':
format = true;
break;
case '0':
if (width)
width *= 10;
else
zero = true;
break;
default:
if (*p >= '1' && *p <= '9')
width = 10 * width + *p - '0';
else
more = false;
break;
}
}
bool hexnum = false;
bool octal = false;
bool sign = false;
switch (*p) {
case 'X':
case 'x':
hexnum = true;
break;
case 'O':
case 'o':
octal = true;
break;
case 'D':
case 'd':
sign = true;
break;
case 'P':
format = true;
[[fallthrough]];
case 'p':
hexnum = true;
break;
}
switch (*p) {
case 'D':
case 'd':
case 'U':
case 'u':
case 'X':
case 'x':
case 'O':
case 'o':
case 'P':
case 'p': {
if (hexnum)
out << std::hex;
if (octal)
out << std::oct;
if (format) {
if (!zero)
out.setf(std::ios::showbase);
else {
if (hexnum) {
out << "0x";
width -= 2;
} else if (octal) {
out << "0";
width -= 1;
}
}
}
if (zero)
out.fill('0');
if (width > 0)
out.width(width);
if (leftjustify && !zero)
out.setf(std::ios::left);
if (sign) {
if (islong)
out << args.get<int64_t>();
else
out << args.get<int32_t>();
} else {
if (islong)
out << args.get<uint64_t>();
else
out << args.get<uint32_t>();
}
if (zero)
out.fill(' ');
if (width > 0)
out.width(0);
out << std::dec;
}
break;
case 's': {
Addr s_ptr = args.get<Addr>();
std::string s;
if (s_ptr)
proxy.readString(s, s_ptr);
else
s = "<NULL>";
if (width > 0)
out.width(width);
if (leftjustify)
out.setf(std::ios::left);
out << s;
}
break;
case 'C':
case 'c': {
uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL;
uint64_t num;
int cwidth;
if (islong) {
num = args.get<uint64_t>();
cwidth = sizeof(uint64_t);
} else {
num = args.get<uint32_t>();
cwidth = sizeof(uint32_t);
}
while (cwidth-- > 0) {
char c = (char)(num & mask);
if (c)
out << c;
num >>= 8;
}
}
break;
case 'b': {
uint64_t n = args.get<uint64_t>();
Addr s_ptr = args.get<Addr>();
std::string s;
proxy.readString(s, s_ptr);
out << s << ": " << n;
}
break;
case '%':
out << '%';
break;
}
++p;
}
break;
case '\n':
out << std::endl;
++p;
break;
case '\r':
++p;
if (*p != '\n')
out << std::endl;
break;
default: {
size_t len = strcspn(p, "%\n\r\0");
out.write(p, len);
p += len;
}
}
}
str = out.str();
return str.length();
}
} // namespace linux
} // namespace gem5