Hi Mark,
updated:
jankratochvil/pie-core
On Tue, 27 Nov 2012 14:29:46 +0100, Mark Wielaard wrote:
On Thu, 2012-10-18 at 00:22 +0200, Jan Kratochvil wrote:
> Shared libraries are located by Dwfl_Callbacks->find_elf which will put them
> proper displacement. But the main executable is only specified via
> --executable and one cannot easily associate it to the proper core segment.
>
> (It may get associated via build-id but build-id does not have to be available
> etc.)
>
> With --core=X --executable=Y order one gets:
> 0x7ff2cfe9b000 0x7ff2d009c000 [pie]
> 0x200000 0x400ac0
> where the second entry is not relocated.
>
> Similarly it looks for the order --executable=Y --core=X:
> 0x200000 0x400ac0
> 0x7ff2cfe9b000 0x7ff2d009c000 [pie]
So before when --core came first dwfl_core_file_report () was called and
then --executable would call dwfl_report_offline () or the other way
around. I am not completely clear on why that results in the bad
mapping, but I assume that is because dwfl_report_segment () and
dwfl_report_offline () don't mix well.
"mix" in the form each works independently while we want them to work
together, to interconnect the core [pie] segment with the PIE on-disk file.
The second case above just cannot work. When you call dwfl_report_offline
without a core file it cannot find out to which VMA to place the file.
The first case could work, dwfl_report_segment works OK, just later
dwfl_module_getelf cannot find the matching disk file, there is no way (except
how I did it in the patch) how to tell dwfl_module_getelf to look up the
executable for that segment 0x7ff2cfe9b000; as long as it cannot find it by
/usr/lib/debug/.build-id/ which apparently is not possible for non-system
binaries.
When one does dwfl_report_offline later it is a new segment which still leaves
that former 0x7ff2cfe9b000 stale (=without its on-disk binary). Moreover the
new segment is placed incorrectly because it is not connected with the
formerly reported [pie].
Maybe there would be some way to 'patch' the former stale segment but this is
IMO exactly what the patch does, via that 'find_elf' callback.
With this patch when both --core and --executable are given in
whatever
order dwfl_core_file_report () is called first and the new
offline_find_elf () callback will replace the Dwfl_Module main.name with
the recorded --executable file when the modname is [exe] or [pie] (which
then triggers opening and reporting of the executable).
Exactly.
It took me a while to realize this is what the patch seems to do
since the
documentation for the find_elf callback doesn't say that will happen when
you do that (actually, there sadly is no documentation at all for this
callback...).
Sorry, I tried to match how elfutils is written.
> + if (opt->e)
> + for (Dwfl_Module *mod = dwfl->modulelist; mod; mod = mod->next)
> + {
> + if (mod->name == NULL
> + || (strcmp (mod->name, "[exe]") != 0
> + && strcmp (mod->name, "[pie]") != 0))
> + continue;
> + mod->userdata = (void *) opt->e;
> + }
Why is this done?
So that offline_find_elf can find the executable name.
Global variable is unsafe as the caller can call it for arbitrary number of
inputs concurrently so where to put it otherwise?
The following documentation in dwflp.h doesn't really make that
clear.
Also it doesn't mention this is only done when --core is given.
> -/* Standard argument parsing for using a standard callback set. */
> +/* Standard argument parsing for using a standard callback set.
> + Field Dwfl_Module->USERDATA is reserved for "[exe]" or
"[pie]" modules. */
> struct argp;
> extern const struct argp *dwfl_standard_argp (void) __attribute__ ((const));
I could comment it otherwise but I have created a new Dwfl_module field
instead. It was too fragile to use USERDATA, in fact it made USERDATA
unavailable for anything else from applications.
Thanks,
Jan
commit acba6b21a933830668081026548c5223eaa2a841
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Thu Oct 18 00:11:30 2012 +0200
libdwfl/
* argp-std.c (offline_find_elf): New function.
(offline_callbacks): Use it for FIND_ELF.
(struct parse_opt): New.
(parse_opt): New KEY ARGP_KEY_INIT. In other make HOOK struct
parse_opt pointer from former Dwfl pointer. Delay 'e and OPT_COREFILE
processing till ARGP_KEY_SUCCESS. Initialize state->INPUT already from
ARGP_KEY_SUCCESS. Modify the cleanup in ARGP_KEY_ERROR. Make the final
state->INPUT initialization optional.
* dwfl_module.c (__libdwfl_module_free): Free EXECUTABLE_FOR_CORE.
* libdwflP.h (struct Dwfl_Module): New field executable_for_core.
tests/
* run-addrname-test.sh: New test for PIE relocation.
* testfile70.core.bz2: New file.
* testfile70.exec.bz2: New file.
* Makefile.am (EXTRA_DIST): Add testfile70.core.bz2 and
testfile70.exec.bz2 .
Signed-off-by: Jan Kratochvil <jan.kratochvil(a)redhat.com>
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index bdd9440..30ee0eb 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,15 @@
+2012-11-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * argp-std.c (offline_find_elf): New function.
+ (offline_callbacks): Use it for FIND_ELF.
+ (struct parse_opt): New.
+ (parse_opt): New KEY ARGP_KEY_INIT. In other make HOOK struct
+ parse_opt pointer from former Dwfl pointer. Delay 'e and OPT_COREFILE
+ processing till ARGP_KEY_SUCCESS. Initialize state->INPUT already from
+ ARGP_KEY_SUCCESS. Modify the cleanup in ARGP_KEY_ERROR. Make the final state->INPUT
initialization optional.
+ * dwfl_module.c (__libdwfl_module_free): Free EXECUTABLE_FOR_CORE.
+ * libdwflP.h (struct Dwfl_Module): New field executable_for_core.
+
2012-10-17 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* dwfl_module_getdwarf.c (mod_verify_build_id): New function with code
diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c
index 2ef4555..a9ea911 100644
--- a/libdwfl/argp-std.c
+++ b/libdwfl/argp-std.c
@@ -60,6 +60,32 @@ static const struct argp_option options[] =
{ NULL, 0, NULL, 0, NULL, 0 }
};
+/* Wrapper to provide proper FILE_NAME for -e|--executable. */
+static int
+offline_find_elf (Dwfl_Module *mod, void **userdata, const char *modname,
+ Dwarf_Addr base, char **file_name, Elf **elfp)
+{
+ if (modname != NULL && (strcmp (modname, "[exe]") == 0
+ || strcmp (modname, "[pie]") == 0)
+ && mod->executable_for_core)
+ {
+ /* When both --core and --executable are given in whatever order
+ dwfl_core_file_report is called first and this callback will replace
+ the Dwfl_Module main.name with the recorded --executable file when the
+ modname is [exe] or [pie] (which then triggers opening and reporting
+ of the executable). */
+ char *e_dup = strdup (mod->executable_for_core);
+ if (e_dup)
+ {
+ free (*file_name);
+ *file_name = e_dup;
+ return -1;
+ }
+ }
+ return INTUSE(dwfl_build_id_find_elf) (mod, userdata, modname, base,
+ file_name, elfp);
+}
+
static char *debuginfo_path;
static const Dwfl_Callbacks offline_callbacks =
@@ -70,7 +96,7 @@ static const Dwfl_Callbacks offline_callbacks =
.section_address = INTUSE(dwfl_offline_section_address),
/* We use this table for core files too. */
- .find_elf = INTUSE(dwfl_build_id_find_elf),
+ .find_elf = offline_find_elf,
};
static const Dwfl_Callbacks proc_callbacks =
@@ -90,6 +116,16 @@ static const Dwfl_Callbacks kernel_callbacks =
.section_address = INTUSE(dwfl_linux_kernel_module_section_address),
};
+/* Structure held at state->HOOK. */
+struct parse_opt
+{
+ Dwfl *dwfl;
+ /* The -e|--executable parameter. */
+ const char *e;
+ /* The --core parameter. */
+ const char *core;
+};
+
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
@@ -111,152 +147,142 @@ parse_opt (int key, char *arg, struct argp_state *state)
switch (key)
{
+ case ARGP_KEY_INIT:
+ {
+ assert (state->hook == NULL);
+ struct parse_opt *opt = calloc (1, sizeof (*opt));
+ if (opt == NULL)
+ failure (NULL, DWFL_E_ERRNO, "calloc");
+ state->hook = opt;
+ }
+ break;
+
case OPT_DEBUGINFO:
debuginfo_path = arg;
break;
case 'e':
{
- Dwfl *dwfl = state->hook;
+ struct parse_opt *opt = state->hook;
+ Dwfl *dwfl = opt->dwfl;
if (dwfl == NULL)
{
dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
if (dwfl == NULL)
return fail (dwfl, -1, arg);
- state->hook = dwfl;
+ opt->dwfl = dwfl;
/* Start at zero so if there is just one -e foo.so,
the DSO is shown without address bias. */
dwfl->offline_next_address = 0;
}
- if (dwfl->callbacks == &offline_callbacks)
- {
- if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
- return fail (dwfl, -1, arg);
- state->hook = dwfl;
- }
- else
+ if (dwfl->callbacks != &offline_callbacks)
{
toomany:
argp_error (state, "%s",
_("only one of -e, -p, -k, -K, or --core allowed"));
return EINVAL;
}
+ opt->e = arg;
}
break;
case 'p':
- if (state->hook == NULL)
- {
- Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
- int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
- if (result != 0)
- return fail (dwfl, result, arg);
- state->hook = dwfl;
- }
- else
- goto toomany;
+ {
+ struct parse_opt *opt = state->hook;
+ if (opt->dwfl == NULL)
+ {
+ Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
+ int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
+ if (result != 0)
+ return fail (dwfl, result, arg);
+ opt->dwfl = dwfl;
+ }
+ else
+ goto toomany;
+ }
break;
case 'M':
- if (state->hook == NULL)
- {
- FILE *f = fopen (arg, "r");
- if (f == NULL)
- nofile:
- {
- int code = errno;
- argp_failure (state, EXIT_FAILURE, code,
- "cannot open '%s'", arg);
- return code;
- }
- Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
- int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
- fclose (f);
- if (result != 0)
- return fail (dwfl, result, arg);
- state->hook = dwfl;
- }
- else
- goto toomany;
+ {
+ struct parse_opt *opt = state->hook;
+ if (opt->dwfl == NULL)
+ {
+ FILE *f = fopen (arg, "r");
+ if (f == NULL)
+ nofile:
+ {
+ int code = errno;
+ argp_failure (state, EXIT_FAILURE, code,
+ "cannot open '%s'", arg);
+ return code;
+ }
+ Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
+ int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
+ fclose (f);
+ if (result != 0)
+ return fail (dwfl, result, arg);
+ opt->dwfl = dwfl;
+ }
+ else
+ goto toomany;
+ }
break;
case OPT_COREFILE:
{
- Dwfl *dwfl = state->hook;
+ struct parse_opt *opt = state->hook;
+ Dwfl *dwfl = opt->dwfl;
if (dwfl == NULL)
- state->hook = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+ opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
/* Permit -e and --core together. */
else if (dwfl->callbacks != &offline_callbacks)
goto toomany;
-
- int fd = open64 (arg, O_RDONLY);
- if (fd < 0)
- goto nofile;
-
- Elf *core;
- Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
- if (error != DWFL_E_NOERROR)
- {
- argp_failure (state, EXIT_FAILURE, 0,
- _("cannot read ELF core file: %s"),
- INTUSE(dwfl_errmsg) (error));
- return error == DWFL_E_ERRNO ? errno : EIO;
- }
-
- int result = INTUSE(dwfl_core_file_report) (dwfl, core);
- if (result < 0)
- {
- elf_end (core);
- close (fd);
- return fail (dwfl, result, arg);
- }
-
- /* From now we leak FD and CORE. */
-
- if (result == 0)
- {
- argp_failure (state, EXIT_FAILURE, 0,
- _("No modules recognized in core file"));
- return ENOENT;
- }
+ opt->core = arg;
}
break;
case 'k':
- if (state->hook == NULL)
- {
- Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
- int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
- if (result != 0)
- return fail (dwfl, result, _("cannot load kernel symbols"));
- result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
- if (result != 0)
- /* Non-fatal to have no modules since we do have the kernel. */
- failure (dwfl, result, _("cannot find kernel modules"));
- state->hook = dwfl;
- }
- else
- goto toomany;
+ {
+ struct parse_opt *opt = state->hook;
+ if (opt->dwfl == NULL)
+ {
+ Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
+ int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
+ if (result != 0)
+ return fail (dwfl, result, _("cannot load kernel symbols"));
+ result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
+ if (result != 0)
+ /* Non-fatal to have no modules since we do have the kernel. */
+ failure (dwfl, result, _("cannot find kernel modules"));
+ opt->dwfl = dwfl;
+ }
+ else
+ goto toomany;
+ }
break;
case 'K':
- if (state->hook == NULL)
- {
- Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
- int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
- NULL);
- if (result != 0)
- return fail (dwfl, result, _("cannot find kernel or modules"));
- state->hook = dwfl;
- }
- else
- goto toomany;
+ {
+ struct parse_opt *opt = state->hook;
+ if (opt->dwfl == NULL)
+ {
+ Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+ int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
+ NULL);
+ if (result != 0)
+ return fail (dwfl, result, _("cannot find kernel or modules"));
+ opt->dwfl = dwfl;
+ }
+ else
+ goto toomany;
+ }
break;
case ARGP_KEY_SUCCESS:
{
- Dwfl *dwfl = state->hook;
+ struct parse_opt *opt = state->hook;
+ Dwfl *dwfl = opt->dwfl;
if (dwfl == NULL)
{
@@ -265,7 +291,53 @@ parse_opt (int key, char *arg, struct argp_state *state)
dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
return fail (dwfl, -1, arg);
- state->hook = dwfl;
+ opt->dwfl = dwfl;
+ }
+
+ if (opt->core)
+ {
+ int fd = open64 (opt->core, O_RDONLY);
+ if (fd < 0)
+ goto nofile;
+
+ Elf *core;
+ Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
+ if (error != DWFL_E_NOERROR)
+ {
+ argp_failure (state, EXIT_FAILURE, 0,
+ _("cannot read ELF core file: %s"),
+ INTUSE(dwfl_errmsg) (error));
+ return error == DWFL_E_ERRNO ? errno : EIO;
+ }
+
+ int result = INTUSE(dwfl_core_file_report) (dwfl, core);
+ if (result < 0)
+ {
+ elf_end (core);
+ close (fd);
+ return fail (dwfl, result, opt->core);
+ }
+
+ /* From now we leak FD and CORE. */
+
+ if (result == 0)
+ {
+ argp_failure (state, EXIT_FAILURE, 0,
+ _("No modules recognized in core file"));
+ return ENOENT;
+ }
+
+ if (opt->e)
+ for (Dwfl_Module *mod = dwfl->modulelist; mod; mod = mod->next)
+ if (mod->name != NULL
+ && (strcmp (mod->name, "[exe]") != 0
+ || strcmp (mod->name, "[pie]") != 0))
+ mod->executable_for_core = strdup (opt->e);
+ }
+ else if (opt->e)
+ {
+ if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
+ return fail (dwfl, -1, arg);
}
/* One of the three flavors has done dwfl_begin and some reporting
@@ -274,12 +346,22 @@ parse_opt (int key, char *arg, struct argp_state *state)
int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
assert (result == 0);
+
+ /* Update the input all along, so a parent parser can see it.
+ As we free OPT the update below will be no longer active. */
+ *(Dwfl **) state->input = dwfl;
+ free (opt);
+ state->hook = NULL;
}
break;
case ARGP_KEY_ERROR:
- dwfl_end (state->hook);
- state->hook = NULL;
+ {
+ struct parse_opt *opt = state->hook;
+ dwfl_end (opt->dwfl);
+ free (opt);
+ state->hook = NULL;
+ }
break;
default:
@@ -287,7 +369,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
}
/* Update the input all along, so a parent parser can see it. */
- *(Dwfl **) state->input = state->hook;
+ struct parse_opt *opt = state->hook;
+ if (opt)
+ *(Dwfl **) state->input = opt->dwfl;
+
return 0;
}
diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c
index e703d27..50c7b29 100644
--- a/libdwfl/dwfl_module.c
+++ b/libdwfl/dwfl_module.c
@@ -84,6 +84,7 @@ __libdwfl_module_free (Dwfl_Module *mod)
free (mod->build_id_bits);
free (mod->name);
+ free (mod->executable_for_core);
free (mod);
}
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index ca8be2f..a9b8643 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -179,6 +179,7 @@ struct Dwfl_Module
Dwarf_CFI *eh_cfi; /* Cached EH CFI for this module. */
int segment; /* Index of first segment table entry. */
+ char *executable_for_core; /* --executable if --core was specified. */
bool gc; /* Mark/sweep flag. */
};
diff --git a/tests/ChangeLog b/tests/ChangeLog
index edb82b4..7078735 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,11 @@
+2012-11-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * run-addrname-test.sh: New test for PIE relocation.
+ * testfile70.core.bz2: New file.
+ * testfile70.exec.bz2: New file.
+ * Makefile.am (EXTRA_DIST): Add testfile70.core.bz2 and
+ testfile70.exec.bz2 .
+
2012-10-27 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* Makefile.am (EXTRA_DIST): Add testfile64.bz2, testfile65.bz2,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f2d2484..6808bd1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -180,7 +180,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
testfile60.bz2 testfile61.bz2 \
run-readelf-vmcoreinfo.sh testfile62.bz2 \
run-readelf-mixed-corenote.sh testfile63.bz2 testfile64.bz2 \
- testfile65.bz2 testfile69.core.bz2 testfile69.so.bz2
+ testfile65.bz2 testfile69.core.bz2 testfile69.so.bz2 \
+ testfile70.core.bz2 testfile70.exec.bz2
if USE_VALGRIND
valgrind_cmd="valgrind -q --trace-children=yes --error-exitcode=1"
diff --git a/tests/run-addrname-test.sh b/tests/run-addrname-test.sh
index cc8aa33..99abf9d 100755
--- a/tests/run-addrname-test.sh
+++ b/tests/run-addrname-test.sh
@@ -306,4 +306,14 @@ libglobal+0x9
??:0
EOF
+testfiles testfile70.exec testfile70.core
+testrun_compare ../src/addr2line -S -e testfile70.exec --core=testfile70.core
0x7ff2cfe9b6b5 <<\EOF
+main+0x9
+??:0
+EOF
+testrun_compare ../src/addr2line -S --core=testfile70.core -e testfile70.exec
0x7ff2cfe9b6b5 <<\EOF
+main+0x9
+??:0
+EOF
+
exit 0
diff --git a/tests/testfile70.core.bz2 b/tests/testfile70.core.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..6c47c6d45b2ba29d6956cedc43d60c48e77e16be
GIT binary patch
literal 2739
zcmV;k3QYAvT4*^jL0KkKSw1<bdjJxwfB*mg_x}I?|9}7W|4;w_|NhVa-_h0XU)}A(
z;@n>U|9jvHp8x;=00000000040ia|6G|*_s0077hG#NAufB*mtj79`88UO}?pwQ3(
zpaz)+fB*)7fHVw%2AT~S000>Qrh_JdkN^Myk%+*CBR~MqG#VNJGyu~e&;S6?5C(ye
z0MkLEAOHg(G|*(wG5`PoGBFqs#ApB-27^OD27nr58UO$q0szo502*jCWB>qU2AT|-
z20#D+21X+S7>xh}K+tGt0MG+WgFpZSKtLJ>Km$z%jDP?PfYU*fK*#_90La8(LlK|=
zXc`R-02%;kkZ1q^XaQ72ARqy#(?s+pYGN}~^b-@wPh~X3YI&k*kv6BbC#Fn?sK{h#
zrkI8yJrmMt=mdIcnomfX83vjjk)tLIiR3$#tEl^azh!0}+Va}At9&*GnzcmA>RPch
z?cM_^y^O^6NoOR7f|e_354@LCem4;j#bk^%$%8gcD{QeVwlP}2p1S?}MJ6w*q)erP
zi!M^twOMVJQpVLqv{LozU2W^tu~<s$$*Rkve7ViALfP%`I>$!Ay|KUJeO{+^m!p`!
znHQczp=rlwhK*Talq$<<x6E<QGBRMnxzBrU9?^xDfwbY$c4?mtzO$&)zFnukQyZVb
z&2z1m?(^_uR`c=WZSPMFdi9f(%%?u8n~sOYSiPv;Q(lu}6|L5WK8oGTq|MM-X9bs^
zl%mOK@%`5m65|GIL*x{gMU_)(xmG5UE~6d|_XC>2e}SW?p|P=-)!<uMrb&%m9M;{I
zYifGtn&s=YGB((1x#cE3OZO{!W5B^k%uFNrP5FXC2vSiH7wX~hzJELP{*GLIT#N`K
zcb7A%tD!b8+=z&Yd%vC1tVBdY^77?ee;-ke*DZ*P(8j)^RVYN@Ybr{y9cJo?MRzvd
zSrG1bYC;<FgPcxVMcqCU$iv#cBi+1Jr!9q)`0F8*u}H$(vz2y<zLPp-CgFPRES&<y
z7cWT|(-ysYj<IeAy2>Z$C54)?DxMP6s<0(82t--&IohUBwqM|wf-5jpIkU!0A|fo2
z1WbZu5SfUwVHA`^N?@5LK{F8(F$heNM8ch|9R$`<9>me4D~)-uuu958W@Z#jK}3@h
zP06GtV#KbPD=-j<<4uV>sf0?^Mm35h5fn^C^!3RiEKEc}4|0&xOhg$HLOq&9GZ8Rf
zB@nE_BN}1ENf;7zi98P*<MDiI@_tVy%hztJ^1MqMIDB23*S=NE%kvEQ-s?Y|W1UQG
z5{SH*Q837&D3mXxq(X^&mV>)!ve_A|PT_((B*Ph|q$6~aEKDIOEG8ktM8XI}W-3s&
zpMCV3Th>+A-|YD}+ea&Rlx0#kb^rd2MXiZ1q*WJ^?UN1T9T}Og+~ll6`eA}5A|pjC
zN<PcZfAgbU(n!3NFSPpn&85+@i#^@7U0Nw+t^NfkHe+R3q%bikYOW~~lfsyYn3#`(
z_sT>L!PLL4<-29E5%m)c)Wk>FOhiWkET5c~mY1Qux;8lfnzuW(BMVu^RQRccLH|iX
z+$9d><-dBUi0+dS2;liW6wMT)Ld?`|)N^(fRIw=HrJFuun^7M1zje<k$bCnc?_OK?
zyS69SNuMVIVcB%?J$&<u*Oyj9YkSa>>q^h1MYZr%H*Ol!@v86AcL`%k@cYLK6kn3N
zwHWN_kyjBUavds$?elk^>Z)m46k%bymr;c8N+KS5O!o=IU@%)V^Vk+vh`gn<8t;mu
zGBBlvD46|6c>i~LzM?ES3{HoV#>A6vmH4Zl`c&sPu93`r_g41q3vk{WRwi*eDa%et
zA=)Ido%HMGy@Rb)Y)U@M?zk%0@RZ1x*?U(hg=BbXI_J<)$$N(}-z*tzB+L^$Nf{zJ
z8|qxLlzXXarX!nPQ)RN1F-fkHFr?}Zl|@xrtyH3E5jQU~wA^1YN1*e1GYbr26r@!u
zu5KNPU72X2JM4`~N+O9&L*8M>w7UJ|TSE8DqSc8q+eHc`fntcNiCC(sQAoDl@%Fp#
zkKyS19aa1t5~?=SV;vFbJ?i>cm|P|Mmaa<Gt#eet4>`hXH`%H2JN(bW<`@`kXg4h!
zjTq)|8S9xl)@u4xdG8A^eK7Fl6_{3Gt746`u576nII-_Mi<)i2Qjx%>1kzcon{~Q4
z`~LBXl=JwCH$3(iG1C_PwBo$hD#VqYx{Plbr;aB|cQ0tCWS?@5s*gE&PLZ(f4`QQb
zl^q&hzna0iu|pEIe^Z|MXs+|9UcX~$`d@V}#beS>K$jzH)co9Sw>fy~-a|EV#`VI|
zdas6fk^TKvHZC-EtY)<B<s7Mww4NOt6<?wInlEOt&_7c#SNORm`FUd0m)PDrhWcw=
zaxc3#txCtON$D#4>~7Wa9|ijy+h1Mjw4W{Y-*N1j&ZYQcW&0L6Pu%g9eCIsG-?$4-
ze-t<_h{n*^yx4jS)vcAPE#^9>EX>H`ue6zNmld7Mr&I02Wk(IoFGu%aJeArGdB}L|
zrjx9D*I2-L&Cly?8qIaj#O_o+0#S3_5~1BYm&RE4m0GGVyx)YD1+lBG@D)+jSgy5{
zSxg7MPq|EICzi(SlT>Hkdv5X@#+-PqG>%T9X=B<7{R>J<@@Q!<=Ce&*hQmHFd@EGZ
zm}&GZ3U-;PTFDhzY-_dD@%$Cb@@TSUvlcBzlMJsl=2w>8c9eDv6f=2SY`239I8%9r
z=dndzU!&;KDKNgj>zVi;4cWfKT-P+?g57uKt1THCkDC9B6>84kIc+Bjkt$<R8Y-(>
zNoOItnAIuvoI6<Cwf5cW-_YG^(d?Pcn=Rry24}3x$)w&fLYWfUBIX9Ba@AEWy=qOE
zs|qz5TpP0r(snug%3h34^^q-SR_xiE#_@{*WF^gR^pSwMMs9X~*2vacQ1z^pc`WzL
zVRUYpyL#shp3Q6OvsvZ~?X!gQAAzjaenuw4OVotOnM{*08<|j<luAoK4*&A|2Yk1z
zTe)?+E>f#5d^c2q=%m8Bh~%@^nn{hWgA-Qy+odS@r4alIs+VHKwF;z4Qjdb|aIwCN
z{h3eY&tWi<idemgzj}|cYeBYOR{F&qq7FNdQ4))+_v$JAihEY$@=>(qcYIn_zEtlt
zn*Jl>GhEWl%<0p<rG8f{vRtxudm7%26)7HzioB}L=~z~@?WsyumD=TfY<Js!R;Mq%
z-#)+R@fh7ZVb?RXJ~W<PK6jF}Y_%A<6<G39NwzU6{!K-Z|A$+8IwPN9YCb|Lm#U(~
zKN|~4xTATu@cR$f>OaVSZl-_J?^AnQNc8;5Q{UFC&ndN0@@cnyWW8eFaTnjr<E44|
zUr^<`*O=y*vX|JHR<mA{_P0w`B=R27N56iKgTl;YW;f4KD+Pq}{-5n|IQY2yZlBVp
zr~7REHKruZ)@2_7wKq@8L_J37(<<9Gk5!Y6(q$^jQ68x3CJ9VIMV#ZSUt%q#xScyF
zvfjOUKtdzcVU=DZmi>&Utbc36dv<dk?Umcg9kDA3JA{YuOgTq@MGv@2T5b~h#yV0j
trV{g%N`(@a@MbEnpGcx3aQduF99O339LFb?*k^wccO+AV2?OJrm#}}-OG5wv
literal 0
HcmV?d00001
diff --git a/tests/testfile70.exec.bz2 b/tests/testfile70.exec.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..f1b969afa667b3166d8052481fad793990abd19f
GIT binary patch
literal 2567
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,KoM%$d1Xdb#tE4
z%wJ(yb%nC)EYr%nN~_0mxkipqL22BErQNf)d&QlRL7VH)1I%L*3{pS@R>(`rtj#4D
zq$w0mu>?Tkl|(5LX_^x9w@49a3T?g?-q&nNC%{68ZlID>RNtSK0)#R6r~2f%F0!(c
z-S%M4;e3c?b@*L|21ot>ldVQJ8dP)_XowsZcjllJW0`zTWH)nOYM^_7>g>FdAz0|b
zjnJnO9lZEXBX_oq9X?+63%dTByNWs8;+PAd;xgR8|1i3eU@&b`YIFFKSoW}RAm91A
dQ(%CARyC}#C++`O#!>&p+>uTcBo8B21%Ok5qx1j(
literal 0
HcmV?d00001