mdb_amd64util.c revision 843e19887f64dde75055cf8842fc4db2171eff45
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/privregs.h>
#include <mdb/mdb_target_impl.h>
#include <mdb/mdb_kreg_impl.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_amd64util.h>
/*
* This array is used by the getareg and putareg entry points, and also by our
* register variable discipline.
*/
const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
{ NULL, 0, 0 }
};
void
{
mdb_printf("%%rax = 0x%0?p %15A %%r9 = 0x%0?p %A\n",
mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
mdb_printf("%%r8 = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n",
mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\t%%gs = 0x%04x\n",
}
/*
* 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
/*
* Sun Studio 10 patch implementation saves %rdi first;
* GCC 3.4.3 Sun branch implementation saves them in reverse order.
*/
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[] = {
0xe5894855, /* pushq %rbp; movq %rsp,%rbp, encoding 1 */
0xec8b4855, /* pushq %rbp; movq %rsp,%rbp, encoding 2 */
0xe58948cc, /* int $0x3; movq %rsp,%rbp, encoding 1 */
0xec8b48cc, /* int $0x3; movq %rsp,%rbp, encoding 2 */
};
/*
* Look for the above instruction sequences as indicators for register
* arguments being available on the stack.
*/
static int
int start_index)
{
int i, j;
uint32_t n;
return (0);
/*
* Make sure framepointer has been saved.
*/
for (i = 0; save_fp_instr[i] != NULL; i++) {
if (n == save_fp_instr[i])
break;
}
if (save_fp_instr[i] == NULL)
return (0);
/*
* Compare against Sun Studio implementation
*/
if (n == save_instr[j]) {
i += 3;
if (++j >= argc)
return (1);
}
}
/*
* Compare against GCC implementation
*/
if (n == save_instr[j]) {
i += 3;
if (--j < start_index)
return (1);
}
}
return (0);
}
/*
* We expect all proper Solaris core files to have STACK_ALIGN-aligned stacks.
* Hence the name. However, if the core file resulted from a
* hypervisor-initiated panic, the hypervisor's frames may only be 64-bit
* aligned instead of 128.
*/
static int
{
return (0);
return (0);
return (1);
}
int
{
long fr_argv[32];
int start_index; /* index to save_instr where to start comparison */
int i;
struct {
} fr;
GElf_Sym s;
int xpv_panic = 0;
#ifndef _KMDB
int xp;
xpv_panic = 1;
#endif
while (fp != 0) {
return (set_errno(EMDB_STKALIGN));
return (-1); /* errno has been set for us */
/*
* 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 ||
start_index = 1;
else
start_index = 0;
} else {
argc = 0;
}
argc, start_index)) {
/* Upto to 6 arguments are passed via registers */
!= 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];
}
if (argc > 6) {
return (-1); /* errno has been set */
}
} else
argc = 0;
break;
/*
* The Xen hypervisor marks a stack frame as belonging to
* an exception by inverting the bits of the pointer to
* that frame. We attempt to identify these frames by
* inverting the pointer and seeing if it is within 0xfff
* bytes of the last frame.
*/
if (xpv_panic)
break;
}
return (0);
}
/*
* Determine the return address for the current frame. Typically this is the
* fr_savpc value from the current frame, but we also perform some special
* handling to see if we are stopped on one of the first two instructions of
* a typical function prologue, in which case %rbp will not be set up yet.
*/
int
{
GElf_Sym s;
char buf[1];
enum {
};
}
}
return (0);
}
return (-1); /* errno is set for us */
}
/*ARGSUSED*/
int
{
enum {
M_REX_LO = 0x40,
M_REX_HI = 0x4f
};
/*
* If the opcode is a near call with relative displacement, assume the
* displacement is a rel32 from the next instruction.
*/
if (curinstr == M_CALL_REL) {
return (0);
}
/* Skip the rex prefix, if any */
sizeof (curinstr))
return (-1); /* errno is set for us */
}
if (curinstr != M_CALL_REG) {
/* It's not a call */
}
return (-1); /* errno is set for us */
*p = npc;
return (0);
}
/*ARGSUSED*/
int
const mdb_tgt_gregset_t *gregs)
{
if (argc != 0) {
}
mdb_printf(")\n");
return (0);
}
int
const mdb_tgt_gregset_t *gregs)
{
/*
* 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;
if (argc != 0) {
}
mdb_printf(")\n");
return (0);
}