base: remove format strings from API

This patch ultimatedly removes format strings from Genode's base API.
Users of the former base/snprintf.h and base/console.h headers may
use the free-standing 'format' library hosted in the ports repository.

Fixes #2064
Fixes #3869
This commit is contained in:
Norman Feske 2023-03-06 16:09:08 +01:00 committed by Christian Helmuth
parent e9b249b709
commit d727d18871
10 changed files with 8 additions and 530 deletions

View File

@ -9,7 +9,6 @@ SRC_CC += bootstrap/thread.cc
SRC_CC += hw/capability.cc
SRC_CC += lib/base/allocator_avl.cc
SRC_CC += lib/base/avl_tree.cc
SRC_CC += lib/base/console.cc
SRC_CC += lib/base/elf_binary.cc
SRC_CC += lib/base/heap.cc
SRC_CC += lib/base/registry.cc

View File

@ -18,7 +18,6 @@
#include <base/env.h>
#include <base/capability.h>
#include <base/log.h>
#include <base/snprintf.h> /* deprecated */
namespace Genode {
@ -47,13 +46,6 @@ class Genode::Connection_base : Noncopyable, Interface
_id_space_element(_parent_client, _env.id_space())
{ }
/**
* Legacy constructor
*
* \noapi
*/
Connection_base();
void upgrade(Session::Resources resources)
{
String<80> const args("ram_quota=", resources.ram_quota, ", "
@ -110,29 +102,6 @@ class Genode::Connection : public Connection_base
private:
/*
* Buffer for storing the session arguments passed to the
* 'session' method that is called before the 'Connection' is
* constructed.
*/
enum { FORMAT_STRING_SIZE = Parent::Session_args::MAX_SIZE };
char _session_args[FORMAT_STRING_SIZE];
Affinity _affinity_arg { };
void _session(Parent &,
Affinity const &affinity,
const char *format_args, va_list list)
{
String_console sc(_session_args, FORMAT_STRING_SIZE);
sc.vprintf(format_args, list);
va_end(list);
_affinity_arg = affinity;
}
using Client_id = Parent::Client::Id;
static Capability<SESSION_TYPE> _request(Env &env,
@ -163,32 +132,10 @@ class Genode::Connection : public Connection_base
}
}
Capability<SESSION_TYPE> _request_cap()
{
try {
return _env.session<SESSION_TYPE>(_id_space_element.id(),
_session_args, _affinity_arg); }
catch (...) {
error(SESSION_TYPE::service_name(), "-session creation failed "
"(", Cstring(_session_args), ")");
throw;
}
}
Capability<SESSION_TYPE> _cap = _request_cap();
Capability<SESSION_TYPE> _cap;
public:
/**
* Constructor
*
* \deprecated
*/
Connection(Env &env, Capability<SESSION_TYPE>)
:
Connection_base(env), _cap(_request_cap())
{ }
Connection(Env &env,
Session_label const &label,
Ram_quota const &ram_quota,
@ -217,36 +164,6 @@ class Genode::Connection : public Connection_base
* Return session capability
*/
Capability<SESSION_TYPE> cap() const { return _cap; }
/**
* Issue session request to the parent
*
* \deprecated
*/
Capability<SESSION_TYPE> session(Parent &parent, const char *format_args, ...)
{
va_list list;
va_start(list, format_args);
_session(parent, Affinity(), format_args, list);
return Capability<SESSION_TYPE>();
}
/**
* Issue session request to the parent
*
* \deprecated
*/
Capability<SESSION_TYPE> session(Parent &parent,
Affinity const &affinity,
char const *format_args, ...)
{
va_list list;
va_start(list, format_args);
_session(parent, affinity, format_args, list);
return Capability<SESSION_TYPE>();
}
};
#endif /* _INCLUDE__BASE__CONNECTION_H_ */

View File

@ -1,60 +0,0 @@
/*
* \brief Simple console for debug output
* \author Norman Feske
* \date 2006-04-07
*/
/*
* Copyright (C) 2006-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__BASE__CONSOLE_H_
#define _INCLUDE__BASE__CONSOLE_H_
#include <stdarg.h>
namespace Genode { class Console; }
class Genode::Console
{
public:
virtual ~Console() {}
/**
* Print format string
*/
void printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
void vprintf(const char *format, va_list) __attribute__((format(printf, 2, 0)));
protected:
/**
* Back end used for the output of a single character
*/
virtual void _out_char(char c) = 0;
/**
* Back end for the output of a null-terminated string
*
* The default implementation uses _out_char. This method may
* be overridden by the backend for improving efficiency.
*
* This method is virtual to enable the use an optimized
* string-output operation on some target platforms, e.g.,
* a kernel debugger that offers a string-output syscall. The
* default implementation calls '_out_char' for each character.
*/
virtual void _out_string(const char *str);
private:
template <typename T> void _out_unsigned(T value, unsigned base = 10, int pad = 0);
template <typename T> void _out_signed(T value, unsigned base = 10);
};
#endif /* _INCLUDE__BASE__CONSOLE_H_ */

View File

@ -1,98 +0,0 @@
/*
* \brief Facility to write format string into character buffer
* \author Norman Feske
* \date 2006-07-17
*/
/*
* Copyright (C) 2006-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__BASE__SNPRINTF_H_
#define _INCLUDE__BASE__SNPRINTF_H_
#include <base/console.h>
#include <base/stdint.h>
namespace Genode {
class String_console;
/**
* Print format string into character buffer
*
* \param dst destination buffer
* \param dst_len size of 'dst' in bytes
* \param format format string followed by the list of arguments
*
* \return number of characters written to destination buffer
*/
inline size_t snprintf(char *dst, size_t dst_size, const char *format, ...)
__attribute__((format(printf, 3, 4)));
}
class Genode::String_console : public Console
{
private:
char *_dst;
size_t _dst_len;
size_t _w_offset { 0 };
/*
* Noncopyable
*/
String_console &operator = (String_console const &);
String_console(String_console const &);
public:
/**
* Constructor
*
* \param dst destination character buffer
* \param dst_len size of 'dst'
*/
String_console(char *dst, size_t dst_len)
: _dst(dst), _dst_len(dst_len)
{ _dst[0] = 0; }
/**
* Return number of characters in destination buffer
*/
size_t len() { return _w_offset; }
/***********************
** Console interface **
***********************/
void _out_char(char c) override
{
/* ensure to leave space for null-termination */
if (_w_offset + 2 > _dst_len)
return;
_dst[_w_offset++] = c;
_dst[_w_offset] = 0;
}
};
inline Genode::size_t Genode::snprintf(char *dst, size_t dst_len, const char *format, ...)
{
va_list list;
va_start(list, format);
String_console sc(dst, dst_len);
sc.vprintf(format, list);
va_end(list);
return sc.len();
}
#endif /* _INCLUDE__BASE__SNPRINTF_H_ */

