aabbaabb updated this revision to Diff 345329.
aabbaabb added a comment.

put libs in 'lib' folder, 'analyze-*' and 'scan-*' compiler wrappers to 
'libexec', also copy the resources in 'libscanbuild'

Tests:

To install:
DESTDIR=${INSTALL_DIR} ninja install-scan-build-py -j1000

Test at source folder:
PATH=~/llvm-project/build/libexec:~/llvm-project/build/bin:$PATH python -m 
unittest tests.unit
PATH=~/llvm-project/build/libexec:~/llvm-project/build/bin:$PATH python -m 
unittest tests.functional.cases

One error in functional test: test_successful_build_on_empty_env
I think this is intended behavior (clang not found?) since the test sets an 
empty environment for make.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D101139/new/

https://reviews.llvm.org/D101139

Files:
  clang/cmake/caches/Fuchsia-stage2.cmake
  clang/tools/CMakeLists.txt
  clang/tools/scan-build-py/CMakeLists.txt
  clang/tools/scan-build-py/bin/analyze-build
  clang/tools/scan-build-py/bin/analyze-c++
  clang/tools/scan-build-py/bin/analyze-cc
  clang/tools/scan-build-py/bin/intercept-build
  clang/tools/scan-build-py/bin/intercept-c++
  clang/tools/scan-build-py/bin/intercept-cc
  clang/tools/scan-build-py/bin/scan-build
  clang/tools/scan-build-py/lib/libear/__init__.py
  clang/tools/scan-build-py/lib/libear/config.h.in
  clang/tools/scan-build-py/lib/libear/ear.c
  clang/tools/scan-build-py/lib/libscanbuild/__init__.py
  clang/tools/scan-build-py/lib/libscanbuild/analyze.py
  clang/tools/scan-build-py/lib/libscanbuild/arguments.py
  clang/tools/scan-build-py/lib/libscanbuild/clang.py
  clang/tools/scan-build-py/lib/libscanbuild/compilation.py
  clang/tools/scan-build-py/lib/libscanbuild/intercept.py
  clang/tools/scan-build-py/lib/libscanbuild/report.py
  clang/tools/scan-build-py/lib/libscanbuild/resources/scanview.css
  clang/tools/scan-build-py/lib/libscanbuild/resources/selectable.js
  clang/tools/scan-build-py/lib/libscanbuild/resources/sorttable.js
  clang/tools/scan-build-py/lib/libscanbuild/shell.py
  clang/tools/scan-build-py/libear/__init__.py
  clang/tools/scan-build-py/libear/config.h.in
  clang/tools/scan-build-py/libear/ear.c
  clang/tools/scan-build-py/libexec/analyze-c++
  clang/tools/scan-build-py/libexec/analyze-cc
  clang/tools/scan-build-py/libexec/intercept-c++
  clang/tools/scan-build-py/libexec/intercept-cc
  clang/tools/scan-build-py/libscanbuild/__init__.py
  clang/tools/scan-build-py/libscanbuild/analyze.py
  clang/tools/scan-build-py/libscanbuild/arguments.py
  clang/tools/scan-build-py/libscanbuild/clang.py
  clang/tools/scan-build-py/libscanbuild/compilation.py
  clang/tools/scan-build-py/libscanbuild/intercept.py
  clang/tools/scan-build-py/libscanbuild/report.py
  clang/tools/scan-build-py/libscanbuild/resources/scanview.css
  clang/tools/scan-build-py/libscanbuild/resources/selectable.js
  clang/tools/scan-build-py/libscanbuild/resources/sorttable.js
  clang/tools/scan-build-py/libscanbuild/shell.py
  clang/tools/scan-build-py/tests/__init__.py
  clang/tools/scan-build-py/tests/functional/cases/__init__.py
  clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
  clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
  clang/tools/scan-build-py/tests/unit/test_analyze.py

Index: clang/tools/scan-build-py/tests/unit/test_analyze.py
===================================================================
--- clang/tools/scan-build-py/tests/unit/test_analyze.py
+++ clang/tools/scan-build-py/tests/unit/test_analyze.py
@@ -18,9 +18,9 @@
     # scan-build can be easily matched up to compare results.
     def test_directory_name_comparison(self):
         with libear.TemporaryDirectory() as tmpdir, \
-             sut.report_directory(tmpdir, False) as report_dir1, \
-             sut.report_directory(tmpdir, False) as report_dir2, \
-             sut.report_directory(tmpdir, False) as report_dir3:
+             sut.report_directory(tmpdir, False, 'html') as report_dir1, \
+             sut.report_directory(tmpdir, False, 'html') as report_dir2, \
+             sut.report_directory(tmpdir, False, 'html') as report_dir3:
             self.assertLess(report_dir1, report_dir2)
             self.assertLess(report_dir2, report_dir3)
 
Index: clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
===================================================================
--- clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
+++ clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
@@ -15,7 +15,7 @@
 def prepare_cdb(name, target_dir):
     target_file = 'build_{0}.json'.format(name)
     this_dir, _ = os.path.split(__file__)
-    path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+    path = os.path.abspath(os.path.join(this_dir, '..', 'src'))
     source_dir = os.path.join(path, 'compilation_database')
     source_file = os.path.join(source_dir, target_file + '.in')
     target_file = os.path.join(target_dir, 'compile_commands.json')
Index: clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
===================================================================
--- clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
+++ clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
@@ -43,7 +43,7 @@
 
     def test_all_exec_calls(self):
         this_dir, _ = os.path.split(__file__)
-        source_dir = os.path.normpath(os.path.join(this_dir, '..', 'exec'))
+        source_dir = os.path.abspath(os.path.join(this_dir, '..', 'exec'))
         with libear.TemporaryDirectory() as tmp_dir:
             expected, result = run(source_dir, tmp_dir)
             self.assertEqualJson(expected, result)
Index: clang/tools/scan-build-py/tests/functional/cases/__init__.py
===================================================================
--- clang/tools/scan-build-py/tests/functional/cases/__init__.py
+++ clang/tools/scan-build-py/tests/functional/cases/__init__.py
@@ -22,7 +22,7 @@
 
 def make_args(target):
     this_dir, _ = os.path.split(__file__)
-    path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+    path = os.path.abspath(os.path.join(this_dir, '..', 'src'))
     return ['make', 'SRCDIR={}'.format(path), 'OBJDIR={}'.format(target), '-f',
             os.path.join(path, 'build', 'Makefile')]
 
Index: clang/tools/scan-build-py/tests/__init__.py
===================================================================
--- clang/tools/scan-build-py/tests/__init__.py
+++ clang/tools/scan-build-py/tests/__init__.py
@@ -3,6 +3,12 @@
 # See https://llvm.org/LICENSE.txt for license information.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
+import os
+import sys
+
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
+
 import unittest
 
 import tests.unit
