mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
d5722aa2fe
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.
168 lines
5.6 KiB
C++
168 lines
5.6 KiB
C++
/* 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 */
|