|
|
8.2 printf-InnenlebenWie funktioniert der printf wirklich im Kern hier beim COBRA-Linux? Das ist die Frage! andreas@gericom:~/Development/COBRA_rot/uClinux/uClinux-dist-20040218-cobra-20040324 \
/linux-2.4.x> find . -name "*" | xargs -n3 grep 'e printf('
./fs/bfs/bfs_defs.h:#define printf(format, args...) \
./arch/i386/kernel/microcode.c:#define printf(x...) printk(##x)
./arch/i386/kernel/microcode.c:#define printf(x...)
./drivers/net/skfp/h/osdef1st.h:#define printf(s,args...) printk(KERN_INFO s, ## args)
./Documentation/cdrom/sbpcd: else printf("this CD is not an XA disk.\n");
andreas@gericom:~/Development/COBRA_rot/uClinux/uClinux-dist-20040218-cobra-20040324/linux-2.4.x>
Also ist printf ein #define. Zumindest auf Kernelebene. Bei der Suche in der libc: andreas@gericom:~/Development/COBRA_rot/uClinux/uClinux-dist-20040218-cobra-20040324 \
/uClibc/libc> find . -name "*" | xargs -n3 grep ' printf('
./inet/rpc/ruserpass.c: printf(_("out of memory"));
./inet/rpc/ruserpass.c: printf(_("out of memory"));
./misc/regex/regex.c: printf("/%lx", (long int) *p++);
./misc/regex/regex.c: printf("[:%lx:]", (long int) *p++);
./misc/regex/regex.c: printf("%C", *p++);
./stdio/stdio.c:int printf(const char * __restrict format, ...);
./stdio/printf.c:int printf(const char * __restrict format, ...)
./stdio/old_vfprintf.c: * 1) printf("%c",0) returned 0 instead of 1.
andreas@gericom:~/Development/COBRA_rot/uClinux/uClinux-dist-20040218-cobra-20040324/uClibc/libc>
Im User-Space dürfte sehr oft die Fassung aus der libc gerufen werden Hier der Blick auf ./stdio/printf.c:int printf(const char * __restrict format, ...) /**********************************************************************/
#ifdef L_printf
int printf(const char * __restrict format, ...)
{
va_list arg;
int rv;
va_start(arg, format);
rv = vfprintf(stdout, format, arg);
va_end(arg);
return rv;
}
#endif
/**********************************************************************/
printf ruft also vfprintf. Diese Funktion findet sich hier: andreas@gericom:~/Development/COBRA_rot/uClinux/uClinux-dist-20040218-cobra-20040324 \
/uClibc/libc/stdio> find . -name "*" | xargs -n3 grep ' vfprintf('
./stdio.c:int vfprintf(FILE * __restrict stream, const char * __restrict format,
./printf.c: rv = vfprintf(&f, format, arg);
./printf.c: rv = vfprintf((FILE *) &f, format, arg);
./printf.c: rv = vfprintf(&f, format, arg);
./printf.c: rv = vfprintf(&f, format, arg);
./printf.c: rv = vfprintf(f, format, arg);
./printf.c: return vfprintf(stdout, format, arg);
./printf.c: rv = vfprintf(stream, format, arg);
./printf.c: rv = vfprintf(stdout, format, arg);
./old_vfprintf.c:int vfprintf(FILE * __restrict op, register const char * __restrict fmt,
andreas@gericom:~/Development/COBRA_rot/uClinux/uClinux-dist-20040218-cobra-20040324 \
/uClibc/libc/stdio>
Konkret ist bei ./stdio.c:int vfprintf(FILE * __restrict stream, const char * __restrict format, der gefundene String auskommentiert und auch nur eine Deklaration. Wirklich definiert wird es immer noch in der Datei printf.c mittels: #ifdef L_vfprintf
#define VFPRINTF vfprintf
#define FMT_TYPE char
#define OUTNSTR _outnstr
#define STRLEN strlen
#define _PPFS_init _ppfs_init
#define OUTPUT(F,S) fputs(S,F)
#define _outnstr(stream, string, len) _stdio_fwrite(string, len, stream)
#define FP_OUT _fp_out_narrow
#ifdef __STDIO_PRINTF_FLOAT
...
#endif /* __STDIO_PRINTF_FLOAT */
#else /* L_vfprintf */
#define VFPRINTF vfwprintf
#define FMT_TYPE wchar_t
#define OUTNSTR _outnwcs
#define STRLEN wcslen
#define _PPFS_init _ppwfs_init
#define OUTPUT(F,S) fputws(S,F)
#define _outnwcs(stream, wstring, len) _wstdio_fwrite(wstring, len, stream)
#define FP_OUT _fp_out_wide
static void _outnstr(FILE *stream, const char *s, size_t wclen)
{
...
}
#ifdef __STDIO_PRINTF_FLOAT
...
#endif /* __STDIO_PRINTF_FLOAT */
static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
{
...
return 0;
}
#endif /* L_vfprintf */
static void _charpad(FILE * __restrict stream, int padchar, size_t numpad)
{
...
}
/* TODO -- Dynamically allocate work space to accomodate stack-poor archs? */
static int _do_one_spec(FILE * __restrict stream,
register ppfs_t *ppfs, int *count)
{
...
#ifdef L_vfprintf
#ifdef __UCLIBC_HAS_WCHAR__
...
#else /* __UCLIBC_HAS_WCHAR__ */
_outnstr(stream, s, slen);
#endif /* __UCLIBC_HAS_WCHAR__ */
#else /* L_vfprintf */
...
#endif /* L_vfprintf */
_charpad(stream, ' ', numpad);
}
return 0;
}
int VFPRINTF (FILE * __restrict stream,
register const FMT_TYPE * __restrict format,
va_list arg)
{
ppfs_t ppfs;
int count, r;
register const FMT_TYPE *s;
__STDIO_THREADLOCK(stream);
count = 0;
s = format;
#if defined(L_vfprintf) && defined(__UCLIBC_HAS_WCHAR__)
...
#endif
if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */
OUTNSTR(stream, (const FMT_TYPE *) ppfs.fmtpos,
STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
#if defined(L_vfprintf) && !defined(NDEBUG)
fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);
#endif
count = -1;
} else {
_ppfs_prepargs(&ppfs, arg); /* This did a va_copy!!! */
do {
while (*format && (*format != '%')) {
++format;
}
if (format-s) { /* output any literal text in format string */
if ( (r = OUTNSTR(stream, s, format-s)) < 0) {
count = -1;
break;
}
count += r;
}
if (!*format) { /* we're done */
break;
}
if (format[1] != '%') { /* if we get here, *format == '%' */
/* TODO: _do_one_spec needs to know what the output funcs are!!! */
ppfs.fmtpos = (const char *)(++format);
/* TODO: check -- should only fail on stream error */
if ( (r = _do_one_spec(stream, &ppfs, &count)) < 0) {
count = -1;
break;
}
s = format = (const FMT_TYPE *) ppfs.fmtpos;
} else { /* %% means literal %, so start new string */
s = ++format;
++format;
}
} while (1);
va_end(ppfs.arg); /* Need to clean up after va_copy! */
}
#if defined(L_vfprintf) && defined(__UCLIBC_HAS_WCHAR__)
DONE:
#endif
__STDIO_THREADUNLOCK(stream);
return count;
}
#endif
/**********************************************************************/
Wie man hier sieht, wird eigentlich die Ausgabe eines zusammenhängenden Strings sehr wohl mittels den zwei Befehlen: int VFPRINTF (FILE * __restrict stream,
register const FMT_TYPE * __restrict format,
va_list arg)
{
...
__STDIO_THREADLOCK(stream);
...
if (format-s) { /* output any literal text in format string */
if ( (r = OUTNSTR(stream, s, format-s)) < 0) {
count = -1;
break;
}
count += r;
}
...
__STDIO_THREADUNLOCK(stream);
return count;
}
also __STDIO_THREADLOCK und __STDIO_THREADUNLOCK eingesperrt, damit nicht ein zweiter Prozess oder Thread Zeichen dazwischen schummeln kann und so Buchstabensalat entsteht. Um mir Klarheit zu verschaffen, werde ich deshalb eine Debugger-Session fahren, in welcher auch die libc unter die Lupe genommen wird. Copyright © Andreas Birkert Letzte Aktualisierung am 20. Dezember 2013 |
|
|