Index: clang/tools/scan-build-py/libscanbuild/resources/sorttable.js
===================================================================
--- clang/tools/scan-build-py/libscanbuild/resources/sorttable.js
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
-  SortTable
-  version 2
-  7th April 2007
-  Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
-
-  Instructions:
-  Download this file
-  Add <script src="sorttable.js"></script> to your HTML
-  Add class="sortable" to any table you'd like to make sortable
-  Click on the headers to sort
-
-  Thanks to many, many people for contributions and suggestions.
-  Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
-  This basically means: do what you want with it.
-*/
-
-
-var stIsIE = /*@cc_on!@*/false;
-
-sorttable = {
-  init: function() {
-    // quit if this function has already been called
-    if (arguments.callee.done) return;
-    // flag this function so we don't do the same thing twice
-    arguments.callee.done = true;
-    // kill the timer
-    if (_timer) clearInterval(_timer);
-
-    if (!document.createElement || !document.getElementsByTagName) return;
-
-    sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
-
-    forEach(document.getElementsByTagName('table'), function(table) {
-      if (table.className.search(/\bsortable\b/) != -1) {
-        sorttable.makeSortable(table);
-      }
-    });
-
-  },
-
-  makeSortable: function(table) {
-    if (table.getElementsByTagName('thead').length == 0) {
-      // table doesn't have a tHead. Since it should have, create one and
-      // put the first table row in it.
-      the = document.createElement('thead');
-      the.appendChild(table.rows[0]);
-      table.insertBefore(the,table.firstChild);
-    }
-    // Safari doesn't support table.tHead, sigh
-    if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
-
-    if (table.tHead.rows.length != 1) return; // can't cope with two header rows
-
-    // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
-    // "total" rows, for example). This is B&R, since what you're supposed
-    // to do is put them in a tfoot. So, if there are sortbottom rows,
-    // for backward compatibility, move them to tfoot (creating it if needed).
-    sortbottomrows = [];
-    for (var i=0; i<table.rows.length; i++) {
-      if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
-        sortbottomrows[sortbottomrows.length] = table.rows[i];
-      }
-    }
-    if (sortbottomrows) {
-      if (table.tFoot == null) {
-        // table doesn't have a tfoot. Create one.
-        tfo = document.createElement('tfoot');
-        table.appendChild(tfo);
-      }
-      for (var i=0; i<sortbottomrows.length; i++) {
-        tfo.appendChild(sortbottomrows[i]);
-      }
-      delete sortbottomrows;
-    }
-
-    // work through each column and calculate its type
-    headrow = table.tHead.rows[0].cells;
-    for (var i=0; i<headrow.length; i++) {
-      // manually override the type with a sorttable_type attribute
-      if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
-        mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
-        if (mtch) { override = mtch[1]; }
-	      if (mtch && typeof sorttable["sort_"+override] == 'function') {
-	        headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
-	      } else {
-	        headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
-	      }
-	      // make it clickable to sort
-	      headrow[i].sorttable_columnindex = i;
-	      headrow[i].sorttable_tbody = table.tBodies[0];
-	      dean_addEvent(headrow[i],"click", function(e) {
-
-          if (this.className.search(/\bsorttable_sorted\b/) != -1) {
-            // if we're already sorted by this column, just
-            // reverse the table, which is quicker
-            sorttable.reverse(this.sorttable_tbody);
-            this.className = this.className.replace('sorttable_sorted',
-                                                    'sorttable_sorted_reverse');
-            this.removeChild(document.getElementById('sorttable_sortfwdind'));
-            sortrevind = document.createElement('span');
-            sortrevind.id = "sorttable_sortrevind";
-            sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
-            this.appendChild(sortrevind);
-            return;
-          }
-          if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
-            // if we're already sorted by this column in reverse, just
-            // re-reverse the table, which is quicker
-            sorttable.reverse(this.sorttable_tbody);
-            this.className = this.className.replace('sorttable_sorted_reverse',
-                                                    'sorttable_sorted');
-            this.removeChild(document.getElementById('sorttable_sortrevind'));
-            sortfwdind = document.createElement('span');
-            sortfwdind.id = "sorttable_sortfwdind";
-            sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
-            this.appendChild(sortfwdind);
-            return;
-          }
-
-          // remove sorttable_sorted classes
-          theadrow = this.parentNode;
-          forEach(theadrow.childNodes, function(cell) {
-            if (cell.nodeType == 1) { // an element
-              cell.className = cell.className.replace('sorttable_sorted_reverse','');
-              cell.className = cell.className.replace('sorttable_sorted','');
-            }
-          });
-          sortfwdind = document.getElementById('sorttable_sortfwdind');
-          if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
-          sortrevind = document.getElementById('sorttable_sortrevind');
-          if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
-
-          this.className += ' sorttable_sorted';
-          sortfwdind = document.createElement('span');
-          sortfwdind.id = "sorttable_sortfwdind";
-          sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
-          this.appendChild(sortfwdind);
-
-	        // build an array to sort. This is a Schwartzian transform thing,
-	        // i.e., we "decorate" each row with the actual sort key,
-	        // sort based on the sort keys, and then put the rows back in order
-	        // which is a lot faster because you only do getInnerText once per row
-	        row_array = [];
-	        col = this.sorttable_columnindex;
-	        rows = this.sorttable_tbody.rows;
-	        for (var j=0; j<rows.length; j++) {
-	          row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
-	        }
-	        /* If you want a stable sort, uncomment the following line */
-	        sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
-	        /* and comment out this one */
-	        //row_array.sort(this.sorttable_sortfunction);
-
-	        tb = this.sorttable_tbody;
-	        for (var j=0; j<row_array.length; j++) {
-	          tb.appendChild(row_array[j][1]);
-	        }
-
-	        delete row_array;
-	      });
-	    }
-    }
-  },
-
-  guessType: function(table, column) {
-    // guess the type of a column based on its first non-blank row
-    sortfn = sorttable.sort_alpha;
-    for (var i=0; i<table.tBodies[0].rows.length; i++) {
-      text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
-      if (text != '') {
-        if (text.match(/^-?[」$、]?[\d,.]+%?$/)) {
-          return sorttable.sort_numeric;
-        }
-        // check for a date: dd/mm/yyyy or dd/mm/yy
-        // can have / or . or - as separator
-        // can be mm/dd as well
-        possdate = text.match(sorttable.DATE_RE)
-        if (possdate) {
-          // looks like a date
-          first = parseInt(possdate[1]);
-          second = parseInt(possdate[2]);
-          if (first > 12) {
-            // definitely dd/mm
-            return sorttable.sort_ddmm;
-          } else if (second > 12) {
-            return sorttable.sort_mmdd;
-          } else {
-            // looks like a date, but we can't tell which, so assume
-            // that it's dd/mm (English imperialism!) and keep looking
-            sortfn = sorttable.sort_ddmm;
-          }
-        }
-      }
-    }
-    return sortfn;
-  },
-
-  getInnerText: function(node) {
-    // gets the text we want to use for sorting for a cell.
-    // strips leading and trailing whitespace.
-    // this is *not* a generic getInnerText function; it's special to sorttable.
-    // for example, you can override the cell text with a customkey attribute.
-    // it also gets .value for <input> fields.
-
-    hasInputs = (typeof node.getElementsByTagName == 'function') &&
-                 node.getElementsByTagName('input').length;
-
-    if (node.getAttribute("sorttable_customkey") != null) {
-      return node.getAttribute("sorttable_customkey");
-    }
-    else if (typeof node.textContent != 'undefined' && !hasInputs) {
-      return node.textContent.replace(/^\s+|\s+$/g, '');
-    }
-    else if (typeof node.innerText != 'undefined' && !hasInputs) {
-      return node.innerText.replace(/^\s+|\s+$/g, '');
-    }
-    else if (typeof node.text != 'undefined' && !hasInputs) {
-      return node.text.replace(/^\s+|\s+$/g, '');
-    }
-    else {
-      switch (node.nodeType) {
-        case 3:
-          if (node.nodeName.toLowerCase() == 'input') {
-            return node.value.replace(/^\s+|\s+$/g, '');
-          }
-        case 4:
-          return node.nodeValue.replace(/^\s+|\s+$/g, '');
-          break;
-        case 1:
-        case 11:
-          var innerText = '';
-          for (var i = 0; i < node.childNodes.length; i++) {
-            innerText += sorttable.getInnerText(node.childNodes[i]);
-          }
-          return innerText.replace(/^\s+|\s+$/g, '');
-          break;
-        default:
-          return '';
-      }
-    }
-  },
-
-  reverse: function(tbody) {
-    // reverse the rows in a tbody
-    newrows = [];
-    for (var i=0; i<tbody.rows.length; i++) {
-      newrows[newrows.length] = tbody.rows[i];
-    }
-    for (var i=newrows.length-1; i>=0; i--) {
-       tbody.appendChild(newrows[i]);
-    }
-    delete newrows;
-  },
-
-  /* sort functions
-     each sort function takes two parameters, a and b
-     you are comparing a[0] and b[0] */
-  sort_numeric: function(a,b) {
-    aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
-    if (isNaN(aa)) aa = 0;
-    bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
-    if (isNaN(bb)) bb = 0;
-    return aa-bb;
-  },
-  sort_alpha: function(a,b) {
-    if (a[0]==b[0]) return 0;
-    if (a[0]<b[0]) return -1;
-    return 1;
-  },
-  sort_ddmm: function(a,b) {
-    mtch = a[0].match(sorttable.DATE_RE);
-    y = mtch[3]; m = mtch[2]; d = mtch[1];
-    if (m.length == 1) m = '0'+m;
-    if (d.length == 1) d = '0'+d;
-    dt1 = y+m+d;
-    mtch = b[0].match(sorttable.DATE_RE);
-    y = mtch[3]; m = mtch[2]; d = mtch[1];
-    if (m.length == 1) m = '0'+m;
-    if (d.length == 1) d = '0'+d;
-    dt2 = y+m+d;
-    if (dt1==dt2) return 0;
-    if (dt1<dt2) return -1;
-    return 1;
-  },
-  sort_mmdd: function(a,b) {
-    mtch = a[0].match(sorttable.DATE_RE);
-    y = mtch[3]; d = mtch[2]; m = mtch[1];
-    if (m.length == 1) m = '0'+m;
-    if (d.length == 1) d = '0'+d;
-    dt1 = y+m+d;
-    mtch = b[0].match(sorttable.DATE_RE);
-    y = mtch[3]; d = mtch[2]; m = mtch[1];
-    if (m.length == 1) m = '0'+m;
-    if (d.length == 1) d = '0'+d;
-    dt2 = y+m+d;
-    if (dt1==dt2) return 0;
-    if (dt1<dt2) return -1;
-    return 1;
-  },
-
-  shaker_sort: function(list, comp_func) {
-    // A stable sort function to allow multi-level sorting of data
-    // see: http://en.wikipedia.org/wiki/Cocktail_sort
-    // thanks to Joseph Nahmias
-    var b = 0;
-    var t = list.length - 1;
-    var swap = true;
-
-    while(swap) {
-        swap = false;
-        for(var i = b; i < t; ++i) {
-            if ( comp_func(list[i], list[i+1]) > 0 ) {
-                var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
-                swap = true;
-            }
-        } // for
-        t--;
-
-        if (!swap) break;
-
-        for(var i = t; i > b; --i) {
-            if ( comp_func(list[i], list[i-1]) < 0 ) {
-                var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
-                swap = true;
-            }
-        } // for
-        b++;
-
-    } // while(swap)
-  }
-}
-
-/* ******************************************************************
-   Supporting functions: bundled here to avoid depending on a library
-   ****************************************************************** */
-
-// Dean Edwards/Matthias Miller/John Resig
-
-/* for Mozilla/Opera9 */
-if (document.addEventListener) {
-    document.addEventListener("DOMContentLoaded", sorttable.init, false);
-}
-
-/* for Internet Explorer */
-/*@cc_on @*/
-/*@if (@_win32)
-    document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
-    var script = document.getElementById("__ie_onload");
-    script.onreadystatechange = function() {
-        if (this.readyState == "complete") {
-            sorttable.init(); // call the onload handler
-        }
-    };
-/*@end @*/
-
-/* for Safari */
-if (/WebKit/i.test(navigator.userAgent)) { // sniff
-    var _timer = setInterval(function() {
-        if (/loaded|complete/.test(document.readyState)) {
-            sorttable.init(); // call the onload handler
-        }
-    }, 10);
-}
-
-/* for other browsers */
-window.onload = sorttable.init;
-
-// written by Dean Edwards, 2005
-// with input from Tino Zijdel, Matthias Miller, Diego Perini
-
-// http://dean.edwards.name/weblog/2005/10/add-event/
-
-function dean_addEvent(element, type, handler) {
-	if (element.addEventListener) {
-		element.addEventListener(type, handler, false);
-	} else {
-		// assign each event handler a unique ID
-		if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
-		// create a hash table of event types for the element
-		if (!element.events) element.events = {};
-		// create a hash table of event handlers for each element/event pair
-		var handlers = element.events[type];
-		if (!handlers) {
-			handlers = element.events[type] = {};
-			// store the existing event handler (if there is one)
-			if (element["on" + type]) {
-				handlers[0] = element["on" + type];
-			}
-		}
-		// store the event handler in the hash table
-		handlers[handler.$$guid] = handler;
-		// assign a global event handler to do all the work
-		element["on" + type] = handleEvent;
-	}
-};
-// a counter used to create unique IDs
-dean_addEvent.guid = 1;
-
-function removeEvent(element, type, handler) {
-	if (element.removeEventListener) {
-		element.removeEventListener(type, handler, false);
-	} else {
-		// delete the event handler from the hash table
-		if (element.events && element.events[type]) {
-			delete element.events[type][handler.$$guid];
-		}
-	}
-};
-
-function handleEvent(event) {
-	var returnValue = true;
-	// grab the event object (IE uses a global event object)
-	event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
-	// get a reference to the hash table of event handlers
-	var handlers = this.events[event.type];
-	// execute each event handler
-	for (var i in handlers) {
-		this.$$handleEvent = handlers[i];
-		if (this.$$handleEvent(event) === false) {
-			returnValue = false;
-		}
-	}
-	return returnValue;
-};
-
-function fixEvent(event) {
-	// add W3C standard event methods
-	event.preventDefault = fixEvent.preventDefault;
-	event.stopPropagation = fixEvent.stopPropagation;
-	return event;
-};
-fixEvent.preventDefault = function() {
-	this.returnValue = false;
-};
-fixEvent.stopPropagation = function() {
-  this.cancelBubble = true;
-}
-
-// Dean's forEach: http://dean.edwards.name/base/forEach.js
-/*
-	forEach, version 1.0
-	Copyright 2006, Dean Edwards
-	License: http://www.opensource.org/licenses/mit-license.php
-*/
-
-// array-like enumeration
-if (!Array.forEach) { // mozilla already supports this
-	Array.forEach = function(array, block, context) {
-		for (var i = 0; i < array.length; i++) {
-			block.call(context, array[i], i, array);
-		}
-	};
-}
-
-// generic enumeration
-Function.prototype.forEach = function(object, block, context) {
-	for (var key in object) {
-		if (typeof this.prototype[key] == "undefined") {
-			block.call(context, object[key], key, object);
-		}
-	}
-};
-
-// character enumeration
-String.forEach = function(string, block, context) {
-	Array.forEach(string.split(""), function(chr, index) {
-		block.call(context, chr, index, string);
-	});
-};
-
-// globally resolve forEach enumeration
-var forEach = function(object, block, context) {
-	if (object) {
-		var resolve = Object; // default
-		if (object instanceof Function) {
-			// functions have a "length" property
-			resolve = Function;
-		} else if (object.forEach instanceof Function) {
-			// the object implements a custom forEach method so use that
-			object.forEach(block, context);
-			return;
-		} else if (typeof object == "string") {
-			// the object is a string
-			resolve = String;
-		} else if (typeof object.length == "number") {
-			// the object is array-like
-			resolve = Array;
-		}
-		resolve.forEach(object, block, context);
-	}
-};
Index: clang/tools/scan-build-py/libexec/intercept-cc
===================================================================
--- clang/tools/scan-build-py/libexec/intercept-cc
+++ clang/tools/scan-build-py/libexec/intercept-cc
@@ -7,7 +7,7 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.intercept import intercept_compiler_wrapper
 sys.exit(intercept_compiler_wrapper())
Index: clang/tools/scan-build-py/libexec/intercept-c++
===================================================================
--- clang/tools/scan-build-py/libexec/intercept-c++
+++ clang/tools/scan-build-py/libexec/intercept-c++
@@ -7,7 +7,7 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.intercept import intercept_compiler_wrapper
 sys.exit(intercept_compiler_wrapper())
Index: clang/tools/scan-build-py/libexec/analyze-cc
===================================================================
--- clang/tools/scan-build-py/libexec/analyze-cc
+++ clang/tools/scan-build-py/libexec/analyze-cc
@@ -7,7 +7,7 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.analyze import analyze_compiler_wrapper
 sys.exit(analyze_compiler_wrapper())
Index: clang/tools/scan-build-py/libexec/analyze-c++
===================================================================
--- clang/tools/scan-build-py/libexec/analyze-c++
+++ clang/tools/scan-build-py/libexec/analyze-c++
@@ -7,7 +7,8 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
+
 
 from libscanbuild.analyze import analyze_compiler_wrapper
 sys.exit(analyze_compiler_wrapper())
Index: clang/tools/scan-build-py/libear/ear.c
===================================================================
--- clang/tools/scan-build-py/libear/ear.c
+++ /dev/null
@@ -1,604 +0,0 @@
-/* -*- coding: utf-8 -*-
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-*/
-
-/**
- * This file implements a shared library. This library can be pre-loaded by
- * the dynamic linker of the Operating System (OS). It implements a few function
- * related to process creation. By pre-load this library the executed process
- * uses these functions instead of those from the standard library.
- *
- * The idea here is to inject a logic before call the real methods. The logic is
- * to dump the call into a file. To call the real method this library is doing
- * the job of the dynamic linker.
- *
- * The only input for the log writing is about the destination directory.
- * This is passed as environment variable.
- */
-
-#include "config.h"
-
-#include <stddef.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <dlfcn.h>
-#include <pthread.h>
-
-#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
-#include <spawn.h>
-#endif
-
-#if defined HAVE_NSGETENVIRON
-# include <crt_externs.h>
-#else
-extern char **environ;
-#endif
-
-#define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
-#ifdef APPLE
-# define ENV_FLAT    "DYLD_FORCE_FLAT_NAMESPACE"
-# define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
-# define ENV_SIZE 3
-#else
-# define ENV_PRELOAD "LD_PRELOAD"
-# define ENV_SIZE 2
-#endif
-
-#define DLSYM(TYPE_, VAR_, SYMBOL_)                                            \
-    union {                                                                    \
-        void *from;                                                            \
-        TYPE_ to;                                                              \
-    } cast;                                                                    \
-    if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) {                        \
-        perror("bear: dlsym");                                                 \
-        exit(EXIT_FAILURE);                                                    \
-    }                                                                          \
-    TYPE_ const VAR_ = cast.to;
-
-
-typedef char const * bear_env_t[ENV_SIZE];
-
-static int bear_capture_env_t(bear_env_t *env);
-static int bear_reset_env_t(bear_env_t *env);
-static void bear_release_env_t(bear_env_t *env);
-static char const **bear_update_environment(char *const envp[], bear_env_t *env);
-static char const **bear_update_environ(char const **in, char const *key, char const *value);
-static char **bear_get_environment();
-static void bear_report_call(char const *fun, char const *const argv[]);
-static char const **bear_strings_build(char const *arg, va_list *ap);
-static char const **bear_strings_copy(char const **const in);
-static char const **bear_strings_append(char const **in, char const *e);
-static size_t bear_strings_length(char const *const *in);
-static void bear_strings_release(char const **);
-
-
-static bear_env_t env_names =
-    { ENV_OUTPUT
-    , ENV_PRELOAD
-#ifdef ENV_FLAT
-    , ENV_FLAT
-#endif
-    };
-
-static bear_env_t initial_env =
-    { 0
-    , 0
-#ifdef ENV_FLAT
-    , 0
-#endif
-    };
-
-static int initialized = 0;
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void on_load(void) __attribute__((constructor));
-static void on_unload(void) __attribute__((destructor));
-
-
-#ifdef HAVE_EXECVE
-static int call_execve(const char *path, char *const argv[],
-                       char *const envp[]);
-#endif
-#ifdef HAVE_EXECVP
-static int call_execvp(const char *file, char *const argv[]);
-#endif
-#ifdef HAVE_EXECVPE
-static int call_execvpe(const char *file, char *const argv[],
-                        char *const envp[]);
-#endif
-#ifdef HAVE_EXECVP2
-static int call_execvP(const char *file, const char *search_path,
-                       char *const argv[]);
-#endif
-#ifdef HAVE_EXECT
-static int call_exect(const char *path, char *const argv[],
-                      char *const envp[]);
-#endif
-#ifdef HAVE_POSIX_SPAWN
-static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
-                            const posix_spawn_file_actions_t *file_actions,
-                            const posix_spawnattr_t *restrict attrp,
-                            char *const argv[restrict],
-                            char *const envp[restrict]);
-#endif
-#ifdef HAVE_POSIX_SPAWNP
-static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
-                             const posix_spawn_file_actions_t *file_actions,
-                             const posix_spawnattr_t *restrict attrp,
-                             char *const argv[restrict],
-                             char *const envp[restrict]);
-#endif
-
-
-/* Initialization method to Captures the relevant environment variables.
- */
-
-static void on_load(void) {
-    pthread_mutex_lock(&mutex);
-    if (!initialized)
-        initialized = bear_capture_env_t(&initial_env);
-    pthread_mutex_unlock(&mutex);
-}
-
-static void on_unload(void) {
-    pthread_mutex_lock(&mutex);
-    bear_release_env_t(&initial_env);
-    initialized = 0;
-    pthread_mutex_unlock(&mutex);
-}
-
-
-/* These are the methods we are try to hijack.
- */
-
-#ifdef HAVE_EXECVE
-int execve(const char *path, char *const argv[], char *const envp[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_execve(path, argv, envp);
-}
-#endif
-
-#ifdef HAVE_EXECV
-#ifndef HAVE_EXECVE
-#error can not implement execv without execve
-#endif
-int execv(const char *path, char *const argv[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    char * const * envp = bear_get_environment();
-    return call_execve(path, argv, envp);
-}
-#endif
-
-#ifdef HAVE_EXECVPE
-int execvpe(const char *file, char *const argv[], char *const envp[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_execvpe(file, argv, envp);
-}
-#endif
-
-#ifdef HAVE_EXECVP
-int execvp(const char *file, char *const argv[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_execvp(file, argv);
-}
-#endif
-
-#ifdef HAVE_EXECVP2
-int execvP(const char *file, const char *search_path, char *const argv[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_execvP(file, search_path, argv);
-}
-#endif
-
-#ifdef HAVE_EXECT
-int exect(const char *path, char *const argv[], char *const envp[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_exect(path, argv, envp);
-}
-#endif
-
-#ifdef HAVE_EXECL
-# ifndef HAVE_EXECVE
-#  error can not implement execl without execve
-# endif
-int execl(const char *path, const char *arg, ...) {
-    va_list args;
-    va_start(args, arg);
-    char const **argv = bear_strings_build(arg, &args);
-    va_end(args);
-
-    bear_report_call(__func__, (char const *const *)argv);
-    char * const * envp = bear_get_environment();
-    int const result = call_execve(path, (char *const *)argv, envp);
-
-    bear_strings_release(argv);
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECLP
-# ifndef HAVE_EXECVP
-#  error can not implement execlp without execvp
-# endif
-int execlp(const char *file, const char *arg, ...) {
-    va_list args;
-    va_start(args, arg);
-    char const **argv = bear_strings_build(arg, &args);
-    va_end(args);
-
-    bear_report_call(__func__, (char const *const *)argv);
-    int const result = call_execvp(file, (char *const *)argv);
-
-    bear_strings_release(argv);
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECLE
-# ifndef HAVE_EXECVE
-#  error can not implement execle without execve
-# endif
-// int execle(const char *path, const char *arg, ..., char * const envp[]);
-int execle(const char *path, const char *arg, ...) {
-    va_list args;
-    va_start(args, arg);
-    char const **argv = bear_strings_build(arg, &args);
-    char const **envp = va_arg(args, char const **);
-    va_end(args);
-
-    bear_report_call(__func__, (char const *const *)argv);
-    int const result =
-        call_execve(path, (char *const *)argv, (char *const *)envp);
-
-    bear_strings_release(argv);
-    return result;
-}
-#endif
-
-#ifdef HAVE_POSIX_SPAWN
-int posix_spawn(pid_t *restrict pid, const char *restrict path,
-                const posix_spawn_file_actions_t *file_actions,
-                const posix_spawnattr_t *restrict attrp,
-                char *const argv[restrict], char *const envp[restrict]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
-}
-#endif
-
-#ifdef HAVE_POSIX_SPAWNP
-int posix_spawnp(pid_t *restrict pid, const char *restrict file,
-                 const posix_spawn_file_actions_t *file_actions,
-                 const posix_spawnattr_t *restrict attrp,
-                 char *const argv[restrict], char *const envp[restrict]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
-}
-#endif
-
-/* These are the methods which forward the call to the standard implementation.
- */
-
-#ifdef HAVE_EXECVE
-static int call_execve(const char *path, char *const argv[],
-                       char *const envp[]) {
-    typedef int (*func)(const char *, char *const *, char *const *);
-
-    DLSYM(func, fp, "execve");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result = (*fp)(path, argv, (char *const *)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECVPE
-static int call_execvpe(const char *file, char *const argv[],
-                        char *const envp[]) {
-    typedef int (*func)(const char *, char *const *, char *const *);
-
-    DLSYM(func, fp, "execvpe");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result = (*fp)(file, argv, (char *const *)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECVP
-static int call_execvp(const char *file, char *const argv[]) {
-    typedef int (*func)(const char *file, char *const argv[]);
-
-    DLSYM(func, fp, "execvp");
-
-    bear_env_t current_env;
-    bear_capture_env_t(&current_env);
-    bear_reset_env_t(&initial_env);
-    int const result = (*fp)(file, argv);
-    bear_reset_env_t(&current_env);
-    bear_release_env_t(&current_env);
-
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECVP2
-static int call_execvP(const char *file, const char *search_path,
-                       char *const argv[]) {
-    typedef int (*func)(const char *, const char *, char *const *);
-
-    DLSYM(func, fp, "execvP");
-
-    bear_env_t current_env;
-    bear_capture_env_t(&current_env);
-    bear_reset_env_t(&initial_env);
-    int const result = (*fp)(file, search_path, argv);
-    bear_reset_env_t(&current_env);
-    bear_release_env_t(&current_env);
-
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECT
-static int call_exect(const char *path, char *const argv[],
-                      char *const envp[]) {
-    typedef int (*func)(const char *, char *const *, char *const *);
-
-    DLSYM(func, fp, "exect");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result = (*fp)(path, argv, (char *const *)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-#ifdef HAVE_POSIX_SPAWN
-static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
-                            const posix_spawn_file_actions_t *file_actions,
-                            const posix_spawnattr_t *restrict attrp,
-                            char *const argv[restrict],
-                            char *const envp[restrict]) {
-    typedef int (*func)(pid_t *restrict, const char *restrict,
-                        const posix_spawn_file_actions_t *,
-                        const posix_spawnattr_t *restrict,
-                        char *const *restrict, char *const *restrict);
-
-    DLSYM(func, fp, "posix_spawn");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result =
-        (*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-#ifdef HAVE_POSIX_SPAWNP
-static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
-                             const posix_spawn_file_actions_t *file_actions,
-                             const posix_spawnattr_t *restrict attrp,
-                             char *const argv[restrict],
-                             char *const envp[restrict]) {
-    typedef int (*func)(pid_t *restrict, const char *restrict,
-                        const posix_spawn_file_actions_t *,
-                        const posix_spawnattr_t *restrict,
-                        char *const *restrict, char *const *restrict);
-
-    DLSYM(func, fp, "posix_spawnp");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result =
-        (*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-/* this method is to write log about the process creation. */
-
-static void bear_report_call(char const *fun, char const *const argv[]) {
-    static int const GS = 0x1d;
-    static int const RS = 0x1e;
-    static int const US = 0x1f;
-
-    if (!initialized)
-        return;
-
-    pthread_mutex_lock(&mutex);
-    const char *cwd = getcwd(NULL, 0);
-    if (0 == cwd) {
-        perror("bear: getcwd");
-        exit(EXIT_FAILURE);
-    }
-    char const * const out_dir = initial_env[0];
-    size_t const path_max_length = strlen(out_dir) + 32;
-    char filename[path_max_length];
-    if (-1 == snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
-        perror("bear: snprintf");
-        exit(EXIT_FAILURE);
-    }
-    FILE * fd = fopen(filename, "a+");
-    if (0 == fd) {
-        perror("bear: fopen");
-        exit(EXIT_FAILURE);
-    }
-    fprintf(fd, "%d%c", getpid(), RS);
-    fprintf(fd, "%d%c", getppid(), RS);
-    fprintf(fd, "%s%c", fun, RS);
-    fprintf(fd, "%s%c", cwd, RS);
-    size_t const argc = bear_strings_length(argv);
-    for (size_t it = 0; it < argc; ++it) {
-        fprintf(fd, "%s%c", argv[it], US);
-    }
-    fprintf(fd, "%c", GS);
-    if (fclose(fd)) {
-        perror("bear: fclose");
-        exit(EXIT_FAILURE);
-    }
-    free((void *)cwd);
-    pthread_mutex_unlock(&mutex);
-}
-
-/* update environment assure that chilren processes will copy the desired
- * behaviour */
-
-static int bear_capture_env_t(bear_env_t *env) {
-    int status = 1;
-    for (size_t it = 0; it < ENV_SIZE; ++it) {
-        char const * const env_value = getenv(env_names[it]);
-        char const * const env_copy = (env_value) ? strdup(env_value) : env_value;
-        (*env)[it] = env_copy;
-        status &= (env_copy) ? 1 : 0;
-    }
-    return status;
-}
-
-static int bear_reset_env_t(bear_env_t *env) {
-    int status = 1;
-    for (size_t it = 0; it < ENV_SIZE; ++it) {
-        if ((*env)[it]) {
-            setenv(env_names[it], (*env)[it], 1);
-        } else {
-            unsetenv(env_names[it]);
-        }
-    }
-    return status;
-}
-
-static void bear_release_env_t(bear_env_t *env) {
-    for (size_t it = 0; it < ENV_SIZE; ++it) {
-        free((void *)(*env)[it]);
-        (*env)[it] = 0;
-    }
-}
-
-static char const **bear_update_environment(char *const envp[], bear_env_t *env) {
-    char const **result = bear_strings_copy((char const **)envp);
-    for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
-        result = bear_update_environ(result, env_names[it], (*env)[it]);
-    return result;
-}
-
-static char const **bear_update_environ(char const *envs[], char const *key, char const * const value) {
-    // find the key if it's there
-    size_t const key_length = strlen(key);
-    char const **it = envs;
-    for (; (it) && (*it); ++it) {
-        if ((0 == strncmp(*it, key, key_length)) &&
-            (strlen(*it) > key_length) && ('=' == (*it)[key_length]))
-            break;
-    }
-    // allocate a environment entry
-    size_t const value_length = strlen(value);
-    size_t const env_length = key_length + value_length + 2;
-    char *env = malloc(env_length);
-    if (0 == env) {
-        perror("bear: malloc [in env_update]");
-        exit(EXIT_FAILURE);
-    }
-    if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
-        perror("bear: snprintf");
-        exit(EXIT_FAILURE);
-    }
-    // replace or append the environment entry
-    if (it && *it) {
-        free((void *)*it);
-        *it = env;
-	return envs;
-    }
-    return bear_strings_append(envs, env);
-}
-
-static char **bear_get_environment() {
-#if defined HAVE_NSGETENVIRON
-    return *_NSGetEnviron();
-#else
-    return environ;
-#endif
-}
-
-/* util methods to deal with string arrays. environment and process arguments
- * are both represented as string arrays. */
-
-static char const **bear_strings_build(char const *const arg, va_list *args) {
-    char const **result = 0;
-    size_t size = 0;
-    for (char const *it = arg; it; it = va_arg(*args, char const *)) {
-        result = realloc(result, (size + 1) * sizeof(char const *));
-        if (0 == result) {
-            perror("bear: realloc");
-            exit(EXIT_FAILURE);
-        }
-        char const *copy = strdup(it);
-        if (0 == copy) {
-            perror("bear: strdup");
-            exit(EXIT_FAILURE);
-        }
-        result[size++] = copy;
-    }
-    result = realloc(result, (size + 1) * sizeof(char const *));
-    if (0 == result) {
-        perror("bear: realloc");
-        exit(EXIT_FAILURE);
-    }
-    result[size++] = 0;
-
-    return result;
-}
-
-static char const **bear_strings_copy(char const **const in) {
-    size_t const size = bear_strings_length(in);
-
-    char const **const result = malloc((size + 1) * sizeof(char const *));
-    if (0 == result) {
-        perror("bear: malloc");
-        exit(EXIT_FAILURE);
-    }
-
-    char const **out_it = result;
-    for (char const *const *in_it = in; (in_it) && (*in_it);
-         ++in_it, ++out_it) {
-        *out_it = strdup(*in_it);
-        if (0 == *out_it) {
-            perror("bear: strdup");
-            exit(EXIT_FAILURE);
-        }
-    }
-    *out_it = 0;
-    return result;
-}
-
-static char const **bear_strings_append(char const **const in,
-                                        char const *const e) {
-    size_t size = bear_strings_length(in);
-    char const **result = realloc(in, (size + 2) * sizeof(char const *));
-    if (0 == result) {
-        perror("bear: realloc");
-        exit(EXIT_FAILURE);
-    }
-    result[size++] = e;
-    result[size++] = 0;
-    return result;
-}
-
-static size_t bear_strings_length(char const *const *const in) {
-    size_t result = 0;
-    for (char const *const *it = in; (it) && (*it); ++it)
-        ++result;
-    return result;
-}
-
-static void bear_strings_release(char const **in) {
-    for (char const *const *it = in; (it) && (*it); ++it) {
-        free((void *)*it);
-    }
-    free((void *)in);
-}
Index: clang/tools/scan-build-py/lib/libscanbuild/resources/sorttable.js
===================================================================
--- /dev/null
+++ clang/tools/scan-build-py/lib/libscanbuild/resources/sorttable.js
@@ -0,0 +1,535 @@
+/*
+  SortTable
+  version 2
+  7th April 2007
+  Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
+
+  Instructions:
+  Download this file
+  Add <script src="sorttable.js"></script> to your HTML
+  Add class="sortable" to any table you'd like to make sortable
+  Click on the headers to sort
+
+  Thanks to many, many people for contributions and suggestions.
+  Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
+  This basically means: do what you want with it.
+*/
+
+var stIsIE = /*@cc_on!@*/ false;
+
+sorttable = {
+  init : function() {
+    // quit if this function has already been called
+    if (arguments.callee.done)
+      return;
+    // flag this function so we don't do the same thing twice
+    arguments.callee.done = true;
+    // kill the timer
+    if (_timer)
+      clearInterval(_timer);
+
+    if (!document.createElement || !document.getElementsByTagName)
+      return;
+
+    sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
+
+    forEach(document.getElementsByTagName('table'), function(table) {
+      if (table.className.search(/\bsortable\b/) != -1) {
+        sorttable.makeSortable(table);
+      }
+    });
+  },
+
+  makeSortable : function(table) {
+    if (table.getElementsByTagName('thead').length == 0) {
+      // table doesn't have a tHead. Since it should have, create one and
+      // put the first table row in it.
+      the = document.createElement('thead');
+      the.appendChild(table.rows[0]);
+      table.insertBefore(the, table.firstChild);
+    }
+    // Safari doesn't support table.tHead, sigh
+    if (table.tHead == null)
+      table.tHead = table.getElementsByTagName('thead')[0];
+
+    if (table.tHead.rows.length != 1)
+      return; // can't cope with two header rows
+
+    // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
+    // "total" rows, for example). This is B&R, since what you're supposed
+    // to do is put them in a tfoot. So, if there are sortbottom rows,
+    // for backward compatibility, move them to tfoot (creating it if needed).
+    sortbottomrows = [];
+    for (var i = 0; i < table.rows.length; i++) {
+      if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
+        sortbottomrows[sortbottomrows.length] = table.rows[i];
+      }
+    }
+    if (sortbottomrows) {
+      if (table.tFoot == null) {
+        // table doesn't have a tfoot. Create one.
+        tfo = document.createElement('tfoot');
+        table.appendChild(tfo);
+      }
+      for (var i = 0; i < sortbottomrows.length; i++) {
+        tfo.appendChild(sortbottomrows[i]);
+      }
+      delete sortbottomrows;
+    }
+
+    // work through each column and calculate its type
+    headrow = table.tHead.rows[0].cells;
+    for (var i = 0; i < headrow.length; i++) {
+      // manually override the type with a sorttable_type attribute
+      if (!headrow[i].className.match(
+              /\bsorttable_nosort\b/)) { // skip this col
+        mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
+        if (mtch) {
+          override = mtch[1];
+        }
+        if (mtch && typeof sorttable["sort_" + override] == 'function') {
+          headrow[i].sorttable_sortfunction = sorttable["sort_" + override];
+        } else {
+          headrow[i].sorttable_sortfunction = sorttable.guessType(table, i);
+        }
+        // make it clickable to sort
+        headrow[i].sorttable_columnindex = i;
+        headrow[i].sorttable_tbody = table.tBodies[0];
+        dean_addEvent(headrow[i], "click", function(e) {
+          if (this.className.search(/\bsorttable_sorted\b/) != -1) {
+            // if we're already sorted by this column, just
+            // reverse the table, which is quicker
+            sorttable.reverse(this.sorttable_tbody);
+            this.className = this.className.replace('sorttable_sorted',
+                                                    'sorttable_sorted_reverse');
+            this.removeChild(document.getElementById('sorttable_sortfwdind'));
+            sortrevind = document.createElement('span');
+            sortrevind.id = "sorttable_sortrevind";
+            sortrevind.innerHTML = stIsIE
+                                       ? '&nbsp<font face="webdings">5</font>'
+                                       : '&nbsp;&#x25B4;';
+            this.appendChild(sortrevind);
+            return;
+          }
+          if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
+            // if we're already sorted by this column in reverse, just
+            // re-reverse the table, which is quicker
+            sorttable.reverse(this.sorttable_tbody);
+            this.className = this.className.replace('sorttable_sorted_reverse',
+                                                    'sorttable_sorted');
+            this.removeChild(document.getElementById('sorttable_sortrevind'));
+            sortfwdind = document.createElement('span');
+            sortfwdind.id = "sorttable_sortfwdind";
+            sortfwdind.innerHTML = stIsIE
+                                       ? '&nbsp<font face="webdings">6</font>'
+                                       : '&nbsp;&#x25BE;';
+            this.appendChild(sortfwdind);
+            return;
+          }
+
+          // remove sorttable_sorted classes
+          theadrow = this.parentNode;
+          forEach(theadrow.childNodes, function(cell) {
+            if (cell.nodeType == 1) { // an element
+              cell.className =
+                  cell.className.replace('sorttable_sorted_reverse', '');
+              cell.className = cell.className.replace('sorttable_sorted', '');
+            }
+          });
+          sortfwdind = document.getElementById('sorttable_sortfwdind');
+          if (sortfwdind) {
+            sortfwdind.parentNode.removeChild(sortfwdind);
+          }
+          sortrevind = document.getElementById('sorttable_sortrevind');
+          if (sortrevind) {
+            sortrevind.parentNode.removeChild(sortrevind);
+          }
+
+          this.className += ' sorttable_sorted';
+          sortfwdind = document.createElement('span');
+          sortfwdind.id = "sorttable_sortfwdind";
+          sortfwdind.innerHTML =
+              stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
+          this.appendChild(sortfwdind);
+
+          // build an array to sort. This is a Schwartzian transform thing,
+          // i.e., we "decorate" each row with the actual sort key,
+          // sort based on the sort keys, and then put the rows back in order
+          // which is a lot faster because you only do getInnerText once per row
+          row_array = [];
+          col = this.sorttable_columnindex;
+          rows = this.sorttable_tbody.rows;
+          for (var j = 0; j < rows.length; j++) {
+            row_array[row_array.length] =
+                [ sorttable.getInnerText(rows[j].cells[col]), rows[j] ];
+          }
+          /* If you want a stable sort, uncomment the following line */
+          sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
+          /* and comment out this one */
+          // row_array.sort(this.sorttable_sortfunction);
+
+          tb = this.sorttable_tbody;
+          for (var j = 0; j < row_array.length; j++) {
+            tb.appendChild(row_array[j][1]);
+          }
+
+          delete row_array;
+        });
+      }
+    }
+  },
+
+  guessType : function(table, column) {
+    // guess the type of a column based on its first non-blank row
+    sortfn = sorttable.sort_alpha;
+    for (var i = 0; i < table.tBodies[0].rows.length; i++) {
+      text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
+      if (text != '') {
+        if (text.match(/^-?[」$、]?[\d,.]+%?$/)) {
+          return sorttable.sort_numeric;
+        }
+        // check for a date: dd/mm/yyyy or dd/mm/yy
+        // can have / or . or - as separator
+        // can be mm/dd as well
+        possdate = text.match(sorttable.DATE_RE)
+        if (possdate) {
+          // looks like a date
+          first = parseInt(possdate[1]);
+          second = parseInt(possdate[2]);
+          if (first > 12) {
+            // definitely dd/mm
+            return sorttable.sort_ddmm;
+          } else if (second > 12) {
+            return sorttable.sort_mmdd;
+          } else {
+            // looks like a date, but we can't tell which, so assume
+            // that it's dd/mm (English imperialism!) and keep looking
+            sortfn = sorttable.sort_ddmm;
+          }
+        }
+      }
+    }
+    return sortfn;
+  },
+
+  getInnerText : function(node) {
+    // gets the text we want to use for sorting for a cell.
+    // strips leading and trailing whitespace.
+    // this is *not* a generic getInnerText function; it's special to sorttable.
+    // for example, you can override the cell text with a customkey attribute.
+    // it also gets .value for <input> fields.
+
+    hasInputs = (typeof node.getElementsByTagName == 'function') &&
+                node.getElementsByTagName('input').length;
+
+    if (node.getAttribute("sorttable_customkey") != null) {
+      return node.getAttribute("sorttable_customkey");
+    } else if (typeof node.textContent != 'undefined' && !hasInputs) {
+      return node.textContent.replace(/^\s+|\s+$/g, '');
+    } else if (typeof node.innerText != 'undefined' && !hasInputs) {
+      return node.innerText.replace(/^\s+|\s+$/g, '');
+    } else if (typeof node.text != 'undefined' && !hasInputs) {
+      return node.text.replace(/^\s+|\s+$/g, '');
+    } else {
+      switch (node.nodeType) {
+      case 3:
+        if (node.nodeName.toLowerCase() == 'input') {
+          return node.value.replace(/^\s+|\s+$/g, '');
+        }
+      case 4:
+        return node.nodeValue.replace(/^\s+|\s+$/g, '');
+        break;
+      case 1:
+      case 11:
+        var innerText = '';
+        for (var i = 0; i < node.childNodes.length; i++) {
+          innerText += sorttable.getInnerText(node.childNodes[i]);
+        }
+        return innerText.replace(/^\s+|\s+$/g, '');
+        break;
+      default:
+        return '';
+      }
+    }
+  },
+
+  reverse : function(tbody) {
+    // reverse the rows in a tbody
+    newrows = [];
+    for (var i = 0; i < tbody.rows.length; i++) {
+      newrows[newrows.length] = tbody.rows[i];
+    }
+    for (var i = newrows.length - 1; i >= 0; i--) {
+      tbody.appendChild(newrows[i]);
+    }
+    delete newrows;
+  },
+
+  /* sort functions
+     each sort function takes two parameters, a and b
+     you are comparing a[0] and b[0] */
+  sort_numeric : function(a, b) {
+    aa = parseFloat(a[0].replace(/[^0-9.-]/g, ''));
+    if (isNaN(aa))
+      aa = 0;
+    bb = parseFloat(b[0].replace(/[^0-9.-]/g, ''));
+    if (isNaN(bb))
+      bb = 0;
+    return aa - bb;
+  },
+  sort_alpha : function(a, b) {
+    if (a[0] == b[0])
+      return 0;
+    if (a[0] < b[0])
+      return -1;
+    return 1;
+  },
+  sort_ddmm : function(a, b) {
+    mtch = a[0].match(sorttable.DATE_RE);
+    y = mtch[3];
+    m = mtch[2];
+    d = mtch[1];
+    if (m.length == 1)
+      m = '0' + m;
+    if (d.length == 1)
+      d = '0' + d;
+    dt1 = y + m + d;
+    mtch = b[0].match(sorttable.DATE_RE);
+    y = mtch[3];
+    m = mtch[2];
+    d = mtch[1];
+    if (m.length == 1)
+      m = '0' + m;
+    if (d.length == 1)
+      d = '0' + d;
+    dt2 = y + m + d;
+    if (dt1 == dt2)
+      return 0;
+    if (dt1 < dt2)
+      return -1;
+    return 1;
+  },
+  sort_mmdd : function(a, b) {
+    mtch = a[0].match(sorttable.DATE_RE);
+    y = mtch[3];
+    d = mtch[2];
+    m = mtch[1];
+    if (m.length == 1)
+      m = '0' + m;
+    if (d.length == 1)
+      d = '0' + d;
+    dt1 = y + m + d;
+    mtch = b[0].match(sorttable.DATE_RE);
+    y = mtch[3];
+    d = mtch[2];
+    m = mtch[1];
+    if (m.length == 1)
+      m = '0' + m;
+    if (d.length == 1)
+      d = '0' + d;
+    dt2 = y + m + d;
+    if (dt1 == dt2)
+      return 0;
+    if (dt1 < dt2)
+      return -1;
+    return 1;
+  },
+
+  shaker_sort : function(list, comp_func) {
+    // A stable sort function to allow multi-level sorting of data
+    // see: http://en.wikipedia.org/wiki/Cocktail_sort
+    // thanks to Joseph Nahmias
+    var b = 0;
+    var t = list.length - 1;
+    var swap = true;
+
+    while (swap) {
+      swap = false;
+      for (var i = b; i < t; ++i) {
+        if (comp_func(list[i], list[i + 1]) > 0) {
+          var q = list[i];
+          list[i] = list[i + 1];
+          list[i + 1] = q;
+          swap = true;
+        }
+      } // for
+      t--;
+
+      if (!swap)
+        break;
+
+      for (var i = t; i > b; --i) {
+        if (comp_func(list[i], list[i - 1]) < 0) {
+          var q = list[i];
+          list[i] = list[i - 1];
+          list[i - 1] = q;
+          swap = true;
+        }
+      } // for
+      b++;
+
+    } // while(swap)
+  }
+}
+
+/* ******************************************************************
+   Supporting functions: bundled here to avoid depending on a library
+   ****************************************************************** */
+
+// Dean Edwards/Matthias Miller/John Resig
+
+/* for Mozilla/Opera9 */
+if (document.addEventListener) {
+  document.addEventListener("DOMContentLoaded", sorttable.init, false);
+}
+
+/* for Internet Explorer */
+/*@cc_on @*/
+/*@if (@_win32)
+    document.write("<script id=__ie_onload defer
+src=javascript:void(0)><\/script>"); var script =
+document.getElementById("__ie_onload"); script.onreadystatechange = function() {
+        if (this.readyState == "complete") {
+            sorttable.init(); // call the onload handler
+        }
+    };
+/*@end @*/
+
+/* for Safari */
+if (/WebKit/i.test(navigator.userAgent)) { // sniff
+  var _timer = setInterval(function() {
+    if (/loaded|complete/.test(document.readyState)) {
+      sorttable.init(); // call the onload handler
+    }
+  }, 10);
+}
+
+/* for other browsers */
+window.onload = sorttable.init;
+
+// written by Dean Edwards, 2005
+// with input from Tino Zijdel, Matthias Miller, Diego Perini
+
+// http://dean.edwards.name/weblog/2005/10/add-event/
+
+function dean_addEvent(element, type, handler) {
+  if (element.addEventListener) {
+    element.addEventListener(type, handler, false);
+  } else {
+    // assign each event handler a unique ID
+    if (!handler.$$guid)
+      handler.$$guid = dean_addEvent.guid++;
+    // create a hash table of event types for the element
+    if (!element.events)
+      element.events = {};
+    // create a hash table of event handlers for each element/event pair
+    var handlers = element.events[type];
+    if (!handlers) {
+      handlers = element.events[type] = {};
+      // store the existing event handler (if there is one)
+      if (element["on" + type]) {
+        handlers[0] = element["on" + type];
+      }
+    }
+    // store the event handler in the hash table
+    handlers[handler.$$guid] = handler;
+    // assign a global event handler to do all the work
+    element["on" + type] = handleEvent;
+  }
+};
+// a counter used to create unique IDs
+dean_addEvent.guid = 1;
+
+function removeEvent(element, type, handler) {
+  if (element.removeEventListener) {
+    element.removeEventListener(type, handler, false);
+  } else {
+    // delete the event handler from the hash table
+    if (element.events && element.events[type]) {
+      delete element.events[type][handler.$$guid];
+    }
+  }
+};
+
+function handleEvent(event) {
+  var returnValue = true;
+  // grab the event object (IE uses a global event object)
+  event =
+      event ||
+      fixEvent(
+          ((this.ownerDocument || this.document || this).parentWindow || window)
+              .event);
+  // get a reference to the hash table of event handlers
+  var handlers = this.events[event.type];
+  // execute each event handler
+  for (var i in handlers) {
+    this.$$handleEvent = handlers[i];
+    if (this.$$handleEvent(event) === false) {
+      returnValue = false;
+    }
+  }
+  return returnValue;
+};
+
+function fixEvent(event) {
+  // add W3C standard event methods
+  event.preventDefault = fixEvent.preventDefault;
+  event.stopPropagation = fixEvent.stopPropagation;
+  return event;
+};
+fixEvent.preventDefault = function() { this.returnValue = false; };
+fixEvent.stopPropagation = function() { this.cancelBubble = true; }
+
+// Dean's forEach: http://dean.edwards.name/base/forEach.js
+/*
+        forEach, version 1.0
+        Copyright 2006, Dean Edwards
+        License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+// array-like enumeration
+if (!Array.forEach) { // mozilla already supports this
+  Array.forEach = function(array, block, context) {
+    for (var i = 0; i < array.length; i++) {
+      block.call(context, array[i], i, array);
+    }
+  };
+}
+
+// generic enumeration
+Function.prototype.forEach = function(object, block, context) {
+  for (var key in object) {
+    if (typeof this.prototype[key] == "undefined") {
+      block.call(context, object[key], key, object);
+    }
+  }
+};
+
+// character enumeration
+String.forEach = function(string, block, context) {
+  Array.forEach(
+      string.split(""),
+      function(chr, index) { block.call(context, chr, index, string); });
+};
+
+// globally resolve forEach enumeration
+var forEach = function(object, block, context) {
+  if (object) {
+    var resolve = Object; // default
+    if (object instanceof Function) {
+      // functions have a "length" property
+      resolve = Function;
+    } else if (object.forEach instanceof Function) {
+      // the object implements a custom forEach method so use that
+      object.forEach(block, context);
+      return;
+    } else if (typeof object == "string") {
+      // the object is a string
+      resolve = String;
+    } else if (typeof object.length == "number") {
+      // the object is array-like
+      resolve = Array;
+    }
+    resolve.forEach(object, block, context);
+  }
+};
Index: clang/tools/scan-build-py/lib/libscanbuild/resources/selectable.js
===================================================================
--- clang/tools/scan-build-py/lib/libscanbuild/resources/selectable.js
+++ clang/tools/scan-build-py/lib/libscanbuild/resources/selectable.js
@@ -1,7 +1,6 @@
-function SetDisplay(RowClass, DisplayVal)
-{
+function SetDisplay(RowClass, DisplayVal) {
   var Rows = document.getElementsByTagName("tr");
-  for ( var i = 0 ; i < Rows.length; ++i ) {
+  for (var i = 0; i < Rows.length; ++i) {
     if (Rows[i].className == RowClass) {
       Rows[i].style.display = DisplayVal;
     }
@@ -10,24 +9,24 @@
 
 function CopyCheckedStateToCheckButtons(SummaryCheckButton) {
   var Inputs = document.getElementsByTagName("input");
-  for ( var i = 0 ; i < Inputs.length; ++i ) {
+  for (var i = 0; i < Inputs.length; ++i) {
     if (Inputs[i].type == "checkbox") {
-      if(Inputs[i] != SummaryCheckButton) {
+      if (Inputs[i] != SummaryCheckButton) {
         Inputs[i].checked = SummaryCheckButton.checked;
         Inputs[i].onclick();
-	  }
+      }
     }
   }
 }
 
-function returnObjById( id ) {
-    if (document.getElementById)
-        var returnVar = document.getElementById(id);
-    else if (document.all)
-        var returnVar = document.all[id];
-    else if (document.layers)
-        var returnVar = document.layers[id];
-    return returnVar;
+function returnObjById(id) {
+  if (document.getElementById)
+    var returnVar = document.getElementById(id);
+  else if (document.all)
+    var returnVar = document.all[id];
+  else if (document.layers)
+    var returnVar = document.layers[id];
+  return returnVar;
 }
 
 var NumUnchecked = 0;
@@ -38,8 +37,7 @@
     if (--NumUnchecked == 0) {
       returnObjById("AllBugsCheck").checked = true;
     }
-  }
-  else {
+  } else {
     SetDisplay(ClassName, "none");
     NumUnchecked++;
     returnObjById("AllBugsCheck").checked = false;
Index: clang/tools/scan-build-py/lib/libear/ear.c
===================================================================
--- /dev/null
+++ clang/tools/scan-build-py/lib/libear/ear.c
@@ -0,0 +1,600 @@
+/* -*- coding: utf-8 -*-
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+*/
+
+/**
+ * This file implements a shared library. This library can be pre-loaded by
+ * the dynamic linker of the Operating System (OS). It implements a few function
+ * related to process creation. By pre-load this library the executed process
+ * uses these functions instead of those from the standard library.
+ *
+ * The idea here is to inject a logic before call the real methods. The logic is
+ * to dump the call into a file. To call the real method this library is doing
+ * the job of the dynamic linker.
+ *
+ * The only input for the log writing is about the destination directory.
+ * This is passed as environment variable.
+ */
+
+#include "config.h"
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
+#include <spawn.h>
+#endif
+
+#if defined HAVE_NSGETENVIRON
+#include <crt_externs.h>
+#else
+extern char **environ;
+#endif
+
+#define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
+#ifdef APPLE
+#define ENV_FLAT "DYLD_FORCE_FLAT_NAMESPACE"
+#define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
+#define ENV_SIZE 3
+#else
+#define ENV_PRELOAD "LD_PRELOAD"
+#define ENV_SIZE 2
+#endif
+
+#define DLSYM(TYPE_, VAR_, SYMBOL_)                                            \
+  union {                                                                      \
+    void *from;                                                                \
+    TYPE_ to;                                                                  \
+  } cast;                                                                      \
+  if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) {                          \
+    perror("bear: dlsym");                                                     \
+    exit(EXIT_FAILURE);                                                        \
+  }                                                                            \
+  TYPE_ const VAR_ = cast.to;
+
+typedef char const *bear_env_t[ENV_SIZE];
+
+static int bear_capture_env_t(bear_env_t *env);
+static int bear_reset_env_t(bear_env_t *env);
+static void bear_release_env_t(bear_env_t *env);
+static char const **bear_update_environment(char *const envp[],
+                                            bear_env_t *env);
+static char const **bear_update_environ(char const **in, char const *key,
+                                        char const *value);
+static char **bear_get_environment();
+static void bear_report_call(char const *fun, char const *const argv[]);
+static char const **bear_strings_build(char const *arg, va_list *ap);
+static char const **bear_strings_copy(char const **const in);
+static char const **bear_strings_append(char const **in, char const *e);
+static size_t bear_strings_length(char const *const *in);
+static void bear_strings_release(char const **);
+
+static bear_env_t env_names = {ENV_OUTPUT, ENV_PRELOAD
+#ifdef ENV_FLAT
+                               ,
+                               ENV_FLAT
+#endif
+};
+
+static bear_env_t initial_env = {0, 0
+#ifdef ENV_FLAT
+                                 ,
+                                 0
+#endif
+};
+
+static int initialized = 0;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void on_load(void) __attribute__((constructor));
+static void on_unload(void) __attribute__((destructor));
+
+#ifdef HAVE_EXECVE
+static int call_execve(const char *path, char *const argv[],
+                       char *const envp[]);
+#endif
+#ifdef HAVE_EXECVP
+static int call_execvp(const char *file, char *const argv[]);
+#endif
+#ifdef HAVE_EXECVPE
+static int call_execvpe(const char *file, char *const argv[],
+                        char *const envp[]);
+#endif
+#ifdef HAVE_EXECVP2
+static int call_execvP(const char *file, const char *search_path,
+                       char *const argv[]);
+#endif
+#ifdef HAVE_EXECT
+static int call_exect(const char *path, char *const argv[], char *const envp[]);
+#endif
+#ifdef HAVE_POSIX_SPAWN
+static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
+                            const posix_spawn_file_actions_t *file_actions,
+                            const posix_spawnattr_t *restrict attrp,
+                            char *const argv[restrict],
+                            char *const envp[restrict]);
+#endif
+#ifdef HAVE_POSIX_SPAWNP
+static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
+                             const posix_spawn_file_actions_t *file_actions,
+                             const posix_spawnattr_t *restrict attrp,
+                             char *const argv[restrict],
+                             char *const envp[restrict]);
+#endif
+
+/* Initialization method to Captures the relevant environment variables.
+ */
+
+static void on_load(void) {
+  pthread_mutex_lock(&mutex);
+  if (!initialized)
+    initialized = bear_capture_env_t(&initial_env);
+  pthread_mutex_unlock(&mutex);
+}
+
+static void on_unload(void) {
+  pthread_mutex_lock(&mutex);
+  bear_release_env_t(&initial_env);
+  initialized = 0;
+  pthread_mutex_unlock(&mutex);
+}
+
+/* These are the methods we are try to hijack.
+ */
+
+#ifdef HAVE_EXECVE
+int execve(const char *path, char *const argv[], char *const envp[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_execve(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECV
+#ifndef HAVE_EXECVE
+#error can not implement execv without execve
+#endif
+int execv(const char *path, char *const argv[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  char *const *envp = bear_get_environment();
+  return call_execve(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+int execvpe(const char *file, char *const argv[], char *const envp[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_execvpe(file, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECVP
+int execvp(const char *file, char *const argv[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_execvp(file, argv);
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+int execvP(const char *file, const char *search_path, char *const argv[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_execvP(file, search_path, argv);
+}
+#endif
+
+#ifdef HAVE_EXECT
+int exect(const char *path, char *const argv[], char *const envp[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_exect(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECL
+#ifndef HAVE_EXECVE
+#error can not implement execl without execve
+#endif
+int execl(const char *path, const char *arg, ...) {
+  va_list args;
+  va_start(args, arg);
+  char const **argv = bear_strings_build(arg, &args);
+  va_end(args);
+
+  bear_report_call(__func__, (char const *const *)argv);
+  char *const *envp = bear_get_environment();
+  int const result = call_execve(path, (char *const *)argv, envp);
+
+  bear_strings_release(argv);
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECLP
+#ifndef HAVE_EXECVP
+#error can not implement execlp without execvp
+#endif
+int execlp(const char *file, const char *arg, ...) {
+  va_list args;
+  va_start(args, arg);
+  char const **argv = bear_strings_build(arg, &args);
+  va_end(args);
+
+  bear_report_call(__func__, (char const *const *)argv);
+  int const result = call_execvp(file, (char *const *)argv);
+
+  bear_strings_release(argv);
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECLE
+#ifndef HAVE_EXECVE
+#error can not implement execle without execve
+#endif
+// int execle(const char *path, const char *arg, ..., char * const envp[]);
+int execle(const char *path, const char *arg, ...) {
+  va_list args;
+  va_start(args, arg);
+  char const **argv = bear_strings_build(arg, &args);
+  char const **envp = va_arg(args, char const **);
+  va_end(args);
+
+  bear_report_call(__func__, (char const *const *)argv);
+  int const result =
+      call_execve(path, (char *const *)argv, (char *const *)envp);
+
+  bear_strings_release(argv);
+  return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+int posix_spawn(pid_t *restrict pid, const char *restrict path,
+                const posix_spawn_file_actions_t *file_actions,
+                const posix_spawnattr_t *restrict attrp,
+                char *const argv[restrict], char *const envp[restrict]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+int posix_spawnp(pid_t *restrict pid, const char *restrict file,
+                 const posix_spawn_file_actions_t *file_actions,
+                 const posix_spawnattr_t *restrict attrp,
+                 char *const argv[restrict], char *const envp[restrict]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
+}
+#endif
+
+/* These are the methods which forward the call to the standard implementation.
+ */
+
+#ifdef HAVE_EXECVE
+static int call_execve(const char *path, char *const argv[],
+                       char *const envp[]) {
+  typedef int (*func)(const char *, char *const *, char *const *);
+
+  DLSYM(func, fp, "execve");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result = (*fp)(path, argv, (char *const *)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+static int call_execvpe(const char *file, char *const argv[],
+                        char *const envp[]) {
+  typedef int (*func)(const char *, char *const *, char *const *);
+
+  DLSYM(func, fp, "execvpe");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result = (*fp)(file, argv, (char *const *)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECVP
+static int call_execvp(const char *file, char *const argv[]) {
+  typedef int (*func)(const char *file, char *const argv[]);
+
+  DLSYM(func, fp, "execvp");
+
+  bear_env_t current_env;
+  bear_capture_env_t(&current_env);
+  bear_reset_env_t(&initial_env);
+  int const result = (*fp)(file, argv);
+  bear_reset_env_t(&current_env);
+  bear_release_env_t(&current_env);
+
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+static int call_execvP(const char *file, const char *search_path,
+                       char *const argv[]) {
+  typedef int (*func)(const char *, const char *, char *const *);
+
+  DLSYM(func, fp, "execvP");
+
+  bear_env_t current_env;
+  bear_capture_env_t(&current_env);
+  bear_reset_env_t(&initial_env);
+  int const result = (*fp)(file, search_path, argv);
+  bear_reset_env_t(&current_env);
+  bear_release_env_t(&current_env);
+
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECT
+static int call_exect(const char *path, char *const argv[],
+                      char *const envp[]) {
+  typedef int (*func)(const char *, char *const *, char *const *);
+
+  DLSYM(func, fp, "exect");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result = (*fp)(path, argv, (char *const *)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
+                            const posix_spawn_file_actions_t *file_actions,
+                            const posix_spawnattr_t *restrict attrp,
+                            char *const argv[restrict],
+                            char *const envp[restrict]) {
+  typedef int (*func)(pid_t *restrict, const char *restrict,
+                      const posix_spawn_file_actions_t *,
+                      const posix_spawnattr_t *restrict, char *const *restrict,
+                      char *const *restrict);
+
+  DLSYM(func, fp, "posix_spawn");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result =
+      (*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
+                             const posix_spawn_file_actions_t *file_actions,
+                             const posix_spawnattr_t *restrict attrp,
+                             char *const argv[restrict],
+                             char *const envp[restrict]) {
+  typedef int (*func)(pid_t *restrict, const char *restrict,
+                      const posix_spawn_file_actions_t *,
+                      const posix_spawnattr_t *restrict, char *const *restrict,
+                      char *const *restrict);
+
+  DLSYM(func, fp, "posix_spawnp");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result =
+      (*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+/* this method is to write log about the process creation. */
+
+static void bear_report_call(char const *fun, char const *const argv[]) {
+  static int const GS = 0x1d;
+  static int const RS = 0x1e;
+  static int const US = 0x1f;
+
+  if (!initialized)
+    return;
+
+  pthread_mutex_lock(&mutex);
+  const char *cwd = getcwd(NULL, 0);
+  if (0 == cwd) {
+    perror("bear: getcwd");
+    exit(EXIT_FAILURE);
+  }
+  char const *const out_dir = initial_env[0];
+  size_t const path_max_length = strlen(out_dir) + 32;
+  char filename[path_max_length];
+  if (-1 ==
+      snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
+    perror("bear: snprintf");
+    exit(EXIT_FAILURE);
+  }
+  FILE *fd = fopen(filename, "a+");
+  if (0 == fd) {
+    perror("bear: fopen");
+    exit(EXIT_FAILURE);
+  }
+  fprintf(fd, "%d%c", getpid(), RS);
+  fprintf(fd, "%d%c", getppid(), RS);
+  fprintf(fd, "%s%c", fun, RS);
+  fprintf(fd, "%s%c", cwd, RS);
+  size_t const argc = bear_strings_length(argv);
+  for (size_t it = 0; it < argc; ++it) {
+    fprintf(fd, "%s%c", argv[it], US);
+  }
+  fprintf(fd, "%c", GS);
+  if (fclose(fd)) {
+    perror("bear: fclose");
+    exit(EXIT_FAILURE);
+  }
+  free((void *)cwd);
+  pthread_mutex_unlock(&mutex);
+}
+
+/* update environment assure that chilren processes will copy the desired
+ * behaviour */
+
+static int bear_capture_env_t(bear_env_t *env) {
+  int status = 1;
+  for (size_t it = 0; it < ENV_SIZE; ++it) {
+    char const *const env_value = getenv(env_names[it]);
+    char const *const env_copy = (env_value) ? strdup(env_value) : env_value;
+    (*env)[it] = env_copy;
+    status &= (env_copy) ? 1 : 0;
+  }
+  return status;
+}
+
+static int bear_reset_env_t(bear_env_t *env) {
+  int status = 1;
+  for (size_t it = 0; it < ENV_SIZE; ++it) {
+    if ((*env)[it]) {
+      setenv(env_names[it], (*env)[it], 1);
+    } else {
+      unsetenv(env_names[it]);
+    }
+  }
+  return status;
+}
+
+static void bear_release_env_t(bear_env_t *env) {
+  for (size_t it = 0; it < ENV_SIZE; ++it) {
+    free((void *)(*env)[it]);
+    (*env)[it] = 0;
+  }
+}
+
+static char const **bear_update_environment(char *const envp[],
+                                            bear_env_t *env) {
+  char const **result = bear_strings_copy((char const **)envp);
+  for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
+    result = bear_update_environ(result, env_names[it], (*env)[it]);
+  return result;
+}
+
+static char const **bear_update_environ(char const *envs[], char const *key,
+                                        char const *const value) {
+  // find the key if it's there
+  size_t const key_length = strlen(key);
+  char const **it = envs;
+  for (; (it) && (*it); ++it) {
+    if ((0 == strncmp(*it, key, key_length)) && (strlen(*it) > key_length) &&
+        ('=' == (*it)[key_length]))
+      break;
+  }
+  // allocate a environment entry
+  size_t const value_length = strlen(value);
+  size_t const env_length = key_length + value_length + 2;
+  char *env = malloc(env_length);
+  if (0 == env) {
+    perror("bear: malloc [in env_update]");
+    exit(EXIT_FAILURE);
+  }
+  if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
+    perror("bear: snprintf");
+    exit(EXIT_FAILURE);
+  }
+  // replace or append the environment entry
+  if (it && *it) {
+    free((void *)*it);
+    *it = env;
+    return envs;
+  }
+  return bear_strings_append(envs, env);
+}
+
+static char **bear_get_environment() {
+#if defined HAVE_NSGETENVIRON
+  return *_NSGetEnviron();
+#else
+  return environ;
+#endif
+}
+
+/* util methods to deal with string arrays. environment and process arguments
+ * are both represented as string arrays. */
+
+static char const **bear_strings_build(char const *const arg, va_list *args) {
+  char const **result = 0;
+  size_t size = 0;
+  for (char const *it = arg; it; it = va_arg(*args, char const *)) {
+    result = realloc(result, (size + 1) * sizeof(char const *));
+    if (0 == result) {
+      perror("bear: realloc");
+      exit(EXIT_FAILURE);
+    }
+    char const *copy = strdup(it);
+    if (0 == copy) {
+      perror("bear: strdup");
+      exit(EXIT_FAILURE);
+    }
+    result[size++] = copy;
+  }
+  result = realloc(result, (size + 1) * sizeof(char const *));
+  if (0 == result) {
+    perror("bear: realloc");
+    exit(EXIT_FAILURE);
+  }
+  result[size++] = 0;
+
+  return result;
+}
+
+static char const **bear_strings_copy(char const **const in) {
+  size_t const size = bear_strings_length(in);
+
+  char const **const result = malloc((size + 1) * sizeof(char const *));
+  if (0 == result) {
+    perror("bear: malloc");
+    exit(EXIT_FAILURE);
+  }
+
+  char const **out_it = result;
+  for (char const *const *in_it = in; (in_it) && (*in_it); ++in_it, ++out_it) {
+    *out_it = strdup(*in_it);
+    if (0 == *out_it) {
+      perror("bear: strdup");
+      exit(EXIT_FAILURE);
+    }
+  }
+  *out_it = 0;
+  return result;
+}
+
+static char const **bear_strings_append(char const **const in,
+                                        char const *const e) {
+  size_t size = bear_strings_length(in);
+  char const **result = realloc(in, (size + 2) * sizeof(char const *));
+  if (0 == result) {
+    perror("bear: realloc");
+    exit(EXIT_FAILURE);
+  }
+  result[size++] = e;
+  result[size++] = 0;
+  return result;
+}
+
+static size_t bear_strings_length(char const *const *const in) {
+  size_t result = 0;
+  for (char const *const *it = in; (it) && (*it); ++it)
+    ++result;
+  return result;
+}
+
+static void bear_strings_release(char const **in) {
+  for (char const *const *it = in; (it) && (*it); ++it) {
+    free((void *)*it);
+  }
+  free((void *)in);
+}
Index: clang/tools/scan-build-py/bin/scan-build
===================================================================
--- clang/tools/scan-build-py/bin/scan-build
+++ clang/tools/scan-build-py/bin/scan-build
@@ -8,7 +8,7 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.analyze import scan_build
 
Index: clang/tools/scan-build-py/bin/intercept-build
===================================================================
--- clang/tools/scan-build-py/bin/intercept-build
+++ clang/tools/scan-build-py/bin/intercept-build
@@ -8,7 +8,7 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.intercept import intercept_build
 
Index: clang/tools/scan-build-py/bin/analyze-build
===================================================================
--- clang/tools/scan-build-py/bin/analyze-build
+++ clang/tools/scan-build-py/bin/analyze-build
@@ -8,7 +8,7 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.analyze import analyze_build
 
Index: clang/tools/scan-build-py/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang/tools/scan-build-py/CMakeLists.txt
@@ -0,0 +1,132 @@
+set (BinFiles
+     "analyze-build"
+     "intercept-build"
+     "scan-build")
+
+set (LibExecs
+     "analyze-c++"
+     "analyze-cc"
+     "intercept-c++"
+     "intercept-cc")
+
+set (LibScanbuild
+     "__init__.py"
+     "analyze.py"
+     "arguments.py"
+     "clang.py"
+     "compilation.py"
+     "intercept.py"
+     "report.py"
+     "shell.py")
+
+set (LibScanbuildResources
+     "scanview.css"
+     "selectable.js"
+     "sorttable.js")
+
+# libear is compiled dynamically in build_libear using the specified cc
+# compiler.
+set (LibEar
+     "__init__.py"
+     "config.h.in"
+     "ear.c")
+
+foreach(BinFile ${BinFiles})
+  if ("${BinFile}" STREQUAL "scan-build")
+    # Need to rename scan-build to scan-build-py to prevent overwriting
+    # scan-build Perl implementation.
+    add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/scan-build-py
+                       COMMAND ${CMAKE_COMMAND} -E make_directory
+                         ${CMAKE_BINARY_DIR}/bin
+                       COMMAND ${CMAKE_COMMAND} -E copy
+                         ${CMAKE_CURRENT_SOURCE_DIR}/bin/scan-build
+                         ${CMAKE_BINARY_DIR}/bin/scan-build-py
+                       DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/scan-build)
+    install (PROGRAMS "bin/scan-build"
+             DESTINATION bin
+             RENAME scan-build-py
+             COMPONENT scan-build-py)
+    list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/scan-build-py)
+  else()
+    add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/${BinFile}
+                       COMMAND ${CMAKE_COMMAND} -E make_directory
+                         ${CMAKE_BINARY_DIR}/bin
+                       COMMAND ${CMAKE_COMMAND} -E copy
+                         ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile}
+                         ${CMAKE_BINARY_DIR}/bin/
+                       DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile})
+    install(PROGRAMS bin/${BinFile}
+            DESTINATION bin
+            COMPONENT scan-build-py)
+    list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile})
+  endif()
+endforeach()
+
+foreach(lib ${LibExecs})
+  add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/libexec/${lib}
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/libexec
+                     COMMAND ${CMAKE_COMMAND} -E copy
+                       ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${lib}
+                       ${CMAKE_BINARY_DIR}/libexec/
+                     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${lib})
+  list(APPEND Depends ${CMAKE_BINARY_DIR}/libexec/${lib})
+  install(PROGRAMS libexec/${lib}
+          DESTINATION libexec
+          COMPONENT scan-build-py)
+endforeach()
+
+foreach(lib ${LibScanbuild})
+  add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/libscanbuild/${lib}
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild
+                     COMMAND ${CMAKE_COMMAND} -E copy
+                       ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/${lib}
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild/
+                     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/${lib})
+  list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libscanbuild/${lib})
+  install(PROGRAMS lib/libscanbuild/${lib}
+          DESTINATION lib/libscanbuild
+          COMPONENT scan-build-py)
+endforeach()
+
+foreach(resource ${LibScanbuildResources})
+  add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources/${resource}
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources
+                     COMMAND ${CMAKE_COMMAND} -E copy
+                       ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/resources/${resource}
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources
+                     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/resources/${resource})
+  list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources/${resource})
+  install(PROGRAMS lib/libscanbuild/resources/${resource}
+          DESTINATION lib/libscanbuild/resources
+          COMPONENT scan-build-py)
+endforeach()
+
+foreach(lib ${LibEar})
+  add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/libear/${lib}
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib/libear
+                     COMMAND ${CMAKE_COMMAND} -E copy
+                       ${CMAKE_CURRENT_SOURCE_DIR}/lib/libear/${lib}
+                       ${CMAKE_BINARY_DIR}/lib/libear/
+                     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libear/${lib})
+  list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libear/${lib})
+  install(PROGRAMS lib/libear/${lib}
+          DESTINATION lib/libear
+          COMPONENT scan-build-py)
+endforeach()
+
+add_custom_target(scan-build-py ALL DEPENDS ${Depends})
+add_llvm_install_targets("install-scan-build-py"
+                         DEPENDS scan-build-py
+                         COMPONENT scan-build-py)
Index: clang/tools/CMakeLists.txt
===================================================================
--- clang/tools/CMakeLists.txt
+++ clang/tools/CMakeLists.txt
@@ -31,6 +31,7 @@
   add_clang_subdirectory(clang-check)
   add_clang_subdirectory(clang-extdef-mapping)
   add_clang_subdirectory(scan-build)
+  add_clang_subdirectory(scan-build-py)
   add_clang_subdirectory(scan-view)
 endif()
 
Index: clang/cmake/caches/Fuchsia-stage2.cmake
===================================================================
--- clang/cmake/caches/Fuchsia-stage2.cmake
+++ clang/cmake/caches/Fuchsia-stage2.cmake
@@ -278,6 +278,7 @@
   llvm-symbolizer
   llvm-xray
   sancov
+  scan-build-py
   CACHE STRING "")
 
 set(LLVM_DISTRIBUTION_COMPONENTS
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to