* compress.c (bfd_uncompress_section_contents): Add ATTRIBUTE_UNUSED.
* dwarf2.c (read_and_uncompress_section): New function.
(read_section): Call it.
(find_line): Likewise.
binutils/ChangeLog:
* objdump.c (load_specific_debug_section): Decompress section contents
before applying relocations.
* readelf.c (load_specific_debug_section): Update section size after
decompression.
gas/ChangeLog:
* Makefile.am: Add compress-debug.c and compress-debug.h.
* Makefile.in: Regenerate.
* config.in: Add HAVE_ZLIB_H.
* configure.in: Check for zlib.h.
* configure: Regenerate.
* as.c (parse_args): Add --compress-debug-sections and
--nocompress-debug-sections.
* as.h (flag_compress_debug): New variable.
* compress-debug.c: New file.
* compress-debug.h: New file.
* write.c: Include compress-debug.h.
(compress_frag): New function.
(compress_debug): New function.
(write_object_file): Compress debug sections if requested.
+2010-07-03 Cary Coutant <ccoutant@google.com>
+
+ * compress.c (bfd_uncompress_section_contents): Add ATTRIBUTE_UNUSED.
+ * dwarf2.c (read_and_uncompress_section): New function.
+ (read_section): Call it.
+ (find_line): Likewise.
+
2010-07-01 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ppc64_elf_edit_toc): Use SYMBOL_CALLS_LOCAL rather
-/* ELF attributes support (based on ARM EABI attributes).
+/* Compressed section support (intended for debug sections).
Copyright 2008, 2010
Free Software Foundation, Inc.
return entry ? entry->head : NULL;
}
+/* Read a section, uncompress it if necessary, and relocate it. */
+
+static bfd_boolean
+read_and_uncompress_section (bfd * abfd,
+ asection * msec,
+ bfd_boolean section_is_compressed,
+ asymbol ** syms,
+ bfd_byte ** section_buffer,
+ bfd_size_type * section_size)
+{
+ /* Get the unrelocated contents of the section. */
+ *section_buffer = (bfd_byte *) bfd_malloc (*section_size);
+ if (! *section_buffer)
+ return FALSE;
+ if (! bfd_get_section_contents (abfd, msec, *section_buffer,
+ 0, *section_size))
+ return FALSE;
+
+ if (section_is_compressed)
+ {
+ if (! bfd_uncompress_section_contents (section_buffer, section_size))
+ {
+ (*_bfd_error_handler) (_("Dwarf Error: unable to decompress %s section."),
+ bfd_get_section_name (abfd, msec));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ }
+
+ if (syms)
+ {
+ /* We want to relocate the data we've already read (and
+ decompressed), so we store a pointer to the data in
+ the bfd_section, and tell it that the contents are
+ already in memory. */
+ BFD_ASSERT (msec->contents == NULL && (msec->flags & SEC_IN_MEMORY) == 0);
+ msec->contents = *section_buffer;
+ msec->flags |= SEC_IN_MEMORY;
+ msec->size = *section_size;
+ *section_buffer
+ = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
+ if (! *section_buffer)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/* Read a section into its appropriate place in the dwarf2_debug
struct (indicated by SECTION_BUFFER and SECTION_SIZE). If SYMS is
not NULL, use bfd_simple_get_relocated_section_contents to read the
}
*section_size = msec->rawsize ? msec->rawsize : msec->size;
- if (syms)
- {
- *section_buffer
- = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
- if (! *section_buffer)
- return FALSE;
- }
- else
- {
- *section_buffer = (bfd_byte *) bfd_malloc (*section_size);
- if (! *section_buffer)
- return FALSE;
- if (! bfd_get_section_contents (abfd, msec, *section_buffer,
- 0, *section_size))
- return FALSE;
- }
- if (section_is_compressed)
- {
- if (! bfd_uncompress_section_contents (section_buffer, section_size))
- {
- (*_bfd_error_handler) (_("Dwarf Error: unable to decompress %s section."), compressed_section_name);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- }
+ if (! read_and_uncompress_section (abfd, msec, section_is_compressed,
+ syms, section_buffer, section_size))
+ return FALSE;
}
/* It is possible to get a bad value for the offset into the section
{
bfd_size_type size = msec->size;
bfd_byte *buffer, *tmp;
+ bfd_boolean is_compressed =
+ strcmp (msec->name, DWARF2_COMPRESSED_DEBUG_INFO) == 0;
if (size == 0)
continue;
- buffer = (bfd_simple_get_relocated_section_contents
- (debug_bfd, msec, NULL, symbols));
- if (! buffer)
+ if (! read_and_uncompress_section (debug_bfd, msec,
+ is_compressed, symbols,
+ &buffer, &size))
goto done;
- if (strcmp (msec->name, DWARF2_COMPRESSED_DEBUG_INFO) == 0)
- {
- if (! bfd_uncompress_section_contents (&buffer, &size))
- {
- free (buffer);
- goto done;
- }
- }
tmp = (bfd_byte *) bfd_realloc (stash->info_ptr_memory,
total_size + size);
if (tmp == NULL)
+2010-07-03 Cary Coutant <ccoutant@google.com>
+
+ * objdump.c (load_specific_debug_section): Decompress section contents
+ before applying relocations.
+ * readelf.c (load_specific_debug_section): Update section size after
+ decompression.
+
2010-06-29 Alan Modra <amodra@gmail.com>
PR binutils/3166
section->size = bfd_get_section_size (sec);
section->start = (unsigned char *) xmalloc (section->size);
- if (is_relocatable && debug_displays [debug].relocate)
- ret = bfd_simple_get_relocated_section_contents (abfd,
- sec,
- section->start,
- syms) != NULL;
- else
- ret = bfd_get_section_contents (abfd, sec, section->start, 0,
- section->size);
+ ret = bfd_get_section_contents (abfd, sec, section->start, 0,
+ section->size);
if (! ret)
{
section->size = size;
}
+ if (is_relocatable && debug_displays [debug].relocate)
+ {
+ /* We want to relocate the data we've already read (and
+ decompressed), so we store a pointer to the data in
+ the bfd_section, and tell it that the contents are
+ already in memory. */
+ sec->contents = section->start;
+ sec->flags |= SEC_IN_MEMORY;
+ sec->size = section->size;
+
+ ret = bfd_simple_get_relocated_section_contents (abfd,
+ sec,
+ section->start,
+ syms) != NULL;
+
+ if (! ret)
+ {
+ free_debug_section (debug);
+ printf (_("\nCan't get contents for section '%s'.\n"),
+ section->name);
+ return 0;
+ }
+ }
+
return 1;
}
return 0;
if (section_is_compressed)
- if (! uncompress_section_contents (§ion->start, §ion->size))
- return 0;
+ {
+ if (! uncompress_section_contents (§ion->start, §ion->size))
+ return 0;
+ sec->sh_size = section->size;
+ }
if (debug_displays [debug].relocate)
apply_relocations ((FILE *) file, sec, section->start);
+2010-07-03 Cary Coutant <ccoutant@google.com>
+
+ * Makefile.am: Add compress-debug.c and compress-debug.h.
+ * Makefile.in: Regenerate.
+ * config.in: Add HAVE_ZLIB_H.
+ * configure.in: Check for zlib.h.
+ * configure: Regenerate.
+
+ * as.c (parse_args): Add --compress-debug-sections and
+ --nocompress-debug-sections.
+ * as.h (flag_compress_debug): New variable.
+ * compress-debug.c: New file.
+ * compress-debug.h: New file.
+ * write.c: Include compress-debug.h.
+ (compress_frag): New function.
+ (compress_debug): New function.
+ (write_object_file): Compress debug sections if requested.
+
2010-07-03 Andreas Schwab <schwab@linux-m68k.org>
* config/tc-ppc.c (ppc_set_cpu): Cast PPC_OPCODE_xxx to ppc_cpu_t
app.c \
as.c \
atof-generic.c \
+ compress-debug.c \
cond.c \
depend.c \
dwarf2dbg.c \
bignum.h \
bit_fix.h \
cgen.h \
+ compress-debug.h \
dwarf2dbg.h \
dw2gencfi.h \
ecoff.h \
CONFIG_CLEAN_VPATH_FILES =
PROGRAMS = $(noinst_PROGRAMS)
am__objects_1 = app.$(OBJEXT) as.$(OBJEXT) atof-generic.$(OBJEXT) \
- cond.$(OBJEXT) depend.$(OBJEXT) dwarf2dbg.$(OBJEXT) \
- dw2gencfi.$(OBJEXT) ecoff.$(OBJEXT) ehopt.$(OBJEXT) \
- expr.$(OBJEXT) flonum-copy.$(OBJEXT) flonum-konst.$(OBJEXT) \
- flonum-mult.$(OBJEXT) frags.$(OBJEXT) hash.$(OBJEXT) \
- input-file.$(OBJEXT) input-scrub.$(OBJEXT) listing.$(OBJEXT) \
- literal.$(OBJEXT) macro.$(OBJEXT) messages.$(OBJEXT) \
- output-file.$(OBJEXT) read.$(OBJEXT) remap.$(OBJEXT) \
- sb.$(OBJEXT) stabs.$(OBJEXT) subsegs.$(OBJEXT) \
+ compress-debug.$(OBJEXT) cond.$(OBJEXT) depend.$(OBJEXT) \
+ dwarf2dbg.$(OBJEXT) dw2gencfi.$(OBJEXT) ecoff.$(OBJEXT) \
+ ehopt.$(OBJEXT) expr.$(OBJEXT) flonum-copy.$(OBJEXT) \
+ flonum-konst.$(OBJEXT) flonum-mult.$(OBJEXT) frags.$(OBJEXT) \
+ hash.$(OBJEXT) input-file.$(OBJEXT) input-scrub.$(OBJEXT) \
+ listing.$(OBJEXT) literal.$(OBJEXT) macro.$(OBJEXT) \
+ messages.$(OBJEXT) output-file.$(OBJEXT) read.$(OBJEXT) \
+ remap.$(OBJEXT) sb.$(OBJEXT) stabs.$(OBJEXT) subsegs.$(OBJEXT) \
symbols.$(OBJEXT) write.$(OBJEXT)
am_as_new_OBJECTS = $(am__objects_1)
as_new_OBJECTS = $(am_as_new_OBJECTS)
app.c \
as.c \
atof-generic.c \
+ compress-debug.c \
cond.c \
depend.c \
dwarf2dbg.c \
bignum.h \
bit_fix.h \
cgen.h \
+ compress-debug.h \
dwarf2dbg.h \
dw2gencfi.h \
ecoff.h \
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atof-vax.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfin-parse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compress-debug.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cond.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/depend.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dw2gencfi.Po@am__quote@
OPTION_AL,
OPTION_HASH_TABLE_SIZE,
OPTION_REDUCE_MEMORY_OVERHEADS,
- OPTION_WARN_FATAL
+ OPTION_WARN_FATAL,
+ OPTION_COMPRESS_DEBUG,
+ OPTION_NOCOMPRESS_DEBUG
/* When you add options here, check that they do
not collide with OPTION_MD_BASE. See as.h. */
};
,{"a", optional_argument, NULL, 'a'}
/* Handle -al=<FILE>. */
,{"al", optional_argument, NULL, OPTION_AL}
+ ,{"compress-debug-sections", no_argument, NULL, OPTION_COMPRESS_DEBUG}
+ ,{"nocompress-debug-sections", no_argument, NULL, OPTION_NOCOMPRESS_DEBUG}
,{"debug-prefix-map", required_argument, NULL, OPTION_DEBUG_PREFIX_MAP}
,{"defsym", required_argument, NULL, OPTION_DEFSYM}
,{"dump-config", no_argument, NULL, OPTION_DUMPCONFIG}
#endif
exit (EXIT_SUCCESS);
+ case OPTION_COMPRESS_DEBUG:
+ flag_compress_debug = 1;
+ break;
+
+ case OPTION_NOCOMPRESS_DEBUG:
+ flag_compress_debug = 0;
+ break;
+
case OPTION_DEBUG_PREFIX_MAP:
add_debug_prefix_map (optarg);
break;
/* True if we should generate a traditional format object file. */
COMMON int flag_traditional_format;
+/* TRUE if debug sections should be compressed. */
+COMMON int flag_compress_debug;
+
/* TRUE if .note.GNU-stack section with SEC_CODE should be created */
COMMON int flag_execstack;
/* Define to 1 if you have the `unlink' function. */
#undef HAVE_UNLINK
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H
+
/* Using i386 COFF? */
#undef I386COFF
enable_build_warnings
enable_nls
enable_maintainer_mode
+with_zlib
'
ac_precious_vars='build_alias
host_alias
--with-pic try to use only PIC/non-PIC objects [default=use
both]
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-zlib include zlib support (auto/yes/no) default=auto
Some influential environment variables:
CC C compiler command
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11196 "configure"
+#line 11198 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11302 "configure"
+#line 11304 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
;;
esac
+# Link in zlib if we can. This allows us to write compressed debug sections.
+
+ # See if the user specified whether he wants zlib support or not.
+
+# Check whether --with-zlib was given.
+if test "${with_zlib+set}" = set; then :
+ withval=$with_zlib;
+else
+ with_zlib=auto
+fi
+
+
+ if test "$with_zlib" != "no"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing zlibVersion" >&5
+$as_echo_n "checking for library containing zlibVersion... " >&6; }
+if test "${ac_cv_search_zlibVersion+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char zlibVersion ();
+int
+main ()
+{
+return zlibVersion ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' z; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_zlibVersion=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if test "${ac_cv_search_zlibVersion+set}" = set; then :
+ break
+fi
+done
+if test "${ac_cv_search_zlibVersion+set}" = set; then :
+
+else
+ ac_cv_search_zlibVersion=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_zlibVersion" >&5
+$as_echo "$ac_cv_search_zlibVersion" >&6; }
+ac_res=$ac_cv_search_zlibVersion
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+ for ac_header in zlib.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_zlib_h" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_ZLIB_H 1
+_ACEOF
+
+fi
+
+done
+
+fi
+
+ if test "$with_zlib" = "yes" -a "$ac_cv_header_zlib_h" != "yes"; then
+ as_fn_error "zlib (libz) library was explicitly requested but not found" "$LINENO" 5
+ fi
+ fi
+
+
# Support for VMS timestamps via cross compile
if test "$ac_cv_header_time_h" = yes; then
BFD_BINARY_FOPEN
+# Link in zlib if we can. This allows us to write compressed debug sections.
+AM_ZLIB
+
# Support for VMS timestamps via cross compile
if test "$ac_cv_header_time_h" = yes; then
#include "output-file.h"
#include "dwarf2dbg.h"
#include "libbfd.h"
+#include "compress-debug.h"
#ifndef TC_ADJUST_RELOC_COUNT
#define TC_ADJUST_RELOC_COUNT(FIX, COUNT)
#endif
}
+static int
+compress_frag (struct z_stream_s *strm, const char *contents, int in_size,
+ fragS **last_newf, struct obstack *ob)
+{
+ int out_size;
+ int total_out_size = 0;
+ fragS *f = *last_newf;
+ char *next_out;
+ int avail_out;
+
+ /* Call the compression routine repeatedly until it has finished
+ processing the frag. */
+ while (in_size > 0)
+ {
+ /* Reserve all the space available in the current chunk.
+ If none is available, start a new frag. */
+ avail_out = obstack_room (ob);
+ if (avail_out <= 0)
+ {
+ obstack_finish (ob);
+ f = frag_alloc (ob);
+ f->fr_type = rs_fill;
+ (*last_newf)->fr_next = f;
+ *last_newf = f;
+ avail_out = obstack_room (ob);
+ }
+ if (avail_out <= 0)
+ as_fatal (_("can't extend frag"));
+ next_out = obstack_next_free (ob);
+ obstack_blank_fast (ob, avail_out);
+ out_size = compress_data (strm, &contents, &in_size,
+ &next_out, &avail_out);
+ if (out_size < 0)
+ return -1;
+
+ f->fr_fix += out_size;
+ total_out_size += out_size;
+
+ /* Return unused space. */
+ if (avail_out > 0)
+ obstack_blank_fast (ob, -avail_out);
+ }
+
+ return total_out_size;
+}
+
+static void
+compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
+{
+ segment_info_type *seginfo = seg_info (sec);
+ fragS *f;
+ fragS *first_newf;
+ fragS *last_newf;
+ struct obstack *ob = &seginfo->frchainP->frch_obstack;
+ bfd_size_type uncompressed_size = (bfd_size_type) sec->size;
+ bfd_size_type compressed_size;
+ const char *section_name;
+ char *compressed_name;
+ char *header;
+ struct z_stream_s *strm;
+ int x;
+
+ if (seginfo == NULL
+ || !(bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
+ || (bfd_get_section_flags (abfd, sec) & SEC_ALLOC))
+ return;
+
+ section_name = bfd_get_section_name (stdoutput, sec);
+ if (strncmp (section_name, ".debug_", 7) != 0)
+ return;
+
+ strm = compress_init ();
+ if (strm == NULL)
+ return;
+
+ /* Create a new frag to contain the "ZLIB" header. */
+ first_newf = frag_alloc (ob);
+ if (obstack_room (ob) < 12)
+ first_newf = frag_alloc (ob);
+ if (obstack_room (ob) < 12)
+ as_fatal (_("can't extend frag %u chars"), 12);
+ last_newf = first_newf;
+ obstack_blank_fast (ob, 12);
+ last_newf->fr_type = rs_fill;
+ last_newf->fr_fix = 12;
+ header = last_newf->fr_literal;
+ memcpy (header, "ZLIB", 4);
+ header[11] = uncompressed_size; uncompressed_size >>= 8;
+ header[10] = uncompressed_size; uncompressed_size >>= 8;
+ header[9] = uncompressed_size; uncompressed_size >>= 8;
+ header[8] = uncompressed_size; uncompressed_size >>= 8;
+ header[7] = uncompressed_size; uncompressed_size >>= 8;
+ header[6] = uncompressed_size; uncompressed_size >>= 8;
+ header[5] = uncompressed_size; uncompressed_size >>= 8;
+ header[4] = uncompressed_size;
+ compressed_size = 12;
+
+ /* Stream the frags through the compression engine, adding new frags
+ as necessary to accomodate the compressed output. */
+ for (f = seginfo->frchainP->frch_root;
+ f;
+ f = f->fr_next)
+ {
+ offsetT fill_size;
+ char *fill_literal;
+ offsetT count;
+ int out_size;
+
+ gas_assert (f->fr_type == rs_fill);
+ if (f->fr_fix)
+ {
+ out_size = compress_frag (strm, f->fr_literal, f->fr_fix,
+ &last_newf, ob);
+ if (out_size < 0)
+ return;
+ compressed_size += out_size;
+ }
+ fill_literal = f->fr_literal + f->fr_fix;
+ fill_size = f->fr_var;
+ count = f->fr_offset;
+ gas_assert (count >= 0);
+ if (fill_size && count)
+ {
+ while (count--)
+ {
+ out_size = compress_frag (strm, fill_literal, (int) fill_size,
+ &last_newf, ob);
+ if (out_size < 0)
+ return;
+ compressed_size += out_size;
+ }
+ }
+ }
+
+ /* Flush the compression state. */
+ for (;;)
+ {
+ int avail_out;
+ char *next_out;
+ int out_size;
+
+ /* Reserve all the space available in the current chunk.
+ If none is available, start a new frag. */
+ avail_out = obstack_room (ob);
+ if (avail_out <= 0)
+ {
+ fragS *newf;
+
+ obstack_finish (ob);
+ newf = frag_alloc (ob);
+ newf->fr_type = rs_fill;
+ last_newf->fr_next = newf;
+ last_newf = newf;
+ avail_out = obstack_room (ob);
+ }
+ if (avail_out <= 0)
+ as_fatal (_("can't extend frag"));
+ next_out = obstack_next_free (ob);
+ obstack_blank_fast (ob, avail_out);
+ x = compress_finish (strm, &next_out, &avail_out, &out_size);
+ if (x < 0)
+ return;
+
+ last_newf->fr_fix += out_size;
+ compressed_size += out_size;
+
+ /* Return unused space. */
+ if (avail_out > 0)
+ obstack_blank_fast (ob, -avail_out);
+
+ if (x == 0)
+ break;
+ }
+
+ /* Replace the uncompressed frag list with the compressed frag list. */
+ seginfo->frchainP->frch_root = first_newf;
+ seginfo->frchainP->frch_last = last_newf;
+
+ /* Update the section size and its name. */
+ x = bfd_set_section_size (abfd, sec, compressed_size);
+ gas_assert (x);
+ compressed_name = (char *) xmalloc (strlen (section_name) + 2);
+ compressed_name[0] = '.';
+ compressed_name[1] = 'z';
+ strcpy (compressed_name + 2, section_name + 1);
+ bfd_section_name (stdoutput, sec) = compressed_name;
+}
+
static void
write_contents (bfd *abfd ATTRIBUTE_UNUSED,
asection *sec,
obj_frob_file_after_relocs ();
#endif
+ /* Once all relocations have been written, we can compress the
+ contents of the debug sections. This needs to be done before
+ we start writing any sections, because it will affect the file
+ layout, which is fixed once we start writing contents. */
+ if (flag_compress_debug)
+ bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
+
bfd_map_over_sections (stdoutput, write_contents, (char *) 0);
}