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.
This commit is contained in:
Pedro Alves 2017-06-14 11:08:52 +01:00
parent 05c966f3c9
commit d5722aa2fe
14 changed files with 230 additions and 31 deletions

View file

@ -1,3 +1,31 @@
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-13 Simon Marchi <simon.marchi@ericsson.com> 2017-06-13 Simon Marchi <simon.marchi@ericsson.com>
* darwin-nat.c: Include "nat/fork-inferior.h". * darwin-nat.c: Include "nat/fork-inferior.h".

View file

@ -61,6 +61,7 @@
#include "arch-utils.h" #include "arch-utils.h"
#include "cli/cli-utils.h" #include "cli/cli-utils.h"
#include "common/function-view.h" #include "common/function-view.h"
#include "common/byte-vector.h"
/* Define whether or not the C operator '/' truncates towards zero for /* Define whether or not the C operator '/' truncates towards zero for
differently signed operands (truncation direction is undefined in C). differently signed operands (truncation direction is undefined in C).
@ -2567,8 +2568,7 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
gdb_byte *unpacked; gdb_byte *unpacked;
const int is_scalar = is_scalar_type (type); const int is_scalar = is_scalar_type (type);
const int is_big_endian = gdbarch_bits_big_endian (get_type_arch (type)); const int is_big_endian = gdbarch_bits_big_endian (get_type_arch (type));
std::unique_ptr<gdb_byte[]> staging; gdb::byte_vector staging;
int staging_len = 0;
type = ada_check_typedef (type); type = ada_check_typedef (type);
@ -2586,14 +2586,14 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
packed, and therefore maybe not at a byte boundary. So, what packed, and therefore maybe not at a byte boundary. So, what
we do, is unpack the data into a byte-aligned buffer, and then we do, is unpack the data into a byte-aligned buffer, and then
use that buffer as our object's value for resolving the type. */ use that buffer as our object's value for resolving the type. */
staging_len = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT; int staging_len = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
staging.reset (new gdb_byte[staging_len]); staging.resize (staging_len);
ada_unpack_from_contents (src, bit_offset, bit_size, ada_unpack_from_contents (src, bit_offset, bit_size,
staging.get (), staging_len, staging.data (), staging.size (),
is_big_endian, has_negatives (type), is_big_endian, has_negatives (type),
is_scalar); is_scalar);
type = resolve_dynamic_type (type, staging.get (), 0); type = resolve_dynamic_type (type, staging.data (), 0);
if (TYPE_LENGTH (type) < (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT) if (TYPE_LENGTH (type) < (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT)
{ {
/* This happens when the length of the object is dynamic, /* This happens when the length of the object is dynamic,
@ -2656,12 +2656,12 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
return v; return v;
} }
if (staging != NULL && staging_len == TYPE_LENGTH (type)) if (staging.size () == TYPE_LENGTH (type))
{ {
/* Small short-cut: If we've unpacked the data into a buffer /* Small short-cut: If we've unpacked the data into a buffer
of the same size as TYPE's length, then we can reuse that, of the same size as TYPE's length, then we can reuse that,
instead of doing the unpacking again. */ instead of doing the unpacking again. */
memcpy (unpacked, staging.get (), staging_len); memcpy (unpacked, staging.data (), staging.size ());
} }
else else
ada_unpack_from_contents (src, bit_offset, bit_size, ada_unpack_from_contents (src, bit_offset, bit_size,

View file

@ -673,7 +673,7 @@ wchar_iterator::iterate (enum wchar_iterate_result *out_result,
++out_request; ++out_request;
if (out_request > m_out.size ()) if (out_request > m_out.size ())
m_out.reserve (out_request); m_out.resize (out_request);
continue; continue;
case EINVAL: case EINVAL:

View file

@ -19,7 +19,7 @@
#ifndef CHARSET_H #ifndef CHARSET_H
#define CHARSET_H #define CHARSET_H
#include <vector> #include "common/def-vector.h"
/* If the target program uses a different character set than the host, /* If the target program uses a different character set than the host,
GDB has some support for translating between the two; GDB converts GDB has some support for translating between the two; GDB converts
@ -144,7 +144,7 @@ class wchar_iterator
size_t m_width; size_t m_width;
/* The output buffer. */ /* The output buffer. */
std::vector<gdb_wchar_t> m_out; gdb::def_vector<gdb_wchar_t> m_out;
}; };

View file

@ -31,7 +31,7 @@
#include "cli/cli-utils.h" #include "cli/cli-utils.h"
#include "gdb_bfd.h" #include "gdb_bfd.h"
#include "filestuff.h" #include "filestuff.h"
#include "common/byte-vector.h"
static const char * static const char *
scan_expression_with_cleanup (const char **cmd, const char *def) scan_expression_with_cleanup (const char **cmd, const char *def)
@ -230,17 +230,17 @@ dump_memory_to_file (const char *cmd, const char *mode, const char *file_format)
/* FIXME: Should use read_memory_partial() and a magic blocking /* FIXME: Should use read_memory_partial() and a magic blocking
value. */ value. */
std::unique_ptr<gdb_byte[]> buf (new gdb_byte[count]); gdb::byte_vector buf (count);
read_memory (lo, buf.get (), count); read_memory (lo, buf.data (), count);
/* Have everything. Open/write the data. */ /* Have everything. Open/write the data. */
if (file_format == NULL || strcmp (file_format, "binary") == 0) if (file_format == NULL || strcmp (file_format, "binary") == 0)
{ {
dump_binary_file (filename, mode, buf.get (), count); dump_binary_file (filename, mode, buf.data (), count);
} }
else else
{ {
dump_bfd_file (filename, mode, file_format, lo, buf.get (), count); dump_bfd_file (filename, mode, file_format, lo, buf.data (), count);
} }
do_cleanups (old_cleanups); do_cleanups (old_cleanups);
@ -545,13 +545,13 @@ restore_binary_file (const char *filename, struct callback_data *data)
perror_with_name (filename); perror_with_name (filename);
/* Now allocate a buffer and read the file contents. */ /* Now allocate a buffer and read the file contents. */
std::unique_ptr<gdb_byte[]> buf (new gdb_byte[len]); gdb::byte_vector buf (len);
if (fread (buf.get (), 1, len, file) != len) if (fread (buf.data (), 1, len, file) != len)
perror_with_name (filename); perror_with_name (filename);
/* Now write the buffer into target memory. */ /* Now write the buffer into target memory. */
len = target_write_memory (data->load_start + data->load_offset, len = target_write_memory (data->load_start + data->load_offset,
buf.get (), len); buf.data (), len);
if (len != 0) if (len != 0)
warning (_("restore: memory write failed (%s)."), safe_strerror (len)); warning (_("restore: memory write failed (%s)."), safe_strerror (len));
do_cleanups (cleanup); do_cleanups (cleanup);

62
gdb/common/byte-vector.h Normal file
View file

@ -0,0 +1,62 @@
/* Copyright (C) 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 COMMON_BYTE_VECTOR_H
#define COMMON_BYTE_VECTOR_H
#include "common/def-vector.h"
namespace gdb {
/* byte_vector is a gdb_byte std::vector with a custom allocator that
unlike std::vector<gdb_byte> does not zero-initialize new elements
by default when the vector is created/resized. This is what you
usually want when working with byte buffers, since if you're
creating or growing a buffer you'll most surely want to fill it in
with data, in which case zero-initialization would be a
pessimization. For example:
gdb::byte_vector buf (some_large_size);
fill_with_data (buf.data (), buf.size ());
On the odd case you do need zero initialization, then you can still
call the overloads that specify an explicit value, like:
gdb::byte_vector buf (some_initial_size, 0);
buf.resize (a_bigger_size, 0);
(Or use std::vector<gdb_byte> instead.)
Note that unlike std::vector<gdb_byte>, function local
gdb::byte_vector objects constructed with an initial size like:
gdb::byte_vector buf (some_size);
fill_with_data (buf.data (), buf.size ());
usually compile down to the exact same as:
std::unique_ptr<byte[]> buf (new gdb_byte[some_size]);
fill_with_data (buf.get (), some_size);
with the former having the advantage of being a bit more readable,
and providing the whole std::vector API, if you end up needing it.
*/
using byte_vector = gdb::def_vector<gdb_byte>;
} /* namespace gdb */
#endif /* COMMON_DEF_VECTOR_H */

36
gdb/common/def-vector.h Normal file
View file

@ -0,0 +1,36 @@
/* Copyright (C) 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 COMMON_DEF_VECTOR_H
#define COMMON_DEF_VECTOR_H
#include <vector>
#include "common/default-init-alloc.h"
namespace gdb {
/* A vector that uses an allocator that default constructs using
default-initialization rather than value-initialization. The idea
is to use this when you don't want zero-initialization of elements
of vectors of trivial types. E.g., byte buffers. */
template<typename T> using def_vector
= std::vector<T, gdb::default_init_allocator<T>>;
} /* namespace gdb */
#endif /* COMMON_DEF_VECTOR_H */

View file

@ -0,0 +1,67 @@
/* Copyright (C) 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 COMMON_DEFAULT_INIT_ALLOC_H
#define COMMON_DEFAULT_INIT_ALLOC_H
namespace gdb {
/* An allocator that default constructs using default-initialization
rather than value-initialization. The idea is to use this when you
don't want to default construct elements of containers of trivial
types using zero-initialization. */
/* Mostly as implementation convenience, this is implemented as an
adapter that given an allocator A, overrides 'A::construct()'. 'A'
defaults to std::allocator<T>. */
template<typename T, typename A = std::allocator<T>>
class default_init_allocator : public A
{
public:
/* Pull in A's ctors. */
using A::A;
/* Override rebind. */
template<typename U>
struct rebind
{
/* A couple helpers just to make it a bit more readable. */
typedef std::allocator_traits<A> traits_;
typedef typename traits_::template rebind_alloc<U> alloc_;
/* This is what we're after. */
typedef default_init_allocator<U, alloc_> other;
};
/* Make the base allocator's construct method(s) visible. */
using A::construct;
/* .. and provide an override/overload for the case of default
construction (i.e., no arguments). This is where we construct
with default-init. */
template <typename U>
void construct (U *ptr)
noexcept (std::is_nothrow_default_constructible<U>::value)
{
::new ((void *) ptr) U; /* default-init */
}
};
} /* namespace gdb */
#endif /* COMMON_DEFAULT_INIT_ALLOC_H */