View File

@ -9,7 +9,6 @@ SRC_CC += slab.cc
SRC_CC += allocator_avl.cc
SRC_CC += heap.cc sliced_heap.cc
SRC_CC += registry.cc
SRC_CC += console.cc
SRC_CC += output.cc
SRC_CC += child.cc
SRC_CC += child_process.cc

View File

@ -124,8 +124,6 @@ _ZN6Genode14Signal_contextD2Ev T
_ZN6Genode14cache_coherentEmm T
_ZN6Genode14env_deprecatedEv T
_ZN6Genode14ipc_reply_waitERKNS_17Native_capabilityENS_18Rpc_exception_codeERNS_11Msgbuf_baseES5_ T
_ZN6Genode15Connection_baseC1Ev T
_ZN6Genode15Connection_baseC2Ev T
_ZN6Genode15Signal_receiver12local_submitENS_6Signal4DataE T
_ZN6Genode15Signal_receiver14pending_signalEv T
_ZN6Genode15Signal_receiver15wait_for_signalEv T
@ -293,12 +291,6 @@ _ZN6Genode6ThreadC2EmPKcmNS0_4TypeEPNS_11Cpu_sessionENS_8Affinity8LocationE T
_ZN6Genode6ThreadD0Ev T
_ZN6Genode6ThreadD1Ev T
_ZN6Genode6ThreadD2Ev T
_ZN6Genode7Console11_out_stringEPKc T
_ZN6Genode7Console6printfEPKcz T
_ZN6Genode7Console7vprintfEPKcP13__va_list_tag T
_ZN6Genode7Console7vprintfEPKcPc T
_ZN6Genode7Console7vprintfEPKcPv T
_ZN6Genode7Console7vprintfEPKcSt9__va_list T
_ZN6Genode7Timeout14_alarm_discardEv T
_ZN6Genode7Timeout17schedule_one_shotENS_12MicrosecondsERNS_15Timeout_handlerE T
_ZN6Genode7Timeout17schedule_periodicENS_12MicrosecondsERNS_15Timeout_handlerE T
@ -390,10 +382,10 @@ _ZTVN6Genode5ChildE D 440
_ZTVN6Genode6OutputE D 48
_ZTVN6Genode6ThreadE D 48
_ZTVN6Genode7ConsoleE D 48
_ZThn236_N5Timer10Connection11set_timeoutEN6Genode12MicrosecondsERNS1_15Timeout_handlerE T
_ZThn236_N5Timer10Connection9curr_timeEv T
_ZThn288_N5Timer10Connection11set_timeoutEN6Genode12MicrosecondsERNS1_15Timeout_handlerE T
_ZThn288_N5Timer10Connection9curr_timeEv T
_ZThn104_N5Timer10Connection11set_timeoutEN6Genode12MicrosecondsERNS1_15Timeout_handlerE T
_ZThn104_N5Timer10Connection9curr_timeEv T
_ZThn52_N5Timer10Connection11set_timeoutEN6Genode12MicrosecondsERNS1_15Timeout_handlerE T
_ZThn52_N5Timer10Connection9curr_timeEv T
_ZThn8_N6Genode17Timeout_scheduler14handle_timeoutENS_8DurationE T
_ZThn8_N6Genode17Timeout_schedulerD0Ev T
_ZThn8_N6Genode17Timeout_schedulerD1Ev T

