Commit 379fd05b authored by Matthias Braun's avatar Matthias Braun
Browse files

- cleanup and rewrite some of the dbgout stuff (no passing around of handles anymore)

- port stabs debug output to beemitter
- support Mach-O in begnuas
- cleanups

[r18292]
parent 55ca37ef
......@@ -49,6 +49,7 @@
#include "../beblocksched.h"
#include "../beirg_t.h"
#include "../begnuas.h"
#include "../be_dbgout.h"
#include "arm_emitter.h"
#include "gen_arm_emitter.h"
......@@ -985,40 +986,6 @@ static void arm_register_emitters(void) {
#undef SILENCE
}
static const char *last_name = NULL;
static unsigned last_line = -1;
static unsigned num = -1;
/**
* Emit the debug support for node node.
*/
static void arm_emit_dbg(const ir_node *irn) {
dbg_info *db = get_irn_dbg_info(irn);
unsigned lineno;
const char *fname = ir_retrieve_dbg_info(db, &lineno);
if (! cg->birg->main_env->options->stabs_debug_support)
return;
if (fname) {
if (last_name != fname) {
last_line = -1;
be_dbg_include_begin(cg->birg->main_env->db_handle, fname);
last_name = fname;
}
if (last_line != lineno) {
char name[64];
snprintf(name, sizeof(name), ".LM%u", ++num);
last_line = lineno;
be_dbg_line(cg->birg->main_env->db_handle, lineno, name);
be_emit_string(name);
be_emit_cstring(":\n");
be_emit_write_line();
}
}
}
/**
* Emits code for a node.
*/
......@@ -1027,7 +994,7 @@ static void arm_emit_node(const ir_node *irn) {
if (op->ops.generic) {
emit_func *emit = (emit_func *)op->ops.generic;
arm_emit_dbg(irn);
be_dbg_set_dbg_info(get_irn_dbg_info(irn));
(*emit)(irn);
} else {
be_emit_cstring("\t/* TODO */");
......@@ -1097,7 +1064,7 @@ static void arm_gen_block(ir_node *block, ir_node *prev_block) {
ir_node *irn;
arm_emit_block_header(block, prev_block);
arm_emit_dbg(block);
be_dbg_set_dbg_info(get_irn_dbg_info(block));
sched_foreach(block, irn) {
arm_emit_node(irn);
}
......
......@@ -27,86 +27,32 @@
#ifndef FIRM_BE_BE_DBGOUT_H
#define FIRM_BE_BE_DBGOUT_H
#include "obst.h"
#include "beabi_t.h"
#include "beabi.h"
typedef struct dbg_handle dbg_handle;
/**
* Debug operations.
*/
typedef struct debug_ops {
/** close the stabs handler. */
void (*close)(dbg_handle *handle);
/** start a new source object (compilation unit) */
void (*so)(dbg_handle *handle, const char *filename);
/** start an include file */
void (*include_begin)(dbg_handle *handle, const char *filename);
/** end an include file */
void (*include_end)(dbg_handle *handle);
/** Main Program */
void (*main_program)(dbg_handle *handle);
/** dumps the stabs for a method begin */
void (*method_begin)(dbg_handle *handle, ir_entity *ent, const be_stack_layout_t *layout);
/** dumps the stabs for a method end */
void (*method_end)(dbg_handle *handle);
/** dumps a line number */
void (*line)(dbg_handle *handle, unsigned lineno, const char *address);
/** dump types */
void (*types)(dbg_handle *handle);
/** dump a variable in the global type */
void (*variable)(dbg_handle *h, struct obstack *obst, ir_entity *ent);
} debug_ops;
/** The base class of all debug implementations. */
struct dbg_handle {
const debug_ops *ops;
};
/* initialize and open debug handle */
void be_dbg_open(void);
/** close a debug handler. */
void be_dbg_close(dbg_handle *handle);
void be_dbg_close(void);
/** start a new source object (compilation unit) */
void be_dbg_so(dbg_handle *handle, const char *filename);
/** start an include file */
void be_dbg_include_begin(dbg_handle *handle, const char *filename);
/** end an include file */
void be_dbg_include_end(dbg_handle *handle);
void be_dbg_so(const char *filename);
/** Main program */
void be_dbg_main_program(dbg_handle *handle);
void be_dbg_main_program(void);
/** debug for a method begin */
void be_dbg_method_begin(dbg_handle *handle, ir_entity *ent, const be_stack_layout_t *layout);
void be_dbg_method_begin(ir_entity *ent, const be_stack_layout_t *layout);
/** debug for a method end */
void be_dbg_method_end(dbg_handle *handle);
/** debug for line number */
void be_dbg_line(dbg_handle *handle, unsigned lineno, const char *address);
void be_dbg_method_end(void);
/** dump types */
void be_dbg_types(dbg_handle *handle);
void be_dbg_types(void);
/** dump a variable in the global type */
void be_dbg_variable(dbg_handle *handle, struct obstack *obst, ir_entity *ent);
/** Opens the NULL handler: no debug support. */
dbg_handle *be_nulldbg_open(void);
void be_dbg_variable(struct obstack *obst, ir_entity *ent);
/** Opens a stabs handler. */
dbg_handle *be_stabs_open(FILE *out);
void be_dbg_set_dbg_info(dbg_info *dbgi);
#endif /* FIRM_BE_BE_DBGOUT_H */
#endif
/*
* Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
*
* This file is part of libFirm.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation and appearing in the file LICENSE.GPL included in the
* packaging of this file.
*
* Licensees holding valid libFirm Professional Edition licenses may use
* this file in accordance with the libFirm Commercial License.
* Agreement provided with the Software.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE.
*/
/**
* @file
* @brief Debug output support.
* @author Michael Beck
* @date 11.9.2006
* @version $Id: be_dbgout.h 17143 2008-01-02 20:56:33Z beck $
*/
#ifndef FIRM_BE_BE_DBGOUT_T_H
#define FIRM_BE_BE_DBGOUT_T_H
#include "obst.h"
#include "beabi_t.h"
#include "firm_types.h"
typedef struct dbg_handle dbg_handle;
/**
* Debug operations.
*/
typedef struct debug_ops {
/** close the stabs handler. */
void (*close)(dbg_handle *handle);
/** start a new source object (compilation unit) */
void (*so)(dbg_handle *handle, const char *filename);
/** Main Program */
void (*main_program)(dbg_handle *handle);
/** dumps the stabs for a method begin */
void (*method_begin)(dbg_handle *handle, ir_entity *ent, const be_stack_layout_t *layout);
/** dumps the stabs for a method end */
void (*method_end)(dbg_handle *handle);
/** dump types */
void (*types)(dbg_handle *handle);
/** dump a variable in the global type */
void (*variable)(dbg_handle *h, struct obstack *obst, ir_entity *ent);
/** notify debug info about position change */
void (*set_dbg_info)(dbg_handle *h, dbg_info *dbgi);
} debug_ops;
/** The base class of all debug implementations. */
struct dbg_handle {
const debug_ops *ops;
};
typedef dbg_handle* (*be_create_dbgout_module_func)(void);
void be_register_dbgout_module(const char *name,
be_create_dbgout_module_func func);
#endif
......@@ -34,7 +34,6 @@
#include "be.h"
#include "bearch.h"
#include "be_dbgout.h"
#include "beirg.h"
#define DUMP_NONE 0
......@@ -68,9 +67,9 @@ struct be_options_t {
int timing; /**< time the backend phases */
int opt_profile; /**< instrument code for profiling */
int omit_fp; /**< try to omit the frame pointer */
int stabs_debug_support; /**< enable stabs debugging support */
int vrfy_option; /**< backend verify option */
int scheduler; /**< the scheduler */
char target_os[128]; /**< target operating system name */
char ilp_server[128]; /**< the ilp server name */
char ilp_solver[128]; /**< the ilp solver name */
int statev; /**< enable stat event dumping */
......@@ -83,7 +82,6 @@ struct be_main_env_t {
be_options_t *options;
arch_code_generator_t *cg;
arch_irn_handler_t *phi_handler;
dbg_handle *db_handle;
const char *cup_name;
};
......
/*
* Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
*
* This file is part of libFirm.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation and appearing in the file LICENSE.GPL included in the
* packaging of this file.
*
* Licensees holding valid libFirm Professional Edition licenses may use
* this file in accordance with the libFirm Commercial License.
* Agreement provided with the Software.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE.
*/
/**
* @file
* @brief Stabs support.
* @author Michael Beck
* @date 11.9.2006
* @version $Id: bestabs.c 17143 2008-01-02 20:56:33Z beck $
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "be_dbgout_t.h"
#include "bemodule.h"
#include "irtools.h"
static dbg_handle *handle = NULL;
void be_dbg_close(void) {
if (handle->ops->close)
handle->ops->close(handle);
}
void be_dbg_so(const char *filename) {
if (handle->ops->so)
handle->ops->so(handle, filename);
}
void be_dbg_main_program(void) {
if (handle->ops->main_program)
handle->ops->main_program(handle);
}
void be_dbg_method_begin(ir_entity *ent, const be_stack_layout_t *layout) {
if (handle->ops->method_begin)
handle->ops->method_begin(handle, ent, layout);
}
void be_dbg_method_end(void) {
if (handle->ops->method_end)
handle->ops->method_end(handle);
}
void be_dbg_types(void) {
if (handle->ops->types)
handle->ops->types(handle);
}
void be_dbg_variable(struct obstack *obst, ir_entity *ent) {
if (handle->ops->variable)
handle->ops->variable(handle, obst, ent);
}
void be_dbg_set_dbg_info(dbg_info *dbgi) {
if (handle->ops->set_dbg_info)
handle->ops->set_dbg_info(handle, dbgi);
}
static be_module_list_entry_t *dbgout_modules = NULL;
static be_create_dbgout_module_func selected_dbgout_module = NULL;
void be_dbg_open(void) {
handle = selected_dbgout_module();
}
void be_register_dbgout_module(const char *name,
be_create_dbgout_module_func func);
void be_register_dbgout_module(const char *name,
be_create_dbgout_module_func func)
{
if (selected_dbgout_module == NULL)
selected_dbgout_module = func;
be_add_module_to_list(&dbgout_modules, name, func);
}
static dbg_handle *create_null_dbgout_module(void)
{
static const debug_ops null_ops;
static dbg_handle null_handle = { &null_ops };
return &null_handle;
}
void be_init_dbgout(void) {
lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
be_add_module_list_opt(be_grp, "debuginfo", "debug info format",
&dbgout_modules, (void**) &selected_dbgout_module);
be_register_dbgout_module("null", create_null_dbgout_module);
}
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_dbgout);
......@@ -50,7 +50,7 @@
typedef struct obstack obstack_t;
/** by default, we generate assembler code for the Linux gas */
be_gas_flavour_t be_gas_flavour = GAS_FLAVOUR_NORMAL;
be_gas_flavour_t be_gas_flavour = GAS_FLAVOUR_ELF;
/**
* Return the pseudo-instruction to be issued for a section switch
......@@ -61,8 +61,8 @@ be_gas_flavour_t be_gas_flavour = GAS_FLAVOUR_NORMAL;
* @return the pseudo-instruction
*/
static const char *get_section_name(be_gas_section_t section) {
static const char *text[GAS_FLAVOUR_MAX][GAS_SECTION_MAX] = {
{
static const char *text[GAS_FLAVOUR_LAST+1][GAS_SECTION_LAST+1] = {
{ /* GAS_FLAVOUR_ELF */
".section\t.text",
".section\t.data",
".section\t.rodata",
......@@ -70,7 +70,7 @@ static const char *get_section_name(be_gas_section_t section) {
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits"
},
{
{ /* GAS_FLAVOUR_MINGW */
".section\t.text",
".section\t.data",
".section .rdata,\"dr\"",
......@@ -78,27 +78,29 @@ static const char *get_section_name(be_gas_section_t section) {
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits"
},
{
{ /* GAS_FLAVOUR_YASM */
".section\t.text",
".section\t.data",
".section\t.rodata",
".section\t.bss",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits"
".section\t.data",
".section\t.rodata",
".section\t.bss",
".section\t.tbss,\"awT\",@nobits",
".section\t.ctors,\"aw\",@progbits"
},
{ /* GAS_FLAVOUR_MACH_O */
".text",
".data",
".const",
".data",
"", /* TLS is not supported on Mach-O */
"" /* constructors aren't marked with sections in Mach-O */
}
};
assert((int) be_gas_flavour >= 0 && be_gas_flavour < GAS_FLAVOUR_MAX);
assert((int) section >= 0 && section < GAS_SECTION_MAX);
assert((int) be_gas_flavour >= 0 && be_gas_flavour <= GAS_FLAVOUR_LAST);
assert((int) section >= 0 && section <= GAS_SECTION_LAST);
return text[be_gas_flavour][section];
}
/**
* Emit necessary code to switch to a section.
*
* @param env the emitter environment
* @param section the section to switch to
*/
void be_gas_emit_switch_section(be_gas_section_t section) {
be_emit_char('\t');
be_emit_string(get_section_name(section));
......@@ -106,6 +108,74 @@ void be_gas_emit_switch_section(be_gas_section_t section) {
be_emit_write_line();
}
void be_gas_emit_function_prolog(ir_entity *entity, unsigned alignment)
{
const char *name = get_entity_ld_name(entity);
be_gas_emit_switch_section(GAS_SECTION_TEXT);
/* write the begin line (used by scripts processing the assembler... */
be_emit_write_line();
be_emit_cstring("# -- Begin ");
be_emit_string(name);
be_emit_char('\n');
be_emit_write_line();
if (be_gas_flavour != GAS_FLAVOUR_MACH_O) {
unsigned maximum_skip = (1 << alignment) - 1;
be_emit_cstring("\t.p2align ");
be_emit_irprintf("%u,,%u\n", alignment, maximum_skip);
be_emit_write_line();
}
if (get_entity_visibility(entity) == visibility_external_visible) {
be_emit_cstring(".global ");
be_emit_string(name);
be_emit_char('\n');
be_emit_write_line();
}
switch (be_gas_flavour) {
case GAS_FLAVOUR_ELF:
be_emit_cstring("\t.type\t");
be_emit_string(name);
be_emit_cstring(", @function\n");
be_emit_write_line();
break;
case GAS_FLAVOUR_MINGW:
be_emit_cstring("\t.def\t");
be_emit_string(name);
be_emit_cstring(";\t.scl\t2;\t.type\t32;\t.endef\n");
be_emit_write_line();
break;
case GAS_FLAVOUR_MACH_O:
case GAS_FLAVOUR_YASM:
break;
}
be_emit_string(name);
be_emit_cstring(":\n");
be_emit_write_line();
}
void be_gas_emit_function_epilog(ir_entity *entity)
{
const char *name = get_entity_ld_name(entity);
if (be_gas_flavour == GAS_FLAVOUR_ELF) {
be_emit_cstring("\t.size\t");
be_emit_string(name);
be_emit_cstring(", .-");
be_emit_string(name);
be_emit_char('\n');
be_emit_write_line();
}
be_emit_cstring("# -- End ");
be_emit_string(name);
be_emit_char('\n');
be_emit_write_line();
}
/**
* An environment containing all needed dumper data.
* Currently we create the file completely in memory first, then
......@@ -385,7 +455,7 @@ static void dump_size_type(obstack_t *obst, size_t size) {
break;
default:
fprintf(stderr, "Try to dump a type with %d bytes\n", size);
fprintf(stderr, "Try to dump a type with %u bytes\n", (unsigned) size);
assert(0);
}
}
......@@ -1003,12 +1073,14 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent, int emit_commons
obst = env->data_obst;
if (is_Method_type(type)) {
if (get_method_img_section(ent) == section_constructors) {
if (be_gas_flavour != GAS_FLAVOUR_MACH_O
&& get_method_img_section(ent) == section_constructors) {
obst = env->ctor_obst;
obstack_printf(obst, ".balign\t%u\n", align);
dump_size_type(obst, align);
obstack_printf(obst, "%s\n", ld_name);
}
return;
}
......@@ -1024,7 +1096,7 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent, int emit_commons
emit_as_common = 1;
}
be_dbg_variable(env->main_env->db_handle, obst, ent);
be_dbg_variable(obst, ent);
/* global or not global */
if (visibility == visibility_external_visible && !emit_as_common) {
......@@ -1046,7 +1118,8 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent, int emit_commons
if (variability == variability_uninitialized) {
if (emit_as_common) {
switch (be_gas_flavour) {
case GAS_FLAVOUR_NORMAL:
case GAS_FLAVOUR_ELF:
case GAS_FLAVOUR_MACH_O:
case GAS_FLAVOUR_YASM:
obstack_printf(obst, "\t.comm %s,%u,%u\n",
ld_name, get_type_size_bytes(type), align);
......@@ -1055,8 +1128,6 @@ static void dump_global(be_gas_decl_env_t *env, ir_entity *ent, int emit_commons
obstack_printf(obst, "\t.comm %s,%u # %u\n",
ld_name, get_type_size_bytes(type), align);
break;
case GAS_FLAVOUR_MAX:
panic("invalid gas flavour selected");
}
} else {
obstack_printf(obst, "\t.zero %u\n", get_type_size_bytes(type));
......
......@@ -34,23 +34,24 @@
* Sections.
*/
typedef enum section_t {
GAS_SECTION_TEXT = 0, /**< text section */
GAS_SECTION_DATA = 1, /**< data section */
GAS_SECTION_RODATA = 2, /**< rodata section */
GAS_SECTION_COMMON = 3, /**< common section */
GAS_SECTION_TLS = 4, /**< thread local storage section */
GAS_SECTION_CTOR = 5, /**< ctor section for instrumentation code init */
GAS_SECTION_MAX = 6
GAS_SECTION_TEXT, /**< text section */
GAS_SECTION_DATA, /**< data section */
GAS_SECTION_RODATA, /**< rodata section */
GAS_SECTION_COMMON, /**< common section */
GAS_SECTION_TLS, /**< thread local storage section */
GAS_SECTION_CTOR, /**< ctor section for instrumentation code init */
GAS_SECTION_LAST = GAS_SECTION_CTOR
} be_gas_section_t;
/**
* Support for some GAS "dialects".
*/
typedef enum asm_flavour_t {
GAS_FLAVOUR_NORMAL = 0, /**< normal gas (ELF) */
GAS_FLAVOUR_MINGW = 1, /**< MinGW variant (no-ELF) */
GAS_FLAVOUR_YASM = 2, /**< YASM GNU parser */
GAS_FLAVOUR_MAX = 3
GAS_FLAVOUR_ELF, /**< ELF variant */
GAS_FLAVOUR_MINGW, /**< MinGW variant (no-ELF) */
GAS_FLAVOUR_YASM, /**< YASM GNU parser */
GAS_FLAVOUR_MACH_O, /**< Mach-O variant (as found on darwin, OS/X) */
GAS_FLAVOUR_LAST = GAS_FLAVOUR_MACH_O
} be_gas_flavour_t;
/** The variable where the GAS dialect is stored. */
......@@ -58,7 +59,6 @@ extern be_gas_flavour_t be_gas_flavour;
/**
* Generate all entities.
* @param env the emitter environment
* @param main_env the main backend environment
* @param emit_commons if non-zero, emit commons (non-local uninitialized entities)
* @param only_emit_marked if non-zero, external allocated entities that do not have
......@@ -70,14 +70,20 @@ void be_gas_emit_decls(const be_main_env_t *main_env,
/**
* Switch the current output section to the given out.
*
* @param env the emitter environment
* @param section the new output section
*/
void be_gas_emit_switch_section(be_gas_section_t section);
/**
* emit assembler instructions necessary before starting function code
*/
void be_gas_emit_function_prolog(ir_entity *entity, unsigned alignment);