View file

@ -43,6 +43,7 @@
#include <vector> #include <vector>
#include <unordered_set> #include <unordered_set>
#include "common/underlying.h" #include "common/underlying.h"
#include "common/byte-vector.h"
extern int dwarf_always_disassemble; extern int dwarf_always_disassemble;
@ -1776,7 +1777,7 @@ rw_pieced_value (struct value *v, struct value *from)
const gdb_byte *from_contents; const gdb_byte *from_contents;
struct piece_closure *c struct piece_closure *c
= (struct piece_closure *) value_computed_closure (v); = (struct piece_closure *) value_computed_closure (v);
std::vector<gdb_byte> buffer; gdb::byte_vector buffer;
int bits_big_endian int bits_big_endian
= gdbarch_bits_big_endian (get_type_arch (value_type (v))); = gdbarch_bits_big_endian (get_type_arch (value_type (v)));
@ -1847,7 +1848,7 @@ rw_pieced_value (struct value *v, struct value *from)
bits_to_skip += p->offset; bits_to_skip += p->offset;
this_size = bits_to_bytes (bits_to_skip, this_size_bits); this_size = bits_to_bytes (bits_to_skip, this_size_bits);
buffer.reserve (this_size); buffer.resize (this_size);
if (from == NULL) if (from == NULL)
{ {
@ -1928,7 +1929,7 @@ rw_pieced_value (struct value *v, struct value *from)
} }
this_size = bits_to_bytes (bits_to_skip, this_size_bits); this_size = bits_to_bytes (bits_to_skip, this_size_bits);
buffer.reserve (this_size); buffer.resize (this_size);
if (from == NULL) if (from == NULL)
{ {

View file

@ -73,6 +73,7 @@
#include "common/function-view.h" #include "common/function-view.h"
#include "common/gdb_optional.h" #include "common/gdb_optional.h"
#include "common/underlying.h" #include "common/underlying.h"
#include "common/byte-vector.h"
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
@ -23245,7 +23246,7 @@ private:
return &*m_vec.end () - size; return &*m_vec.end () - size;
} }
std::vector<gdb_byte> m_vec; gdb::byte_vector m_vec;
}; };
/* An entry in the symbol table. */ /* An entry in the symbol table. */

View file

@ -17,6 +17,7 @@
#include "defs.h" #include "defs.h"
#include "gdb_regex.h" #include "gdb_regex.h"
#include "common/def-vector.h"
compiled_regex::compiled_regex (const char *regex, int cflags, compiled_regex::compiled_regex (const char *regex, int cflags,
const char *message) const char *message)
@ -28,10 +29,10 @@ compiled_regex::compiled_regex (const char *regex, int cflags,
if (code != 0) if (code != 0)
{ {
size_t length = regerror (code, &m_pattern, NULL, 0); size_t length = regerror (code, &m_pattern, NULL, 0);
std::unique_ptr<char[]> err (new char[length]); gdb::def_vector<char> err (length);
regerror (code, &m_pattern, err.get (), length); regerror (code, &m_pattern, err.data (), length);
error (("%s: %s"), message, err.get ()); error (("%s: %s"), message, err.data ());
} }
} }

View file

@ -55,6 +55,7 @@
#include "gdbcmd.h" #include "gdbcmd.h"
#include "observer.h" #include "observer.h"
#include "common/gdb_optional.h" #include "common/gdb_optional.h"
#include "common/byte-vector.h"
#include <ctype.h> #include <ctype.h>
#include "run-time-clock.h" #include "run-time-clock.h"
@ -1466,12 +1467,12 @@ mi_cmd_data_read_memory (const char *command, char **argv, int argc)
/* Create a buffer and read it in. */ /* Create a buffer and read it in. */
total_bytes = word_size * nr_rows * nr_cols; total_bytes = word_size * nr_rows * nr_cols;
std::unique_ptr<gdb_byte[]> mbuf (new gdb_byte[total_bytes]); gdb::byte_vector mbuf (total_bytes);
/* Dispatch memory reads to the topmost target, not the flattened /* Dispatch memory reads to the topmost target, not the flattened
current_target. */ current_target. */
nr_bytes = target_read (current_target.beneath, nr_bytes = target_read (current_target.beneath,
TARGET_OBJECT_MEMORY, NULL, mbuf.get (), TARGET_OBJECT_MEMORY, NULL, mbuf.data (),
addr, total_bytes); addr, total_bytes);
if (nr_bytes <= 0) if (nr_bytes <= 0)
error (_("Unable to read memory.")); error (_("Unable to read memory."));

View file

@ -48,6 +48,7 @@
#include "cli/cli-script.h" #include "cli/cli-script.h"
#include "format.h" #include "format.h"
#include "source.h" #include "source.h"
#include "common/byte-vector.h"
#ifdef TUI #ifdef TUI
#include "tui/tui.h" /* For tui_active et al. */ #include "tui/tui.h" /* For tui_active et al. */
@ -407,7 +408,7 @@ print_scalar_formatted (const gdb_byte *valaddr, struct type *type,
/* Historically gdb has printed floats by first casting them to a /* Historically gdb has printed floats by first casting them to a
long, and then printing the long. PR cli/16242 suggests changing long, and then printing the long. PR cli/16242 suggests changing
this to using C-style hex float format. */ this to using C-style hex float format. */
std::vector<gdb_byte> converted_float_bytes; gdb::byte_vector converted_float_bytes;
if (TYPE_CODE (type) == TYPE_CODE_FLT if (TYPE_CODE (type) == TYPE_CODE_FLT
&& (options->format == 'o' && (options->format == 'o'
|| options->format == 'x' || options->format == 'x'

View file

@ -37,6 +37,7 @@
#include "typeprint.h" #include "typeprint.h"
#include <ctype.h> #include <ctype.h>
#include <algorithm> #include <algorithm>
#include "common/byte-vector.h"
/* Maximum number of wchars returned from wchar_iterate. */ /* Maximum number of wchars returned from wchar_iterate. */
#define MAX_WCHARS 4 #define MAX_WCHARS 4
@ -1721,7 +1722,7 @@ print_octal_chars (struct ui_file *stream, const gdb_byte *valaddr,
static bool static bool
maybe_negate_by_bytes (const gdb_byte *bytes, unsigned len, maybe_negate_by_bytes (const gdb_byte *bytes, unsigned len,
enum bfd_endian byte_order, enum bfd_endian byte_order,
std::vector<gdb_byte> *out_vec) gdb::byte_vector *out_vec)
{ {
gdb_byte sign_byte; gdb_byte sign_byte;
if (byte_order == BFD_ENDIAN_BIG) if (byte_order == BFD_ENDIAN_BIG)
@ -1780,7 +1781,7 @@ print_decimal_chars (struct ui_file *stream, const gdb_byte *valaddr,
int dummy; int dummy;
int flip; int flip;
std::vector<gdb_byte> negated_bytes; gdb::byte_vector negated_bytes;
if (is_signed if (is_signed
&& maybe_negate_by_bytes (valaddr, len, byte_order, &negated_bytes)) && maybe_negate_by_bytes (valaddr, len, byte_order, &negated_bytes))
{ {