static CORE_ADDR amd64_skip_prologue (CORE_ADDR start_pc) { struct x86_frame_cache cache; CORE_ADDR pc, endaddr; x86_initialize_frame_cache (&cache, 8); if (find_pc_partial_function_no_inlined (start_pc, NULL, NULL, &endaddr) == 0) endaddr = start_pc + 512; /* 512 bytes is more than enough. */ endaddr = refine_prologue_limit (start_pc, endaddr, 3); pc = x86_analyze_prologue (start_pc, endaddr, &cache); return pc; }
enum mi_cmd_result mi_cmd_disassemble (char *command, char **argv, int argc) { int mixed_source_and_assembly; struct symtab *s; /* Which options have we processed ... */ int file_seen = 0; int line_seen = 0; int start_seen = 0; int end_seen = 0; int num_seen = 0; int prev_seen = 0; int peeklimit_seen = 0; /* ... and their corresponding value. */ char *file_string = NULL; int line_num = -1; int how_many = -1; CORE_ADDR low = 0; CORE_ADDR high = 0; CORE_ADDR start = 0; int prev = 0; int peeklimit = -1; /* Options processing stuff. */ int optind = 0; char *optarg; enum opt { FILE_OPT, LINE_OPT, NUM_OPT, START_OPT, END_OPT, PREV_OPT, PEEKLIMIT_OPT }; static struct mi_opt opts[] = { { "f", FILE_OPT, 1 }, { "l", LINE_OPT, 1 }, { "n", NUM_OPT, 1 }, { "s", START_OPT, 1 }, { "e", END_OPT, 1 }, { "p", PREV_OPT, 1 }, { "P", PEEKLIMIT_OPT, 1 }, { NULL, 0, 0 } }; /* Get the options with their arguments. Keep track of what we encountered. */ while (1) { int opt = mi_getopt ("mi_cmd_disassemble", argc, argv, opts, &optind, &optarg); if (opt < 0) break; switch ((enum opt)opt) { case FILE_OPT: file_string = xstrdup(optarg); file_seen = 1; break; case LINE_OPT: line_num = atoi(optarg); line_seen = 1; break; case NUM_OPT: how_many = atoi(optarg); num_seen = 1; break; case START_OPT: start = parse_and_eval_address(optarg); start_seen = 1; break; case END_OPT: high = parse_and_eval_address(optarg); end_seen = 1; break; case PREV_OPT: prev = atoi(optarg); prev_seen = 1; break; case PEEKLIMIT_OPT: peeklimit = atoi(optarg); peeklimit_seen = 1; break; default: break; } } argv += optind; argc -= optind; if (argc < 1) mi_cmd_disassemble_usage ("Must specify mixed mode argument."); if (argc > 1) mi_cmd_disassemble_usage ("Extra arguments present."); if ((argv[0][0] == '\0') || (argv[0][1] != '\0')) mi_cmd_disassemble_usage ("Mixed mode argument must be 0 or 1."); if ((argv[0][0] != '0') && (argv[0][0] != '1')) mi_cmd_disassemble_usage ("Mixed mode argument must be 0 or 1."); mixed_source_and_assembly = (argv[0][0] == '1'); if (start_seen && line_seen) mi_cmd_disassemble_usage ("May not specify both a line number and a start address."); if ((line_seen && !file_seen) || (file_seen && !line_seen)) mi_cmd_disassemble_usage ("File and line number must be specified together."); if (line_seen && file_seen) { s = lookup_symtab (file_string); if (s == NULL) error ("mi_cmd_disassemble: Invalid filename."); if (! find_line_pc (s, line_num, &start)) error ("mi_cmd_disassemble: Invalid line number."); } else if (! start_seen) mi_cmd_disassemble_usage ("No starting point specified."); if (end_seen) { if (num_seen || prev_seen) mi_cmd_disassemble_usage ("May not specify both an ending address and -n or -p."); gdb_disassembly (uiout, start, high, mixed_source_and_assembly, how_many); return MI_CMD_DONE; } if (find_pc_partial_function_no_inlined (start, NULL, &low, &high) == 0) error ("mi_cmd_disassemble: No function contains the specified address."); if (! num_seen) { /* If only the start address is given, disassemble the entire function around the start address. */ gdb_disassembly(uiout, low, high, mixed_source_and_assembly, how_many); return MI_CMD_DONE; } /* And finally, now we know start_seen, !line_seen, !file_seen, !end_seen, and num_seen. */ if (prev_seen) { CORE_ADDR tmp; int ret; if (peeklimit_seen >= 1) ret = find_pc_offset(start, &tmp, -prev, 1, peeklimit); else ret = find_pc_offset(start, &tmp, -prev, 1, -1); if ((ret != -1) && (tmp != INVALID_ADDRESS)) start = tmp; } gdb_disassembly(uiout, start, high, mixed_source_and_assembly, how_many); return MI_CMD_DONE; }
int find_pc_offset(CORE_ADDR start, CORE_ADDR *result, int offset, int funclimit, int peeklimit) { CORE_ADDR low = INVALID_ADDRESS; CORE_ADDR high = INVALID_ADDRESS; CORE_ADDR cur; CORE_ADDR constrained; int length; struct disassemble_info di = gdb_disassemble_info_null(current_gdbarch); CORE_ADDR *addrs = NULL; unsigned int index; struct cleanup *cleanup = NULL; *result = INVALID_ADDRESS; cur = start; /* If we are constraining the address to stay in the same function, we need to be able to find its boundaries. */ if (funclimit) { if (find_pc_partial_function_no_inlined(start, NULL, &low, &high) == 0) { /* We were unable to find the start of the function. */ return -1; } } /* If the architecture has fixed-sized instructions, just use simple arithmetic. */ length = gdbarch_instruction_length(current_gdbarch); if (length > 0) { cur = (start + (length * offset)); /* Constrain to be within the function limits if appropriate. */ if (funclimit && (cur > high)) constrained = high; else if (funclimit && (cur < low)) constrained = low; else constrained = cur; /* Return 1 if we constrained the address; 0 otherwise. */ *result = constrained; return (constrained != cur); } /* From here, we must assume variable-sized instructions. */ if ((! funclimit) && (offset < 0)) { /* FIXME: We don't support seeking backwards past the beginning of a function. */ return -1; } /* If we have a positive offset, start seeking forward until we are either done, or reach the end of the function. */ cur = start; while (offset > 0) { cur += TARGET_PRINT_INSN(cur, &di); offset--; if (funclimit && (cur > high)) { /* We went past the end of the function without ever reaching the purportedly final instruction. */ return -1; } if (funclimit && (cur == high)) { /* We reached the end of the function. Return 1 if we had to constrain the address; 0 otherwise. */ *result = cur; return (offset > 0); } } if (offset == 0) { *result = cur; return 0; } /* 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; }