xref: /OK3568_Linux_fs/yocto/scripts/crosstap (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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