diff options
| author | sherrym <none@none> | 2005-07-14 17:18:02 -0700 |
|---|---|---|
| committer | sherrym <none@none> | 2005-07-14 17:18:02 -0700 |
| commit | 159eb9e1f62c284a23f12ecf781cdf352c9158f8 (patch) | |
| tree | 62423ef26d29a27f51949ea18266c885db94c1ef | |
| parent | 2bac1547bd2542defca8ad987edd71bbfc2edd14 (diff) | |
| download | illumos-joyent-159eb9e1f62c284a23f12ecf781cdf352c9158f8.tar.gz | |
6260772 mdb_ctf_func_info needs to be more sophisticated
6290893 Need to print out function arguments when they are available
| -rw-r--r-- | usr/src/cmd/mdb/common/mdb/mdb_ctf.c | 29 | ||||
| -rw-r--r-- | usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c | 246 |
2 files changed, 267 insertions, 8 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c index 2de57f5978..82c304f7be 100644 --- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c +++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c @@ -297,6 +297,7 @@ mdb_ctf_module_lookup(const char *name, mdb_ctf_id_t *p) return (0); } +/*ARGSUSED*/ int mdb_ctf_func_info(const GElf_Sym *symp, const mdb_syminfo_t *sip, mdb_ctf_funcinfo_t *mfp) @@ -304,20 +305,40 @@ mdb_ctf_func_info(const GElf_Sym *symp, const mdb_syminfo_t *sip, ctf_file_t *fp = NULL; ctf_funcinfo_t f; mdb_tgt_t *t = mdb.m_target; + char name[MDB_SYM_NAMLEN]; + const mdb_map_t *mp; + mdb_syminfo_t si; + int err; - if (symp == NULL || sip == NULL || mfp == NULL) + if (symp == NULL || mfp == NULL) return (set_errno(EINVAL)); - if ((fp = mdb_tgt_addr_to_ctf(t, symp->st_value)) == NULL) + /* + * In case the input symbol came from a merged or private symbol table, + * re-lookup the address as a symbol, and then perform a fully scoped + * lookup of that symbol name to get the mdb_syminfo_t for its CTF. + */ + if ((fp = mdb_tgt_addr_to_ctf(t, symp->st_value)) == NULL || + (mp = mdb_tgt_addr_to_map(t, symp->st_value)) == NULL || + mdb_tgt_lookup_by_addr(t, symp->st_value, MDB_TGT_SYM_FUZZY, + name, sizeof (name), NULL, NULL) != 0) + return (-1); /* errno is set for us */ + + if (strchr(name, '`') != NULL) + err = mdb_tgt_lookup_by_scope(t, name, NULL, &si); + else + err = mdb_tgt_lookup_by_name(t, mp->map_name, name, NULL, &si); + + if (err != 0) return (-1); /* errno is set for us */ - if (ctf_func_info(fp, sip->sym_id, &f) == CTF_ERR) + if (ctf_func_info(fp, si.sym_id, &f) == CTF_ERR) return (set_errno(ctf_to_errno(ctf_errno(fp)))); set_ctf_id(&mfp->mtf_return, fp, f.ctc_return); mfp->mtf_argc = f.ctc_argc; mfp->mtf_flags = f.ctc_flags; - mfp->mtf_symidx = sip->sym_id; + mfp->mtf_symidx = si.sym_id; return (0); } diff --git a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c index 1cdf827f98..46083adc9c 100644 --- a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c +++ b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c @@ -37,6 +37,7 @@ #include <mdb/mdb_debug.h> #include <mdb/mdb_modapi.h> #include <mdb/mdb_amd64util.h> +#include <mdb/mdb_ctf.h> #include <mdb/mdb_err.h> #include <mdb/mdb.h> @@ -139,6 +140,169 @@ mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs) kregs[KREG_ERR], (kregs[KREG_GS] & 0xffff), kregs[KREG_GSBASE]); } + + +/* + * Sun Studio 10 patch compiler and gcc 3.4.3 Sun branch implemented a + * "-save_args" option on amd64. When the option is specified, INTEGER + * type function arguments passed via registers will be saved on the stack + * immediately after %rbp, and will not be modified through out the life + * of the routine. + * + * +--------+ + * %rbp --> | %rbp | + * +--------+ + * -0x8(%rbp) | %rdi | + * +--------+ + * -0x10(%rbp) | %rsi | + * +--------+ + * -0x18(%rbp) | %rdx | + * +--------+ + * -0x20(%rbp) | %rcx | + * +--------+ + * -0x28(%rbp) | %r8 | + * +--------+ + * -0x30(%rbp) | %r9 | + * +--------+ + * + * + * For example, for the following function, + * + * void + * foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7) + * { + * ... + * } + * + * Disassembled code will look something like the following: + * + * pushq %rbp + * movq %rsp, %rbp + * subq $imm8, %rsp ** + * movq %rdi, -0x8(%rbp) + * movq %rsi, -0x10(%rbp) + * movq %rdx, -0x18(%rbp) + * movq %rcx, -0x20(%rbp) + * movq %r8, -0x28(%rbp) + * movq %r9, -0x30(%rbp) + * ... + * or + * pushq %rbp + * movq %rsp, %rbp + * subq $imm8, %rsp ** + * movq %r9, -0x30(%rbp) + * movq %r8, -0x28(%rbp) + * movq %rcx, -0x20(%rbp) + * movq %rdx, -0x18(%rbp) + * movq %rsi, -0x10(%rbp) + * movq %rdi, -0x8(%rbp) + * ... + * + * **: The space being reserved is in addition to what the current + * function prolog already reserves. + * + * If there are odd number of arguments to a function, additional space is + * reserved on the stack to maintain 16-byte alignment. For example, + * + * argc == 0: no argument saving. + * argc == 3: save 3, but space for 4 is reserved + * argc == 7: save 6. + */ + +/* + * The longest instruction sequence in bytes before all 6 arguments are + * saved on the stack. This value depends on compiler implementation, + * therefore it should be examined periodically to guarantee accuracy. + */ +#define SEQ_LEN 80 + +/* + * Size of the instruction sequence arrays. It should correspond to + * the maximum number of arguments passed via registers. + */ +#define INSTR_ARRAY_SIZE 6 + +#define INSTR4(ins, off) \ + (ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16) + \ + (ins[(off) + 3] << 24)) + +/* + * Sun Studio 10 patch implementation saves %rdi first; + * GCC 3.4.3 Sun branch implementation saves them in reverse order. + */ +static const uint32_t save_instr[INSTR_ARRAY_SIZE] = { + 0xf87d8948, /* movq %rdi, -0x8(%rbp) */ + 0xf0758948, /* movq %rsi, -0x10(%rbp) */ + 0xe8558948, /* movq %rdx, -0x18(%rbp) */ + 0xe04d8948, /* movq %rcx, -0x20(%rbp) */ + 0xd845894c, /* movq %r8, -0x28(%rbp) */ + 0xd04d894c /* movq %r9, -0x30(%rbp) */ +}; + +static const uint32_t save_fp_instr[2] = { + 0xe5894855, /* pushq %rbp; movq %rsp,%rbp, encoding 1 */ + 0xec8b4855 /* pushq %rbp; movq %rsp,%rbp, encoding 2 */ +}; + +/* + * Look for the above instruction sequences as indicators for register + * arguments being available on the stack. + */ +static int +is_argsaved(mdb_tgt_t *t, uintptr_t fstart, uint64_t size, uint_t argc, + int start_index) +{ + uint8_t ins[SEQ_LEN]; + int i, j; + uint32_t n; + + size = MIN(size, SEQ_LEN); + argc = MIN((start_index + argc), INSTR_ARRAY_SIZE); + + if (mdb_tgt_vread(t, ins, size, fstart) != size) + return (0); + + /* + * Make sure framepointer has been saved. + */ + n = INSTR4(ins, 0); + for (i = 0; i < 2; i++) { + if (n == save_fp_instr[i]) + break; + } + + if (i >= 2) + return (0); + + /* + * Compare against Sun Studio implementation + */ + for (i = 8, j = start_index; i < size - 4; i++) { + n = INSTR4(ins, i); + + if (n == save_instr[j]) { + i += 3; + if (++j >= argc) + return (1); + } + } + + /* + * Compare against GCC implementation + */ + for (i = 8, j = argc - 1; i < size - 4; i++) { + n = INSTR4(ins, i); + + if (n == save_instr[j]) { + i += 3; + if (--j < start_index) + return (1); + } + } + + return (0); +} + int mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, mdb_tgt_stack_f *func, void *arg) @@ -146,6 +310,10 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, mdb_tgt_gregset_t gregs; kreg_t *kregs = &gregs.kregs[0]; int got_pc = (gsp->kregs[KREG_RIP] != 0); + uint_t argc, reg_argc; + long fr_argv[32]; + int start_index; /* index to save_instr where to start comparison */ + int i; struct { uintptr_t fr_savfp; @@ -154,18 +322,77 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, uintptr_t fp = gsp->kregs[KREG_RBP]; uintptr_t pc = gsp->kregs[KREG_RIP]; + uintptr_t curpc; + + ssize_t size; + + GElf_Sym s; + mdb_syminfo_t sip; + mdb_ctf_funcinfo_t mfp; bcopy(gsp, &gregs, sizeof (gregs)); while (fp != 0) { + curpc = pc; + if (fp & (STACK_ALIGN - 1)) return (set_errno(EMDB_STKALIGN)); - bzero(&fr, sizeof (fr)); - (void) mdb_tgt_vread(t, &fr, sizeof (fr), fp); + if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr)) + return (-1); /* errno has been set for us */ + + if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY, + NULL, 0, &s, &sip) == 0) && + (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) { + int return_type = mdb_ctf_type_kind(mfp.mtf_return); + argc = mfp.mtf_argc; + /* + * If the function returns a structure or union, + * %rdi contains the address in which to store the + * return value rather than for an argument. + */ + if (return_type == CTF_K_STRUCT || + return_type == CTF_K_UNION) + start_index = 1; + else + start_index = 0; + } else { + argc = 0; + } - if (got_pc && func(arg, pc, 0, NULL, &gregs) != 0) + if (argc != 0 && is_argsaved(t, s.st_value, s.st_size, + argc, start_index)) { + + /* Upto to 6 arguments are passed via registers */ + reg_argc = MIN(6, mfp.mtf_argc); + size = reg_argc * sizeof (long); + + if (mdb_tgt_vread(t, fr_argv, size, (fp - size)) + != size) + return (-1); /* errno has been set for us */ + + /* + * Arrange the arguments in the right order for + * printing. + */ + for (i = 0; i < (reg_argc >> 1); i++) { + long t = fr_argv[i]; + + fr_argv[i] = fr_argv[reg_argc - i - 1]; + fr_argv[reg_argc - i - 1] = t; + } + + if (argc > 6) { + size = (argc - 6) * sizeof (long); + if (mdb_tgt_vread(t, &fr_argv[6], size, + fp + sizeof (fr)) != size) + return (-1); /* errno has been set */ + } + } else + argc = 0; + + if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0) break; kregs[KREG_RSP] = kregs[KREG_RBP]; @@ -173,6 +400,9 @@ mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, kregs[KREG_RBP] = fp = fr.fr_savfp; kregs[KREG_RIP] = pc = fr.fr_savpc; + if (curpc == pc) + break; + got_pc = (pc != 0); } @@ -282,7 +512,15 @@ int mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv, const mdb_tgt_gregset_t *gregs) { - argc = MIN(argc, (uintptr_t)arglim); + /* + * Historically adb limited stack trace argument display to a fixed- + * size number of arguments since no symbolic debugging info existed. + * On amd64 we can detect the true number of saved arguments so only + * respect an arglim of zero; otherwise display the entire argv[]. + */ + if (arglim == 0) + argc = 0; + mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc); if (argc != 0) { |
