+static void gen_enum_type(stabs_handle *h, ir_type *tp)
+{
+ unsigned type_num = get_type_number(h, tp);
+ int i, n;
+
+ SET_TYPE_READY(tp);
+ be_emit_cstring("\t.stabs\t\"");
+ emit_type_name(tp);
+ be_emit_irprintf(":T%u=e", type_num);
+ for (i = 0, n = get_enumeration_n_enums(tp); i < n; ++i) {
+ ir_enum_const *ec = get_enumeration_const(tp, i);
+ char buf[64];
+
+ tarval_snprintf(buf, sizeof(buf), get_enumeration_value(ec));
+ be_emit_irprintf("%s:%s,", get_enumeration_const_name(ec), buf);
+ }
+ be_emit_irprintf(";\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+}
+
+/**
+ * print a pointer type
+ */
+static void print_pointer_type(stabs_handle *h, ir_type *tp, int local)
+{
+ unsigned type_num = local ? h->next_type_nr++ : get_type_number(h, tp);
+ ir_type *el_tp = get_pointer_points_to_type(tp);
+ unsigned el_num = get_type_number(h, el_tp);
+
+ be_emit_irprintf("%u=*%u", type_num, el_num);
+}
+
+/**
+ * Generates a pointer type
+ *
+ * @param env the walker environment
+ * @param tp the type
+ */
+static void gen_pointer_type(wenv_t *env, ir_type *tp)
+{
+ stabs_handle *h = env->h;
+ ir_type *el_tp = get_pointer_points_to_type(tp);
+
+ SET_TYPE_READY(tp);
+ if (! IS_TYPE_READY(el_tp))
+ waitq_put(env->wq, el_tp);
+
+ be_emit_cstring("\t.stabs\t\"");
+ emit_type_name(tp);
+ be_emit_cstring(":t");
+ print_pointer_type(h, tp, 0);
+ be_emit_irprintf("\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+}
+
+/**
+ * print an array type
+ */
+static void print_array_type(stabs_handle *h, ir_type *tp, int local)
+{
+ ir_type *etp = get_array_element_type(tp);
+ size_t i, n = get_array_n_dimensions(tp);
+ unsigned type_num = local ? h->next_type_nr++ : get_type_number(h, tp);
+ size_t *perm;
+
+ be_emit_irprintf("%u=a", type_num);
+ perm = ALLOCAN(size_t, n);
+ for (i = 0; i < n; ++i) {
+ perm[i] = get_array_order(tp, i);
+ }
+
+ for (i = 0; i < n; ++i) {
+ size_t dim = perm[i];
+
+ if (is_Const(get_array_lower_bound(tp, dim)) && is_Const(get_array_upper_bound(tp, dim))) {
+ long min = get_array_lower_bound_int(tp, dim);
+ long max = get_array_upper_bound_int(tp, dim);
+
+ /* FIXME r1 must be integer type, but seems to work for now */
+ be_emit_irprintf("r1;%ld;%ld;", min, max-1);
+ }
+ }
+
+ type_num = get_type_number(h, etp);
+ be_emit_irprintf("%d", type_num);
+}
+
+/**
+ * Generates an array type
+ *
+ * @param env the walker environment
+ * @param tp the type
+ */
+static void gen_array_type(wenv_t *env, ir_type *tp)
+{
+ stabs_handle *h = env->h;
+ ir_type *etp = get_array_element_type(tp);
+
+ SET_TYPE_READY(tp);
+ if (! IS_TYPE_READY(etp))
+ waitq_put(env->wq, etp);
+
+ be_emit_cstring("\t.stabs\t\"");
+ emit_type_name(tp);
+ be_emit_cstring(":t");
+
+ print_array_type(h, tp, 0);
+
+ be_emit_irprintf("\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+}
+
+/**
+ * Generates a struct/union type
+ *
+ * @param env the walker environment
+ * @param tp the type
+ */
+static void gen_struct_union_type(wenv_t *env, ir_type *tp)
+{
+ stabs_handle *h = env->h;
+ unsigned type_num = get_type_number(h, tp);
+ int i, n;
+ char desc = 's';
+
+ SET_TYPE_READY(tp);
+ if (is_Struct_type(tp)) {
+ desc = 's';
+ if (get_type_mode(tp) != NULL) {
+ /* this is a bitfield type, ignore it safely */
+ return;
+ }
+ }
+ else if (is_Union_type(tp))
+ desc = 'u';
+
+ be_emit_cstring("\t.stabs\t\"");
+ emit_type_name(tp);
+ be_emit_irprintf(":Tt%u=%c%d", type_num, desc, get_type_size_bytes(tp));
+
+ for (i = 0, n = get_compound_n_members(tp); i < n; ++i) {
+ ir_entity *ent = get_compound_member(tp, i);
+ ir_type *mtp = get_entity_type(ent);
+ int ofs;
+ unsigned size;
+
+ if (! IS_TYPE_READY(mtp))
+ waitq_put(env->wq, mtp);
+ ofs = get_entity_offset(ent);
+ if (is_Struct_type(mtp) && get_type_mode(mtp) != NULL) {
+ /* this structure is a bitfield, skip */
+ int m;
+ int n_members = get_struct_n_members(mtp);
+
+ for (m = 0; m < n_members; ++m) {
+ ir_entity *member = get_struct_member(mtp, m);
+ ir_type *member_tp = get_entity_type(member);
+ int bofs;
+
+ type_num = get_type_number(h, member_tp);
+ size = get_type_size_bytes(member_tp) * 8;
+ bofs = (ofs + get_entity_offset(member)) * 8 + get_entity_offset_bits_remainder(member);
+
+ /* name:type, bit offset from the start of the struct', number of bits in the element. */
+ be_emit_irprintf("%s:%u,%d,%u;", get_entity_name(member), type_num, bofs, size);
+ }
+ } else {
+ /* no bitfield */
+ be_emit_irprintf("%s:", get_entity_name(ent));
+
+ if (is_Array_type(mtp)) {
+ /* use a local array definition */
+ print_array_type(h, mtp, 1);
+ } else if (is_Pointer_type(mtp)) {
+ /* use local pointer definition */
+ print_pointer_type(h, mtp, 1);
+ } else {
+ type_num = get_type_number(h, mtp);
+
+ /* name:type, bit offset from the start of the struct', number of bits in the element. */
+ be_emit_irprintf("%u", type_num);
+ }
+ size = get_type_size_bytes(mtp) * 8;
+ be_emit_irprintf(",%d,%u;", ofs * 8, size);
+ }
+ }
+ be_emit_irprintf(";\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+}
+
+/**
+ * Generates a method type
+ *
+ * @param env the walker environment
+ * @param tp the type
+ */
+static void gen_method_type(wenv_t *env, ir_type *tp)
+{
+ stabs_handle *h = env->h;
+ unsigned type_num = get_type_number(h, tp);
+ ir_type *rtp = NULL;
+ unsigned res_type_num;
+ int i, n = get_method_n_ress(tp);
+
+ SET_TYPE_READY(tp);
+ if (n > 0) {
+ rtp = get_method_res_type(tp, 0);
+ if (! IS_TYPE_READY(rtp))
+ waitq_put(env->wq, rtp);
+ }
+ res_type_num = get_type_number(h, rtp);
+
+ be_emit_cstring("\t.stabs\t\"");
+ emit_type_name(tp);
+ be_emit_irprintf(":t%u=f%u", type_num, res_type_num);
+
+ /* handle more than one return type */
+ for (i = 1; i < n; ++i) {
+ rtp = get_method_res_type(tp, i);
+ if (! IS_TYPE_READY(rtp))
+ waitq_put(env->wq, rtp);
+ res_type_num = get_type_number(h, rtp);
+ be_emit_irprintf(",%u", res_type_num);
+ }
+ be_emit_irprintf("\",%d,0,0,0\n", N_LSYM);
+ be_emit_write_line();
+}
+
+/**
+ * type-walker: generate declaration for simple types,
+ * put all other types on a wait queue
+ */
+static void walk_type(type_or_ent tore, void *ctx)
+{
+ wenv_t *env = (wenv_t*)ctx;
+ ir_type *tp;
+
+ if (is_type(tore.typ)) {
+ tp = tore.typ;
+
+ /* ignore the unknown type */
+ if (is_unknown_type(tp))
+ return;
+ } else {
+ return;
+ }
+
+ switch (get_type_tpop_code(tp)) {
+ case tpo_class:
+ if (tp == get_glob_type()) {
+ SET_TYPE_READY(tp);
+ return;
+ }
+ /* fall through */
+ case tpo_struct:
+ case tpo_union:
+ gen_struct_union_type(env, tp);
+ return;
+
+ case tpo_enumeration:
+ gen_enum_type(env->h, tp);
+ return;
+
+ case tpo_primitive:
+ gen_primitive_type(env->h, tp);
+ return;
+
+ case tpo_method:
+ gen_method_type(env, tp);
+ return;
+
+ case tpo_array:
+ gen_array_type(env, tp);
+ return;
+
+ case tpo_pointer:
+ gen_pointer_type(env, tp);
+ return;
+
+ case tpo_code:
+ case tpo_none:
+ case tpo_unknown:
+ case tpo_uninitialized:
+ /* the unknown type: ignore */
+ SET_TYPE_READY(tp);
+ return;
+ }
+ panic("Unknown tpop code");
+}
+
+/**
+ * generate declaration for all types
+ */
+static void finish_types(wenv_t *env)
+{
+ waitq *wq = env->wq;
+
+ while (! waitq_empty(wq)) {
+ ir_type *tp = (ir_type*)waitq_get(wq);
+ if (IS_TYPE_READY(tp))
+ continue;
+
+ switch (get_type_tpop_code(tp)) {
+ case tpo_method:
+ gen_method_type(env, tp);
+ break;
+ case tpo_class:
+ case tpo_union:
+ case tpo_struct:
+ gen_struct_union_type(env, tp);
+ break;
+ case tpo_enumeration:
+ gen_enum_type(env->h, tp);
+ break;
+ case tpo_primitive:
+ gen_primitive_type(env->h, tp);
+ break;
+ case tpo_array:
+ gen_array_type(env, tp);
+ break;
+ case tpo_pointer:
+ gen_pointer_type(env, tp);
+ break;
+ case tpo_unknown:
+ /* the unknown type: ignore */
+ SET_TYPE_READY(tp);
+ break;
+ default:
+ assert(! "Unknown tpop code");
+ }
+ }
+}
+
+/**
+ * generate all types.
+ */
+static void gen_types(stabs_handle *h)
+{
+ wenv_t env;
+
+ env.h = h;
+ env.wq = new_waitq();
+
+ irp_reserve_resources(irp, IRP_RESOURCE_TYPE_LINK);
+ type_walk(NULL, walk_type, &env);
+ irp_free_resources(irp, IRP_RESOURCE_TYPE_LINK);
+
+ finish_types(&env);
+ del_waitq(env.wq);
+
+}
+
+
+/* -------------------------- I/F ----------------------------- */
+
+/**
+ * start a new source object (compilation unit)
+ */
+static void stabs_unit_begin(dbg_handle *handle, const char *filename)
+{