View File

@ -1,261 +0,0 @@
/*
* \brief Output of format strings
* \author Norman Feske
* \date 2006-04-07
*
* NOTE: Support for long long ints is not required by Core.
* Hence, this functionality and further features such
* as floating point numbers should better be placed
* in another 'rich_conole' lib outside of the Genode's
* base repository.
*/
/*
* Copyright (C) 2006-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/console.h>
#include <base/stdint.h>
/* base-internal includes */
#include <base/internal/output.h>
using namespace Genode;
/**
* Format string command representation
*/
class Format_command
{
public:
enum Type { INT, UINT, STRING, CHAR, PTR, PERCENT, INVALID };
enum Length { DEFAULT, LONG, SIZE_T, LONG_LONG };
private:
/**
* Read decimal value from string
*/
int decode_decimal(const char *str, int *consumed)
{
int res = 0;
while (1) {
char c = str[*consumed];
if (!c || c < '0' || c > '0' + 9)
return res;
res = (res * 10) + c - '0';
(*consumed)++;
}
}
public:
Type type = INVALID; /* format argument type */
Length length = DEFAULT; /* format argument length */
int padding = 0; /* min number of characters to print */
int base = 10; /* base of numeric arguments */
bool zeropad = false; /* pad with zero instead of space */
bool uppercase = false; /* use upper case for hex numbers */
int consumed = 0; /* nb of consumed format string chars */
/**
* Constructor
*
* \param format begin of command in format string
*/
explicit Format_command(const char *format)
{
/* check for command begin and eat the character */
if (format[consumed] != '%') return;
if (!format[++consumed]) return;
/* heading zero indicates zero-padding */
zeropad = (format[consumed] == '0');
/* read decimal padding value */
padding = decode_decimal(format, &consumed);
if (!format[consumed]) return;
/* decode length */
switch (format[consumed]) {
case 'l':
{
/* long long ints are marked by a subsequenting 'l' character */
bool is_long_long = (format[consumed + 1] == 'l');
length = is_long_long ? LONG_LONG : LONG;
consumed += is_long_long ? 2 : 1;
break;
}
case 'z':
length = SIZE_T;
consumed++;
break;
case 'p':
length = LONG;
break;
default: break;
}
if (!format[consumed]) return;
/* decode type */
switch (format[consumed]) {
case 'd':
case 'i': type = INT; base = 10; break;
case 'o': type = UINT; base = 8; break;
case 'u': type = UINT; base = 10; break;
case 'x': type = UINT; base = 16; break;
case 'X': type = UINT; base = 16; uppercase = 1; break;
case 'p': type = PTR; base = 16; break;
case 'c': type = CHAR; break;
case 's': type = STRING; break;
case '%': type = PERCENT; break;
case 0: return;
default: break;
}
/* eat type character */
consumed++;
}
int numeric()
{
return (type == INT || type == UINT || type == PTR);
}
};
void Console::_out_string(const char *str)
{
if (!str)
_out_string("<NULL>");
else
while (*str) _out_char(*str++);
}
void Console::printf(const char *format, ...)
{
va_list list;
va_start(list, format);
vprintf(format, list);
va_end(list);
}
void Console::vprintf(const char *format, va_list list)
{
while (*format) {
/* eat and output plain characters */
if (*format != '%') {
_out_char(*format++);
continue;
}
/* parse format argument descriptor */
Format_command cmd(format);
/* read numeric argument from va_list */
long long numeric_arg = 0;
if (cmd.numeric()) {
switch (cmd.length) {
case Format_command::LONG_LONG:
numeric_arg = va_arg(list, long long);
break;
case Format_command::LONG:
numeric_arg = (cmd.type == Format_command::UINT) ?
(long long)va_arg(list, unsigned long) : va_arg(list, long);
break;
case Format_command::SIZE_T:
numeric_arg = va_arg(list, size_t);
break;
case Format_command::DEFAULT:
numeric_arg = (cmd.type == Format_command::UINT) ?
(long long)va_arg(list, unsigned int) : va_arg(list, int);
break;
}
}
/* call type-specific output routines */
switch (cmd.type) {
case Format_command::INT:
if (cmd.length == Format_command::LONG_LONG)
out_signed<long long>(numeric_arg, cmd.base,
[&] (char c) { _out_char(c); });
else
out_signed<long>((long)numeric_arg, cmd.base,
[&] (char c) { _out_char(c); });
break;
case Format_command::UINT:
if (cmd.length == Format_command::LONG_LONG) {
out_unsigned<unsigned long long>(numeric_arg, cmd.base, cmd.padding,
[&] (char c) { _out_char(c); });
break;
}
/* fall through */
case Format_command::PTR:
out_unsigned<unsigned long>((long)numeric_arg, cmd.base, cmd.padding,
[&] (char c) { _out_char(c); });
break;
case Format_command::CHAR:
_out_char((char)va_arg(list, int));
break;
case Format_command::STRING:
_out_string(va_arg(list, const char *));
break;
case Format_command::PERCENT:
_out_char('%');
break;
case Format_command::INVALID:
_out_string("<warning: unsupported format string argument>");
/* consume the argument of the unsupported command */
va_arg(list, long);
break;
}
/* proceed with format string after command */
format += cmd.consumed;
}
}

