Home | History | Annotate | Download | only in ltrace
      1 /*
      2  * This file is part of ltrace.
      3  * Copyright (C) 2011, 2012 Petr Machata, Red Hat Inc.
      4  *
      5  * This program is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU General Public License as
      7  * published by the Free Software Foundation; either version 2 of the
      8  * License, or (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful, but
     11  * WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program; if not, write to the Free Software
     17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
     18  * 02110-1301 USA
     19  */
     20 
     21 #include <stdlib.h>
     22 #include <assert.h>
     23 #include <string.h>
     24 
     25 #include "lens_enum.h"
     26 #include "lens_default.h"
     27 #include "value.h"
     28 #include "sysdep.h"
     29 #include "type.h"
     30 
     31 struct enum_entry {
     32 	char *key;
     33 	int own_key;
     34 	struct value *value;
     35 	int own_value;
     36 };
     37 
     38 static void
     39 enum_entry_dtor(struct enum_entry *entry, void *data)
     40 {
     41 	if (entry->own_key)
     42 		free(entry->key);
     43 	if (entry->own_value) {
     44 		value_destroy(entry->value);
     45 		free(entry->value);
     46 	}
     47 }
     48 
     49 static void
     50 enum_lens_destroy_cb(struct lens *lens)
     51 {
     52 	struct enum_lens *self = (void *)lens;
     53 
     54 	VECT_DESTROY(&self->entries, struct enum_entry,
     55 		     enum_entry_dtor, NULL);
     56 }
     57 
     58 enum {
     59 #ifdef ARCH_ENDIAN_BIG
     60 	big_endian = 1,
     61 #elif defined (ARCH_ENDIAN_LITTLE)
     62 	big_endian = 0,
     63 #else
     64 # error Undefined endianness.
     65 #endif
     66 };
     67 
     68 /* Returns 0 if they are not equal, >0 if they are, and <0 if there
     69  * was an error.  */
     70 static int
     71 enum_values_equal(struct value *inf_value, struct value *enum_value,
     72 		  struct value_dict *arguments)
     73 {
     74 	/* Width may not match between what's defined in config file
     75 	 * and what arrives from the back end.  Typically, if there is
     76 	 * a mismatch, the config file size will be larger, as we are
     77 	 * in a situation where 64-bit tracer traces 32-bit process.
     78 	 * But opposite situation can occur e.g. on PPC, where it's
     79 	 * apparently possible for 32-bit tracer to trace 64-bit
     80 	 * inferior, or hypothetically in a x32/x86_64 situation.  */
     81 
     82 	unsigned char *inf_data = value_get_data(inf_value, arguments);
     83 	size_t inf_sz = value_size(inf_value, arguments);
     84 	if (inf_data == NULL || inf_sz == (size_t)-1)
     85 		return -1;
     86 
     87 	assert(inf_value->type->type == enum_value->type->type);
     88 
     89 	unsigned char *enum_data = value_get_data(enum_value, arguments);
     90 	size_t enum_sz = value_size(enum_value, arguments);
     91 	if (enum_data == NULL || enum_sz == (size_t)-1)
     92 		return -1;
     93 
     94 	size_t sz = enum_sz > inf_sz ? inf_sz : enum_sz;
     95 
     96 	if (big_endian)
     97 		return memcmp(enum_data + enum_sz - sz,
     98 			      inf_data + inf_sz - sz, sz) == 0;
     99 	else
    100 		return memcmp(enum_data, inf_data, sz) == 0;
    101 }
    102 
    103 static const char *
    104 enum_get(struct enum_lens *lens, struct value *value,
    105 	 struct value_dict *arguments)
    106 {
    107 	size_t i;
    108 	for (i = 0; i < vect_size(&lens->entries); ++i) {
    109 		struct enum_entry *entry = VECT_ELEMENT(&lens->entries,
    110 							struct enum_entry, i);
    111 		int st = enum_values_equal(value, entry->value, arguments);
    112 		if (st < 0)
    113 			return NULL;
    114 		else if (st != 0)
    115 			return entry->key;
    116 	}
    117 	return NULL;
    118 }
    119 
    120 static int
    121 enum_lens_format_cb(struct lens *lens, FILE *stream,
    122 		    struct value *value, struct value_dict *arguments)
    123 {
    124 	struct enum_lens *self = (void *)lens;
    125 
    126 	const char *name = enum_get(self, value, arguments);
    127 	if (name != NULL)
    128 		return fprintf(stream, "%s", name);
    129 
    130 	return lens_format(&default_lens, stream, value, arguments);
    131 }
    132 
    133 
    134 void
    135 lens_init_enum(struct enum_lens *lens)
    136 {
    137 	*lens = (struct enum_lens){
    138 		{
    139 			.format_cb = enum_lens_format_cb,
    140 			.destroy_cb = enum_lens_destroy_cb,
    141 		},
    142 	};
    143 	VECT_INIT(&lens->entries, struct enum_entry);
    144 }
    145 
    146 int
    147 lens_enum_add(struct enum_lens *lens,
    148 	      const char *key, int own_key,
    149 	      struct value *value, int own_value)
    150 {
    151 	struct enum_entry entry = { (char *)key, own_key, value, own_value };
    152 	return VECT_PUSHBACK(&lens->entries, &entry);
    153 }
    154 
    155 size_t
    156 lens_enum_size(struct enum_lens *lens)
    157 {
    158 	return vect_size(&lens->entries);
    159 }
    160