binutils-gdb/gdb/charset.h
Pedro Alves d5722aa2fe Introduce gdb::byte_vector, add allocator that default-initializes
In some cases we've been replacing heap-allocated gdb_byte buffers
managed with xmalloc/make_cleanup(xfree) with gdb::vector<gdb_byte>.
That usually pessimizes the code a little bit because std::vector
value-initializes elements (which for gdb_byte means
zero-initialization), while if you're creating a temporary buffer,
you're most certaintly going to fill it in with some data.  An
alternative is to use

  unique_ptr<gdb_byte[]> buf (new gdb_byte[size]);

but it looks like that's not very popular.

Recently, a use of obstacks in dwarf2read.c was replaced with
std::vector<gdb_byte> and that as well introduced a pessimization for
always memsetting the buffer when it's garanteed that the zeros will
be overwritten immediately.  (see dwarf2read.c change in this patch to
find it.)

So here's a different take at addressing this issue "by design":

#1 - Introduce default_init_allocator<T>

I.e., a custom allocator that does default construction using default
initialization, meaning, no more zero initialization.  That's the
default_init_allocation<T> class added in this patch.

See "Notes" at
<http://en.cppreference.com/w/cpp/container/vector/resize>.

#2 - Introduce def_vector<T>

I.e., a convenience typedef, because typing the allocator is annoying:

  using def_vector<T> = std::vector<T, gdb::default_init_allocator<T>>;

#3 - Introduce byte_vector

Because gdb_byte vectors will be the common thing, add a convenience
"byte_vector" typedef:

  using byte_vector = def_vector<gdb_byte>;

which is really the same as:

  std::vector<gdb_byte, gdb::default_init_allocator<gdb_byte>>;

The intent then is to make "gdb::byte_vector" be the go-to for dynamic
byte buffers.  So the less friction, the better.

#4 - Adjust current code to use it.

To set the example going forward.  Replace std::vector uses and also
unique_ptr<byte[]> uses.

One nice thing is that with this allocator, for changes like these:

  -std::unique_ptr<byte[]> buf (new gdb_byte[some_size]);
  +gdb::byte_vector buf (some_size);
   fill_with_data (buf.data (), buf.size ());

the generated code is the same as before.  I.e., the compiler
de-structures the vector and gets rid of the unused "reserved vs size"
related fields.

The other nice thing is that it's easier to write
  gdb::byte_vector buf (size);
than
  std::unique_ptr<gdb_byte[]> buf (new gdb_byte[size]);
or even (C++14):
  auto buf = std::make_unique<gdb_byte[]> (size); // zero-initializes...

#5 - Suggest s/std::vector<gdb_byte>/gdb::byte_vector/ going forward.

Note that this commit actually fixes a couple of bugs where the current
code is incorrectly using "std::vector::reserve(new_size)" and then
accessing the vector's internal buffer beyond the vector's size: see
dwarf2loc.c and charset.c.  That's undefined behavior and may trigger
debug mode assertion failures.  With default_init_allocator,
"resize()" behaves like "reserve()" performance wise, in that it
leaves new elements with unspecified values, but, it does that safely
without triggering undefined behavior when you access those values.

gdb/ChangeLog:
2017-06-14  Pedro Alves  <palves@redhat.com>

	* ada-lang.c: Include "common/byte-vector.h".
	(ada_value_primitive_packed_val): Use gdb::byte_vector.
	* charset.c (wchar_iterator::iterate): Resize the vector instead
	of reserving it.
	* common/byte-vector.h: Include "common/def-vector.h".
	(wchar_iterator::m_out): Now a gdb::def_vector<gdb_wchar_t>.
	* cli/cli-dump.c: Include "common/byte-vector.h".
	(dump_memory_to_file, restore_binary_file): Use gdb::byte_vector.
	* common/byte-vector.h: New file.
	* common/def-vector.h: New file.
	* common/default-init-alloc.h: New file.
	* dwarf2loc.c: Include "common/byte-vector.h".
	(rw_pieced_value): Use gdb::byte_vector, and resize the vector
	instead of reserving it.
	* dwarf2read.c: Include "common/byte-vector.h".
	(data_buf::m_vec): Now a gdb::byte_vector.
	* gdb_regex.c: Include "common/def-vector.h".
	(compiled_regex::compiled_regex): Use gdb::def_vector<char>.
	* mi/mi-main.c: Include "common/byte-vector.h".
	(mi_cmd_data_read_memory): Use gdb::byte_vector.
	* printcmd.c: Include "common/byte-vector.h".
	(print_scalar_formatted): Use gdb::byte_vector.
	* valprint.c: Include "common/byte-vector.h".
	(maybe_negate_by_bytes, print_decimal_chars): Use
	gdb::byte_vector.
