emu/debug/debugcmd.cpp: Add NUL-terminated string argument support to printf/logerror. (#12124)

* Use %s to read NUL-terminated strings from emulated memory.  Precision sets maximum length.
* Also added left-justification option for numeric and string formats.
* Made documentation more consistent and removed duplication.
This commit is contained in:
Patrick Mackinlay 2024-03-20 23:12:11 +07:00 committed by GitHub
parent 80e9125a5b
commit f93a04010a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 98 additions and 43 deletions

View File

@ -190,18 +190,22 @@ available:
%c
Prints the corresponding argument as an 8-bit character.
%[0][<n>]d
%[-][0][<n>]d
Prints the corresponding argument as a decimal number with optional
minimum field width and zero fill.
%[0][<n>]o
left justification, zero fill and minimum field width.
%[-][0][<n>]o
Prints the corresponding argument as an octal number with optional
minimum field width and zero fill using lowercase letters.
%[0][<n>]x
Prints the corresponding argument as a hexadecimal number with
optional minimum field width and zero fill using lowercase letters.
%[0][<n>]X
Prints the corresponding argument as a hexadecimal number with
optional minimum field width and zero fill using uppercase letters.
left justification, zero fill and minimum field width.
%[-][0][<n>]x
Prints the corresponding argument as a lowercase hexadecimal number
with optional left justification, zero fill and minimum field width.
%[-][0][<n>]X
Prints the corresponding argument as an uppercase hexadecimal number
with optional left justification, zero fill and minimum field width.
%[-][<n>][.[<n>]]s
Prints a null-terminated string of 8-bit characters from the address
and address space given by the corresponding argument, with optional
left justification, minimum and maximum field widths.
\%%
Prints a literal percent symbol.
\\n

View File

@ -471,7 +471,7 @@ void debugger_commands::execute_print(const std::vector<std::string_view> &param
bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std::string_view> &params)
{
std::string_view format(params[0]);
std::string_view const format(params[0]);
auto f = format.begin();
int param = 1;
@ -499,21 +499,48 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
// formatting
else if (c == '%')
{
bool left_justify = false;
bool zero_fill = false;
int width = 0;
int zerofill = 0;
int precision = 0;
// parse out the width
while (f != format.end() && *f >= '0' && *f <= '9')
// parse optional left justification flag
if (f != format.end() && *f == '-')
{
c = *f++;
if (c == '0' && width == 0)
zerofill = 1;
width = width * 10 + (c - '0');
left_justify = true;
f++;
}
// parse optional zero fill flag
if (f != format.end() && *f == '0')
{
zero_fill = true;
f++;
}
// parse optional width
while (f != format.end() && isdigit(*f))
width = width * 10 + (*f++ - '0');
if (f == format.end())
break;
// apply left justification
if (left_justify)
width = -width;
if ((c = *f++) == '.')
{
// parse optional precision
while (f != format.end() && isdigit(*f))
precision = precision * 10 + (*f++ - '0');
// get the format
if (f != format.end())
c = *f++;
else
break;
}
if (f == format.end()) break;
// get the format
c = *f++;
switch (c)
{
case '%':
@ -522,7 +549,7 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
case 'X':
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
util::stream_format(stream, zerofill ? "%0*X" : "%*X", width, number);
util::stream_format(stream, zero_fill ? "%0*X" : "%*X", width, number);
else
{
m_console.printf("Not enough parameters for format!\n");
@ -531,7 +558,7 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
break;
case 'x':
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
util::stream_format(stream, zerofill ? "%0*x" : "%*x", width, number);
util::stream_format(stream, zero_fill ? "%0*x" : "%*x", width, number);
else
{
m_console.printf("Not enough parameters for format!\n");
@ -542,7 +569,7 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
case 'O':
case 'o':
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
util::stream_format(stream, zerofill ? "%0*o" : "%*o", width, number);
util::stream_format(stream, zero_fill ? "%0*o" : "%*o", width, number);
else
{
m_console.printf("Not enough parameters for format!\n");
@ -553,7 +580,7 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
case 'D':
case 'd':
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
util::stream_format(stream, zerofill ? "%0*d" : "%*d", width, number);
util::stream_format(stream, zero_fill ? "%0*d" : "%*d", width, number);
else
{
m_console.printf("Not enough parameters for format!\n");
@ -572,6 +599,38 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
}
break;
case 's':
{
address_space *space;
if (param < params.size() && m_console.validate_target_address_parameter(params[param++], -1, space, number))
{
address_space *tspace;
std::string s;
for (u32 address = u32(number), taddress; space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, taddress = address, tspace); address++)
{
u8 const data = tspace->read_byte(taddress);
if (!data)
break;
s += data;
if (precision == 1)
break;
else if (precision)
precision--;
}
util::stream_format(stream, "%*s", width, s);
}
else
{
m_console.printf("Not enough parameters for format!\n");
return false;
}
}
break;
}
}

View File

@ -359,11 +359,12 @@ const help_item f_static_help_list[] =
"The printf command performs a C-style printf to the debugger console. Only a very limited set of "
"formatting options are available:\n"
"\n"
" %c -- 8-bit character\n"
" %[0][<n>]d -- decimal number with optional digit count and zero-fill\n"
" %[0][<n>]o -- octal number with optional digit count and zero-fill\n"
" %[0][<n>]x -- hexadecimal number with optional digit count and zero-fill (lowercase digits)\n"
" %[0][<n>]X -- hexadecimal number with optional digit count and zero-fill (uppercase digits)\n"
" %c -- 8-bit character\n"
" %[-][0][<n>]d -- decimal number with optional left justification, zero fill and minimum width\n"
" %[-][0][<n>]o -- octal number with optional left justification, zero fill and minimum width\n"
" %[-][0][<n>]x -- lowercase hexadecimal number with optional left justification, zero fill and minimum width\n"
" %[-][0][<n>]X -- uppercase hexadecimal number with optional left justification, zero fill and minimum width\n"
" %[-][<n>][.[<n>]]s -- null-terminated string of 8-bit characters with optional left justification, minimum and maximum width\n"
"\n"
"All remaining formatting options are ignored. Use %% to output a % character. Multiple lines can be "
"printed by embedding a \\n in the text.\n"
@ -371,7 +372,7 @@ const help_item f_static_help_list[] =
"Examples:\n"
"\n"
"printf \"PC=%04X\",pc\n"
" Prints PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
" Prints PC=<pcval> where <pcval> is displayed in uppercase hexadecimal with 4 digits and zero fill.\n"
"\n"
"printf \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
" Prints A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
@ -382,21 +383,12 @@ const help_item f_static_help_list[] =
" logerror <format>[,<item>[,...]]\n"
"\n"
"The logerror command performs a C-style printf to the error log. Only a very limited set of "
"formatting options are available:\n"
"\n"
" %c -- 8-bit character\n"
" %[0][<n>]d -- decimal number with optional digit count and zero-fill\n"
" %[0][<n>]o -- octal number with optional digit count and zero-fill\n"
" %[0][<n>]x -- hexadecimal number with optional digit count and zero-fill (lowercase digits)\n"
" %[0][<n>]X -- hexadecimal number with optional digit count and zero-fill (uppercase digits)\n"
"\n"
"All remaining formatting options are ignored. Use %% to output a % character. Multiple lines can be "
"printed by embedding a \\n in the text.\n"
"formatting options are available. See the 'printf' help for details.\n"
"\n"
"Examples:\n"
"\n"
"logerror \"PC=%04X\",pc\n"
" Logs PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
"logerror \"PC=%04x\",pc\n"
" Logs PC=<pcval> where <pcval> is displayed in lowercase hexadecimal with 4 digits and zero fill.\n"
"\n"
"logerror \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
" Logs A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"