293 lines
7.9 KiB
Perl
293 lines
7.9 KiB
Perl
#! /usr/bin/perl
|
|
# $OpenBSD: build-debug-info,v 1.49 2023/05/09 17:41:10 espie 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 v5.36;
|
|
|
|
my $ports1;
|
|
BEGIN {
|
|
$ports1 = $ENV{PORTSDIR} || '/usr/ports';
|
|
}
|
|
|
|
use lib "$ports1/infrastructure/lib";
|
|
use OpenBSD::BaseFS;
|
|
use OpenBSD::BasePlistReader;
|
|
|
|
package PlistFactory;
|
|
our @ISA = qw(OpenBSD::BasePlistFactory);
|
|
|
|
# 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($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($s)
|
|
{
|
|
$s->SUPER::handle_options;
|
|
}
|
|
|
|
# Most of the heavy lifting is done by visitor methods, as always
|
|
|
|
package OpenBSD::PackingElement;
|
|
# $self->write_debug_info($base, $fh, $o):
|
|
# write debug info (duh) for packing element $self relative to
|
|
# fake dir $base to filehandle $fh perusing debug object
|
|
# $o for storing useful info
|
|
sub write_debug_info($, $, $, $)
|
|
{
|
|
}
|
|
|
|
package OpenBSD::PackingElement::PkgPath;
|
|
sub write_debug_info($self, $, $fh, $)
|
|
{
|
|
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($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($self, $base, $fh, $o)
|
|
{
|
|
return if $self->{nodebug};
|
|
my $s = $self->name;
|
|
my $dbg = $self->mogrify($s);
|
|
my $dir = $dbg;
|
|
$dir =~ s/(\/\.debug\/)[^\/]+/$1/;
|
|
my $path = $base.$self->fullname;
|
|
my $dbgpath = $base.$self->mogrify($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) {
|
|
$self->write_debug_entry($fh, $dir, $dbg, $o);
|
|
$o->{linkstash}{$k} = $dbg;
|
|
$self->write_rule($o, $fh, $s, $path, $dbgpath,
|
|
"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_debug_entry($fh, $dir, $n, $o);
|
|
$self->write_rule($o, $fh, $l, $path, $dbgpath, "LINK_RULE");
|
|
} else {
|
|
$o->{state}->fatal("Error: #1 does not exist", $path);
|
|
}
|
|
}
|
|
|
|
sub write_debug_entry($self, $fh, $dir, $dbg, $o)
|
|
{
|
|
print $fh $dbg, "\n";
|
|
if (!exists $o->{dirstash}{$dir}) {
|
|
print $fh $dir, "\n";
|
|
$o->{dirstash}{$dir} = 1;
|
|
}
|
|
$o->{ostash}{$dbg} = 1;
|
|
delete $o->{empty};
|
|
}
|
|
|
|
sub write_rule($self, $o, $fh, $s, $p1, $p2, $what)
|
|
{
|
|
my $mk = $o->{mk};
|
|
print $mk "all: $p2\n";
|
|
print $mk "$p2: $p1\n";
|
|
print $mk "\t\@\$\{$what\}\n\n";
|
|
}
|
|
|
|
sub mogrify($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($self, $, $fh, $)
|
|
{
|
|
$self->write($fh);
|
|
}
|
|
|
|
package OpenBSD::PackingElement::IsBranch;
|
|
sub write_debug_info($self, $, $fh, $)
|
|
{
|
|
$self->write($fh);
|
|
}
|
|
|
|
package OpenBSD::PackingElement::Conflict;
|
|
sub write_debug_info($self, $, $fh, $)
|
|
{
|
|
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($state)
|
|
{
|
|
$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($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($class)
|
|
{
|
|
return $class->SUPER::new(undef, BuildDebugInfo::State->new);
|
|
}
|
|
|
|
my $self = BuildDebugInfo->new;
|
|
my $state = $self->{state};
|
|
$state->{exitcode} = 0;
|
|
my $base = PlistFactory->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.49 2023/05/09 17:41:10 espie 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 && \
|
|
llvm-objcopy --only-keep-debug $? $@ && \
|
|
${DWZ} $@ && \
|
|
strip -d -o $?.stripped $? && cp $?.stripped $? && rm $?.stripped && \
|
|
llvm-objcopy --add-gnu-debuglink=$@ $? $?.debuglink && cp $?.debuglink $? && rm $?.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} = $base."/".$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($base, $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});
|