blob: 4a27fba6bd4d4bf447c03194abefa87e0dfe1c09 [file] [edit]
/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
*
* This file is part of PRoot.
*
* Copyright (C) 2013 STMicroelectronics
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/user.h>
#include <stddef.h>
#include "ptrace/user.h"
#include "cli/note.h"
#if defined(ARCH_X86_64)
/**
* Return the index in the "regs" field of a 64-bit "user" area that
* corresponds to the specified @index in the "regs" field of a 32-bit
* "user" area.
*/
static inline size_t convert_user_regs_index(size_t index)
{
static size_t mapping[USER32_NB_REGS] = {
05, /* ?bx */ 11, /* ?cx */ 12, /* ?dx */
13, /* ?si */ 14, /* ?di */ 04, /* ?bp */
10, /* ?ax */ 23, /* ds */ 24, /* es */
25, /* fs */ 26, /* gs */ 15, /* orig_?ax */
16, /* ?ip */ 17, /* cs */ 18, /* eflags */
19, /* ?sp */ 20, /* ss */ };
/* Sanity check. */
assert(index < USER32_NB_REGS);
return mapping[index];
}
/* Layout of a 32-bit "user" area. */
#define USER32_REGS_OFFSET 0
#define USER32_REGS_SIZE (USER32_NB_REGS * sizeof(uint32_t))
#define USER32_FPVALID_OFFSET (USER32_REGS_OFFSET + USER32_REGS_SIZE)
#define USER32_I387_OFFSET (USER32_FPVALID_OFFSET + sizeof(uint32_t))
#define USER32_I387_SIZE (USER32_NB_FPREGS * sizeof(uint32_t))
#define USER32_TSIZE_OFFSET (USER32_I387_OFFSET + USER32_I387_SIZE)
#define USER32_DSIZE_OFFSET (USER32_TSIZE_OFFSET + sizeof(uint32_t))
#define USER32_SSIZE_OFFSET (USER32_DSIZE_OFFSET + sizeof(uint32_t))
#define USER32_START_CODE_OFFSET (USER32_SSIZE_OFFSET + sizeof(uint32_t))
#define USER32_START_STACK_OFFSET (USER32_START_CODE_OFFSET + sizeof(uint32_t))
#define USER32_SIGNAL_OFFSET (USER32_START_STACK_OFFSET + sizeof(uint32_t))
#define USER32_RESERVED_OFFSET (USER32_SIGNAL_OFFSET + sizeof(uint32_t))
#define USER32_AR0_OFFSET (USER32_RESERVED_OFFSET + sizeof(uint32_t))
#define USER32_FPSTATE_OFFSET (USER32_AR0_OFFSET + sizeof(uint32_t))
#define USER32_MAGIC_OFFSET (USER32_FPSTATE_OFFSET + sizeof(uint32_t))
#define USER32_COMM_OFFSET (USER32_MAGIC_OFFSET + sizeof(uint32_t))
#define USER32_COMM_SIZE (32 * sizeof(uint8_t))
#define USER32_DEBUGREG_OFFSET (USER32_COMM_OFFSET + USER32_COMM_SIZE)
#define USER32_DEBUGREG_SIZE (8 * sizeof(uint32_t))
/**
* Return the offset in the "debugreg" field of a 64-bit "user" area
* that corresponds to the specified @offset in the "debugreg" field
* of a 32-bit "user" area.
*/
static inline size_t convert_user_debugreg_offset(size_t offset)
{
size_t index;
/* Sanity check. */
assert(offset >= USER32_DEBUGREG_OFFSET
&& offset < USER32_DEBUGREG_OFFSET + USER32_DEBUGREG_SIZE);
index = (offset - USER32_DEBUGREG_OFFSET) / sizeof(uint32_t);
return offsetof(struct user, u_debugreg) + index * sizeof(uint64_t);
}
/**
* Return the offset in a 64-bit "user" area that corresponds to the
* specified @offset in a 32-bit "user" area. This function returns
* "(word_t) -1" if the specified @offset is invalid.
*/
word_t convert_user_offset(word_t offset)
{
const char *area_name = NULL;
if (/* offset >= 0 && */ offset < USER32_REGS_OFFSET + USER32_REGS_SIZE) {
/* Sanity checks. */
if ((offset % sizeof(uint32_t)) != 0)
return (word_t) -1;
return convert_user_regs_index(offset / sizeof(uint32_t)) * sizeof(uint64_t);
}
else if (offset == USER32_FPVALID_OFFSET)
area_name = "fpvalid"; /* Not yet supported. */
else if (offset >= USER32_I387_OFFSET && offset < USER32_I387_OFFSET + USER32_I387_SIZE)
area_name = "i387"; /* Not yet supported. */
else if (offset == USER32_TSIZE_OFFSET)
area_name = "tsize"; /* Not yet supported. */
else if (offset == USER32_DSIZE_OFFSET)
area_name = "dsize"; /* Not yet supported. */
else if (offset == USER32_SSIZE_OFFSET)
area_name = "ssize"; /* Not yet supported. */
else if (offset == USER32_START_CODE_OFFSET)
area_name = "start_code"; /* Not yet supported. */
else if (offset == USER32_START_STACK_OFFSET)
area_name = "start_stack"; /* Not yet supported. */
else if (offset == USER32_SIGNAL_OFFSET)
area_name = "signal"; /* Not yet supported. */
else if (offset == USER32_RESERVED_OFFSET)
area_name = "reserved"; /* Not yet supported. */
else if (offset == USER32_AR0_OFFSET)
area_name = "ar0"; /* Not yet supported. */
else if (offset == USER32_FPSTATE_OFFSET)
area_name = "fpstate"; /* Not yet supported. */
else if (offset == USER32_MAGIC_OFFSET)
area_name = "magic"; /* Not yet supported. */
else if (offset >= USER32_COMM_OFFSET && offset < USER32_COMM_OFFSET + USER32_COMM_SIZE)
area_name = "comm"; /* Not yet supported. */
else if (offset >= USER32_DEBUGREG_OFFSET && offset < USER32_DEBUGREG_OFFSET + USER32_DEBUGREG_SIZE)
return convert_user_debugreg_offset(offset);
else
area_name = "<unknown>";
note(NULL, WARNING, INTERNAL, "ptrace user area '%s' not supported yet", area_name);
return (word_t) -1; /* Unknown offset. */
}
/**
* Convert the "regs" field from a 64-bit "user" area into a "regs"
* field from a 32-bit "user" area, or vice versa according to
* @reverse.
*/
void convert_user_regs_struct(bool reverse, uint64_t *user_regs64,
uint32_t user_regs32[USER32_NB_REGS])
{
size_t index32;
for (index32 = 0; index32 < USER32_NB_REGS; index32++) {
size_t index64 = convert_user_regs_index(index32);
assert(index64 != (size_t) -1);
if (reverse)
user_regs64[index64] = (uint64_t) user_regs32[index32];
else
user_regs32[index32] = (uint32_t) user_regs64[index64];
}
}
#endif /* ARCH_X86_64 */