2017-06-14 11:08:52 +01:00

168 lines
5.6 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Character set conversion support for GDB.
Copyright (C) 2001-2017 Free Software Foundation, Inc.
This file is part of GDB.
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 3 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, see <http://www.gnu.org/licenses/>. */
#ifndef CHARSET_H
#define CHARSET_H
#include "common/def-vector.h"
/* If the target program uses a different character set than the host,
GDB has some support for translating between the two; GDB converts
characters and strings to the host character set before displaying
them, and converts characters and strings appearing in expressions
entered by the user to the target character set.
GDB's code pretty much assumes that the host character set is some
superset of ASCII; there are plenty if ('0' + n) expressions and
the like. */
/* Return the name of the current host/target character set. The
result is owned by the charset module; the caller should not free
it. */
const char *host_charset (void);
const char *target_charset (struct gdbarch *gdbarch);
const char *target_wide_charset (struct gdbarch *gdbarch);
/* These values are used to specify the type of transliteration done
by convert_between_encodings. */
enum transliterations
{
/* Error on failure to convert. */
translit_none,
/* Transliterate to host char. */
translit_char
};
/* Convert between two encodings.
FROM is the name of the source encoding.
TO is the name of the target encoding.
BYTES holds the bytes to convert; this is assumed to be characters
in the target encoding.
NUM_BYTES is the number of bytes.
WIDTH is the width of a character from the FROM charset, in bytes.
For a variable width encoding, WIDTH should be the size of a "base
character".
OUTPUT is an obstack where the converted data is written. The
caller is responsible for initializing the obstack, and for
destroying the obstack should an error occur.
TRANSLIT specifies how invalid conversions should be handled. */
void convert_between_encodings (const char *from, const char *to,
const gdb_byte *bytes,
unsigned int num_bytes,
int width, struct obstack *output,
enum transliterations translit);
/* These values are used by wchar_iterate to report errors. */
enum wchar_iterate_result
{
/* Ordinary return. */
wchar_iterate_ok,
/* Invalid input sequence. */
wchar_iterate_invalid,
/* Incomplete input sequence at the end of the input. */
wchar_iterate_incomplete,
/* EOF. */
wchar_iterate_eof
};
/* An iterator that returns host wchar_t's from a target string. */
class wchar_iterator
{
public:
/* Create a new character iterator which returns wchar_t's. INPUT is
the input buffer. BYTES is the number of bytes in the input
buffer. CHARSET is the name of the character set in which INPUT is
encoded. WIDTH is the number of bytes in a base character of
CHARSET.
This constructor can throw on error. */
wchar_iterator (const gdb_byte *input, size_t bytes, const char *charset,
size_t width);
~wchar_iterator ();
/* Perform a single iteration of a wchar_t iterator.
Returns the number of characters converted. A negative result
means that EOF has been reached. A positive result indicates the
number of valid wchar_ts in the result; *OUT_CHARS is updated to
point to the first valid character.
In all cases aside from EOF, *PTR is set to point to the first
converted target byte. *LEN is set to the number of bytes
converted.
A zero result means one of several unusual results. *OUT_RESULT is
set to indicate the type of un-ordinary return.
wchar_iterate_invalid means that an invalid input character was
seen. The iterator is advanced by WIDTH (the argument to
the wchar_iterator constructor) bytes.
wchar_iterate_incomplete means that an incomplete character was
seen at the end of the input sequence.
wchar_iterate_eof means that all bytes were successfully
converted. The other output arguments are not set. */
int iterate (enum wchar_iterate_result *out_result, gdb_wchar_t **out_chars,
const gdb_byte **ptr, size_t *len);
private:
/* The underlying iconv descriptor. */
#ifdef PHONY_ICONV
int m_desc;
#else
iconv_t m_desc;
#endif
/* The input string. This is updated as we convert characters. */
const gdb_byte *m_input;
/* The number of bytes remaining in the input. */
size_t m_bytes;
/* The width of an input character. */
size_t m_width;
/* The output buffer. */
gdb::def_vector<gdb_wchar_t> m_out;
};
/* GDB needs to know a few details of its execution character set.
This knowledge is isolated here and in charset.c. */
/* The escape character. */
#define HOST_ESCAPE_CHAR 27
/* Convert a letter, like 'c', to its corresponding control
character. */
char host_letter_to_control_character (char c);
/* Convert a hex digit character to its numeric value. E.g., 'f' is
converted to 15. This function assumes that C is a valid hex
digit. Both upper- and lower-case letters are recognized. */
int host_hex_value (char c);
#endif /* CHARSET_H */