View File

@ -38,13 +38,3 @@ Id_space<Parent::Client> &Genode::env_session_id_space()
return id_space;
}
/*
* \deprecated
*/
Connection_base::Connection_base()
:
_env(internal_env()),
_id_space_element(_parent_client, _env.id_space())
{ }

View File

@ -41,8 +41,8 @@
[init -> test-ldso] *
[init -> test-ldso] Catch exceptions in program*
[init -> test-ldso] ---------------------------*
[init -> test-ldso] *Error: ROM-session creation failed (ram_quota=*, cap_quota=*, label="unknown_rom")*
[init -> test-ldso] *Error: Could not open ROM session for "unknown_rom"*
[init -> test-ldso] *Error: ROM-session creation failed*label="unknown_rom"*
[init -> test-ldso] *Error: could not open ROM session for "unknown_rom"*
[init -> test-ldso] exception in remote procedure call: caught*
[init -> test-ldso] exception in program: caught*
[init -> test-ldso] exception in shared lib: caught*

View File

@ -26,7 +26,7 @@
[init -> test-report_rom] Reporter: start reporting (while the ROM client still listens)
[init -> test-report_rom] ROM client: wait for update notification
[init -> test-report_rom] ROM client: try to open the same report again
[init -> test-report_rom] *Error: Report-session creation failed (label="brightness", ram_quota=14336, cap_quota=3, buffer_size=4096)*
[init -> test-report_rom] *Error: Report-session creation failed*label="brightness"*
[init -> test-report_rom] ROM client: caught Service_denied - OK
[init -> test-report_rom] --- test-report_rom finished ---
[init] child "test-report_rom" exited with exit value 0