Commit d7b22927 authored by Petr Machata's avatar Petr Machata

Add module zero.c/zero.h

parent eff655b7
2012-01-06 Petr Machata <[email protected]>
* zero.c, zero.h: New module
* read_config_file.c (parse_zero, wrap_in_zero): New functions
(parse_argnum): Support "zero" length
(parse_enum): New function, code moved from...
(parse_nonpointer_type): ... here
2012-01-06 Petr Machata <[email protected]>
* read_config_file.c (parse_char): New function
......
......@@ -36,6 +36,7 @@ libltrace_la_SOURCES = \
expr.c \
fetch.c \
vect.c \
zero.c
libltrace_la_LIBADD = \
$(libelf_LIBS) \
......@@ -79,6 +80,7 @@ noinst_HEADERS = \
expr.h \
fetch.h \
vect.h \
zero.h
dist_man1_MANS = \
ltrace.1
......
......@@ -34,6 +34,7 @@
#include "expr.h"
#include "type.h"
#include "common.h"
#include "zero.h"
#define READER(NAME, TYPE) \
static int \
......@@ -272,9 +273,8 @@ format_array(FILE *stream, struct value *value, struct value_dict *arguments,
* space. */
typedef char assert__long_enough_long[-(sizeof(long) < sizeof(void *))];
long l = options.strlen;
if (length != NULL) /* XXX emulate node ZERO before it lands */
if (expr_eval_word(length, value, arguments, &l) < 0)
return -1;
if (expr_eval_word(length, value, arguments, &l) < 0)
return -1;
size_t len = (size_t)l;
int written = 0;
......@@ -295,8 +295,6 @@ format_array(FILE *stream, struct value *value, struct value_dict *arguments,
struct value element;
if (value_init_element(&element, value, i) < 0)
return -1;
if (value_is_zero(&element, arguments)) /* XXX emulate ZERO */
break;
int o = format_argument(stream, &element, arguments);
if (o < 0)
return -1;
......@@ -313,7 +311,7 @@ format_array(FILE *stream, struct value *value, struct value_dict *arguments,
int
format_argument(FILE *stream, struct value *value, struct value_dict *arguments)
{
struct expr_node *length = NULL;
struct expr_node *length = expr_node_zero();
switch (value->type->type) {
case ARGTYPE_VOID:
return fprintf(stream, "<void>");
......
......@@ -26,11 +26,13 @@
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include "common.h"
#include "type.h"
#include "expr.h"
#include "errno.h"
#include "zero.h"
static int line_no;
static char *filename;
......@@ -237,6 +239,44 @@ parse_char(char **str, char expected)
return 0;
}
static struct expr_node *parse_argnum(char **str, int zero);
static struct expr_node *
parse_zero(char **str, struct expr_node *ret)
{
eat_spaces(str);
if (**str == '(') {
++*str;
struct expr_node *arg = parse_argnum(str, 0);
if (arg == NULL)
return NULL;
if (parse_char(str, ')') < 0) {
fail:
expr_destroy(arg);
free(arg);
return NULL;
}
struct expr_node *ret = build_zero_w_arg(arg, 1);
if (ret == NULL)
goto fail;
return ret;
} else {
return expr_node_zero();
}
}
static int
wrap_in_zero(struct expr_node **nodep)
{
struct expr_node *n = build_zero_w_arg(*nodep, 1);
if (n == NULL)
return -1;
*nodep = n;
return 0;
}
/*
* Input:
* argN : The value of argument #N, counting from 1
......@@ -245,7 +285,7 @@ parse_char(char **str, char expected)
* N : The numeric value N
*/
static struct expr_node *
parse_argnum(char **str)
parse_argnum(char **str, int zero)
{
struct expr_node *expr = malloc(sizeof(*expr));
if (expr == NULL)
......@@ -260,6 +300,9 @@ parse_argnum(char **str)
expr_init_const_word(expr, l, type_get_simple(ARGTYPE_LONG), 0);
if (zero && wrap_in_zero(&expr) < 0)
goto fail;
return expr;
} else {
......@@ -297,11 +340,21 @@ parse_argnum(char **str)
} else if (strcmp(name, "retval") == 0) {
expr_init_named(expr, "retval", 0);
} else {
} else if (strcmp(name, "zero") == 0) {
struct expr_node *ret = parse_zero(str, expr);
if (ret == NULL)
goto fail;
return ret;
} else {
report_error(filename, line_no,
"Unknown length specifier: '%s'", name);
goto fail;
}
if (zero && wrap_in_zero(&expr) < 0)
goto fail;
return expr;
}
......@@ -397,6 +450,77 @@ parse_struct(char **str, struct arg_type_info *info)
}
}
/* Syntax: enum ( keyname=value,keyname=value,... ) */
static int
parse_enum(char **str, struct arg_type_info *info)
{
struct enum_opt {
char *key;
int value;
struct enum_opt *next;
};
struct enum_opt *list = NULL;
struct enum_opt *p;
int entries = 0;
int ii;
eat_spaces(str);
(*str)++; // Get past open paren
eat_spaces(str);
int last_val = 0;
while (**str && **str != ')') {
p = (struct enum_opt *) malloc(sizeof(*p));
eat_spaces(str);
char *key = parse_ident(str);
if (key == NULL) {
err:
free(key);
return -1;
}
if (**str == '=') {
++*str;
eat_spaces(str);
long l;
if (parse_int(str, &l) < 0 || check_int(l) < 0)
goto err;
last_val = l;
} else {
last_val++;
}
p->key = key;
p->value = last_val;
p->next = list;
list = p;
++entries;
// Skip comma
eat_spaces(str);
if (**str == ',') {
(*str)++;
eat_spaces(str);
}
}
info->u.enum_info.entries = entries;
info->u.enum_info.keys = (char **) malloc(entries * sizeof(char *));
info->u.enum_info.values = (int *) malloc(entries * sizeof(int));
for (ii = 0, p = NULL; list; ++ii, list = list->next) {
if (p != NULL)
free(p);
info->u.enum_info.keys[ii] = list->key;
info->u.enum_info.values[ii] = list->value;
p = list;
}
if (p != NULL)
free(p);
return 0;
}
static struct arg_type_info *
parse_nonpointer_type(char **str) {
struct arg_type_info *simple;
......@@ -422,6 +546,7 @@ parse_nonpointer_type(char **str) {
/* Code to parse parameterized types will go into the following
switch statement. */
int (*parser) (char **, struct arg_type_info *) = NULL;
switch (info->type) {
/* Syntax: array ( type, N|argN ) */
......@@ -432,80 +557,13 @@ parse_nonpointer_type(char **str) {
return NULL;
(*str)++; // Get past comma
eat_spaces(str);
info->u.array_info.length = parse_argnum(str);
info->u.array_info.length = parse_argnum(str, 0);
(*str)++; // Get past close paren
return info;
/* Syntax: enum ( keyname=value,keyname=value,... ) */
case ARGTYPE_ENUM:{
struct enum_opt {
char *key;
int value;
struct enum_opt *next;
};
struct enum_opt *list = NULL;
struct enum_opt *p;
int entries = 0;
int ii;
eat_spaces(str);
(*str)++; // Get past open paren
eat_spaces(str);
while (**str && **str != ')') {
p = (struct enum_opt *) malloc(sizeof(*p));
eat_spaces(str);
p->key = parse_ident(str);
if (error_count) {
free(p);
return NULL;
}
eat_spaces(str);
if (**str != '=') {
fail:
free(p->key);
free(p);
output_line(0,
"Syntax error in `%s', line %d: expected '=', got '%c'",
filename, line_no, **str);
error_count++;
return NULL;
}
++(*str);
eat_spaces(str);
long l;
if (parse_int(str, &l) < 0 || check_int(l) < 0)
goto fail;
p->value = l;
p->next = list;
list = p;
++entries;
// Skip comma
eat_spaces(str);
if (**str == ',') {
(*str)++;
eat_spaces(str);
}
}
info->u.enum_info.entries = entries;
info->u.enum_info.keys =
(char **) malloc(entries * sizeof(char *));
info->u.enum_info.values =
(int *) malloc(entries * sizeof(int));
for (ii = 0, p = NULL; list; ++ii, list = list->next) {
if (p)
free(p);
info->u.enum_info.keys[ii] = list->key;
info->u.enum_info.values[ii] = list->value;
p = list;
}
if (p)
free(p);
return info;
}
case ARGTYPE_ENUM:
parser = parse_enum;
break;
case ARGTYPE_STRING:
if (!isdigit(**str) && **str != '[') {
......@@ -518,28 +576,21 @@ parse_nonpointer_type(char **str) {
/* Backwards compatibility for string0, string1, ... */
if (isdigit(**str)) {
info->u.string_n_info.length = parse_argnum(str);
info->u.string_n_info.length = parse_argnum(str, 1);
return info;
}
(*str)++; // Skip past opening [
eat_spaces(str);
info->u.string_n_info.length = parse_argnum(str);
info->u.string_n_info.length = parse_argnum(str, 1);
eat_spaces(str);
(*str)++; // Skip past closing ]
return info;
// Syntax: struct ( type,type,type,... )
case ARGTYPE_STRUCT:{
if (parse_struct(str, info) < 0) {
free(info);
output_line(0, "Parse error in `%s', line %d",
filename, line_no);
error_count++;
return NULL;
}
return info;
}
case ARGTYPE_STRUCT:
parser = parse_struct;
break;
default:
if (info->type == ARGTYPE_UNKNOWN) {
......@@ -553,6 +604,14 @@ parse_nonpointer_type(char **str) {
return info;
}
}
assert(parser != NULL);
if (parser(str, info) < 0) {
free(info);
return NULL;
}
return info;
}
static struct arg_type_info *
......
/*
* This file is part of ltrace.
* Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <error.h>
#include <errno.h>
#include "zero.h"
#include "common.h"
#include "type.h"
#include "value.h"
#include "expr.h"
static int
zero_callback_max(struct value *ret_value, struct value *lhs,
struct value_dict *arguments,
size_t max, void *data)
{
size_t i;
for (i = 0; i < max; ++i) {
struct value element;
if (value_init_element(&element, lhs, i) < 0)
return -1;
int zero = value_is_zero(&element, arguments);
value_destroy(&element);
if (zero)
break;
}
struct arg_type_info *long_type = type_get_simple(ARGTYPE_LONG);
value_init_detached(ret_value, NULL, long_type, 0);
value_set_long(ret_value, i);
return 0;
}
/* LHS->zero(RHS). Looks for a length of zero-terminated array, but
* looks no further than first RHS bytes. */
static int
zero_callback(struct value *ret_value, struct value *lhs,
struct value *rhs, struct value_dict *arguments, void *data)
{
long l;
if (value_extract_word(rhs, &l, arguments) < 0)
return -1;
if (l < 0)
/* It might just be a positive value >2GB, but that's
* not likely. */
report_global_error("maximum array length seems negative");
size_t max = (size_t)l;
return zero_callback_max(ret_value, lhs, arguments, max, data);
}
/* LHS->zero. Looks for a length of zero-terminated array, without
* limit. */
static int
zero1_callback(struct value *ret_value, struct value *lhs,
struct value_dict *arguments, void *data)
{
return zero_callback_max(ret_value, lhs, arguments, (size_t)-1, data);
}
struct expr_node *
build_zero_w_arg(struct expr_node *expr, int own)
{
struct expr_node *e_z = malloc(sizeof(*e_z));
if (e_z == NULL)
return NULL;
expr_init_cb2(e_z, &zero_callback,
expr_self(), 0, expr, own, NULL);
return e_z;
}
struct expr_node *
expr_node_zero(void)
{
static struct expr_node *node = NULL;
if (node == NULL) {
node = malloc(sizeof(*node));
if (node == NULL)
error(1, errno, "malloc expr_node_zero");
expr_init_cb1(node, &zero1_callback,
expr_self(), 0, (void *)-1);
}
return node;
}
/*
* This file is part of ltrace.
* Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef ZERO_H
#define ZERO_H
#include "forward.h"
/* This returns a pre-built "zero" node without argument. Share, but
don't free. */
struct expr_node *expr_node_zero(void);
/* This builds a new "zero" node with EXPR as argument. EXPR is owned
* by the built node if OWN. Returns NULL if something failed. */
struct expr_node *build_zero_w_arg(struct expr_node *expr, int own);
#endif /* ZERO_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment