/* DWARF 2 support.
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions
(gavin@cygnus.com).
unsigned short version;
bfd_vma prologue_length;
unsigned char minimum_instruction_length;
+ unsigned char maximum_ops_per_insn;
unsigned char default_is_stmt;
int line_base;
unsigned char line_range;
by its reference. */
bfd_byte *info_ptr_unit;
+ /* Pointer to the start of the debug section, for DW_FORM_ref_addr. */
+ bfd_byte *sec_info_ptr;
+
/* The offset into .debug_line of the line number table. */
unsigned long line_offset;
if (! read_section (abfd, ".debug_abbrev", ".zdebug_abbrev",
stash->syms, offset,
&stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size))
- return 0;
+ return NULL;
amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE;
abbrevs = (struct abbrev_info **) bfd_zalloc (abfd, amt);
+ if (abbrevs == NULL)
+ return NULL;
abbrev_ptr = stash->dwarf_abbrev_buffer + offset;
abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
{
amt = sizeof (struct abbrev_info);
cur_abbrev = (struct abbrev_info *) bfd_zalloc (abfd, amt);
+ if (cur_abbrev == NULL)
+ return NULL;
/* Read in abbrev header. */
cur_abbrev->number = abbrev_number;
case DW_FORM_ref_addr:
/* DW_FORM_ref_addr is an address in DWARF2, and an offset in
DWARF3. */
- if (unit->version == 3)
+ if (unit->version == 3 || unit->version == 4)
{
if (unit->offset_size == 4)
attr->u.val = read_4_bytes (unit->abfd, info_ptr);
attr->u.val = read_address (unit, info_ptr);
info_ptr += unit->addr_size;
break;
+ case DW_FORM_sec_offset:
+ if (unit->offset_size == 4)
+ attr->u.val = read_4_bytes (unit->abfd, info_ptr);
+ else
+ attr->u.val = read_8_bytes (unit->abfd, info_ptr);
+ info_ptr += unit->offset_size;
+ break;
case DW_FORM_block2:
amt = sizeof (struct dwarf_block);
blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
+ if (blk == NULL)
+ return NULL;
blk->size = read_2_bytes (abfd, info_ptr);
info_ptr += 2;
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
case DW_FORM_block4:
amt = sizeof (struct dwarf_block);
blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
+ if (blk == NULL)
+ return NULL;
blk->size = read_4_bytes (abfd, info_ptr);
info_ptr += 4;
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
attr->u.str = read_indirect_string (unit, info_ptr, &bytes_read);
info_ptr += bytes_read;
break;
+ case DW_FORM_exprloc:
case DW_FORM_block:
amt = sizeof (struct dwarf_block);
blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
+ if (blk == NULL)
+ return NULL;
blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
case DW_FORM_block1:
amt = sizeof (struct dwarf_block);
blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
+ if (blk == NULL)
+ return NULL;
blk->size = read_1_byte (abfd, info_ptr);
info_ptr += 1;
blk->data = read_n_bytes (abfd, info_ptr, blk->size);
attr->u.val = read_1_byte (abfd, info_ptr);
info_ptr += 1;
break;
+ case DW_FORM_flag_present:
+ attr->u.val = 1;
+ break;
case DW_FORM_sdata:
attr->u.sval = read_signed_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
attr->u.val = read_8_bytes (abfd, info_ptr);
info_ptr += 8;
break;
+ case DW_FORM_ref_sig8:
+ attr->u.val = read_8_bytes (abfd, info_ptr);
+ info_ptr += 8;
+ break;
case DW_FORM_ref_udata:
attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;
(*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %u."),
form);
bfd_set_error (bfd_error_bad_value);
+ return NULL;
}
return info_ptr;
}
char *filename;
unsigned int line;
unsigned int column;
- int end_sequence; /* End of (sequential) code sequence. */
+ unsigned char op_index;
+ unsigned char end_sequence; /* End of (sequential) code sequence. */
};
struct fileinfo
{
return (new_line->address > line->address
|| (new_line->address == line->address
- && new_line->end_sequence < line->end_sequence));
+ && (new_line->op_index > line->op_index
+ || (new_line->op_index == line->op_index
+ && new_line->end_sequence < line->end_sequence))));
}
highest to lowest VMA (with possible duplicates); that is,
line_info->prev_line always accesses an equal or smaller VMA. */
-static void
+static bfd_boolean
add_line_info (struct line_info_table *table,
bfd_vma address,
+ unsigned char op_index,
char *filename,
unsigned int line,
unsigned int column,
struct line_sequence* seq = table->sequences;
struct line_info* info = (struct line_info *) bfd_alloc (table->abfd, amt);
+ if (info == NULL)
+ return FALSE;
+
/* Set member data of 'info'. */
+ info->prev_line = NULL;
info->address = address;
+ info->op_index = op_index;
info->line = line;
info->column = column;
info->end_sequence = end_sequence;
if (filename && filename[0])
{
info->filename = (char *) bfd_alloc (table->abfd, strlen (filename) + 1);
- if (info->filename)
- strcpy (info->filename, filename);
+ if (info->filename == NULL)
+ return FALSE;
+ strcpy (info->filename, filename);
}
else
info->filename = NULL;
if (seq
&& seq->last_line->address == address
+ && seq->last_line->op_index == op_index
&& seq->last_line->end_sequence == end_sequence)
{
/* We only keep the last entry with the same address and end
/* Start a new line sequence. */
amt = sizeof (struct line_sequence);
seq = (struct line_sequence *) bfd_malloc (amt);
+ if (seq == NULL)
+ return FALSE;
seq->low_pc = address;
seq->prev_sequence = table->sequences;
seq->last_line = info;
if (address < seq->low_pc)
seq->low_pc = address;
}
+ return TRUE;
}
/* Extract a fully qualified filename from a line info table.
if (!IS_ABSOLUTE_PATH (filename))
{
- char *dirname = NULL;
- char *subdirname = NULL;
+ char *dir_name = NULL;
+ char *subdir_name = NULL;
char *name;
size_t len;
if (table->files[file - 1].dir)
- subdirname = table->dirs[table->files[file - 1].dir - 1];
+ subdir_name = table->dirs[table->files[file - 1].dir - 1];
- if (!subdirname || !IS_ABSOLUTE_PATH (subdirname))
- dirname = table->comp_dir;
+ if (!subdir_name || !IS_ABSOLUTE_PATH (subdir_name))
+ dir_name = table->comp_dir;
- if (!dirname)
+ if (!dir_name)
{
- dirname = subdirname;
- subdirname = NULL;
+ dir_name = subdir_name;
+ subdir_name = NULL;
}
- if (!dirname)
+ if (!dir_name)
return strdup (filename);
- len = strlen (dirname) + strlen (filename) + 2;
+ len = strlen (dir_name) + strlen (filename) + 2;
- if (subdirname)
+ if (subdir_name)
{
- len += strlen (subdirname) + 1;
+ len += strlen (subdir_name) + 1;
name = (char *) bfd_malloc (len);
if (name)
- sprintf (name, "%s/%s/%s", dirname, subdirname, filename);
+ sprintf (name, "%s/%s/%s", dir_name, subdir_name, filename);
}
else
{
name = (char *) bfd_malloc (len);
if (name)
- sprintf (name, "%s/%s", dirname, filename);
+ sprintf (name, "%s/%s", dir_name, filename);
}
return name;
return strdup (filename);
}
-static void
-arange_add (bfd *abfd, struct arange *first_arange, bfd_vma low_pc, bfd_vma high_pc)
+static bfd_boolean
+arange_add (bfd *abfd, struct arange *first_arange,
+ bfd_vma low_pc, bfd_vma high_pc)
{
struct arange *arange;
{
first_arange->low = low_pc;
first_arange->high = high_pc;
- return;
+ return TRUE;
}
/* Next see if we can cheaply extend an existing range. */
if (low_pc == arange->high)
{
arange->high = high_pc;
- return;
+ return TRUE;
}
if (high_pc == arange->low)
{
arange->low = low_pc;
- return;
+ return TRUE;
}
arange = arange->next;
}
/* Need to allocate a new arange and insert it into the arange list.
Order isn't significant, so just insert after the first arange. */
arange = (struct arange *) bfd_zalloc (abfd, sizeof (*arange));
+ if (arange == NULL)
+ return FALSE;
arange->low = low_pc;
arange->high = high_pc;
arange->next = first_arange->next;
first_arange->next = arange;
+ return TRUE;
}
/* Compare function for line sequences. */
if (seq1->last_line->address > seq2->last_line->address)
return -1;
+ if (seq1->last_line->op_index < seq2->last_line->op_index)
+ return 1;
+ if (seq1->last_line->op_index > seq2->last_line->op_index)
+ return -1;
+
return 0;
}
/* Sort the line sequences for quick lookup. */
-static void
+static bfd_boolean
sort_line_sequences (struct line_info_table* table)
{
bfd_size_type amt;
bfd_vma last_high_pc;
if (num_sequences == 0)
- return;
+ return TRUE;
/* Allocate space for an array of sequences. */
amt = sizeof (struct line_sequence) * num_sequences;
sequences = (struct line_sequence *) bfd_alloc (table->abfd, amt);
+ if (sequences == NULL)
+ return FALSE;
/* Copy the linked list into the array, freeing the original nodes. */
seq = table->sequences;
table->sequences = sequences;
table->num_sequences = num_sequences;
+ return TRUE;
}
/* Decode the line number information for UNIT. */
if (! read_section (abfd, ".debug_line", ".zdebug_line",
stash->syms, unit->line_offset,
&stash->dwarf_line_buffer, &stash->dwarf_line_size))
- return 0;
+ return NULL;
amt = sizeof (struct line_info_table);
table = (struct line_info_table *) bfd_alloc (abfd, amt);
+ if (table == NULL)
+ return NULL;
table->abfd = abfd;
table->comp_dir = unit->comp_dir;
}
line_end = line_ptr + lh.total_length;
lh.version = read_2_bytes (abfd, line_ptr);
+ if (lh.version < 2 || lh.version > 4)
+ {
+ (*_bfd_error_handler)
+ (_("Dwarf Error: Unhandled .debug_line version %d."), lh.version);
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+ }
line_ptr += 2;
if (offset_size == 4)
lh.prologue_length = read_4_bytes (abfd, line_ptr);
line_ptr += offset_size;
lh.minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
+ if (lh.version >= 4)
+ {
+ lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr);
+ line_ptr += 1;
+ }
+ else
+ lh.maximum_ops_per_insn = 1;
+ if (lh.maximum_ops_per_insn == 0)
+ {
+ (*_bfd_error_handler)
+ (_("Dwarf Error: Invalid maximum operations per instruction."));
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+ }
lh.default_is_stmt = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh.line_base = read_1_signed_byte (abfd, line_ptr);
tmp = (char **) bfd_realloc (table->dirs, amt);
if (tmp == NULL)
- {
- free (table->dirs);
- return NULL;
- }
+ goto fail;
table->dirs = tmp;
}
tmp = (struct fileinfo *) bfd_realloc (table->files, amt);
if (tmp == NULL)
- {
- free (table->files);
- free (table->dirs);
- return NULL;
- }
+ goto fail;
table->files = tmp;
}
{
/* State machine registers. */
bfd_vma address = 0;
+ unsigned char op_index = 0;
char * filename = table->num_files ? concat_filename (table, 1) : NULL;
unsigned int line = 1;
unsigned int column = 0;
{
/* Special operand. */
adj_opcode = op_code - lh.opcode_base;
- address += (adj_opcode / lh.line_range)
- * lh.minimum_instruction_length;
+ if (lh.maximum_ops_per_insn == 1)
+ address += (adj_opcode / lh.line_range)
+ * lh.minimum_instruction_length;
+ else
+ {
+ address += ((op_index + (adj_opcode / lh.line_range))
+ / lh.maximum_ops_per_insn)
+ * lh.minimum_instruction_length;
+ op_index = (op_index + (adj_opcode / lh.line_range))
+ % lh.maximum_ops_per_insn;
+ }
line += lh.line_base + (adj_opcode % lh.line_range);
/* Append row to matrix using current values. */
- add_line_info (table, address, filename, line, column, 0);
+ if (!add_line_info (table, address, op_index, filename,
+ line, column, 0))
+ goto line_fail;
if (address < low_pc)
low_pc = address;
if (address > high_pc)
{
case DW_LNE_end_sequence:
end_sequence = 1;
- add_line_info (table, address, filename, line, column,
- end_sequence);
+ if (!add_line_info (table, address, op_index, filename,
+ line, column, end_sequence))
+ goto line_fail;
if (address < low_pc)
low_pc = address;
if (address > high_pc)
high_pc = address;
- arange_add (unit->abfd, &unit->arange, low_pc, high_pc);
+ if (!arange_add (unit->abfd, &unit->arange, low_pc, high_pc))
+ goto line_fail;
break;
case DW_LNE_set_address:
address = read_address (unit, line_ptr);
+ op_index = 0;
line_ptr += unit->addr_size;
break;
case DW_LNE_define_file:
amt *= sizeof (struct fileinfo);
tmp = (struct fileinfo *) bfd_realloc (table->files, amt);
if (tmp == NULL)
- {
- free (table->files);
- free (table->dirs);
- free (filename);
- return NULL;
- }
+ goto line_fail;
table->files = tmp;
}
table->files[table->num_files].name = cur_file;
default:
(*_bfd_error_handler) (_("Dwarf Error: mangled line number section."));
bfd_set_error (bfd_error_bad_value);
- free (filename);
- free (table->files);
- free (table->dirs);
- return NULL;
+ line_fail:
+ if (filename != NULL)
+ free (filename);
+ goto fail;
}
break;
case DW_LNS_copy:
- add_line_info (table, address, filename, line, column, 0);
+ if (!add_line_info (table, address, op_index,
+ filename, line, column, 0))
+ goto line_fail;
if (address < low_pc)
low_pc = address;
if (address > high_pc)
high_pc = address;
break;
case DW_LNS_advance_pc:
- address += lh.minimum_instruction_length
- * read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+ if (lh.maximum_ops_per_insn == 1)
+ address += lh.minimum_instruction_length
+ * read_unsigned_leb128 (abfd, line_ptr,
+ &bytes_read);
+ else
+ {
+ bfd_vma adjust = read_unsigned_leb128 (abfd, line_ptr,
+ &bytes_read);
+ address = ((op_index + adjust) / lh.maximum_ops_per_insn)
+ * lh.minimum_instruction_length;
+ op_index = (op_index + adjust) % lh.maximum_ops_per_insn;
+ }
line_ptr += bytes_read;
break;
case DW_LNS_advance_line:
case DW_LNS_set_basic_block:
break;
case DW_LNS_const_add_pc:
- address += lh.minimum_instruction_length
- * ((255 - lh.opcode_base) / lh.line_range);
+ if (lh.maximum_ops_per_insn == 1)
+ address += lh.minimum_instruction_length
+ * ((255 - lh.opcode_base) / lh.line_range);
+ else
+ {
+ bfd_vma adjust = ((255 - lh.opcode_base) / lh.line_range);
+ address += lh.minimum_instruction_length
+ * ((op_index + adjust) / lh.maximum_ops_per_insn);
+ op_index = (op_index + adjust) % lh.maximum_ops_per_insn;
+ }
break;
case DW_LNS_fixed_advance_pc:
address += read_2_bytes (abfd, line_ptr);
+ op_index = 0;
line_ptr += 2;
break;
default:
free (filename);
}
- sort_line_sequences (table);
+ if (sort_line_sequences (table))
+ return table;
- return table;
+ fail:
+ if (table->sequences != NULL)
+ free (table->sequences);
+ if (table->files != NULL)
+ free (table->files);
+ if (table->dirs != NULL)
+ free (table->dirs);
+ return NULL;
}
/* If ADDR is within TABLE set the output parameters and return TRUE,
if (!die_ref)
abort ();
- info_ptr = unit->stash->sec_info_ptr + die_ref;
+ info_ptr = unit->sec_info_ptr + die_ref;
}
else
info_ptr = unit->info_ptr_unit + die_ref;
{
for (i = 0; i < abbrev->num_attrs; ++i)
{
- info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);
+ info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit,
+ info_ptr);
+ if (info_ptr == NULL)
+ break;
switch (attr.name)
{
case DW_AT_name:
- /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */
+ /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
+ over DW_AT_name. */
if (name == NULL)
name = attr.u.str;
break;
case DW_AT_specification:
name = find_abstract_instance_name (unit, &attr);
break;
+ case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
name = attr.u.str;
break;
}
}
}
- return (name);
+ return name;
}
-static void
-read_rangelist (struct comp_unit *unit, struct arange *arange, bfd_uint64_t offset)
+static bfd_boolean
+read_rangelist (struct comp_unit *unit, struct arange *arange,
+ bfd_uint64_t offset)
{
bfd_byte *ranges_ptr;
bfd_vma base_address = unit->base_address;
if (! unit->stash->dwarf_ranges_buffer)
{
if (! read_debug_ranges (unit))
- return;
+ return FALSE;
}
ranges_ptr = unit->stash->dwarf_ranges_buffer + offset;
if (low_pc == -1UL && high_pc != -1UL)
base_address = high_pc;
else
- arange_add (unit->abfd, arange, base_address + low_pc, base_address + high_pc);
+ {
+ if (!arange_add (unit->abfd, arange,
+ base_address + low_pc, base_address + high_pc))
+ return FALSE;
+ }
}
+ return TRUE;
}
/* DWARF2 Compilation unit functions. */
abbrev = lookup_abbrev (abbrev_number,unit->abbrevs);
if (! abbrev)
{
- (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."),
- abbrev_number);
+ (*_bfd_error_handler)
+ (_("Dwarf Error: Could not find abbrev number %u."),
+ abbrev_number);
bfd_set_error (bfd_error_bad_value);
- free (nested_funcs);
- return FALSE;
+ goto fail;
}
var = NULL;
{
bfd_size_type amt = sizeof (struct funcinfo);
func = (struct funcinfo *) bfd_zalloc (abfd, amt);
+ if (func == NULL)
+ goto fail;
func->tag = abbrev->tag;
func->prev_func = unit->function_table;
unit->function_table = func;
{
bfd_size_type amt = sizeof (struct varinfo);
var = (struct varinfo *) bfd_zalloc (abfd, amt);
+ if (var == NULL)
+ goto fail;
var->tag = abbrev->tag;
var->stack = 1;
var->prev_var = unit->variable_table;
for (i = 0; i < abbrev->num_attrs; ++i)
{
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);
+ if (info_ptr == NULL)
+ return FALSE;
if (func)
{
switch (attr.name)
{
case DW_AT_call_file:
- func->caller_file = concat_filename (unit->line_table, attr.u.val);
+ func->caller_file = concat_filename (unit->line_table,
+ attr.u.val);
break;
case DW_AT_call_line:
break;
case DW_AT_name:
- /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */
+ /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
+ over DW_AT_name. */
if (func->name == NULL)
func->name = attr.u.str;
break;
+ case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
func->name = attr.u.str;
break;
break;
case DW_AT_ranges:
- read_rangelist (unit, &func->arange, attr.u.val);
+ if (!read_rangelist (unit, &func->arange, attr.u.val))
+ goto fail;
break;
case DW_AT_decl_file:
case DW_FORM_block1:
case DW_FORM_block2:
case DW_FORM_block4:
+ case DW_FORM_exprloc:
if (*attr.u.blk->data == DW_OP_addr)
{
var->stack = 0;
if (func && high_pc != 0)
{
- arange_add (unit->abfd, &func->arange, low_pc, high_pc);
+ if (!arange_add (unit->abfd, &func->arange, low_pc, high_pc))
+ goto fail;
}
if (abbrev->has_children)
bfd_realloc (nested_funcs,
(nested_funcs_size * sizeof (struct funcinfo *)));
if (tmp == NULL)
- {
- free (nested_funcs);
- return FALSE;
- }
+ goto fail;
nested_funcs = tmp;
}
nested_funcs[nesting_level] = 0;
free (nested_funcs);
return TRUE;
+
+ fail:
+ free (nested_funcs);
+ return FALSE;
}
/* Parse a DWARF2 compilation unit starting at INFO_PTR. This
addr_size = read_1_byte (abfd, info_ptr);
info_ptr += 1;
- if (version != 2 && version != 3)
+ if (version != 2 && version != 3 && version != 4)
{
- (*_bfd_error_handler) (_("Dwarf Error: found dwarf version '%u', this reader only handles version 2 and 3 information."), version);
+ (*_bfd_error_handler) (_("Dwarf Error: found dwarf version '%u', this reader only handles version 2, 3 and 4 information."), version);
bfd_set_error (bfd_error_bad_value);
return 0;
}
amt = sizeof (struct comp_unit);
unit = (struct comp_unit *) bfd_zalloc (abfd, amt);
+ if (unit == NULL)
+ return NULL;
unit->abfd = abfd;
unit->version = version;
unit->addr_size = addr_size;
unit->end_ptr = end_ptr;
unit->stash = stash;
unit->info_ptr_unit = info_ptr_unit;
+ unit->sec_info_ptr = stash->sec_info_ptr;
for (i = 0; i < abbrev->num_attrs; ++i)
{
info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);
+ if (info_ptr == NULL)
+ return NULL;
/* Store the data if it is of an attribute we want to keep in a
partial symbol table. */
break;
case DW_AT_ranges:
- read_rangelist (unit, &unit->arange, attr.u.val);
+ if (!read_rangelist (unit, &unit->arange, attr.u.val))
+ return NULL;
break;
case DW_AT_comp_dir:
}
if (high_pc != 0)
{
- arange_add (unit->abfd, &unit->arange, low_pc, high_pc);
+ if (!arange_add (unit->abfd, &unit->arange, low_pc, high_pc))
+ return NULL;
}
unit->first_child_die_ptr = info_ptr;
msec = find_debug_info (debug_bfd, msec))
{
bfd_size_type size = msec->size;
- bfd_byte* buffer;
+ bfd_byte *buffer, *tmp;
if (size == 0)
continue;
goto done;
}
}
- stash->info_ptr_memory = (bfd_byte *)
- bfd_realloc (stash->info_ptr_memory, total_size + size);
+ tmp = (bfd_byte *) bfd_realloc (stash->info_ptr_memory,
+ total_size + size);
+ if (tmp == NULL)
+ {
+ free (buffer);
+ goto done;
+ }
+ stash->info_ptr_memory = tmp;
memcpy (stash->info_ptr_memory + total_size, buffer, size);
free (buffer);
total_size += size;