1*4882a593Smuzhiyun#!/usr/bin/env python3 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# Build a systemtap script for a given image, kernel 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun# Effectively script extracts needed information from set of 6*4882a593Smuzhiyun# 'bitbake -e' commands and contructs proper invocation of stap on 7*4882a593Smuzhiyun# host to build systemtap script for a given target. 8*4882a593Smuzhiyun# 9*4882a593Smuzhiyun# By default script will compile scriptname.ko that could be copied 10*4882a593Smuzhiyun# to taget and activated with 'staprun scriptname.ko' command. Or if 11*4882a593Smuzhiyun# --remote user@hostname option is specified script will build, load 12*4882a593Smuzhiyun# execute script on target. 13*4882a593Smuzhiyun# 14*4882a593Smuzhiyun# This script is very similar and inspired by crosstap shell script. 15*4882a593Smuzhiyun# The major difference that this script supports user-land related 16*4882a593Smuzhiyun# systemtap script, whereas crosstap could deal only with scripts 17*4882a593Smuzhiyun# related to kernel. 18*4882a593Smuzhiyun# 19*4882a593Smuzhiyun# Copyright (c) 2018, Cisco Systems. 20*4882a593Smuzhiyun# 21*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 22*4882a593Smuzhiyun# 23*4882a593Smuzhiyun 24*4882a593Smuzhiyunimport sys 25*4882a593Smuzhiyunimport re 26*4882a593Smuzhiyunimport subprocess 27*4882a593Smuzhiyunimport os 28*4882a593Smuzhiyunimport optparse 29*4882a593Smuzhiyun 30*4882a593Smuzhiyunclass Stap(object): 31*4882a593Smuzhiyun def __init__(self, script, module, remote): 32*4882a593Smuzhiyun self.script = script 33*4882a593Smuzhiyun self.module = module 34*4882a593Smuzhiyun self.remote = remote 35*4882a593Smuzhiyun self.stap = None 36*4882a593Smuzhiyun self.sysroot = None 37*4882a593Smuzhiyun self.runtime = None 38*4882a593Smuzhiyun self.tapset = None 39*4882a593Smuzhiyun self.arch = None 40*4882a593Smuzhiyun self.cross_compile = None 41*4882a593Smuzhiyun self.kernel_release = None 42*4882a593Smuzhiyun self.target_path = None 43*4882a593Smuzhiyun self.target_ld_library_path = None 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun if not self.remote: 46*4882a593Smuzhiyun if not self.module: 47*4882a593Smuzhiyun # derive module name from script 48*4882a593Smuzhiyun self.module = os.path.basename(self.script) 49*4882a593Smuzhiyun if self.module[-4:] == ".stp": 50*4882a593Smuzhiyun self.module = self.module[:-4] 51*4882a593Smuzhiyun # replace - if any with _ 52*4882a593Smuzhiyun self.module = self.module.replace("-", "_") 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun def command(self, args): 55*4882a593Smuzhiyun ret = [] 56*4882a593Smuzhiyun ret.append(self.stap) 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun if self.remote: 59*4882a593Smuzhiyun ret.append("--remote") 60*4882a593Smuzhiyun ret.append(self.remote) 61*4882a593Smuzhiyun else: 62*4882a593Smuzhiyun ret.append("-p4") 63*4882a593Smuzhiyun ret.append("-m") 64*4882a593Smuzhiyun ret.append(self.module) 65*4882a593Smuzhiyun 66*4882a593Smuzhiyun ret.append("-a") 67*4882a593Smuzhiyun ret.append(self.arch) 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun ret.append("-B") 70*4882a593Smuzhiyun ret.append("CROSS_COMPILE=" + self.cross_compile) 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun ret.append("-r") 73*4882a593Smuzhiyun ret.append(self.kernel_release) 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun ret.append("-I") 76*4882a593Smuzhiyun ret.append(self.tapset) 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun ret.append("-R") 79*4882a593Smuzhiyun ret.append(self.runtime) 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun if self.sysroot: 82*4882a593Smuzhiyun ret.append("--sysroot") 83*4882a593Smuzhiyun ret.append(self.sysroot) 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun ret.append("--sysenv=PATH=" + self.target_path) 86*4882a593Smuzhiyun ret.append("--sysenv=LD_LIBRARY_PATH=" + self.target_ld_library_path) 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun ret = ret + args 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun ret.append(self.script) 91*4882a593Smuzhiyun return ret 92*4882a593Smuzhiyun 93*4882a593Smuzhiyun def additional_environment(self): 94*4882a593Smuzhiyun ret = {} 95*4882a593Smuzhiyun ret["SYSTEMTAP_DEBUGINFO_PATH"] = "+:.debug:build" 96*4882a593Smuzhiyun return ret 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun def environment(self): 99*4882a593Smuzhiyun ret = os.environ.copy() 100*4882a593Smuzhiyun additional = self.additional_environment() 101*4882a593Smuzhiyun for e in additional: 102*4882a593Smuzhiyun ret[e] = additional[e] 103*4882a593Smuzhiyun return ret 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun def display_command(self, args): 106*4882a593Smuzhiyun additional_env = self.additional_environment() 107*4882a593Smuzhiyun command = self.command(args) 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun print("#!/bin/sh") 110*4882a593Smuzhiyun for e in additional_env: 111*4882a593Smuzhiyun print("export %s=\"%s\"" % (e, additional_env[e])) 112*4882a593Smuzhiyun print(" ".join(command)) 113*4882a593Smuzhiyun 114*4882a593Smuzhiyunclass BitbakeEnvInvocationException(Exception): 115*4882a593Smuzhiyun def __init__(self, message): 116*4882a593Smuzhiyun self.message = message 117*4882a593Smuzhiyun 118*4882a593Smuzhiyunclass BitbakeEnv(object): 119*4882a593Smuzhiyun BITBAKE="bitbake" 120*4882a593Smuzhiyun 121*4882a593Smuzhiyun def __init__(self, package): 122*4882a593Smuzhiyun self.package = package 123*4882a593Smuzhiyun self.cmd = BitbakeEnv.BITBAKE + " -e " + self.package 124*4882a593Smuzhiyun self.popen = subprocess.Popen(self.cmd, shell=True, 125*4882a593Smuzhiyun stdout=subprocess.PIPE, 126*4882a593Smuzhiyun stderr=subprocess.STDOUT) 127*4882a593Smuzhiyun self.__lines = self.popen.stdout.readlines() 128*4882a593Smuzhiyun self.popen.wait() 129*4882a593Smuzhiyun 130*4882a593Smuzhiyun self.lines = [] 131*4882a593Smuzhiyun for line in self.__lines: 132*4882a593Smuzhiyun self.lines.append(line.decode('utf-8')) 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun def get_vars(self, vars): 135*4882a593Smuzhiyun if self.popen.returncode: 136*4882a593Smuzhiyun raise BitbakeEnvInvocationException( 137*4882a593Smuzhiyun "\nFailed to execute '" + self.cmd + 138*4882a593Smuzhiyun "' with the following message:\n" + 139*4882a593Smuzhiyun ''.join(self.lines)) 140*4882a593Smuzhiyun 141*4882a593Smuzhiyun search_patterns = [] 142*4882a593Smuzhiyun retdict = {} 143*4882a593Smuzhiyun for var in vars: 144*4882a593Smuzhiyun # regular not exported variable 145*4882a593Smuzhiyun rexpr = "^" + var + "=\"(.*)\"" 146*4882a593Smuzhiyun re_compiled = re.compile(rexpr) 147*4882a593Smuzhiyun search_patterns.append((var, re_compiled)) 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun # exported variable 150*4882a593Smuzhiyun rexpr = "^export " + var + "=\"(.*)\"" 151*4882a593Smuzhiyun re_compiled = re.compile(rexpr) 152*4882a593Smuzhiyun search_patterns.append((var, re_compiled)) 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun for line in self.lines: 155*4882a593Smuzhiyun for var, rexpr in search_patterns: 156*4882a593Smuzhiyun m = rexpr.match(line) 157*4882a593Smuzhiyun if m: 158*4882a593Smuzhiyun value = m.group(1) 159*4882a593Smuzhiyun retdict[var] = value 160*4882a593Smuzhiyun 161*4882a593Smuzhiyun # fill variables values in order how they were requested 162*4882a593Smuzhiyun ret = [] 163*4882a593Smuzhiyun for var in vars: 164*4882a593Smuzhiyun ret.append(retdict.get(var)) 165*4882a593Smuzhiyun 166*4882a593Smuzhiyun # if it is single value list return it as scalar, not the list 167*4882a593Smuzhiyun if len(ret) == 1: 168*4882a593Smuzhiyun ret = ret[0] 169*4882a593Smuzhiyun 170*4882a593Smuzhiyun return ret 171*4882a593Smuzhiyun 172*4882a593Smuzhiyunclass ParamDiscovery(object): 173*4882a593Smuzhiyun SYMBOLS_CHECK_MESSAGE = """ 174*4882a593SmuzhiyunWARNING: image '%s' does not have dbg-pkgs IMAGE_FEATURES enabled and no 175*4882a593Smuzhiyun"image-combined-dbg" in inherited classes is specified. As result the image 176*4882a593Smuzhiyundoes not have symbols for user-land processes DWARF based probes. Consider 177*4882a593Smuzhiyunadding 'dbg-pkgs' to EXTRA_IMAGE_FEATURES or adding "image-combined-dbg" to 178*4882a593SmuzhiyunUSER_CLASSES. I.e add this line 'USER_CLASSES += "image-combined-dbg"' to 179*4882a593Smuzhiyunlocal.conf file. 180*4882a593Smuzhiyun 181*4882a593SmuzhiyunOr you may use IMAGE_GEN_DEBUGFS="1" option, and then after build you need 182*4882a593Smuzhiyunrecombine/unpack image and image-dbg tarballs and pass resulting dir location 183*4882a593Smuzhiyunwith --sysroot option. 184*4882a593Smuzhiyun""" 185*4882a593Smuzhiyun 186*4882a593Smuzhiyun def __init__(self, image): 187*4882a593Smuzhiyun self.image = image 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun self.image_rootfs = None 190*4882a593Smuzhiyun self.image_features = None 191*4882a593Smuzhiyun self.image_gen_debugfs = None 192*4882a593Smuzhiyun self.inherit = None 193*4882a593Smuzhiyun self.base_bindir = None 194*4882a593Smuzhiyun self.base_sbindir = None 195*4882a593Smuzhiyun self.base_libdir = None 196*4882a593Smuzhiyun self.bindir = None 197*4882a593Smuzhiyun self.sbindir = None 198*4882a593Smuzhiyun self.libdir = None 199*4882a593Smuzhiyun 200*4882a593Smuzhiyun self.staging_bindir_toolchain = None 201*4882a593Smuzhiyun self.target_prefix = None 202*4882a593Smuzhiyun self.target_arch = None 203*4882a593Smuzhiyun self.target_kernel_builddir = None 204*4882a593Smuzhiyun 205*4882a593Smuzhiyun self.staging_dir_native = None 206*4882a593Smuzhiyun 207*4882a593Smuzhiyun self.image_combined_dbg = False 208*4882a593Smuzhiyun 209*4882a593Smuzhiyun def discover(self): 210*4882a593Smuzhiyun if self.image: 211*4882a593Smuzhiyun benv_image = BitbakeEnv(self.image) 212*4882a593Smuzhiyun (self.image_rootfs, 213*4882a593Smuzhiyun self.image_features, 214*4882a593Smuzhiyun self.image_gen_debugfs, 215*4882a593Smuzhiyun self.inherit, 216*4882a593Smuzhiyun self.base_bindir, 217*4882a593Smuzhiyun self.base_sbindir, 218*4882a593Smuzhiyun self.base_libdir, 219*4882a593Smuzhiyun self.bindir, 220*4882a593Smuzhiyun self.sbindir, 221*4882a593Smuzhiyun self.libdir 222*4882a593Smuzhiyun ) = benv_image.get_vars( 223*4882a593Smuzhiyun ("IMAGE_ROOTFS", 224*4882a593Smuzhiyun "IMAGE_FEATURES", 225*4882a593Smuzhiyun "IMAGE_GEN_DEBUGFS", 226*4882a593Smuzhiyun "INHERIT", 227*4882a593Smuzhiyun "base_bindir", 228*4882a593Smuzhiyun "base_sbindir", 229*4882a593Smuzhiyun "base_libdir", 230*4882a593Smuzhiyun "bindir", 231*4882a593Smuzhiyun "sbindir", 232*4882a593Smuzhiyun "libdir" 233*4882a593Smuzhiyun )) 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun benv_kernel = BitbakeEnv("virtual/kernel") 236*4882a593Smuzhiyun (self.staging_bindir_toolchain, 237*4882a593Smuzhiyun self.target_prefix, 238*4882a593Smuzhiyun self.target_arch, 239*4882a593Smuzhiyun self.target_kernel_builddir 240*4882a593Smuzhiyun ) = benv_kernel.get_vars( 241*4882a593Smuzhiyun ("STAGING_BINDIR_TOOLCHAIN", 242*4882a593Smuzhiyun "TARGET_PREFIX", 243*4882a593Smuzhiyun "TRANSLATED_TARGET_ARCH", 244*4882a593Smuzhiyun "B" 245*4882a593Smuzhiyun )) 246*4882a593Smuzhiyun 247*4882a593Smuzhiyun benv_systemtap = BitbakeEnv("systemtap-native") 248*4882a593Smuzhiyun (self.staging_dir_native 249*4882a593Smuzhiyun ) = benv_systemtap.get_vars(["STAGING_DIR_NATIVE"]) 250*4882a593Smuzhiyun 251*4882a593Smuzhiyun if self.inherit: 252*4882a593Smuzhiyun if "image-combined-dbg" in self.inherit.split(): 253*4882a593Smuzhiyun self.image_combined_dbg = True 254*4882a593Smuzhiyun 255*4882a593Smuzhiyun def check(self, sysroot_option): 256*4882a593Smuzhiyun ret = True 257*4882a593Smuzhiyun if self.image_rootfs: 258*4882a593Smuzhiyun sysroot = self.image_rootfs 259*4882a593Smuzhiyun if not os.path.isdir(self.image_rootfs): 260*4882a593Smuzhiyun print("ERROR: Cannot find '" + sysroot + 261*4882a593Smuzhiyun "' directory. Was '" + self.image + "' image built?") 262*4882a593Smuzhiyun ret = False 263*4882a593Smuzhiyun 264*4882a593Smuzhiyun stap = self.staging_dir_native + "/usr/bin/stap" 265*4882a593Smuzhiyun if not os.path.isfile(stap): 266*4882a593Smuzhiyun print("ERROR: Cannot find '" + stap + 267*4882a593Smuzhiyun "'. Was 'systemtap-native' built?") 268*4882a593Smuzhiyun ret = False 269*4882a593Smuzhiyun 270*4882a593Smuzhiyun if not os.path.isdir(self.target_kernel_builddir): 271*4882a593Smuzhiyun print("ERROR: Cannot find '" + self.target_kernel_builddir + 272*4882a593Smuzhiyun "' directory. Was 'kernel/virtual' built?") 273*4882a593Smuzhiyun ret = False 274*4882a593Smuzhiyun 275*4882a593Smuzhiyun if not sysroot_option and self.image_rootfs: 276*4882a593Smuzhiyun dbg_pkgs_found = False 277*4882a593Smuzhiyun 278*4882a593Smuzhiyun if self.image_features: 279*4882a593Smuzhiyun image_features = self.image_features.split() 280*4882a593Smuzhiyun if "dbg-pkgs" in image_features: 281*4882a593Smuzhiyun dbg_pkgs_found = True 282*4882a593Smuzhiyun 283*4882a593Smuzhiyun if not dbg_pkgs_found \ 284*4882a593Smuzhiyun and not self.image_combined_dbg: 285*4882a593Smuzhiyun print(ParamDiscovery.SYMBOLS_CHECK_MESSAGE % (self.image)) 286*4882a593Smuzhiyun 287*4882a593Smuzhiyun if not ret: 288*4882a593Smuzhiyun print("") 289*4882a593Smuzhiyun 290*4882a593Smuzhiyun return ret 291*4882a593Smuzhiyun 292*4882a593Smuzhiyun def __map_systemtap_arch(self): 293*4882a593Smuzhiyun a = self.target_arch 294*4882a593Smuzhiyun ret = a 295*4882a593Smuzhiyun if re.match('(athlon|x86.64)$', a): 296*4882a593Smuzhiyun ret = 'x86_64' 297*4882a593Smuzhiyun elif re.match('i.86$', a): 298*4882a593Smuzhiyun ret = 'i386' 299*4882a593Smuzhiyun elif re.match('arm$', a): 300*4882a593Smuzhiyun ret = 'arm' 301*4882a593Smuzhiyun elif re.match('aarch64$', a): 302*4882a593Smuzhiyun ret = 'arm64' 303*4882a593Smuzhiyun elif re.match('mips(isa|)(32|64|)(r6|)(el|)$', a): 304*4882a593Smuzhiyun ret = 'mips' 305*4882a593Smuzhiyun elif re.match('p(pc|owerpc)(|64)', a): 306*4882a593Smuzhiyun ret = 'powerpc' 307*4882a593Smuzhiyun return ret 308*4882a593Smuzhiyun 309*4882a593Smuzhiyun def fill_stap(self, stap): 310*4882a593Smuzhiyun stap.stap = self.staging_dir_native + "/usr/bin/stap" 311*4882a593Smuzhiyun if not stap.sysroot: 312*4882a593Smuzhiyun if self.image_rootfs: 313*4882a593Smuzhiyun if self.image_combined_dbg: 314*4882a593Smuzhiyun stap.sysroot = self.image_rootfs + "-dbg" 315*4882a593Smuzhiyun else: 316*4882a593Smuzhiyun stap.sysroot = self.image_rootfs 317*4882a593Smuzhiyun stap.runtime = self.staging_dir_native + "/usr/share/systemtap/runtime" 318*4882a593Smuzhiyun stap.tapset = self.staging_dir_native + "/usr/share/systemtap/tapset" 319*4882a593Smuzhiyun stap.arch = self.__map_systemtap_arch() 320*4882a593Smuzhiyun stap.cross_compile = self.staging_bindir_toolchain + "/" + \ 321*4882a593Smuzhiyun self.target_prefix 322*4882a593Smuzhiyun stap.kernel_release = self.target_kernel_builddir 323*4882a593Smuzhiyun 324*4882a593Smuzhiyun # do we have standard that tells in which order these need to appear 325*4882a593Smuzhiyun target_path = [] 326*4882a593Smuzhiyun if self.sbindir: 327*4882a593Smuzhiyun target_path.append(self.sbindir) 328*4882a593Smuzhiyun if self.bindir: 329*4882a593Smuzhiyun target_path.append(self.bindir) 330*4882a593Smuzhiyun if self.base_sbindir: 331*4882a593Smuzhiyun target_path.append(self.base_sbindir) 332*4882a593Smuzhiyun if self.base_bindir: 333*4882a593Smuzhiyun target_path.append(self.base_bindir) 334*4882a593Smuzhiyun stap.target_path = ":".join(target_path) 335*4882a593Smuzhiyun 336*4882a593Smuzhiyun target_ld_library_path = [] 337*4882a593Smuzhiyun if self.libdir: 338*4882a593Smuzhiyun target_ld_library_path.append(self.libdir) 339*4882a593Smuzhiyun if self.base_libdir: 340*4882a593Smuzhiyun target_ld_library_path.append(self.base_libdir) 341*4882a593Smuzhiyun stap.target_ld_library_path = ":".join(target_ld_library_path) 342*4882a593Smuzhiyun 343*4882a593Smuzhiyun 344*4882a593Smuzhiyundef main(): 345*4882a593Smuzhiyun usage = """usage: %prog -s <systemtap-script> [options] [-- [systemtap options]] 346*4882a593Smuzhiyun 347*4882a593Smuzhiyun%prog cross compile given SystemTap script against given image, kernel 348*4882a593Smuzhiyun 349*4882a593SmuzhiyunIt needs to run in environtment set for bitbake - it uses bitbake -e 350*4882a593Smuzhiyuninvocations to retrieve information to construct proper stap cross build 351*4882a593Smuzhiyuninvocation arguments. It assumes that systemtap-native is built in given 352*4882a593Smuzhiyunbitbake workspace. 353*4882a593Smuzhiyun 354*4882a593SmuzhiyunAnything after -- option is passed directly to stap. 355*4882a593Smuzhiyun 356*4882a593SmuzhiyunLegacy script invocation style supported but deprecated: 357*4882a593Smuzhiyun %prog <user@hostname> <sytemtap-script> [systemtap options] 358*4882a593Smuzhiyun 359*4882a593SmuzhiyunTo enable most out of systemtap the following site.conf or local.conf 360*4882a593Smuzhiyunconfiguration is recommended: 361*4882a593Smuzhiyun 362*4882a593Smuzhiyun# enables symbol + target binaries rootfs-dbg in workspace 363*4882a593SmuzhiyunIMAGE_GEN_DEBUGFS = "1" 364*4882a593SmuzhiyunIMAGE_FSTYPES_DEBUGFS = "tar.bz2" 365*4882a593SmuzhiyunUSER_CLASSES += "image-combined-dbg" 366*4882a593Smuzhiyun 367*4882a593Smuzhiyun# enables kernel debug symbols 368*4882a593SmuzhiyunKERNEL_EXTRA_FEATURES:append = " features/debug/debug-kernel.scc" 369*4882a593Smuzhiyun 370*4882a593Smuzhiyun# minimal, just run-time systemtap configuration in target image 371*4882a593SmuzhiyunPACKAGECONFIG:pn-systemtap = "monitor" 372*4882a593Smuzhiyun 373*4882a593Smuzhiyun# add systemtap run-time into target image if it is not there yet 374*4882a593SmuzhiyunIMAGE_INSTALL:append = " systemtap" 375*4882a593Smuzhiyun""" 376*4882a593Smuzhiyun option_parser = optparse.OptionParser(usage=usage) 377*4882a593Smuzhiyun 378*4882a593Smuzhiyun option_parser.add_option("-s", "--script", dest="script", 379*4882a593Smuzhiyun help="specify input script FILE name", 380*4882a593Smuzhiyun metavar="FILE") 381*4882a593Smuzhiyun 382*4882a593Smuzhiyun option_parser.add_option("-i", "--image", dest="image", 383*4882a593Smuzhiyun help="specify image name for which script should be compiled") 384*4882a593Smuzhiyun 385*4882a593Smuzhiyun option_parser.add_option("-r", "--remote", dest="remote", 386*4882a593Smuzhiyun help="specify username@hostname of remote target to run script " 387*4882a593Smuzhiyun "optional, it assumes that remote target can be accessed through ssh") 388*4882a593Smuzhiyun 389*4882a593Smuzhiyun option_parser.add_option("-m", "--module", dest="module", 390*4882a593Smuzhiyun help="specify module name, optional, has effect only if --remote is not used, " 391*4882a593Smuzhiyun "if not specified module name will be derived from passed script name") 392*4882a593Smuzhiyun 393*4882a593Smuzhiyun option_parser.add_option("-y", "--sysroot", dest="sysroot", 394*4882a593Smuzhiyun help="explicitely specify image sysroot location. May need to use it in case " 395*4882a593Smuzhiyun "when IMAGE_GEN_DEBUGFS=\"1\" option is used and recombined with symbols " 396*4882a593Smuzhiyun "in different location", 397*4882a593Smuzhiyun metavar="DIR") 398*4882a593Smuzhiyun 399*4882a593Smuzhiyun option_parser.add_option("-o", "--out", dest="out", 400*4882a593Smuzhiyun action="store_true", 401*4882a593Smuzhiyun help="output shell script that equvivalent invocation of this script with " 402*4882a593Smuzhiyun "given set of arguments, in given bitbake environment. It could be stored in " 403*4882a593Smuzhiyun "separate shell script and could be repeated without incuring bitbake -e " 404*4882a593Smuzhiyun "invocation overhead", 405*4882a593Smuzhiyun default=False) 406*4882a593Smuzhiyun 407*4882a593Smuzhiyun option_parser.add_option("-d", "--debug", dest="debug", 408*4882a593Smuzhiyun action="store_true", 409*4882a593Smuzhiyun help="enable debug output. Use this option to see resulting stap invocation", 410*4882a593Smuzhiyun default=False) 411*4882a593Smuzhiyun 412*4882a593Smuzhiyun # is invocation follow syntax from orignal crosstap shell script 413*4882a593Smuzhiyun legacy_args = False 414*4882a593Smuzhiyun 415*4882a593Smuzhiyun # check if we called the legacy way 416*4882a593Smuzhiyun if len(sys.argv) >= 3: 417*4882a593Smuzhiyun if sys.argv[1].find("@") != -1 and os.path.exists(sys.argv[2]): 418*4882a593Smuzhiyun legacy_args = True 419*4882a593Smuzhiyun 420*4882a593Smuzhiyun # fill options values for legacy invocation case 421*4882a593Smuzhiyun options = optparse.Values 422*4882a593Smuzhiyun options.script = sys.argv[2] 423*4882a593Smuzhiyun options.remote = sys.argv[1] 424*4882a593Smuzhiyun options.image = None 425*4882a593Smuzhiyun options.module = None 426*4882a593Smuzhiyun options.sysroot = None 427*4882a593Smuzhiyun options.out = None 428*4882a593Smuzhiyun options.debug = None 429*4882a593Smuzhiyun remaining_args = sys.argv[3:] 430*4882a593Smuzhiyun 431*4882a593Smuzhiyun if not legacy_args: 432*4882a593Smuzhiyun (options, remaining_args) = option_parser.parse_args() 433*4882a593Smuzhiyun 434*4882a593Smuzhiyun if not options.script or not os.path.exists(options.script): 435*4882a593Smuzhiyun print("'-s FILE' option is missing\n") 436*4882a593Smuzhiyun option_parser.print_help() 437*4882a593Smuzhiyun else: 438*4882a593Smuzhiyun stap = Stap(options.script, options.module, options.remote) 439*4882a593Smuzhiyun discovery = ParamDiscovery(options.image) 440*4882a593Smuzhiyun discovery.discover() 441*4882a593Smuzhiyun if not discovery.check(options.sysroot): 442*4882a593Smuzhiyun option_parser.print_help() 443*4882a593Smuzhiyun else: 444*4882a593Smuzhiyun stap.sysroot = options.sysroot 445*4882a593Smuzhiyun discovery.fill_stap(stap) 446*4882a593Smuzhiyun 447*4882a593Smuzhiyun if options.out: 448*4882a593Smuzhiyun stap.display_command(remaining_args) 449*4882a593Smuzhiyun else: 450*4882a593Smuzhiyun cmd = stap.command(remaining_args) 451*4882a593Smuzhiyun env = stap.environment() 452*4882a593Smuzhiyun 453*4882a593Smuzhiyun if options.debug: 454*4882a593Smuzhiyun print(" ".join(cmd)) 455*4882a593Smuzhiyun 456*4882a593Smuzhiyun os.execve(cmd[0], cmd, env) 457*4882a593Smuzhiyun 458*4882a593Smuzhiyunmain() 459