binaries for packages using DEBUG_PACKAGES. This avoids the current situation where a backtrace is useless (function names all "??") if a package was built with DEBUG_PACKAGES but the debug-foo package is not installed. ok espie@ pirofti@
300 lines
7.7 KiB
Perl
Executable File
300 lines
7.7 KiB
Perl
Executable File
#! /usr/bin/perl
|
|
# $OpenBSD: build-debug-info,v 1.38 2020/12/04 15:04:52 sthen Exp $
|
|
# Copyright (c) 2019 Marc Espie <espie@openbsd.org>
|
|
#
|
|
# Permission to use, copy, modify, and distribute this software for any
|
|
# purpose with or without fee is hereby granted, provided that the above
|
|
# copyright notice and this permission notice appear in all copies.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
my $ports1;
|
|
BEGIN {
|
|
$ports1 = $ENV{PORTSDIR} || '/usr/ports';
|
|
}
|
|
|
|
use lib "$ports1/infrastructure/lib";
|
|
use OpenBSD::BaseFS;
|
|
use OpenBSD::CommonPlist;
|
|
|
|
# PlistReader is "just" a specialized version of PkgCreate algorithm
|
|
# that does mimic what PkgCreate reader does with a few specialized methods
|
|
package PlistReader;
|
|
our @ISA = qw(OpenBSD::BasePlistReader);
|
|
|
|
# note that contrary to update-plist, we never build the "new" plist, but
|
|
# write it on the fly (should we use nlist as well here ?)
|
|
sub stateclass
|
|
{
|
|
return 'PlistReader::State';
|
|
}
|
|
|
|
sub command_name
|
|
{
|
|
return 'build-debug-info';
|
|
}
|
|
|
|
sub process_next_subpackage
|
|
{
|
|
my ($class, $o) = @_;
|
|
|
|
my $r = $class->SUPER::process_next_subpackage($o);
|
|
if ($r->{state}{bad} != 0) {
|
|
$o->{state}{exitcode} = 1;
|
|
}
|
|
}
|
|
|
|
package PlistReader::State;
|
|
our @ISA = qw(OpenBSD::BasePlistReader::State);
|
|
|
|
sub substclass
|
|
{
|
|
return 'OpenBSD::Subst';
|
|
}
|
|
|
|
sub handle_options
|
|
{
|
|
my $s = shift;
|
|
$s->SUPER::handle_options;
|
|
$s->{prefix} = "$s->{base}$s->{prefix}";
|
|
}
|
|
# Most of the heavy lifting is done by visitor methods, as always
|
|
|
|
package OpenBSD::PackingElement;
|
|
sub write_debug_info
|
|
{
|
|
}
|
|
|
|
package OpenBSD::PackingElement::CVSTag;
|
|
sub write_debug_info
|
|
{
|
|
my ($self, $fh, $o) = @_;
|
|
$self->write($fh);
|
|
}
|
|
|
|
package OpenBSD::PackingElement::PkgPath;
|
|
sub write_debug_info
|
|
{
|
|
my ($self, $fh, $o) = @_;
|
|
print $fh "\@", $self->keyword, " debug/", $self->name, "\n";
|
|
}
|
|
|
|
package OpenBSD::PackingElement::Cwd;
|
|
# so the reader stuffs a default cwd in the packing-list, which is VERY
|
|
# useful for absolute names, BUT we don't want to copy the first one.
|
|
|
|
# copy the later ones, even if there is nothing to emit afterwards (this
|
|
# is cheap)
|
|
sub write_debug_info
|
|
{
|
|
my ($self, $fh, $o) = @_;
|
|
if ($o->{first_cwd}) {
|
|
$o->{first_cwd} = 0;
|
|
} else {
|
|
$self->write($fh);
|
|
}
|
|
}
|
|
|
|
|
|
package OpenBSD::PackingElement::FileWithDebugInfo;
|
|
use File::Basename;
|
|
sub write_debug_info
|
|
{
|
|
my ($self, $fh, $o) = @_;
|
|
return if $self->{nodebug};
|
|
my $s = $self->name;
|
|
my $dbg = $self->mogrify($s);
|
|
my $dir = $dbg;
|
|
$dir =~ s/(\/\.debug\/)[^\/]+/$1/;
|
|
my $path = $self->fullname;
|
|
if (-l $path) {
|
|
# turns out we don't need to do anything, egdb follows symlinks
|
|
return;
|
|
}
|
|
if (-f $path) {
|
|
my $k = join('/', (stat $path)[0,1]);
|
|
my $l = $o->{linkstash}{$k};
|
|
if (!defined $l) {
|
|
$o->{linkstash}{$k} = $dbg;
|
|
$self->write_rule($o, $fh, $s, $dbg, $dir,
|
|
"OBJCOPY_RULE");
|
|
return;
|
|
}
|
|
my $ldir = dirname($l)."/";
|
|
if ($ldir eq $dir) {
|
|
# if both mogrified dirs are the same
|
|
# the debug-info link will do the right thing
|
|
return;
|
|
}
|
|
# so we need to create a link in our dir but that link
|
|
# must have the right name
|
|
my $n = $dir.basename($l);
|
|
# that link may already exist! don't emit it again
|
|
# TODO missing checks to be certain there's no ambiguity, just
|
|
# need to write an actual example and verify I can detect it.
|
|
return if exists $o->{ostash}{$n};
|
|
$self->write_rule($o, $fh, $l, $n, $dir, "LINK_RULE");
|
|
} else {
|
|
$o->{state}->fatal("Error: #1 does not exist", $path);
|
|
}
|
|
}
|
|
|
|
sub write_rule
|
|
{
|
|
my ($self, $o, $fh, $s, $dbg, $dir, $what) = @_;
|
|
if (!exists $o->{dirstash}{$dir}) {
|
|
print $fh $dir, "\n";
|
|
$o->{dirstash}{$dir} = 1;
|
|
}
|
|
print $fh $dbg, "\n";
|
|
my $mk = $o->{mk};
|
|
print $mk "all: $o->{prefix}/$dbg\n";
|
|
print $mk "$o->{prefix}/$dbg: $o->{prefix}/$s\n";
|
|
print $mk "\t\@\$\{$what\}\n\n";
|
|
$o->{ostash}{$dbg} = 1;
|
|
delete $o->{empty};
|
|
}
|
|
|
|
sub mogrify
|
|
{
|
|
my ($self, $s) = @_;
|
|
$s =~ s,([^\/]+)$,.debug/$1.dbg,;
|
|
return $s;
|
|
}
|
|
|
|
package OpenBSD::PackingElement::StaticLib;
|
|
sub write_debug_info
|
|
{
|
|
# don't do anything
|
|
}
|
|
|
|
package OpenBSD::PackingElement::NoDefaultConflict;
|
|
sub write_debug_info
|
|
{
|
|
&OpenBSD::PackingElement::CVSTag::write_debug_info;
|
|
}
|
|
|
|
package OpenBSD::PackingElement::Conflict;
|
|
sub write_debug_info
|
|
{
|
|
my ($self, $fh, $o) = @_;
|
|
my $m = join('|', map {"debug-$_"} split(/\|/, $self->name));
|
|
print $fh "\@", $self->keyword, " $m\n";
|
|
}
|
|
|
|
# This is the BuildDebugInfo main code proper
|
|
package BuildDebugInfo::State;
|
|
our @ISA = qw(OpenBSD::AddCreateDelete::State);
|
|
sub handle_options
|
|
{
|
|
my $state = shift;
|
|
$state->SUPER::handle_options('vqFP:',
|
|
'[-Fmnqvx]',
|
|
'-P pkgdir',
|
|
'-- pkg_create_args ...');
|
|
$state->{pkgdir} = $state->opt('P');
|
|
if (!defined $state->{pkgdir}) {
|
|
$state->fatal("-P pkgdir is mandatory");
|
|
}
|
|
$state->{verbose} = $state->opt('v');
|
|
$state->{quiet} = $state->opt('q');
|
|
}
|
|
|
|
sub openfile
|
|
{
|
|
my ($self, $name) = @_;
|
|
open my $fh, ">", $name or
|
|
$self->fatal("Can't write to #1: #2", $name, $!);
|
|
$self->say("Writing #1", $name) unless $self->{quiet};
|
|
return $fh;
|
|
}
|
|
|
|
package BuildDebugInfo;
|
|
our @ISA = qw(OpenBSD::BaseFS);
|
|
use File::Basename;
|
|
use File::Compare;
|
|
|
|
sub new
|
|
{
|
|
my $class = shift;
|
|
return $class->SUPER::new(undef, BuildDebugInfo::State->new);
|
|
}
|
|
|
|
my $self = BuildDebugInfo->new;
|
|
my $state = $self->{state};
|
|
$state->{exitcode} = 0;
|
|
PlistReader->parse_args($self);
|
|
use File::Basename;
|
|
$self->{mk} = $state->openfile($state->{pkgdir}."/Makefile.new");
|
|
print {$self->{mk}} << 'EOPREAMBLE';
|
|
# Makefile generated by build-debug-info $OpenBSD: build-debug-info,v 1.38 2020/12/04 15:04:52 sthen Exp $
|
|
# No serviceable parts
|
|
# Intended to run under the stage area after cd ${WRKINST}
|
|
|
|
OBJCOPY_RULE = ${INSTALL_DATA_DIR} ${@D} && \
|
|
perm=`stat -f "%p" $?` && chmod u+rw $? && \
|
|
echo "> Extracting debug info from $?" && \
|
|
if readelf 2>/dev/null -wi $?|cmp -s /dev/null -; then \
|
|
echo "Warning: no debug-info in $?"; \
|
|
fi && \
|
|
objcopy --only-keep-debug $? $@ && \
|
|
${DWZ} $@ && \
|
|
strip -d $? && \
|
|
objcopy --add-gnu-debuglink=$@ $? && \
|
|
chmod $$perm $? && \
|
|
touch $@
|
|
|
|
LINK_RULE = ${INSTALL_DATA_DIR} ${@D} && \
|
|
echo "> Link debug info from $? to $@" && ln $? $@
|
|
|
|
all:
|
|
.PHONY: all
|
|
|
|
EOPREAMBLE
|
|
|
|
# XXX even though links may end up in different subpackages, the
|
|
# logic has to be global, as this is used by the generated makefile
|
|
# to extract debug info. pkg_create/pkg_add may then create copies,
|
|
# but they will contain the right information
|
|
$self->{linkstash} = {};
|
|
$self->{ostash} = {};
|
|
for my $l (@{$self->{lists}}) {
|
|
$self->{empty} = 1;
|
|
$self->{dirstash} = {};
|
|
$self->{prefix} = $l->{state}{prefix};
|
|
my $name = pop @{$l->{base_plists}};
|
|
$name = $state->{pkgdir}."/".(basename $name);
|
|
my $fh = $state->openfile($name);
|
|
$self->{first_cwd} = 1;
|
|
$l->olist->write_debug_info($fh, $self);
|
|
close($fh) or $state->fatal("Can't write plist: #1", $!);
|
|
$self->warn_if_empty($state, $l);
|
|
}
|
|
|
|
close($self->{mk}) or $state->fatal("Can't close Makefile.new: #1", $!);
|
|
|
|
sub warn_if_empty
|
|
{
|
|
my ($self, $state, $l) = @_;
|
|
return unless $self->{empty};
|
|
$state->errsay("Warning: no debug-info in #1", $l->olist->pkgname);
|
|
return if @{$self->{lists}} == 1;
|
|
$state->errsay("Set DEBUG_PACKAGES manually ?");
|
|
}
|
|
|
|
if (!$state->{exitcode}) {
|
|
my $f = $state->{pkgdir}."/Makefile";
|
|
$state->say("Renaming #1 to #2", "$f.new", "Makefile") unless $state->{quiet};
|
|
rename("$f.new", $f) or $state->fatal("Can't create Makefile: #1", $!);
|
|
}
|
|
exit($state->{exitcode});
|