+/* Insert temporary breakpoint on "main" function of newly loaded
+ SPE context OBJFILE. */
+static void
+spu_catch_start (struct objfile *objfile)
+{
+ struct minimal_symbol *minsym;
+ struct symtab *symtab;
+ CORE_ADDR pc;
+ char buf[32];
+
+ /* Do this only if requested by "set spu stop-on-load on". */
+ if (!spu_stop_on_load_p)
+ return;
+
+ /* Consider only SPU objfiles. */
+ if (!objfile || bfd_get_arch (objfile->obfd) != bfd_arch_spu)
+ return;
+
+ /* The main objfile is handled differently. */
+ if (objfile == symfile_objfile)
+ return;
+
+ /* There can be multiple symbols named "main". Search for the
+ "main" in *this* objfile. */
+ minsym = lookup_minimal_symbol ("main", NULL, objfile);
+ if (!minsym)
+ return;
+
+ /* If we have debugging information, try to use it -- this
+ will allow us to properly skip the prologue. */
+ pc = SYMBOL_VALUE_ADDRESS (minsym);
+ symtab = find_pc_sect_symtab (pc, SYMBOL_OBJ_SECTION (minsym));
+ if (symtab != NULL)
+ {
+ struct blockvector *bv = BLOCKVECTOR (symtab);
+ struct block *block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ struct symbol *sym;
+ struct symtab_and_line sal;
+
+ sym = lookup_block_symbol (block, "main", NULL, VAR_DOMAIN);
+ if (sym)
+ {
+ fixup_symbol_section (sym, objfile);
+ sal = find_function_start_sal (sym, 1);
+ pc = sal.pc;
+ }
+ }
+
+ /* Use a numerical address for the set_breakpoint command to avoid having
+ the breakpoint re-set incorrectly. */
+ xsnprintf (buf, sizeof buf, "*%s", core_addr_to_string (pc));
+ set_breakpoint (get_objfile_arch (objfile),
+ buf, NULL /* condition */,
+ 0 /* hardwareflag */, 1 /* tempflag */,
+ -1 /* thread */, 0 /* ignore_count */,
+ 0 /* pending */, 1 /* enabled */);
+}
+
+
+/* Look up OBJFILE loaded into FRAME's SPU context. */
+static struct objfile *
+spu_objfile_from_frame (struct frame_info *frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ struct objfile *obj;
+
+ if (gdbarch_bfd_arch_info (gdbarch)->arch != bfd_arch_spu)
+ return NULL;
+
+ ALL_OBJFILES (obj)
+ {
+ if (obj->sections != obj->sections_end
+ && SPUADDR_SPU (obj_section_addr (obj->sections)) == tdep->id)
+ return obj;
+ }
+
+ return NULL;
+}
+
+/* Flush cache for ea pointer access if available. */
+static void
+flush_ea_cache (void)
+{
+ struct minimal_symbol *msymbol;
+ struct objfile *obj;
+
+ if (!has_stack_frames ())
+ return;
+
+ obj = spu_objfile_from_frame (get_current_frame ());
+ if (obj == NULL)
+ return;
+
+ /* Lookup inferior function __cache_flush. */
+ msymbol = lookup_minimal_symbol ("__cache_flush", NULL, obj);
+ if (msymbol != NULL)
+ {
+ struct type *type;
+ CORE_ADDR addr;
+
+ type = objfile_type (obj)->builtin_void;
+ type = lookup_function_type (type);
+ type = lookup_pointer_type (type);
+ addr = SYMBOL_VALUE_ADDRESS (msymbol);
+
+ call_function_by_hand (value_from_pointer (type, addr), 0, NULL);
+ }
+}
+
+/* This handler is called when the inferior has stopped. If it is stopped in
+ SPU architecture then flush the ea cache if used. */
+static void
+spu_attach_normal_stop (struct bpstats *bs, int print_frame)
+{
+ if (!spu_auto_flush_cache_p)
+ return;
+
+ /* Temporarily reset spu_auto_flush_cache_p to avoid recursively
+ re-entering this function when __cache_flush stops. */
+ spu_auto_flush_cache_p = 0;
+ flush_ea_cache ();
+ spu_auto_flush_cache_p = 1;
+}
+
+