You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

753 lines
22 KiB

From de119ea9797f3ccfa3842e3926b6ea8198607207 Mon Sep 17 00:00:00 2001
From: Jan Kratochvil <jan.kratochvil@redhat.com>
Date: Sat, 1 Aug 2020 10:43:12 +0200
Subject: [PATCH 2/6] [NFC] debugedit: Move code from edit_dwarf2() to
edit_info().
---
tools/debugedit.c | 672 +++++++++++++++++++++++-----------------------
1 file changed, 343 insertions(+), 329 deletions(-)
diff --git a/tools/debugedit.c b/tools/debugedit.c
index a351adec8..cad0cc349 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -1964,6 +1964,106 @@ line_rel_cmp (const void *a, const void *b)
return 0;
}
+static int
+edit_info (DSO *dso, int phase)
+{
+ unsigned char *ptr, *endcu, *endsec;
+ uint32_t value;
+ htab_t abbrev;
+ struct abbrev_tag tag, *t;
+
+ ptr = debug_sections[DEBUG_INFO].data;
+ setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype);
+ endsec = ptr + debug_sections[DEBUG_INFO].size;
+ while (ptr < endsec)
+ {
+ if (ptr + 11 > endsec)
+ {
+ error (0, 0, "%s: .debug_info CU header too small",
+ dso->filename);
+ return 1;
+ }
+
+ endcu = ptr + 4;
+ endcu += read_32 (ptr);
+ if (endcu == ptr + 0xffffffff)
+ {
+ error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
+ return 1;
+ }
+
+ if (endcu > endsec)
+ {
+ error (0, 0, "%s: .debug_info too small", dso->filename);
+ return 1;
+ }
+
+ cu_version = read_16 (ptr);
+ if (cu_version != 2 && cu_version != 3 && cu_version != 4)
+ {
+ error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
+ cu_version);
+ return 1;
+ }
+
+ value = read_32_relocated (ptr);
+ if (value >= debug_sections[DEBUG_ABBREV].size)
+ {
+ if (debug_sections[DEBUG_ABBREV].data == NULL)
+ error (0, 0, "%s: .debug_abbrev not present", dso->filename);
+ else
+ error (0, 0, "%s: DWARF CU abbrev offset too large",
+ dso->filename);
+ return 1;
+ }
+
+ if (ptr_size == 0)
+ {
+ ptr_size = read_8 (ptr);
+ if (ptr_size != 4 && ptr_size != 8)
+ {
+ error (0, 0, "%s: Invalid DWARF pointer size %d",
+ dso->filename, ptr_size);
+ return 1;
+ }
+ }
+ else if (read_8 (ptr) != ptr_size)
+ {
+ error (0, 0, "%s: DWARF pointer size differs between CUs",
+ dso->filename);
+ return 1;
+ }
+
+ abbrev = read_abbrev (dso,
+ debug_sections[DEBUG_ABBREV].data + value);
+ if (abbrev == NULL)
+ return 1;
+
+ while (ptr < endcu)
+ {
+ tag.entry = read_uleb128 (ptr);
+ if (tag.entry == 0)
+ continue;
+ t = htab_find_with_hash (abbrev, &tag, tag.entry);
+ if (t == NULL)
+ {
+ error (0, 0, "%s: Could not find DWARF abbreviation %d",
+ dso->filename, tag.entry);
+ htab_delete (abbrev);
+ return 1;
+ }
+
+ ptr = edit_attributes (dso, ptr, t, phase);
+ if (ptr == NULL)
+ break;
+ }
+
+ htab_delete (abbrev);
+ }
+
+ return 0;
+}
+
static int
edit_dwarf2 (DSO *dso)
{
@@ -2100,385 +2200,299 @@ edit_dwarf2 (DSO *dso)
return 1;
}
- if (debug_sections[DEBUG_INFO].data != NULL)
+ if (debug_sections[DEBUG_INFO].data == NULL)
+ return 0;
+
+ unsigned char *ptr, *endcu, *endsec;
+ uint32_t value;
+ htab_t abbrev;
+ struct abbrev_tag tag, *t;
+ int phase;
+ bool info_rel_updated = false;
+ bool macro_rel_updated = false;
+
+ for (phase = 0; phase < 2; phase++)
{
- unsigned char *ptr, *endcu, *endsec;
- uint32_t value;
- htab_t abbrev;
- struct abbrev_tag tag, *t;
- int phase;
- bool info_rel_updated = false;
- bool macro_rel_updated = false;
+ /* If we don't need to update anyhing, skip phase 1. */
+ if (phase == 1
+ && !need_strp_update
+ && !need_string_replacement
+ && !need_stmt_update)
+ break;
- for (phase = 0; phase < 2; phase++)
+ rel_updated = false;
+ if (edit_info (dso, phase))
+ return 1;
+
+ /* Remember whether any .debug_info relocations might need
+ to be updated. */
+ info_rel_updated = rel_updated;
+
+ /* We might have to recalculate/rewrite the debug_line
+ section. We need to do that before going into phase one
+ so we have all new offsets. We do this separately from
+ scanning the dirs/file names because the DW_AT_stmt_lists
+ might not be in order or skip some padding we might have
+ to (re)move. */
+ if (phase == 0 && need_stmt_update)
{
- /* If we don't need to update anyhing, skip phase 1. */
- if (phase == 1
- && !need_strp_update
- && !need_string_replacement
- && !need_stmt_update)
- break;
+ edit_dwarf2_line (dso);
- ptr = debug_sections[DEBUG_INFO].data;
- setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype);
- rel_updated = false;
- endsec = ptr + debug_sections[DEBUG_INFO].size;
- while (ptr < endsec)
+ /* The line table programs will be moved
+ forward/backwards a bit in the new data. Update the
+ debug_line relocations to the new offsets. */
+ int rndx = debug_sections[DEBUG_LINE].relsec;
+ if (rndx != 0)
{
- if (ptr + 11 > endsec)
- {
- error (0, 0, "%s: .debug_info CU header too small",
- dso->filename);
- return 1;
- }
-
- endcu = ptr + 4;
- endcu += read_32 (ptr);
- if (endcu == ptr + 0xffffffff)
- {
- error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
- return 1;
- }
-
- if (endcu > endsec)
- {
- error (0, 0, "%s: .debug_info too small", dso->filename);
- return 1;
- }
-
- cu_version = read_16 (ptr);
- if (cu_version != 2 && cu_version != 3 && cu_version != 4)
- {
- error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
- cu_version);
- return 1;
- }
-
- value = read_32_relocated (ptr);
- if (value >= debug_sections[DEBUG_ABBREV].size)
+ LINE_REL *rbuf;
+ size_t rels;
+ Elf_Data *rdata = elf_getdata (dso->scn[rndx], NULL);
+ int rtype = dso->shdr[rndx].sh_type;
+ rels = dso->shdr[rndx].sh_size / dso->shdr[rndx].sh_entsize;
+ rbuf = malloc (rels * sizeof (LINE_REL));
+ if (rbuf == NULL)
+ error (1, errno, "%s: Could not allocate line relocations",
+ dso->filename);
+
+ /* Sort them by offset into section. */
+ for (size_t i = 0; i < rels; i++)
{
- if (debug_sections[DEBUG_ABBREV].data == NULL)
- error (0, 0, "%s: .debug_abbrev not present", dso->filename);
+ if (rtype == SHT_RELA)
+ {
+ GElf_Rela rela;
+ if (gelf_getrela (rdata, i, &rela) == NULL)
+ error (1, 0, "Couldn't get relocation: %s",
+ elf_errmsg (-1));
+ rbuf[i].r_offset = rela.r_offset;
+ rbuf[i].ndx = i;
+ }
else
- error (0, 0, "%s: DWARF CU abbrev offset too large",
- dso->filename);
- return 1;
- }
-
- if (ptr_size == 0)
- {
- ptr_size = read_8 (ptr);
- if (ptr_size != 4 && ptr_size != 8)
{
- error (0, 0, "%s: Invalid DWARF pointer size %d",
- dso->filename, ptr_size);
- return 1;
+ GElf_Rel rel;
+ if (gelf_getrel (rdata, i, &rel) == NULL)
+ error (1, 0, "Couldn't get relocation: %s",
+ elf_errmsg (-1));
+ rbuf[i].r_offset = rel.r_offset;
+ rbuf[i].ndx = i;
}
}
- else if (read_8 (ptr) != ptr_size)
- {
- error (0, 0, "%s: DWARF pointer size differs between CUs",
- dso->filename);
- return 1;
- }
+ qsort (rbuf, rels, sizeof (LINE_REL), line_rel_cmp);
- abbrev = read_abbrev (dso,
- debug_sections[DEBUG_ABBREV].data + value);
- if (abbrev == NULL)
- return 1;
-
- while (ptr < endcu)
+ size_t lndx = 0;
+ for (size_t i = 0; i < rels; i++)
{
- tag.entry = read_uleb128 (ptr);
- if (tag.entry == 0)
- continue;
- t = htab_find_with_hash (abbrev, &tag, tag.entry);
- if (t == NULL)
+ /* These relocations only happen in ET_REL files
+ and are section offsets. */
+ GElf_Addr r_offset;
+ size_t ndx = rbuf[i].ndx;
+
+ GElf_Rel rel;
+ GElf_Rela rela;
+ if (rtype == SHT_RELA)
{
- error (0, 0, "%s: Could not find DWARF abbreviation %d",
- dso->filename, tag.entry);
- htab_delete (abbrev);
- return 1;
+ if (gelf_getrela (rdata, ndx, &rela) == NULL)
+ error (1, 0, "Couldn't get relocation: %s",
+ elf_errmsg (-1));
+ r_offset = rela.r_offset;
+ }
+ else
+ {
+ if (gelf_getrel (rdata, ndx, &rel) == NULL)
+ error (1, 0, "Couldn't get relocation: %s",
+ elf_errmsg (-1));
+ r_offset = rel.r_offset;
}
- ptr = edit_attributes (dso, ptr, t, phase);
- if (ptr == NULL)
- break;
- }
+ while (lndx < dso->lines.used
+ && r_offset > (dso->lines.table[lndx].old_idx
+ + 4
+ + dso->lines.table[lndx].unit_length))
+ lndx++;
- htab_delete (abbrev);
- }
+ if (lndx >= dso->lines.used)
+ error (1, 0,
+ ".debug_line relocation offset out of range");
- /* Remember whether any .debug_info relocations might need
- to be updated. */
- info_rel_updated = rel_updated;
-
- /* We might have to recalculate/rewrite the debug_line
- section. We need to do that before going into phase one
- so we have all new offsets. We do this separately from
- scanning the dirs/file names because the DW_AT_stmt_lists
- might not be in order or skip some padding we might have
- to (re)move. */
- if (phase == 0 && need_stmt_update)
- {
- edit_dwarf2_line (dso);
+ /* Offset (pointing into the line program) moves
+ from old to new index including the header
+ size diff. */
+ r_offset += (ssize_t)((dso->lines.table[lndx].new_idx
+ - dso->lines.table[lndx].old_idx)
+ + dso->lines.table[lndx].size_diff);
- /* The line table programs will be moved
- forward/backwards a bit in the new data. Update the
- debug_line relocations to the new offsets. */
- int rndx = debug_sections[DEBUG_LINE].relsec;
- if (rndx != 0)
- {
- LINE_REL *rbuf;
- size_t rels;
- Elf_Data *rdata = elf_getdata (dso->scn[rndx], NULL);
- int rtype = dso->shdr[rndx].sh_type;
- rels = dso->shdr[rndx].sh_size / dso->shdr[rndx].sh_entsize;
- rbuf = malloc (rels * sizeof (LINE_REL));
- if (rbuf == NULL)
- error (1, errno, "%s: Could not allocate line relocations",
- dso->filename);
-
- /* Sort them by offset into section. */
- for (size_t i = 0; i < rels; i++)
+ if (rtype == SHT_RELA)
{
- if (rtype == SHT_RELA)
- {
- GElf_Rela rela;
- if (gelf_getrela (rdata, i, &rela) == NULL)
- error (1, 0, "Couldn't get relocation: %s",
- elf_errmsg (-1));
- rbuf[i].r_offset = rela.r_offset;
- rbuf[i].ndx = i;
- }
- else
- {
- GElf_Rel rel;
- if (gelf_getrel (rdata, i, &rel) == NULL)
- error (1, 0, "Couldn't get relocation: %s",
- elf_errmsg (-1));
- rbuf[i].r_offset = rel.r_offset;
- rbuf[i].ndx = i;
- }
+ rela.r_offset = r_offset;
+ if (gelf_update_rela (rdata, ndx, &rela) == 0)
+ error (1, 0, "Couldn't update relocation: %s",
+ elf_errmsg (-1));
}
- qsort (rbuf, rels, sizeof (LINE_REL), line_rel_cmp);
-
- size_t lndx = 0;
- for (size_t i = 0; i < rels; i++)
+ else
{
- /* These relocations only happen in ET_REL files
- and are section offsets. */
- GElf_Addr r_offset;
- size_t ndx = rbuf[i].ndx;
-
- GElf_Rel rel;
- GElf_Rela rela;
- if (rtype == SHT_RELA)
- {
- if (gelf_getrela (rdata, ndx, &rela) == NULL)
- error (1, 0, "Couldn't get relocation: %s",
- elf_errmsg (-1));
- r_offset = rela.r_offset;
- }
- else
- {
- if (gelf_getrel (rdata, ndx, &rel) == NULL)
- error (1, 0, "Couldn't get relocation: %s",
- elf_errmsg (-1));
- r_offset = rel.r_offset;
- }
-
- while (lndx < dso->lines.used
- && r_offset > (dso->lines.table[lndx].old_idx
- + 4
- + dso->lines.table[lndx].unit_length))
- lndx++;
-
- if (lndx >= dso->lines.used)
- error (1, 0,
- ".debug_line relocation offset out of range");
-
- /* Offset (pointing into the line program) moves
- from old to new index including the header
- size diff. */
- r_offset += (ssize_t)((dso->lines.table[lndx].new_idx
- - dso->lines.table[lndx].old_idx)
- + dso->lines.table[lndx].size_diff);
-
- if (rtype == SHT_RELA)
- {
- rela.r_offset = r_offset;
- if (gelf_update_rela (rdata, ndx, &rela) == 0)
- error (1, 0, "Couldn't update relocation: %s",
- elf_errmsg (-1));
- }
- else
- {
- rel.r_offset = r_offset;
- if (gelf_update_rel (rdata, ndx, &rel) == 0)
- error (1, 0, "Couldn't update relocation: %s",
- elf_errmsg (-1));
- }
+ rel.r_offset = r_offset;
+ if (gelf_update_rel (rdata, ndx, &rel) == 0)
+ error (1, 0, "Couldn't update relocation: %s",
+ elf_errmsg (-1));
}
-
- elf_flagdata (rdata, ELF_C_SET, ELF_F_DIRTY);
- free (rbuf);
}
+
+ elf_flagdata (rdata, ELF_C_SET, ELF_F_DIRTY);
+ free (rbuf);
}
+ }
- /* The .debug_macro section also contains offsets into the
- .debug_str section and references to the .debug_line
- tables, so we need to update those as well if we update
- the strings or the stmts. */
- if ((need_strp_update || need_stmt_update)
- && debug_sections[DEBUG_MACRO].data)
+ /* The .debug_macro section also contains offsets into the
+ .debug_str section and references to the .debug_line
+ tables, so we need to update those as well if we update
+ the strings or the stmts. */
+ if ((need_strp_update || need_stmt_update)
+ && debug_sections[DEBUG_MACRO].data)
+ {
+ /* There might be multiple (COMDAT) .debug_macro sections. */
+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
+ while (macro_sec != NULL)
{
- /* There might be multiple (COMDAT) .debug_macro sections. */
- struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
- while (macro_sec != NULL)
- {
- setup_relbuf(dso, macro_sec, &reltype);
- rel_updated = false;
+ setup_relbuf(dso, macro_sec, &reltype);
+ rel_updated = false;
- ptr = macro_sec->data;
- endsec = ptr + macro_sec->size;
- int op = 0, macro_version, macro_flags;
- int offset_len = 4, line_offset = 0;
+ ptr = macro_sec->data;
+ endsec = ptr + macro_sec->size;
+ int op = 0, macro_version, macro_flags;
+ int offset_len = 4, line_offset = 0;
- while (ptr < endsec)
+ while (ptr < endsec)
+ {
+ if (!op)
{
- if (!op)
- {
- macro_version = read_16 (ptr);
- macro_flags = read_8 (ptr);
- if (macro_version < 4 || macro_version > 5)
- error (1, 0, "unhandled .debug_macro version: %d",
- macro_version);
- if ((macro_flags & ~2) != 0)
- error (1, 0, "unhandled .debug_macro flags: 0x%x",
- macro_flags);
-
- offset_len = (macro_flags & 0x01) ? 8 : 4;
- line_offset = (macro_flags & 0x02) ? 1 : 0;
-
- if (offset_len != 4)
- error (0, 1,
- "Cannot handle 8 byte macro offsets: %s",
- dso->filename);
-
- /* Update the line_offset if it is there. */
- if (line_offset)
- {
- if (phase == 0)
- ptr += offset_len;
- else
- {
- size_t idx, new_idx;
- idx = do_read_32_relocated (ptr);
- new_idx = find_new_list_offs (&dso->lines,
- idx);
- write_32_relocated (ptr, new_idx);
- }
- }
- }
+ macro_version = read_16 (ptr);
+ macro_flags = read_8 (ptr);
+ if (macro_version < 4 || macro_version > 5)
+ error (1, 0, "unhandled .debug_macro version: %d",
+ macro_version);
+ if ((macro_flags & ~2) != 0)
+ error (1, 0, "unhandled .debug_macro flags: 0x%x",
+ macro_flags);
+
+ offset_len = (macro_flags & 0x01) ? 8 : 4;
+ line_offset = (macro_flags & 0x02) ? 1 : 0;
+
+ if (offset_len != 4)
+ error (0, 1,
+ "Cannot handle 8 byte macro offsets: %s",
+ dso->filename);
- op = read_8 (ptr);
- if (!op)
- continue;
- switch(op)
+ /* Update the line_offset if it is there. */
+ if (line_offset)
{
- case DW_MACRO_GNU_define:
- case DW_MACRO_GNU_undef:
- read_uleb128 (ptr);
- ptr = ((unsigned char *) strchr ((char *) ptr, '\0')
- + 1);
- break;
- case DW_MACRO_GNU_start_file:
- read_uleb128 (ptr);
- read_uleb128 (ptr);
- break;
- case DW_MACRO_GNU_end_file:
- break;
- case DW_MACRO_GNU_define_indirect:
- case DW_MACRO_GNU_undef_indirect:
- read_uleb128 (ptr);
if (phase == 0)
- {
- size_t idx = read_32_relocated (ptr);
- record_existing_string_entry_idx (&dso->strings,
- idx);
- }
+ ptr += offset_len;
else
{
- struct stridxentry *entry;
size_t idx, new_idx;
idx = do_read_32_relocated (ptr);
- entry = string_find_entry (&dso->strings, idx);
- new_idx = strent_offset (entry->entry);
+ new_idx = find_new_list_offs (&dso->lines,
+ idx);
write_32_relocated (ptr, new_idx);
}
- break;
- case DW_MACRO_GNU_transparent_include:
- ptr += offset_len;
- break;
- default:
- error (1, 0, "Unhandled DW_MACRO op 0x%x", op);
- break;
}
}
- if (rel_updated)
- macro_rel_updated = true;
- macro_sec = macro_sec->next;
+ op = read_8 (ptr);
+ if (!op)
+ continue;
+ switch(op)
+ {
+ case DW_MACRO_GNU_define:
+ case DW_MACRO_GNU_undef:
+ read_uleb128 (ptr);
+ ptr = ((unsigned char *) strchr ((char *) ptr, '\0')
+ + 1);
+ break;
+ case DW_MACRO_GNU_start_file:
+ read_uleb128 (ptr);
+ read_uleb128 (ptr);
+ break;
+ case DW_MACRO_GNU_end_file:
+ break;
+ case DW_MACRO_GNU_define_indirect:
+ case DW_MACRO_GNU_undef_indirect:
+ read_uleb128 (ptr);
+ if (phase == 0)
+ {
+ size_t idx = read_32_relocated (ptr);
+ record_existing_string_entry_idx (&dso->strings,
+ idx);
+ }
+ else
+ {
+ struct stridxentry *entry;
+ size_t idx, new_idx;
+ idx = do_read_32_relocated (ptr);
+ entry = string_find_entry (&dso->strings, idx);
+ new_idx = strent_offset (entry->entry);
+ write_32_relocated (ptr, new_idx);
+ }
+ break;
+ case DW_MACRO_GNU_transparent_include:
+ ptr += offset_len;
+ break;
+ default:
+ error (1, 0, "Unhandled DW_MACRO op 0x%x", op);
+ break;
+ }
}
- }
- /* Same for the debug_str section. Make sure everything is
- in place for phase 1 updating of debug_info
- references. */
- if (phase == 0 && need_strp_update)
- {
- Strtab *strtab = dso->strings.str_tab;
- Elf_Data *strdata = debug_sections[DEBUG_STR].elf_data;
- int strndx = debug_sections[DEBUG_STR].sec;
- Elf_Scn *strscn = dso->scn[strndx];
-
- /* Out with the old. */
- strdata->d_size = 0;
- /* In with the new. */
- strdata = elf_newdata (strscn);
-
- /* We really should check whether we had enough memory,
- but the old ebl version will just abort on out of
- memory... */
- strtab_finalize (strtab, strdata);
- debug_sections[DEBUG_STR].size = strdata->d_size;
- dso->strings.str_buf = strdata->d_buf;
+ if (rel_updated)
+ macro_rel_updated = true;
+ macro_sec = macro_sec->next;
}
+ }
+ /* Same for the debug_str section. Make sure everything is
+ in place for phase 1 updating of debug_info
+ references. */
+ if (phase == 0 && need_strp_update)
+ {
+ Strtab *strtab = dso->strings.str_tab;
+ Elf_Data *strdata = debug_sections[DEBUG_STR].elf_data;
+ int strndx = debug_sections[DEBUG_STR].sec;
+ Elf_Scn *strscn = dso->scn[strndx];
+
+ /* Out with the old. */
+ strdata->d_size = 0;
+ /* In with the new. */
+ strdata = elf_newdata (strscn);
+
+ /* We really should check whether we had enough memory,
+ but the old ebl version will just abort on out of
+ memory... */
+ strtab_finalize (strtab, strdata);
+ debug_sections[DEBUG_STR].size = strdata->d_size;
+ dso->strings.str_buf = strdata->d_buf;
}
- /* After phase 1 we might have rewritten the debug_info with
- new strp, strings and/or linep offsets. */
- if (need_strp_update || need_string_replacement || need_stmt_update)
- dirty_section (DEBUG_INFO);
- if (need_strp_update || need_stmt_update)
- dirty_section (DEBUG_MACRO);
- if (need_stmt_update)
- dirty_section (DEBUG_LINE);
+ }
+
+ /* After phase 1 we might have rewritten the debug_info with
+ new strp, strings and/or linep offsets. */
+ if (need_strp_update || need_string_replacement || need_stmt_update)
+ dirty_section (DEBUG_INFO);
+ if (need_strp_update || need_stmt_update)
+ dirty_section (DEBUG_MACRO);
+ if (need_stmt_update)
+ dirty_section (DEBUG_LINE);
- /* Update any relocations addends we might have touched. */
- if (info_rel_updated)
- update_rela_data (dso, &debug_sections[DEBUG_INFO]);
+ /* Update any relocations addends we might have touched. */
+ if (info_rel_updated)
+ update_rela_data (dso, &debug_sections[DEBUG_INFO]);
- if (macro_rel_updated)
+ if (macro_rel_updated)
+ {
+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
+ while (macro_sec != NULL)
{
- struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
- while (macro_sec != NULL)
- {
- update_rela_data (dso, macro_sec);
- macro_sec = macro_sec->next;
- }
+ update_rela_data (dso, macro_sec);
+ macro_sec = macro_sec->next;
}
}
--
2.18.4