cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

kernel_abi.py (5166B)


      1# -*- coding: utf-8; mode: python -*-
      2# coding=utf-8
      3# SPDX-License-Identifier: GPL-2.0
      4#
      5u"""
      6    kernel-abi
      7    ~~~~~~~~~~
      8
      9    Implementation of the ``kernel-abi`` reST-directive.
     10
     11    :copyright:  Copyright (C) 2016  Markus Heiser
     12    :copyright:  Copyright (C) 2016-2020  Mauro Carvalho Chehab
     13    :maintained-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
     14    :license:    GPL Version 2, June 1991 see Linux/COPYING for details.
     15
     16    The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the
     17    scripts/get_abi.pl script to parse the Kernel ABI files.
     18
     19    Overview of directive's argument and options.
     20
     21    .. code-block:: rst
     22
     23        .. kernel-abi:: <ABI directory location>
     24            :debug:
     25
     26    The argument ``<ABI directory location>`` is required. It contains the
     27    location of the ABI files to be parsed.
     28
     29    ``debug``
     30      Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
     31      what reST is generated.
     32
     33"""
     34
     35import codecs
     36import os
     37import subprocess
     38import sys
     39import re
     40import kernellog
     41
     42from os import path
     43
     44from docutils import nodes, statemachine
     45from docutils.statemachine import ViewList
     46from docutils.parsers.rst import directives, Directive
     47from docutils.utils.error_reporting import ErrorString
     48from sphinx.util.docutils import switch_source_input
     49
     50__version__  = '1.0'
     51
     52def setup(app):
     53
     54    app.add_directive("kernel-abi", KernelCmd)
     55    return dict(
     56        version = __version__
     57        , parallel_read_safe = True
     58        , parallel_write_safe = True
     59    )
     60
     61class KernelCmd(Directive):
     62
     63    u"""KernelABI (``kernel-abi``) directive"""
     64
     65    required_arguments = 1
     66    optional_arguments = 2
     67    has_content = False
     68    final_argument_whitespace = True
     69
     70    option_spec = {
     71        "debug"     : directives.flag,
     72        "rst"       : directives.unchanged
     73    }
     74
     75    def run(self):
     76
     77        doc = self.state.document
     78        if not doc.settings.file_insertion_enabled:
     79            raise self.warning("docutils: file insertion disabled")
     80
     81        env = doc.settings.env
     82        cwd = path.dirname(doc.current_source)
     83        cmd = "get_abi.pl rest --enable-lineno --dir "
     84        cmd += self.arguments[0]
     85
     86        if 'rst' in self.options:
     87            cmd += " --rst-source"
     88
     89        srctree = path.abspath(os.environ["srctree"])
     90
     91        fname = cmd
     92
     93        # extend PATH with $(srctree)/scripts
     94        path_env = os.pathsep.join([
     95            srctree + os.sep + "scripts",
     96            os.environ["PATH"]
     97        ])
     98        shell_env = os.environ.copy()
     99        shell_env["PATH"]    = path_env
    100        shell_env["srctree"] = srctree
    101
    102        lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
    103        nodeList = self.nestedParse(lines, self.arguments[0])
    104        return nodeList
    105
    106    def runCmd(self, cmd, **kwargs):
    107        u"""Run command ``cmd`` and return its stdout as unicode."""
    108
    109        try:
    110            proc = subprocess.Popen(
    111                cmd
    112                , stdout = subprocess.PIPE
    113                , stderr = subprocess.PIPE
    114                , **kwargs
    115            )
    116            out, err = proc.communicate()
    117
    118            out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
    119
    120            if proc.returncode != 0:
    121                raise self.severe(
    122                    u"command '%s' failed with return code %d"
    123                    % (cmd, proc.returncode)
    124                )
    125        except OSError as exc:
    126            raise self.severe(u"problems with '%s' directive: %s."
    127                              % (self.name, ErrorString(exc)))
    128        return out
    129
    130    def nestedParse(self, lines, fname):
    131        env = self.state.document.settings.env
    132        content = ViewList()
    133        node = nodes.section()
    134
    135        if "debug" in self.options:
    136            code_block = "\n\n.. code-block:: rst\n    :linenos:\n"
    137            for l in lines.split("\n"):
    138                code_block += "\n    " + l
    139            lines = code_block + "\n\n"
    140
    141        line_regex = re.compile("^\.\. LINENO (\S+)\#([0-9]+)$")
    142        ln = 0
    143        n = 0
    144        f = fname
    145
    146        for line in lines.split("\n"):
    147            n = n + 1
    148            match = line_regex.search(line)
    149            if match:
    150                new_f = match.group(1)
    151
    152                # Sphinx parser is lazy: it stops parsing contents in the
    153                # middle, if it is too big. So, handle it per input file
    154                if new_f != f and content:
    155                    self.do_parse(content, node)
    156                    content = ViewList()
    157
    158                    # Add the file to Sphinx build dependencies
    159                    env.note_dependency(os.path.abspath(f))
    160
    161                f = new_f
    162
    163                # sphinx counts lines from 0
    164                ln = int(match.group(2)) - 1
    165            else:
    166                content.append(line, f, ln)
    167
    168        kernellog.info(self.state.document.settings.env.app, "%s: parsed %i lines" % (fname, n))
    169
    170        if content:
    171            self.do_parse(content, node)
    172
    173        return node.children
    174
    175    def do_parse(self, content, node):
    176        with switch_source_input(self.state, content):
    177            self.state.nested_parse(content, 0, node, match_titles=1)