static CORE_ADDR
tilegx_push_dummy_call (struct gdbarch *gdbarch,
struct value *function,
struct regcache *regcache,
CORE_ADDR bp_addr, int nargs,
struct value **args,
CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR stack_dest = sp;
int argreg = TILEGX_R0_REGNUM;
int i, j;
int typelen, slacklen, alignlen;
static const gdb_byte four_zero_words[16] = { 0 };
/* If struct_return is 1, then the struct return address will
consume one argument-passing register. */
if (struct_return)
regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
/* Arguments are passed in R0 - R9, and as soon as an argument
will not fit completely in the remaining registers, then it,
and all remaining arguments, are put on the stack. */
for (i = 0; i < nargs && argreg <= TILEGX_R9_REGNUM; i++)
{
const gdb_byte *val;
typelen = TYPE_LENGTH (value_enclosing_type (args[i]));
if (typelen > (TILEGX_R9_REGNUM - argreg + 1) * tilegx_reg_size)
break;
/* Put argument into registers wordwise. */
val = value_contents (args[i]);
for (j = 0; j < typelen; j += tilegx_reg_size)
{
/* ISSUE: Why special handling for "typelen = 4x + 1"?
I don't ever see "typelen" values except 4 and 8. */
int n = (typelen - j == 1) ? 1 : tilegx_reg_size;
ULONGEST w = extract_unsigned_integer (val + j, n, byte_order);
regcache_cooked_write_unsigned (regcache, argreg++, w);
}
}
/* Align SP. */
stack_dest = tilegx_frame_align (gdbarch, stack_dest);
/* Loop backwards through remaining arguments and push them on
the stack, word aligned. */
for (j = nargs - 1; j >= i; j--)
{
gdb_byte *val;
struct cleanup *back_to;
const gdb_byte *contents = value_contents (args[j]);
typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
slacklen = align_up (typelen, 8) - typelen;
val = xmalloc (typelen + slacklen);
back_to = make_cleanup (xfree, val);
memcpy (val, contents, typelen);
memset (val + typelen, 0, slacklen);
/* Now write data to the stack. The stack grows downwards. */
stack_dest -= typelen + slacklen;
write_memory (stack_dest, val, typelen + slacklen);
do_cleanups (back_to);
}
/* Add 16 bytes for linkage space to the stack. */
stack_dest = stack_dest - 16;
write_memory (stack_dest, four_zero_words, 16);
/* Update stack pointer. */
regcache_cooked_write_unsigned (regcache, TILEGX_SP_REGNUM, stack_dest);
/* Set the return address register to point to the entry point of
the program, where a breakpoint lies in wait. */
regcache_cooked_write_unsigned (regcache, TILEGX_LR_REGNUM, bp_addr);
return stack_dest;
}
//.........这里部分代码省略.........
catch_command_errors (tty_command, ttyarg, !batch, RETURN_MASK_ALL);
/* Error messages should no longer be distinguished with extra output. */
error_pre_print = NULL;
quit_pre_print = NULL;
warning_pre_print = _("warning: ");
/* Read the .gdbinit file in the current directory, *if* it isn't
the same as the $HOME/.gdbinit file (it should exist, also). */
if (!homedir
|| memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat)))
if (!inhibit_gdbinit)
{
catch_command_errors (source_command, gdbinit, 0, RETURN_MASK_ALL);
}
for (i = 0; i < ncmd; i++)
{
#if 0
/* NOTE: cagney/1999-11-03: SET_TOP_LEVEL() was a macro that
expanded into a call to setjmp(). */
if (!SET_TOP_LEVEL ()) /* NB: This is #if 0'd out */
{
/* NOTE: I am commenting this out, because it is not clear
where this feature is used. It is very old and
undocumented. ezannoni: 1999-05-04 */
#if 0
if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
read_command_file (stdin);
else
#endif
source_command (cmdarg[i], !batch);
do_cleanups (ALL_CLEANUPS);
}
#endif
catch_command_errors (source_command, cmdarg[i], !batch, RETURN_MASK_ALL);
}
xfree (cmdarg);
/* Read in the old history after all the command files have been read. */
init_history ();
if (batch)
{
if (attach_flag)
/* Either there was a problem executing the command in the
batch file aborted early, or the batch file forgot to do an
explicit detach. Explicitly detach the inferior ensuring
that there are no zombies. */
target_detach (NULL, 0);
/* We have hit the end of the batch file. */
exit (0);
}
/* Do any host- or target-specific hacks. This is used for i960 targets
to force the user to set a nindy target and spec its parameters. */
#ifdef BEFORE_MAIN_LOOP_HOOK
BEFORE_MAIN_LOOP_HOOK;
#endif
/* Show time and/or space usage. */
if (display_time)
//.........这里部分代码省略.........
explicit_loc.label_name = oarg;
break;
case EXPLICIT_LINE_OPT:
is_explicit = 1;
explicit_loc.line_offset = linespec_parse_line_offset (oarg);
break;
}
}
if (oind >= argc && !is_explicit)
error (_("-%s-insert: Missing <location>"),
dprintf ? "dprintf" : "break");
if (dprintf)
{
int format_num = is_explicit ? oind : oind + 1;
if (hardware || tracepoint)
error (_("-dprintf-insert: does not support -h or -a"));
if (format_num >= argc)
error (_("-dprintf-insert: Missing <format>"));
extra_string = mi_argv_to_format (argv + format_num, argc - format_num);
make_cleanup (xfree, extra_string);
address = argv[oind];
}
else
{
if (is_explicit)
{
if (oind < argc)
error (_("-break-insert: Garbage following explicit location"));
}
else
{
if (oind < argc - 1)
error (_("-break-insert: Garbage following <location>"));
address = argv[oind];
}
}
/* Now we have what we need, let's insert the breakpoint! */
setup_breakpoint_reporting ();
if (tracepoint)
{
/* Note that to request a fast tracepoint, the client uses the
"hardware" flag, although there's nothing of hardware related to
fast tracepoints -- one can implement slow tracepoints with
hardware breakpoints, but fast tracepoints are always software.
"fast" is a misnomer, actually, "jump" would be more appropriate.
A simulator or an emulator could conceivably implement fast
regular non-jump based tracepoints. */
type_wanted = hardware ? bp_fast_tracepoint : bp_tracepoint;
ops = &tracepoint_breakpoint_ops;
}
else if (dprintf)
{
type_wanted = bp_dprintf;
ops = &dprintf_breakpoint_ops;
}
else
{
type_wanted = hardware ? bp_hardware_breakpoint : bp_breakpoint;
ops = &bkpt_breakpoint_ops;
}
if (is_explicit)
{
/* Error check -- we must have one of the other
parameters specified. */
if (explicit_loc.source_filename != NULL
&& explicit_loc.function_name == NULL
&& explicit_loc.label_name == NULL
&& explicit_loc.line_offset.sign == LINE_OFFSET_UNKNOWN)
error (_("-%s-insert: --source option requires --function, --label,"
" or --line"), dprintf ? "dprintf" : "break");
location = new_explicit_location (&explicit_loc);
}
else
{
location = string_to_event_location (&address, current_language);
if (*address)
{
delete_event_location (location);
error (_("Garbage '%s' at end of location"), address);
}
}
make_cleanup_delete_event_location (location);
create_breakpoint (get_current_arch (), location, condition, thread,
extra_string,
0 /* condition and thread are valid. */,
temp_p, type_wanted,
ignore_count,
pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
ops, 0, enabled, 0, 0);
do_cleanups (back_to);
}
//.........这里部分代码省略.........
/* Now open and digest the file the user requested, if any. */
if (!filename)
{
if (from_tty)
printf_unfiltered (_("No executable file now.\n"));
set_gdbarch_from_file (NULL);
}
else
{
struct cleanup *cleanups;
char *scratch_pathname;
int scratch_chan;
scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, filename,
write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY,
&scratch_pathname);
#if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__)
if (scratch_chan < 0)
{
char *exename = alloca (strlen (filename) + 5);
strcat (strcpy (exename, filename), ".exe");
scratch_chan = openp (getenv ("PATH"), OPF_TRY_CWD_FIRST, exename,
write_files ? O_RDWR | O_BINARY : O_RDONLY | O_BINARY,
&scratch_pathname);
}
#endif
if (scratch_chan < 0)
perror_with_name (filename);
exec_bfd = bfd_fopen (scratch_pathname, gnutarget,
write_files ? FOPEN_RUB : FOPEN_RB,
scratch_chan);
if (!exec_bfd)
{
close (scratch_chan);
error (_("\"%s\": could not open as an executable file: %s"),
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
/* At this point, scratch_pathname and exec_bfd->name both point to the
same malloc'd string. However exec_close() will attempt to free it
via the exec_bfd->name pointer, so we need to make another copy and
leave exec_bfd as the new owner of the original copy. */
scratch_pathname = xstrdup (scratch_pathname);
cleanups = make_cleanup (xfree, scratch_pathname);
if (!bfd_check_format (exec_bfd, bfd_object))
{
/* Make sure to close exec_bfd, or else "run" might try to use
it. */
exec_close (0);
error (_("\"%s\": not in executable format: %s"),
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
/* FIXME - This should only be run for RS6000, but the ifdef is a poor
way to accomplish. */
#ifdef DEPRECATED_IBM6000_TARGET
/* Setup initial vmap. */
map_vmap (exec_bfd, 0);
if (vmap == NULL)
{
/* Make sure to close exec_bfd, or else "run" might try to use
it. */
exec_close (0);
error (_("\"%s\": can't find the file sections: %s"),
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
#endif /* DEPRECATED_IBM6000_TARGET */
if (build_section_table (exec_bfd, &exec_ops.to_sections,
&exec_ops.to_sections_end))
{
/* Make sure to close exec_bfd, or else "run" might try to use
it. */
exec_close (0);
error (_("\"%s\": can't find the file sections: %s"),
scratch_pathname, bfd_errmsg (bfd_get_error ()));
}
exec_bfd_mtime = bfd_get_mtime (exec_bfd);
validate_files ();
set_gdbarch_from_file (exec_bfd);
push_target (&exec_ops);
/* Tell display code (if any) about the changed file name. */
if (deprecated_exec_file_display_hook)
(*deprecated_exec_file_display_hook) (filename);
do_cleanups (cleanups);
}
bfd_cache_close_all ();
observer_notify_executable_changed ();
}
开发者ID:davearrama,项目名称:gdb,代码行数:101,代码来源:exec.c
示例8: read_pe_exported_syms
//.........这里部分代码省略.........
if (vaddr <= export_rva && vaddr + vsize > export_rva)
{
expptr = fptr + (export_rva - vaddr);
if (export_rva + export_size > vaddr + vsize)
export_size = vsize - (export_rva - vaddr);
break;
}
}
if (export_size == 0)
{
/* Empty export table. */
return;
}
/* Scan sections and store the base and size of the relevant sections. */
for (i = 0; i < nsections; i++)
{
unsigned long secptr1 = secptr + 40 * i;
unsigned long vsize = pe_get32 (dll, secptr1 + 8);
unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
unsigned long flags = pe_get32 (dll, secptr1 + 36);
char sec_name[9];
int sectix;
sec_name[8] = '\0';
bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
bfd_bread (sec_name, (bfd_size_type) 8, dll);
sectix = read_pe_section_index (sec_name);
if (sectix != PE_SECTION_INDEX_INVALID)
{
section_data[sectix].rva_start = vaddr;
section_data[sectix].rva_end = vaddr + vsize;
}
}
expdata = (unsigned char *) xmalloc (export_size);
back_to = make_cleanup (xfree, expdata);
bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
bfd_bread (expdata, (bfd_size_type) export_size, dll);
erva = expdata - export_rva;
nexp = pe_as32 (expdata + 24);
name_rvas = pe_as32 (expdata + 32);
ordinals = pe_as32 (expdata + 36);
ordbase = pe_as32 (expdata + 16);
exp_funcbase = pe_as32 (expdata + 28);
/* Use internal dll name instead of full pathname. */
dll_name = pe_as32 (expdata + 12) + erva;
bfd_map_over_sections (dll, get_section_vmas, section_data);
/* Adjust the vma_offsets in case this PE got relocated. This
assumes that *all* sections share the same relocation offset
as the text section. */
for (i = 0; i < PE_SECTION_TABLE_SIZE; i++)
{
section_data[i].vma_offset
+= ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
}
printf_filtered ("Minimal symbols from %s...", dll_name);
wrap_here ("");
/* Truncate name at first dot. Should maybe also convert to all
lower case for convenience on Windows. */
read_pe_truncate_name (dll_name);
/* Iterate through the list of symbols. */
for (i = 0; i < nexp; i++)
{
/* Pointer to the names vector. */
unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
/* Pointer to the function address vector. */
unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4);
/* Find this symbol's section in our own array. */
int sectix = 0;
for (sectix = 0; sectix < PE_SECTION_TABLE_SIZE; ++sectix)
{
if ((func_rva >= section_data[sectix].rva_start)
&& (func_rva < section_data[sectix].rva_end))
{
add_pe_exported_sym (erva + name_rva,
func_rva,
section_data + sectix, dll_name, objfile);
break;
}
}
}
/* discard expdata. */
do_cleanups (back_to);
}
enum mi_cmd_result
mi_execute_async_cli_command (char *mi, char *args, int from_tty)
{
struct cleanup *old_cleanups;
char *run;
char *async_args;
if (target_can_async_p ())
{
async_args = (char *) xmalloc (strlen (args) + 2);
make_exec_cleanup (free, async_args);
strcpy (async_args, args);
strcat (async_args, "&");
run = xstrprintf ("%s %s", mi, async_args);
make_exec_cleanup (free, run);
add_continuation (mi_exec_async_cli_cmd_continuation, NULL);
old_cleanups = NULL;
}
else
{
run = xstrprintf ("%s %s", mi, args);
old_cleanups = make_cleanup (xfree, run);
}
if (!target_can_async_p ())
{
/* NOTE: For synchronous targets asynchronous behavour is faked by
printing out the GDB prompt before we even try to execute the
command. */
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
fputs_unfiltered ("^running\n", raw_stdout);
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
}
else
{
/* FIXME: cagney/1999-11-29: Printing this message before
calling execute_command is wrong. It should only be printed
once gdb has confirmed that it really has managed to send a
run command to the target. */
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
fputs_unfiltered ("^running\n", raw_stdout);
}
execute_command ( /*ui */ run, 0 /*from_tty */ );
if (!target_can_async_p ())
{
/* Do this before doing any printing. It would appear that some
print code leaves garbage around in the buffer. */
do_cleanups (old_cleanups);
/* If the target was doing the operation synchronously we fake
the stopped message. */
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
fputs_unfiltered ("*stopped", raw_stdout);
mi_out_put (uiout, raw_stdout);
mi_out_rewind (uiout);
fputs_unfiltered ("\n", raw_stdout);
return MI_CMD_QUIET;
}
return MI_CMD_DONE;
}
开发者ID:debrouxl,项目名称:tiemu,代码行数:65,代码来源:mi-main.c
示例10: find_pc_offset
//.........这里部分代码省略.........
/* From here out we can assume we are doing a negative offset. */
gdb_assert(low <= start);
gdb_assert(offset < 0);
/* A sanity check: If we've stepped into some area of memory where
gdb doesn't have symbols and the GUI requests we disassemble from $pc,
gdb can come up with very large LOW-HIGH regions of memory to disassemble
through. As a sanity check, if this function starts four pages before
the given $pc and we're in MI mode (so we have a GUI that may be
requesting nonsensical things), shortcircuit this operation. */
if (((off_t)(start - low) > -offset) && ((start - low) > 16384)
&& ui_out_is_mi_like_p(uiout))
{
*result = start;
return 1;
}
/* There's no point searching for more instructions slots than there
are bytes. If we were given a PEEKLIMIT of -1, or a PEEKLIMIT
higher than we need, set it to the number of bytes from the start
of the function. */
if ((peeklimit < 0) || ((CORE_ADDR)peeklimit > (start - low)))
peeklimit = (int)(start - low);
/* If PEEKLIMIT is less than (start - low), we can still attempt the
search --- maybe enough of the instruction stream will be
multi-byte that we'll find our address regardless. */
addrs = (CORE_ADDR *)xmalloc(peeklimit * sizeof(CORE_ADDR));
cleanup = make_cleanup(xfree, addrs);
/* We can assume that we are constrained to the current function at
this point (see the comment above). */
gdb_assert(funclimit);
cur = low;
index = 0;
/* Seek forward until we either reach our starting point, or reach
PEEKLIMIT. */
for (;;)
{
if (cur >= start)
break;
if (index >= (unsigned int)peeklimit)
break;
gdb_assert((int)index < peeklimit);
addrs[index++] = cur;
cur += TARGET_PRINT_INSN(cur, &di);
}
if (cur == start)
{
/* We were able to seek all the way forward to the start address. */
gdb_assert(funclimit);
gdb_assert(offset < 0);
if ((off_t)index < -offset)
{
/* We weren't able to go far enough back; return the earliest
instruction of the function. */
*result = low;
do_cleanups(cleanup);
return 1;
}
else
{
*result = addrs[index + offset];
do_cleanups(cleanup);
return 0;
}
}
if (cur > start)
{
/* We seeked forward right past the start address, without ever
hitting it. */
do_cleanups(cleanup);
return -1;
}
if (index >= (unsigned int)peeklimit)
{
/* We went past PEEKLIMIT instructions, and hence, weren't able
to complete the backwards seek. */
do_cleanups(cleanup);
return -1;
}
internal_error(__FILE__, __LINE__, "should never have reached here");
do_cleanups(cleanup);
return -1;
}
//.........这里部分代码省略.........
int thread = -1;
int ignore_count = 0;
char *condition = NULL;
int pending = 0;
int enabled = 1;
int tracepoint = 0;
struct cleanup *back_to;
enum bptype type_wanted;
struct breakpoint_ops *ops;
enum opt
{
HARDWARE_OPT, TEMP_OPT, CONDITION_OPT,
IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT,
TRACEPOINT_OPT,
};
static const struct mi_opt opts[] =
{
{"h", HARDWARE_OPT, 0},
{"t", TEMP_OPT, 0},
{"c", CONDITION_OPT, 1},
{"i", IGNORE_COUNT_OPT, 1},
{"p", THREAD_OPT, 1},
{"f", PENDING_OPT, 0},
{"d", DISABLE_OPT, 0},
{"a", TRACEPOINT_OPT, 0},
{ 0, 0, 0 }
};
/* Parse arguments. It could be -r or -h or -t, <location> or ``--''
to denote the end of the option list. */
int oind = 0;
char *oarg;
while (1)
{
int opt = mi_getopt ("-break-insert", argc, argv,
opts, &oind, &oarg);
if (opt < 0)
break;
switch ((enum opt) opt)
{
case TEMP_OPT:
temp_p = 1;
break;
case HARDWARE_OPT:
hardware = 1;
break;
case CONDITION_OPT:
condition = oarg;
break;
case IGNORE_COUNT_OPT:
ignore_count = atol (oarg);
break;
case THREAD_OPT:
thread = atol (oarg);
break;
case PENDING_OPT:
pending = 1;
break;
case DISABLE_OPT:
enabled = 0;
break;
case TRACEPOINT_OPT:
tracepoint = 1;
break;
}
}
if (oind >= argc)
error (_("-break-insert: Missing <location>"));
if (oind < argc - 1)
error (_("-break-insert: Garbage following <location>"));
address = argv[oind];
/* Now we have what we need, let's insert the breakpoint! */
back_to = setup_breakpoint_reporting ();
/* Note that to request a fast tracepoint, the client uses the
"hardware" flag, although there's nothing of hardware related to
fast tracepoints -- one can implement slow tracepoints with
hardware breakpoints, but fast tracepoints are always software.
"fast" is a misnomer, actually, "jump" would be more appropriate.
A simulator or an emulator could conceivably implement fast
regular non-jump based tracepoints. */
type_wanted = (tracepoint
? (hardware ? bp_fast_tracepoint : bp_tracepoint)
: (hardware ? bp_hardware_breakpoint : bp_breakpoint));
ops = tracepoint ? &tracepoint_breakpoint_ops : &bkpt_breakpoint_ops;
create_breakpoint (get_current_arch (), address, condition, thread,
NULL,
0 /* condition and thread are valid. */,
temp_p, type_wanted,
ignore_count,
pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
ops, 0, enabled, 0, 0);
do_cleanups (back_to);
}
//.........这里部分代码省略.........
int rdst, rsrc;
rdst = opc.op[0].reg;
rsrc = opc.op[1].reg;
reg[rdst] = reg[rsrc];
if (rdst == RX_FP_REGNUM && rsrc == RX_SP_REGNUM)
after_last_frame_setup_insn = next_pc;
}
else if (opc.id == RXO_mov /* mov.l rsrc, [-SP] */
&& opc.op[0].type == RX_Operand_Predec
&& opc.op[0].reg == RX_SP_REGNUM
&& opc.op[1].type == RX_Operand_Register
&& opc.size == RX_Long)
{
int rsrc;
rsrc = opc.op[1].reg;
reg[RX_SP_REGNUM] = pv_add_constant (reg[RX_SP_REGNUM], -4);
pv_area_store (stack, reg[RX_SP_REGNUM], 4, reg[rsrc]);
after_last_frame_setup_insn = next_pc;
}
else if (opc.id == RXO_add /* add #const, rsrc, rdst */
&& opc.op[0].type == RX_Operand_Register
&& opc.op[1].type == RX_Operand_Immediate
&& opc.op[2].type == RX_Operand_Register)
{
int rdst = opc.op[0].reg;
int addend = opc.op[1].addend;
int rsrc = opc.op[2].reg;
reg[rdst] = pv_add_constant (reg[rsrc], addend);
/* Negative adjustments to the stack pointer or frame pointer
are (most likely) part of the prologue. */
if ((rdst == RX_SP_REGNUM || rdst == RX_FP_REGNUM) && addend < 0)
after_last_frame_setup_insn = next_pc;
}
else if (opc.id == RXO_mov
&& opc.op[0].type == RX_Operand_Indirect
&& opc.op[1].type == RX_Operand_Register
&& opc.size == RX_Long
&& (opc.op[0].reg == RX_SP_REGNUM
|| opc.op[0].reg == RX_FP_REGNUM)
&& (RX_R1_REGNUM <= opc.op[1].reg
&& opc.op[1].reg <= RX_R4_REGNUM))
{
/* This moves an argument register to the stack. Don't
record it, but allow it to be a part of the prologue. */
}
else if (opc.id == RXO_branch
&& opc.op[0].type == RX_Operand_Immediate
&& next_pc < opc.op[0].addend)
{
/* When a loop appears as the first statement of a function
body, gcc 4.x will use a BRA instruction to branch to the
loop condition checking code. This BRA instruction is
marked as part of the prologue. We therefore set next_pc
to this branch target and also stop the prologue scan.
The instructions at and beyond the branch target should
no longer be associated with the prologue.
Note that we only consider forward branches here. We
presume that a forward branch is being used to skip over
a loop body.
A backwards branch is covered by the default case below.
If we were to encounter a backwards branch, that would
most likely mean that we've scanned through a loop body.
We definitely want to stop the prologue scan when this
happens and that is precisely what is done by the default
case below. */
after_last_frame_setup_insn = opc.op[0].addend;
break; /* Scan no further if we hit this case. */
}
else
{
/* Terminate the prologue scan. */
break;
}
pc = next_pc;
}
/* Is the frame size (offset, really) a known constant? */
if (pv_is_register (reg[RX_SP_REGNUM], RX_SP_REGNUM))
result->frame_size = reg[RX_SP_REGNUM].k;
/* Was the frame pointer initialized? */
if (pv_is_register (reg[RX_FP_REGNUM], RX_SP_REGNUM))
{
result->has_frame_ptr = 1;
result->frame_ptr_offset = reg[RX_FP_REGNUM].k;
}
/* Record where all the registers were saved. */
pv_area_scan (stack, check_for_saved, (void *) result);
result->prologue_end = after_last_frame_setup_insn;
do_cleanups (back_to);
}
请发表评论