forked from OSchip/llvm-project
Create install targets for scan-build-py.
A new revision identical to https://reviews.llvm.org/D101139 The parent revision of aforementioned revision seems to cause pre-merge checks to fail opaquely. Seeing if creating a new revision will work. Reviewed By: phosek Differential Revision: https://reviews.llvm.org/D104138
This commit is contained in:
parent
e2c2124a4b
commit
d9cf8291e7
|
@ -291,6 +291,7 @@ set(LLVM_TOOLCHAIN_TOOLS
|
|||
llvm-symbolizer
|
||||
llvm-xray
|
||||
sancov
|
||||
scan-build-py
|
||||
CACHE STRING "")
|
||||
|
||||
set(LLVM_DISTRIBUTION_COMPONENTS
|
||||
|
|
|
@ -32,6 +32,7 @@ if(CLANG_ENABLE_STATIC_ANALYZER)
|
|||
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()
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -8,7 +8,7 @@ import multiprocessing
|
|||
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
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import multiprocessing
|
|||
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
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import multiprocessing
|
|||
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
|
||||
|
||||
|
|
|
@ -0,0 +1,601 @@
|
|||
/* -*- 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.
|
||||
*/
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
#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(¤t_env);
|
||||
bear_reset_env_t(&initial_env);
|
||||
int const result = (*fp)(file, argv);
|
||||
bear_reset_env_t(¤t_env);
|
||||
bear_release_env_t(¤t_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(¤t_env);
|
||||
bear_reset_env_t(&initial_env);
|
||||
int const result = (*fp)(file, search_path, argv);
|
||||
bear_reset_env_t(¤t_env);
|
||||
bear_release_env_t(¤t_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);
|
||||
}
|
|
@ -379,7 +379,8 @@ def merge_sarif_files(output_dir, sort_files=False):
|
|||
def parse_bug_plist(filename):
|
||||
""" Returns the generator of bugs from a single .plist file. """
|
||||
|
||||
content = plistlib.readPlist(filename)
|
||||
with open(filename, 'rb') as fp:
|
||||
content = plistlib.load(fp)
|
||||
files = content.get('files')
|
||||
for bug in content.get('diagnostics', []):
|
||||
if len(files) <= int(bug['location']['file']):
|
|
@ -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,9 +9,9 @@ function SetDisplay(RowClass, DisplayVal)
|
|||
|
||||
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();
|
||||
}
|
||||
|
@ -20,7 +19,7 @@ function CopyCheckedStateToCheckButtons(SummaryCheckButton) {
|
|||
}
|
||||
}
|
||||
|
||||
function returnObjById( id ) {
|
||||
function returnObjById(id) {
|
||||
if (document.getElementById)
|
||||
var returnVar = document.getElementById(id);
|
||||
else if (document.all)
|
||||
|
@ -38,8 +37,7 @@ function ToggleDisplay(CheckButton, ClassName) {
|
|||
if (--NumUnchecked == 0) {
|
||||
returnObjById("AllBugsCheck").checked = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
SetDisplay(ClassName, "none");
|
||||
NumUnchecked++;
|
||||
returnObjById("AllBugsCheck").checked = false;
|
|
@ -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
|
||||
? ' <font face="webdings">5</font>'
|
||||
: ' ▴';
|
||||
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
|
||||
? ' <font face="webdings">6</font>'
|
||||
: ' ▾';
|
||||
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 ? ' <font face="webdings">6</font>' : ' ▾';
|
||||
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);
|
||||
}
|
||||
};
|
|
@ -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(¤t_env);
|
||||
bear_reset_env_t(&initial_env);
|
||||
int const result = (*fp)(file, argv);
|
||||
bear_reset_env_t(¤t_env);
|
||||
bear_release_env_t(¤t_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(¤t_env);
|
||||
bear_reset_env_t(&initial_env);
|
||||
int const result = (*fp)(file, search_path, argv);
|
||||
bear_reset_env_t(¤t_env);
|
||||
bear_release_env_t(¤t_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);
|
||||
}
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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())
|
|
@ -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
|
||||
|
|
|
@ -22,7 +22,7 @@ def load_tests(loader, suite, pattern):
|
|||
|
||||
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')]
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class ExecAnatomyTest(unittest.TestCase):
|
|||
|
||||
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)
|
||||
|
|
|
@ -15,7 +15,7 @@ import glob
|
|||
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')
|
||||
|
|
|
@ -17,7 +17,7 @@ class OutputDirectoryTest(unittest.TestCase):
|
|||
@staticmethod
|
||||
def run_analyzer(outdir, args, cmd):
|
||||
return check_call_and_report(
|
||||
['scan-build', '--intercept-first', '-o', outdir] + args,
|
||||
['scan-build-py', '--intercept-first', '-o', outdir] + args,
|
||||
cmd)
|
||||
|
||||
def test_regular_keeps_report_dir(self):
|
||||
|
@ -49,7 +49,7 @@ class RunAnalyzerTest(unittest.TestCase):
|
|||
with libear.TemporaryDirectory() as tmpdir:
|
||||
make = make_args(tmpdir) + ['build_regular']
|
||||
outdir = check_call_and_report(
|
||||
['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
|
||||
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler'],
|
||||
make)
|
||||
|
||||
self.assertTrue(os.path.isdir(outdir))
|
||||
|
@ -59,7 +59,7 @@ class RunAnalyzerTest(unittest.TestCase):
|
|||
with libear.TemporaryDirectory() as tmpdir:
|
||||
make = make_args(tmpdir) + ['build_regular']
|
||||
outdir = check_call_and_report(
|
||||
['scan-build', '--plist', '-o', tmpdir, '--intercept-first',
|
||||
['scan-build-py', '--plist', '-o', tmpdir, '--intercept-first',
|
||||
'--override-compiler'],
|
||||
make)
|
||||
|
||||
|
@ -70,7 +70,7 @@ class RunAnalyzerTest(unittest.TestCase):
|
|||
with libear.TemporaryDirectory() as tmpdir:
|
||||
make = make_args(tmpdir) + ['build_regular']
|
||||
outdir = check_call_and_report(
|
||||
['scan-build', '--plist', '-o', tmpdir, '--intercept-first'],
|
||||
['scan-build-py', '--plist', '-o', tmpdir, '--intercept-first'],
|
||||
make)
|
||||
|
||||
self.assertTrue(os.path.isdir(outdir))
|
||||
|
@ -89,21 +89,21 @@ class RunAnalyzerTest(unittest.TestCase):
|
|||
def test_interposition_cc_works(self):
|
||||
with libear.TemporaryDirectory() as tmpdir:
|
||||
outdir = check_call_and_report(
|
||||
['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
|
||||
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler'],
|
||||
self.compile_empty_source_file(tmpdir, False))
|
||||
self.assertEqual(self.get_plist_count(outdir), 1)
|
||||
|
||||
def test_interposition_cxx_works(self):
|
||||
with libear.TemporaryDirectory() as tmpdir:
|
||||
outdir = check_call_and_report(
|
||||
['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
|
||||
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler'],
|
||||
self.compile_empty_source_file(tmpdir, True))
|
||||
self.assertEqual(self.get_plist_count(outdir), 1)
|
||||
|
||||
def test_intercept_cc_works(self):
|
||||
with libear.TemporaryDirectory() as tmpdir:
|
||||
outdir = check_call_and_report(
|
||||
['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
|
||||
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler',
|
||||
'--intercept-first'],
|
||||
self.compile_empty_source_file(tmpdir, False))
|
||||
self.assertEqual(self.get_plist_count(outdir), 1)
|
||||
|
@ -111,7 +111,7 @@ class RunAnalyzerTest(unittest.TestCase):
|
|||
def test_intercept_cxx_works(self):
|
||||
with libear.TemporaryDirectory() as tmpdir:
|
||||
outdir = check_call_and_report(
|
||||
['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
|
||||
['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler',
|
||||
'--intercept-first'],
|
||||
self.compile_empty_source_file(tmpdir, True))
|
||||
self.assertEqual(self.get_plist_count(outdir), 1)
|
||||
|
|
|
@ -18,9 +18,9 @@ class ReportDirectoryTest(unittest.TestCase):
|
|||
# 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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue