|
Packit |
0021fb |
/*
|
|
Packit |
0021fb |
* This file is part of ltrace.
|
|
Packit |
0021fb |
* Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
Packit |
0021fb |
* Copyright (C) 2007,2008 Juan Cespedes
|
|
Packit |
0021fb |
*
|
|
Packit |
0021fb |
* This program is free software; you can redistribute it and/or
|
|
Packit |
0021fb |
* modify it under the terms of the GNU General Public License as
|
|
Packit |
0021fb |
* published by the Free Software Foundation; either version 2 of the
|
|
Packit |
0021fb |
* License, or (at your option) any later version.
|
|
Packit |
0021fb |
*
|
|
Packit |
0021fb |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
0021fb |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
0021fb |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
0021fb |
* General Public License for more details.
|
|
Packit |
0021fb |
*
|
|
Packit |
0021fb |
* You should have received a copy of the GNU General Public License
|
|
Packit |
0021fb |
* along with this program; if not, write to the Free Software
|
|
Packit |
0021fb |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
Packit |
0021fb |
* 02110-1301 USA
|
|
Packit |
0021fb |
*/
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
#include <assert.h>
|
|
Packit |
0021fb |
#include <stdlib.h>
|
|
Packit |
0021fb |
#include <limits.h>
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
#include "type.h"
|
|
Packit |
0021fb |
#include "sysdep.h"
|
|
Packit |
0021fb |
#include "expr.h"
|
|
Packit |
0021fb |
#include "lens.h"
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct arg_type_info *
|
|
Packit |
0021fb |
type_get_simple(enum arg_type type)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
#define HANDLE(T) { \
|
|
Packit |
0021fb |
static struct arg_type_info t = { T }; \
|
|
Packit |
0021fb |
case T: \
|
|
Packit |
0021fb |
return &t; \
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
switch (type) {
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_VOID)
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_INT)
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_UINT)
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_LONG)
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_ULONG)
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_CHAR)
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_SHORT)
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_USHORT)
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_FLOAT)
|
|
Packit |
0021fb |
HANDLE(ARGTYPE_DOUBLE)
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
#undef HANDLE
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
case ARGTYPE_POINTER:
|
|
Packit |
0021fb |
assert(!"Not a simple type!");
|
|
Packit |
0021fb |
};
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct arg_type_info *
|
|
Packit |
0021fb |
type_get_voidptr(void)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct arg_type_info *void_info = type_get_simple(ARGTYPE_VOID);
|
|
Packit |
0021fb |
static struct arg_type_info *ret;
|
|
Packit |
0021fb |
if (ret == NULL) {
|
|
Packit |
0021fb |
static struct arg_type_info ptr_info;
|
|
Packit |
0021fb |
type_init_pointer(&ptr_info, void_info, 0);
|
|
Packit |
0021fb |
ret = &ptr_info;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
return ret;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
type_init_common(struct arg_type_info *info, enum arg_type type)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
info->type = type;
|
|
Packit |
0021fb |
info->lens = NULL;
|
|
Packit |
0021fb |
info->own_lens = 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct struct_field {
|
|
Packit |
0021fb |
struct arg_type_info *info;
|
|
Packit |
0021fb |
int own_info;
|
|
Packit |
0021fb |
};
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
type_init_struct(struct arg_type_info *info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
type_init_common(info, ARGTYPE_STRUCT);
|
|
Packit |
0021fb |
VECT_INIT(&info->u.entries, struct struct_field);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
type_struct_add(struct arg_type_info *info,
|
|
Packit |
0021fb |
struct arg_type_info *field_info, int own)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(info->type == ARGTYPE_STRUCT);
|
|
Packit |
0021fb |
struct struct_field field = { field_info, own };
|
|
Packit |
0021fb |
return VECT_PUSHBACK(&info->u.entries, &field);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct arg_type_info *
|
|
Packit |
0021fb |
type_struct_get(struct arg_type_info *info, size_t idx)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(info->type == ARGTYPE_STRUCT);
|
|
Packit |
0021fb |
return VECT_ELEMENT(&info->u.entries, struct struct_field, idx)->info;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t
|
|
Packit |
0021fb |
type_struct_size(struct arg_type_info *info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(info->type == ARGTYPE_STRUCT);
|
|
Packit |
0021fb |
return vect_size(&info->u.entries);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
struct_field_dtor(struct struct_field *field, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (field->own_info) {
|
|
Packit |
0021fb |
type_destroy(field->info);
|
|
Packit |
0021fb |
free(field->info);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
type_struct_destroy(struct arg_type_info *info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
VECT_DESTROY(&info->u.entries, struct struct_field,
|
|
Packit |
0021fb |
struct_field_dtor, NULL);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static int
|
|
Packit |
0021fb |
layout_struct(struct process *proc, struct arg_type_info *info,
|
|
Packit |
0021fb |
size_t *sizep, size_t *alignmentp, size_t *offsetofp)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
size_t sz = 0;
|
|
Packit |
0021fb |
size_t max_alignment = 0;
|
|
Packit |
0021fb |
size_t i;
|
|
Packit |
0021fb |
size_t offsetof_field = (size_t)-1;
|
|
Packit |
0021fb |
if (offsetofp != NULL)
|
|
Packit |
0021fb |
offsetof_field = *offsetofp;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
assert(info->type == ARGTYPE_STRUCT);
|
|
Packit |
0021fb |
for (i = 0; i < vect_size(&info->u.entries); ++i) {
|
|
Packit |
0021fb |
struct struct_field *field
|
|
Packit |
0021fb |
= VECT_ELEMENT(&info->u.entries,
|
|
Packit |
0021fb |
struct struct_field, i);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t alignment = type_alignof(proc, field->info);
|
|
Packit |
0021fb |
if (alignment == (size_t)-1)
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
/* Add padding to SZ to align the next element. */
|
|
Packit |
0021fb |
sz = align(sz, alignment);
|
|
Packit |
0021fb |
if (i == offsetof_field) {
|
|
Packit |
0021fb |
*offsetofp = sz;
|
|
Packit |
0021fb |
if (sizep == NULL && alignmentp == NULL)
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t size = type_sizeof(proc, field->info);
|
|
Packit |
0021fb |
if (size == (size_t)-1)
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
sz += size;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (alignment > max_alignment)
|
|
Packit |
0021fb |
max_alignment = alignment;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (max_alignment > 0)
|
|
Packit |
0021fb |
sz = align(sz, max_alignment);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (sizep != NULL)
|
|
Packit |
0021fb |
*sizep = sz;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (alignmentp != NULL)
|
|
Packit |
0021fb |
*alignmentp = max_alignment;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
type_init_array(struct arg_type_info *info,
|
|
Packit |
0021fb |
struct arg_type_info *element_info, int own_info,
|
|
Packit |
0021fb |
struct expr_node *length_expr, int own_length)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
type_init_common(info, ARGTYPE_ARRAY);
|
|
Packit |
0021fb |
info->u.array_info.elt_type = element_info;
|
|
Packit |
0021fb |
info->u.array_info.own_info = own_info;
|
|
Packit |
0021fb |
info->u.array_info.length = length_expr;
|
|
Packit |
0021fb |
info->u.array_info.own_length = own_length;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
type_array_destroy(struct arg_type_info *info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (info->u.array_info.own_info) {
|
|
Packit |
0021fb |
type_destroy(info->u.array_info.elt_type);
|
|
Packit |
0021fb |
free(info->u.array_info.elt_type);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
if (info->u.array_info.own_length) {
|
|
Packit |
0021fb |
expr_destroy(info->u.array_info.length);
|
|
Packit |
0021fb |
free(info->u.array_info.length);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
type_init_pointer(struct arg_type_info *info,
|
|
Packit |
0021fb |
struct arg_type_info *pointee_info, int own_info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
type_init_common(info, ARGTYPE_POINTER);
|
|
Packit |
0021fb |
info->u.ptr_info.info = pointee_info;
|
|
Packit |
0021fb |
info->u.ptr_info.own_info = own_info;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
type_pointer_destroy(struct arg_type_info *info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (info->u.ptr_info.own_info) {
|
|
Packit |
0021fb |
type_destroy(info->u.ptr_info.info);
|
|
Packit |
0021fb |
free(info->u.ptr_info.info);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
type_destroy(struct arg_type_info *info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (info == NULL)
|
|
Packit |
0021fb |
return;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
switch (info->type) {
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
type_struct_destroy(info);
|
|
Packit |
0021fb |
break;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
type_array_destroy(info);
|
|
Packit |
0021fb |
break;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_POINTER:
|
|
Packit |
0021fb |
type_pointer_destroy(info);
|
|
Packit |
0021fb |
break;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_VOID:
|
|
Packit |
0021fb |
case ARGTYPE_INT:
|
|
Packit |
0021fb |
case ARGTYPE_UINT:
|
|
Packit |
0021fb |
case ARGTYPE_LONG:
|
|
Packit |
0021fb |
case ARGTYPE_ULONG:
|
|
Packit |
0021fb |
case ARGTYPE_CHAR:
|
|
Packit |
0021fb |
case ARGTYPE_SHORT:
|
|
Packit |
0021fb |
case ARGTYPE_USHORT:
|
|
Packit |
0021fb |
case ARGTYPE_FLOAT:
|
|
Packit |
0021fb |
case ARGTYPE_DOUBLE:
|
|
Packit |
0021fb |
break;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (info->own_lens) {
|
|
Packit |
0021fb |
lens_destroy(info->lens);
|
|
Packit |
0021fb |
free(info->lens);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static int
|
|
Packit |
0021fb |
type_alloc_and_clone(struct arg_type_info **retpp,
|
|
Packit |
0021fb |
struct arg_type_info *info, int own)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
*retpp = info;
|
|
Packit |
0021fb |
if (own) {
|
|
Packit |
0021fb |
*retpp = malloc(sizeof **retpp);
|
|
Packit |
0021fb |
if (*retpp == NULL || type_clone(*retpp, info) < 0) {
|
|
Packit |
0021fb |
free(*retpp);
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static enum callback_status
|
|
Packit |
0021fb |
clone_struct_add_field(const struct struct_field *field, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct arg_type_info *retp = data;
|
|
Packit |
0021fb |
struct arg_type_info *info;
|
|
Packit |
0021fb |
if (type_alloc_and_clone(&info, field->info, field->own_info) < 0) {
|
|
Packit |
0021fb |
fail:
|
|
Packit |
0021fb |
if (info != field->info)
|
|
Packit |
0021fb |
free(info);
|
|
Packit |
0021fb |
return CBS_STOP;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (type_struct_add(retp, info, field->own_info) < 0) {
|
|
Packit |
0021fb |
if (field->own_info)
|
|
Packit |
0021fb |
type_destroy(info);
|
|
Packit |
0021fb |
goto fail;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return CBS_CONT;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
type_clone(struct arg_type_info *retp, const struct arg_type_info *info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
switch (info->type) {
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
type_init_struct(retp);
|
|
Packit |
0021fb |
if (VECT_EACH_CST(&info->u.entries, struct struct_field, NULL,
|
|
Packit |
0021fb |
clone_struct_add_field, retp) != NULL) {
|
|
Packit |
0021fb |
type_destroy(retp);
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
break;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:;
|
|
Packit |
0021fb |
struct arg_type_info *elt_type;
|
|
Packit |
0021fb |
if (type_alloc_and_clone(&elt_type, info->u.array_info.elt_type,
|
|
Packit |
0021fb |
info->u.array_info.own_info) < 0)
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
assert(!info->u.array_info.own_length); // XXXXXXX
|
|
Packit |
0021fb |
type_init_array(retp, elt_type, info->u.array_info.own_info,
|
|
Packit |
0021fb |
info->u.array_info.length,
|
|
Packit |
0021fb |
info->u.array_info.own_length);
|
|
Packit |
0021fb |
break;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_POINTER:;
|
|
Packit |
0021fb |
struct arg_type_info *ninfo;
|
|
Packit |
0021fb |
if (type_alloc_and_clone(&ninfo, info->u.ptr_info.info,
|
|
Packit |
0021fb |
info->u.ptr_info.own_info) < 0)
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
type_init_pointer(retp, ninfo, info->u.ptr_info.own_info);
|
|
Packit |
0021fb |
break;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_VOID:
|
|
Packit |
0021fb |
case ARGTYPE_INT:
|
|
Packit |
0021fb |
case ARGTYPE_UINT:
|
|
Packit |
0021fb |
case ARGTYPE_LONG:
|
|
Packit |
0021fb |
case ARGTYPE_ULONG:
|
|
Packit |
0021fb |
case ARGTYPE_CHAR:
|
|
Packit |
0021fb |
case ARGTYPE_SHORT:
|
|
Packit |
0021fb |
case ARGTYPE_USHORT:
|
|
Packit |
0021fb |
case ARGTYPE_FLOAT:
|
|
Packit |
0021fb |
case ARGTYPE_DOUBLE:
|
|
Packit |
0021fb |
*retp = *info;
|
|
Packit |
0021fb |
break;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
assert(!info->own_lens);
|
|
Packit |
0021fb |
retp->lens = info->lens;
|
|
Packit |
0021fb |
retp->own_lens = info->own_lens;
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
#ifdef ARCH_HAVE_SIZEOF
|
|
Packit |
0021fb |
size_t arch_type_sizeof(struct process *proc, struct arg_type_info *arg);
|
|
Packit |
0021fb |
#else
|
|
Packit |
0021fb |
size_t
|
|
Packit |
0021fb |
arch_type_sizeof(struct process *proc, struct arg_type_info *arg)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
/* Use default value. */
|
|
Packit |
0021fb |
return (size_t)-2;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
#endif
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
#ifdef ARCH_HAVE_ALIGNOF
|
|
Packit |
0021fb |
size_t arch_type_alignof(struct process *proc, struct arg_type_info *arg);
|
|
Packit |
0021fb |
#else
|
|
Packit |
0021fb |
size_t
|
|
Packit |
0021fb |
arch_type_alignof(struct process *proc, struct arg_type_info *arg)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
/* Use default value. */
|
|
Packit |
0021fb |
return (size_t)-2;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
#endif
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
/* We need to support alignments that are not power of two. E.g. long
|
|
Packit |
0021fb |
* double on x86 has alignment of 12. */
|
|
Packit |
0021fb |
size_t
|
|
Packit |
0021fb |
align(size_t sz, size_t alignment)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(alignment != 0);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if ((sz % alignment) != 0)
|
|
Packit |
0021fb |
sz = ((sz / alignment) + 1) * alignment;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return sz;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t
|
|
Packit |
0021fb |
type_sizeof(struct process *proc, struct arg_type_info *type)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
size_t arch_size = arch_type_sizeof(proc, type);
|
|
Packit |
0021fb |
if (arch_size != (size_t)-2)
|
|
Packit |
0021fb |
return arch_size;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
switch (type->type) {
|
|
Packit |
0021fb |
size_t size;
|
|
Packit |
0021fb |
case ARGTYPE_CHAR:
|
|
Packit |
0021fb |
return sizeof(char);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_SHORT:
|
|
Packit |
0021fb |
case ARGTYPE_USHORT:
|
|
Packit |
0021fb |
return sizeof(short);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_INT:
|
|
Packit |
0021fb |
case ARGTYPE_UINT:
|
|
Packit |
0021fb |
return sizeof(int);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_LONG:
|
|
Packit |
0021fb |
case ARGTYPE_ULONG:
|
|
Packit |
0021fb |
return sizeof(long);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_FLOAT:
|
|
Packit |
0021fb |
return sizeof(float);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_DOUBLE:
|
|
Packit |
0021fb |
return sizeof(double);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
if (layout_struct(proc, type, &size, NULL, NULL) < 0)
|
|
Packit |
0021fb |
return (size_t)-1;
|
|
Packit |
0021fb |
return size;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_POINTER:
|
|
Packit |
0021fb |
return sizeof(void *);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
if (expr_is_compile_constant(type->u.array_info.length)) {
|
|
Packit |
0021fb |
long l;
|
|
Packit |
0021fb |
if (expr_eval_constant(type->u.array_info.length,
|
|
Packit |
0021fb |
&l) < 0)
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct arg_type_info *elt_ti
|
|
Packit |
0021fb |
= type->u.array_info.elt_type;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t elt_size = type_sizeof(proc, elt_ti);
|
|
Packit |
0021fb |
if (elt_size == (size_t)-1)
|
|
Packit |
0021fb |
return (size_t)-1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return ((size_t)l) * elt_size;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
} else {
|
|
Packit |
0021fb |
/* Flexible arrays don't count into the
|
|
Packit |
0021fb |
* sizeof. */
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_VOID:
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
#undef alignof
|
|
Packit |
0021fb |
#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st))
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t
|
|
Packit |
0021fb |
type_alignof(struct process *proc, struct arg_type_info *type)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
size_t arch_alignment = arch_type_alignof(proc, type);
|
|
Packit |
0021fb |
if (arch_alignment != (size_t)-2)
|
|
Packit |
0021fb |
return arch_alignment;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct { char c; char C; } cC;
|
|
Packit |
0021fb |
struct { char c; short s; } cs;
|
|
Packit |
0021fb |
struct { char c; int i; } ci;
|
|
Packit |
0021fb |
struct { char c; long l; } cl;
|
|
Packit |
0021fb |
struct { char c; void* p; } cp;
|
|
Packit |
0021fb |
struct { char c; float f; } cf;
|
|
Packit |
0021fb |
struct { char c; double d; } cd;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static size_t char_alignment = alignof(C, cC);
|
|
Packit |
0021fb |
static size_t short_alignment = alignof(s, cs);
|
|
Packit |
0021fb |
static size_t int_alignment = alignof(i, ci);
|
|
Packit |
0021fb |
static size_t long_alignment = alignof(l, cl);
|
|
Packit |
0021fb |
static size_t ptr_alignment = alignof(p, cp);
|
|
Packit |
0021fb |
static size_t float_alignment = alignof(f, cf);
|
|
Packit |
0021fb |
static size_t double_alignment = alignof(d, cd);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
switch (type->type) {
|
|
Packit |
0021fb |
size_t alignment;
|
|
Packit |
0021fb |
case ARGTYPE_LONG:
|
|
Packit |
0021fb |
case ARGTYPE_ULONG:
|
|
Packit |
0021fb |
return long_alignment;
|
|
Packit |
0021fb |
case ARGTYPE_CHAR:
|
|
Packit |
0021fb |
return char_alignment;
|
|
Packit |
0021fb |
case ARGTYPE_SHORT:
|
|
Packit |
0021fb |
case ARGTYPE_USHORT:
|
|
Packit |
0021fb |
return short_alignment;
|
|
Packit |
0021fb |
case ARGTYPE_FLOAT:
|
|
Packit |
0021fb |
return float_alignment;
|
|
Packit |
0021fb |
case ARGTYPE_DOUBLE:
|
|
Packit |
0021fb |
return double_alignment;
|
|
Packit |
0021fb |
case ARGTYPE_POINTER:
|
|
Packit |
0021fb |
return ptr_alignment;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
return type_alignof(proc, type->u.array_info.elt_type);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
if (layout_struct(proc, type, NULL, &alignment, NULL) < 0)
|
|
Packit |
0021fb |
return (size_t)-1;
|
|
Packit |
0021fb |
return alignment;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
default:
|
|
Packit |
0021fb |
return int_alignment;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t
|
|
Packit |
0021fb |
type_offsetof(struct process *proc, struct arg_type_info *type, size_t emt)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(type->type == ARGTYPE_STRUCT
|
|
Packit |
0021fb |
|| type->type == ARGTYPE_ARRAY);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
switch (type->type) {
|
|
Packit |
0021fb |
size_t alignment;
|
|
Packit |
0021fb |
size_t size;
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
alignment = type_alignof(proc, type->u.array_info.elt_type);
|
|
Packit |
0021fb |
if (alignment == (size_t)-1)
|
|
Packit |
0021fb |
return (size_t)-1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size = type_sizeof(proc, type->u.array_info.elt_type);
|
|
Packit |
0021fb |
if (size == (size_t)-1)
|
|
Packit |
0021fb |
return (size_t)-1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return emt * align(size, alignment);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
if (layout_struct(proc, type, NULL, NULL, &emt) < 0)
|
|
Packit |
0021fb |
return (size_t)-1;
|
|
Packit |
0021fb |
return emt;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
default:
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct arg_type_info *
|
|
Packit |
0021fb |
type_element(struct arg_type_info *info, size_t emt)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(info->type == ARGTYPE_STRUCT
|
|
Packit |
0021fb |
|| info->type == ARGTYPE_ARRAY);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
switch (info->type) {
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
return info->u.array_info.elt_type;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
assert(emt < type_struct_size(info));
|
|
Packit |
0021fb |
return type_struct_get(info, emt);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
default:
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t
|
|
Packit |
0021fb |
type_aggregate_size(struct arg_type_info *info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(info->type == ARGTYPE_STRUCT
|
|
Packit |
0021fb |
|| info->type == ARGTYPE_ARRAY);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
switch (info->type) {
|
|
Packit |
0021fb |
long ret;
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
if (expr_eval_constant(info->u.array_info.length, &ret) < 0)
|
|
Packit |
0021fb |
return (size_t)-1;
|
|
Packit |
0021fb |
return (size_t)ret;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
return type_struct_size(info);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
default:
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
type_is_integral(enum arg_type type)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
switch (type) {
|
|
Packit |
0021fb |
case ARGTYPE_INT:
|
|
Packit |
0021fb |
case ARGTYPE_UINT:
|
|
Packit |
0021fb |
case ARGTYPE_LONG:
|
|
Packit |
0021fb |
case ARGTYPE_ULONG:
|
|
Packit |
0021fb |
case ARGTYPE_CHAR:
|
|
Packit |
0021fb |
case ARGTYPE_SHORT:
|
|
Packit |
0021fb |
case ARGTYPE_USHORT:
|
|
Packit |
0021fb |
return 1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_VOID:
|
|
Packit |
0021fb |
case ARGTYPE_FLOAT:
|
|
Packit |
0021fb |
case ARGTYPE_DOUBLE:
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
case ARGTYPE_POINTER:
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
type_is_signed(enum arg_type type)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(type_is_integral(type));
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
switch (type) {
|
|
Packit |
0021fb |
case ARGTYPE_CHAR:
|
|
Packit |
0021fb |
return CHAR_MIN != 0;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_SHORT:
|
|
Packit |
0021fb |
case ARGTYPE_INT:
|
|
Packit |
0021fb |
case ARGTYPE_LONG:
|
|
Packit |
0021fb |
return 1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_UINT:
|
|
Packit |
0021fb |
case ARGTYPE_ULONG:
|
|
Packit |
0021fb |
case ARGTYPE_USHORT:
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_VOID:
|
|
Packit |
0021fb |
case ARGTYPE_FLOAT:
|
|
Packit |
0021fb |
case ARGTYPE_DOUBLE:
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
case ARGTYPE_POINTER:
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct arg_type_info *
|
|
Packit |
0021fb |
type_get_fp_equivalent(struct arg_type_info *info)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
/* Extract innermost structure. Give up early if any
|
|
Packit |
0021fb |
* component has more than one element. */
|
|
Packit |
0021fb |
while (info->type == ARGTYPE_STRUCT) {
|
|
Packit |
0021fb |
if (type_struct_size(info) != 1)
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
info = type_element(info, 0);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
switch (info->type) {
|
|
Packit |
0021fb |
case ARGTYPE_CHAR:
|
|
Packit |
0021fb |
case ARGTYPE_SHORT:
|
|
Packit |
0021fb |
case ARGTYPE_INT:
|
|
Packit |
0021fb |
case ARGTYPE_LONG:
|
|
Packit |
0021fb |
case ARGTYPE_UINT:
|
|
Packit |
0021fb |
case ARGTYPE_ULONG:
|
|
Packit |
0021fb |
case ARGTYPE_USHORT:
|
|
Packit |
0021fb |
case ARGTYPE_VOID:
|
|
Packit |
0021fb |
case ARGTYPE_ARRAY:
|
|
Packit |
0021fb |
case ARGTYPE_POINTER:
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_FLOAT:
|
|
Packit |
0021fb |
case ARGTYPE_DOUBLE:
|
|
Packit |
0021fb |
return info;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
case ARGTYPE_STRUCT:
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
abort();
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct arg_type_info *
|
|
Packit |
0021fb |
type_get_hfa_type(struct arg_type_info *info, size_t *countp)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(info != NULL);
|
|
Packit |
0021fb |
if (info->type != ARGTYPE_STRUCT
|
|
Packit |
0021fb |
&& info->type != ARGTYPE_ARRAY)
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t n = type_aggregate_size(info);
|
|
Packit |
0021fb |
if (n == (size_t)-1)
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct arg_type_info *ret = NULL;
|
|
Packit |
0021fb |
*countp = 0;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
while (n-- > 0) {
|
|
Packit |
0021fb |
struct arg_type_info *emt = type_element(info, n);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t emt_count = 1;
|
|
Packit |
0021fb |
if (emt->type == ARGTYPE_STRUCT || emt->type == ARGTYPE_ARRAY)
|
|
Packit |
0021fb |
emt = type_get_hfa_type(emt, &emt_count);
|
|
Packit |
0021fb |
if (emt == NULL)
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
if (ret == NULL) {
|
|
Packit |
0021fb |
if (emt->type != ARGTYPE_FLOAT
|
|
Packit |
0021fb |
&& emt->type != ARGTYPE_DOUBLE)
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
ret = emt;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
if (emt->type != ret->type)
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
*countp += emt_count;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
return ret;
|
|
Packit |
0021fb |
}
|