From eb8dc40360f0cfef56fb6947cc817a547d6d9bc6 Mon Sep 17 00:00:00 2001 From: Dave Cobbley Date: Tue, 14 Aug 2018 10:05:37 -0700 Subject: [Subtree] Removing import-layers directory As part of the move to subtrees, need to bring all the import layers content to the top level. Change-Id: I4a163d10898cbc6e11c27f776f60e1a470049d8f Signed-off-by: Dave Cobbley Signed-off-by: Brad Bishop --- poky/scripts/crosstap | 469 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 469 insertions(+) create mode 100755 poky/scripts/crosstap (limited to 'poky/scripts/crosstap') diff --git a/poky/scripts/crosstap b/poky/scripts/crosstap new file mode 100755 index 000000000..e33fa4ad4 --- /dev/null +++ b/poky/scripts/crosstap @@ -0,0 +1,469 @@ +#!/usr/bin/env python3 +# +# Build a systemtap script for a given image, kernel +# +# Effectively script extracts needed information from set of +# 'bitbake -e' commands and contructs proper invocation of stap on +# host to build systemtap script for a given target. +# +# By default script will compile scriptname.ko that could be copied +# to taget and activated with 'staprun scriptname.ko' command. Or if +# --remote user@hostname option is specified script will build, load +# execute script on target. +# +# This script is very similar and inspired by crosstap shell script. +# The major difference that this script supports user-land related +# systemtap script, whereas crosstap could deal only with scripts +# related to kernel. +# +# Copyright (c) 2018, Cisco Systems. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import sys +import re +import subprocess +import os +import optparse + +class Stap(object): + def __init__(self, script, module, remote): + self.script = script + self.module = module + self.remote = remote + self.stap = None + self.sysroot = None + self.runtime = None + self.tapset = None + self.arch = None + self.cross_compile = None + self.kernel_release = None + self.target_path = None + self.target_ld_library_path = None + + if not self.remote: + if not self.module: + # derive module name from script + self.module = os.path.basename(self.script) + if self.module[-4:] == ".stp": + self.module = self.module[:-4] + # replace - if any with _ + self.module = self.module.replace("-", "_") + + def command(self, args): + ret = [] + ret.append(self.stap) + + if self.remote: + ret.append("--remote") + ret.append(self.remote) + else: + ret.append("-p4") + ret.append("-m") + ret.append(self.module) + + ret.append("-a") + ret.append(self.arch) + + ret.append("-B") + ret.append("CROSS_COMPILE=" + self.cross_compile) + + ret.append("-r") + ret.append(self.kernel_release) + + ret.append("-I") + ret.append(self.tapset) + + ret.append("-R") + ret.append(self.runtime) + + if self.sysroot: + ret.append("--sysroot") + ret.append(self.sysroot) + + ret.append("--sysenv=PATH=" + self.target_path) + ret.append("--sysenv=LD_LIBRARY_PATH=" + self.target_ld_library_path) + + ret = ret + args + + ret.append(self.script) + return ret + + def additional_environment(self): + ret = {} + ret["SYSTEMTAP_DEBUGINFO_PATH"] = "+:.debug:build" + return ret + + def environment(self): + ret = os.environ.copy() + additional = self.additional_environment() + for e in additional: + ret[e] = additional[e] + return ret + + def display_command(self, args): + additional_env = self.additional_environment() + command = self.command(args) + + print("#!/bin/sh") + for e in additional_env: + print("export %s=\"%s\"" % (e, additional_env[e])) + print(" ".join(command)) + +class BitbakeEnvInvocationException(Exception): + def __init__(self, message): + self.message = message + +class BitbakeEnv(object): + BITBAKE="bitbake" + + def __init__(self, package): + self.package = package + self.cmd = BitbakeEnv.BITBAKE + " -e " + self.package + self.popen = subprocess.Popen(self.cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + self.__lines = self.popen.stdout.readlines() + self.popen.wait() + + self.lines = [] + for line in self.__lines: + self.lines.append(line.decode('utf-8')) + + def get_vars(self, vars): + if self.popen.returncode: + raise BitbakeEnvInvocationException( + "\nFailed to execute '" + self.cmd + + "' with the following message:\n" + + ''.join(self.lines)) + + search_patterns = [] + retdict = {} + for var in vars: + # regular not exported variable + rexpr = "^" + var + "=\"(.*)\"" + re_compiled = re.compile(rexpr) + search_patterns.append((var, re_compiled)) + + # exported variable + rexpr = "^export " + var + "=\"(.*)\"" + re_compiled = re.compile(rexpr) + search_patterns.append((var, re_compiled)) + + for line in self.lines: + for var, rexpr in search_patterns: + m = rexpr.match(line) + if m: + value = m.group(1) + retdict[var] = value + + # fill variables values in order how they were requested + ret = [] + for var in vars: + ret.append(retdict.get(var)) + + # if it is single value list return it as scalar, not the list + if len(ret) == 1: + ret = ret[0] + + return ret + +class ParamDiscovery(object): + SYMBOLS_CHECK_MESSAGE = """ +WARNING: image '%s' does not have dbg-pkgs IMAGE_FEATURES enabled and no +"image-combined-dbg" in inherited classes is specified. As result the image +does not have symbols for user-land processes DWARF based probes. Consider +adding 'dbg-pkgs' to EXTRA_IMAGE_FEATURES or adding "image-combined-dbg" to +USER_CLASSES. I.e add this line 'USER_CLASSES += "image-combined-dbg"' to +local.conf file. + +Or you may use IMAGE_GEN_DEBUGFS="1" option, and then after build you need +recombine/unpack image and image-dbg tarballs and pass resulting dir location +with --sysroot option. +""" + + def __init__(self, image): + self.image = image + + self.image_rootfs = None + self.image_features = None + self.image_gen_debugfs = None + self.inherit = None + self.base_bindir = None + self.base_sbindir = None + self.base_libdir = None + self.bindir = None + self.sbindir = None + self.libdir = None + + self.staging_bindir_toolchain = None + self.target_prefix = None + self.target_arch = None + self.target_kernel_builddir = None + + self.staging_dir_native = None + + self.image_combined_dbg = False + + def discover(self): + if self.image: + benv_image = BitbakeEnv(self.image) + (self.image_rootfs, + self.image_features, + self.image_gen_debugfs, + self.inherit, + self.base_bindir, + self.base_sbindir, + self.base_libdir, + self.bindir, + self.sbindir, + self.libdir + ) = benv_image.get_vars( + ("IMAGE_ROOTFS", + "IMAGE_FEATURES", + "IMAGE_GEN_DEBUGFS", + "INHERIT", + "base_bindir", + "base_sbindir", + "base_libdir", + "bindir", + "sbindir", + "libdir" + )) + + benv_kernel = BitbakeEnv("virtual/kernel") + (self.staging_bindir_toolchain, + self.target_prefix, + self.target_arch, + self.target_kernel_builddir + ) = benv_kernel.get_vars( + ("STAGING_BINDIR_TOOLCHAIN", + "TARGET_PREFIX", + "TRANSLATED_TARGET_ARCH", + "B" + )) + + benv_systemtap = BitbakeEnv("systemtap-native") + (self.staging_dir_native + ) = benv_systemtap.get_vars(["STAGING_DIR_NATIVE"]) + + if self.inherit: + if "image-combined-dbg" in self.inherit.split(): + self.image_combined_dbg = True + + def check(self, sysroot_option): + ret = True + if self.image_rootfs: + sysroot = self.image_rootfs + if not os.path.isdir(self.image_rootfs): + print("ERROR: Cannot find '" + sysroot + + "' directory. Was '" + self.image + "' image built?") + ret = False + + stap = self.staging_dir_native + "/usr/bin/stap" + if not os.path.isfile(stap): + print("ERROR: Cannot find '" + stap + + "'. Was 'systemtap-native' built?") + ret = False + + if not os.path.isdir(self.target_kernel_builddir): + print("ERROR: Cannot find '" + self.target_kernel_builddir + + "' directory. Was 'kernel/virtual' built?") + ret = False + + if not sysroot_option and self.image_rootfs: + dbg_pkgs_found = False + + if self.image_features: + image_features = self.image_features.split() + if "dbg-pkgs" in image_features: + dbg_pkgs_found = True + + if not dbg_pkgs_found \ + and not self.image_combined_dbg: + print(ParamDiscovery.SYMBOLS_CHECK_MESSAGE % (self.image)) + + if not ret: + print("") + + return ret + + def __map_systemtap_arch(self): + a = self.target_arch + ret = a + if re.match('(athlon|x86.64)$', a): + ret = 'x86_64' + elif re.match('i.86$', a): + ret = 'i386' + elif re.match('arm$', a): + ret = 'arm' + elif re.match('aarch64$', a): + ret = 'arm64' + elif re.match('mips(isa|)(32|64|)(r6|)(el|)$', a): + ret = 'mips' + elif re.match('p(pc|owerpc)(|64)', a): + ret = 'powerpc' + return ret + + def fill_stap(self, stap): + stap.stap = self.staging_dir_native + "/usr/bin/stap" + if not stap.sysroot: + if self.image_rootfs: + if self.image_combined_dbg: + stap.sysroot = self.image_rootfs + "-dbg" + else: + stap.sysroot = self.image_rootfs + stap.runtime = self.staging_dir_native + "/usr/share/systemtap/runtime" + stap.tapset = self.staging_dir_native + "/usr/share/systemtap/tapset" + stap.arch = self.__map_systemtap_arch() + stap.cross_compile = self.staging_bindir_toolchain + "/" + \ + self.target_prefix + stap.kernel_release = self.target_kernel_builddir + + # do we have standard that tells in which order these need to appear + target_path = [] + if self.sbindir: + target_path.append(self.sbindir) + if self.bindir: + target_path.append(self.bindir) + if self.base_sbindir: + target_path.append(self.base_sbindir) + if self.base_bindir: + target_path.append(self.base_bindir) + stap.target_path = ":".join(target_path) + + target_ld_library_path = [] + if self.libdir: + target_ld_library_path.append(self.libdir) + if self.base_libdir: + target_ld_library_path.append(self.base_libdir) + stap.target_ld_library_path = ":".join(target_ld_library_path) + + +def main(): + usage = """usage: %prog -s [options] [-- [systemtap options]] + +%prog cross compile given SystemTap script against given image, kernel + +It needs to run in environtment set for bitbake - it uses bitbake -e +invocations to retrieve information to construct proper stap cross build +invocation arguments. It assumes that systemtap-native is built in given +bitbake workspace. + +Anything after -- option is passed directly to stap. + +Legacy script invocation style supported but depreciated: + %prog [systemtap options] + +To enable most out of systemtap the following site.conf or local.conf +configuration is recommended: + +# enables symbol + target binaries rootfs-dbg in workspace +IMAGE_GEN_DEBUGFS = "1" +IMAGE_FSTYPES_DEBUGFS = "tar.bz2" +USER_CLASSES += "image-combined-dbg" + +# enables kernel debug symbols +KERNEL_EXTRA_FEATURES_append = " features/debug/debug-kernel.scc" + +# minimal, just run-time systemtap configuration in target image +PACKAGECONFIG_pn-systemtap = "monitor" + +# add systemtap run-time into target image if it is not there yet +IMAGE_INSTALL_append = " systemtap" +""" + option_parser = optparse.OptionParser(usage=usage) + + option_parser.add_option("-s", "--script", dest="script", + help="specify input script FILE name", + metavar="FILE") + + option_parser.add_option("-i", "--image", dest="image", + help="specify image name for which script should be compiled") + + option_parser.add_option("-r", "--remote", dest="remote", + help="specify username@hostname of remote target to run script " + "optional, it assumes that remote target can be accessed through ssh") + + option_parser.add_option("-m", "--module", dest="module", + help="specify module name, optional, has effect only if --remote is not used, " + "if not specified module name will be derived from passed script name") + + option_parser.add_option("-y", "--sysroot", dest="sysroot", + help="explicitely specify image sysroot location. May need to use it in case " + "when IMAGE_GEN_DEBUGFS=\"1\" option is used and recombined with symbols " + "in different location", + metavar="DIR") + + option_parser.add_option("-o", "--out", dest="out", + action="store_true", + help="output shell script that equvivalent invocation of this script with " + "given set of arguments, in given bitbake environment. It could be stored in " + "separate shell script and could be repeated without incuring bitbake -e " + "invocation overhead", + default=False) + + option_parser.add_option("-d", "--debug", dest="debug", + action="store_true", + help="enable debug output. Use this option to see resulting stap invocation", + default=False) + + # is invocation follow syntax from orignal crosstap shell script + legacy_args = False + + # check if we called the legacy way + if len(sys.argv) >= 3: + if sys.argv[1].find("@") != -1 and os.path.exists(sys.argv[2]): + legacy_args = True + + # fill options values for legacy invocation case + options = optparse.Values + options.script = sys.argv[2] + options.remote = sys.argv[1] + options.image = None + options.module = None + options.sysroot = None + options.out = None + options.debug = None + remaining_args = sys.argv[3:] + + if not legacy_args: + (options, remaining_args) = option_parser.parse_args() + + if not options.script or not os.path.exists(options.script): + print("'-s FILE' option is missing\n") + option_parser.print_help() + else: + stap = Stap(options.script, options.module, options.remote) + discovery = ParamDiscovery(options.image) + discovery.discover() + if not discovery.check(options.sysroot): + option_parser.print_help() + else: + stap.sysroot = options.sysroot + discovery.fill_stap(stap) + + if options.out: + stap.display_command(remaining_args) + else: + cmd = stap.command(remaining_args) + env = stap.environment() + + if options.debug: + print(" ".join(cmd)) + + os.execve(cmd[0], cmd, env) + +main() -- cgit v1.2.3