Allow parsing binaries via `pacparse`

This commit is contained in:
Martchus 2023-11-17 01:00:12 +01:00
parent df55813d59
commit 653867a49c
2 changed files with 94 additions and 19 deletions

View File

@ -24,14 +24,35 @@ set(CONFIGURATION_PACKAGE_SUFFIX
find_package(c++utilities${CONFIGURATION_PACKAGE_SUFFIX} 5.0.0 REQUIRED) find_package(c++utilities${CONFIGURATION_PACKAGE_SUFFIX} 5.0.0 REQUIRED)
use_cpp_utilities() use_cpp_utilities()
# find reflective-rapidjson
find_package(reflective_rapidjson${CONFIGURATION_PACKAGE_SUFFIX} REQUIRED)
use_reflective_rapidjson(VISIBILITY PUBLIC)
# find backend libraries # find backend libraries
find_package(libpkg ${META_APP_VERSION} REQUIRED) find_package(libpkg ${META_APP_VERSION} REQUIRED)
use_libpkg() use_libpkg()
list(APPEND PRIVATE_LIBRARIES pthread) list(APPEND PRIVATE_LIBRARIES pthread)
# include modules to apply configuration # apply basic configuration
include(BasicConfig) include(BasicConfig)
# add reflection generator invocation
include(ReflectionGenerator)
add_reflection_generator_invocation(
INPUT_FILES
main.cpp
CLANG_OPTIONS_FROM_TARGETS
"${META_TARGET_NAME}"
CLANG_OPTIONS_FROM_DEPENDENCIES
"${PUBLIC_LIBRARIES};${PRIVATE_LIBRARIES}"
GENERATORS
json
OUTPUT_LISTS
SRC_FILES
ERROR_RESILIENT)
# apply further configuration
include(WindowsResources) include(WindowsResources)
include(AppTarget) include(AppTarget)
include(TestTarget) include(TestTarget)

View File

@ -11,6 +11,8 @@
#include <reflective_rapidjson/json/reflector.h> #include <reflective_rapidjson/json/reflector.h>
#include <atomic>
#include <cstdlib>
#include <iostream> #include <iostream>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
@ -18,56 +20,106 @@
using namespace CppUtilities; using namespace CppUtilities;
struct BinaryInfo : public ReflectiveRapidJSON::JsonSerializable<BinaryInfo> {
std::string name;
std::string architecture;
std::set<std::string> symbols;
std::set<std::string> requiredLibs;
std::string rpath;
std::string prefix;
bool isBigEndian = false;
};
struct PacparseResults : public ReflectiveRapidJSON::JsonSerializable<PacparseResults> {
std::vector<std::shared_ptr<LibPkg::Package>> packages;
std::vector<BinaryInfo> binaries;
};
int main(int argc, const char *argv[]) int main(int argc, const char *argv[])
{ {
SET_APPLICATION_INFO; SET_APPLICATION_INFO;
// read cli args // read cli args
auto parser = ArgumentParser(); auto parser = ArgumentParser();
auto packagesArg = Argument("packages", 'p', "specifies the paths of the package files to parse"); auto packagesArg = ConfigValueArgument("packages", 'p', "specifies the paths of the package files to parse", { "path" });
packagesArg.setRequiredValueCount(Argument::varValueCount); packagesArg.setRequiredValueCount(Argument::varValueCount);
packagesArg.setValueNames({ "path" });
packagesArg.setImplicit(true); packagesArg.setImplicit(true);
parser.setMainArguments({ &packagesArg, &parser.helpArg() }); auto binariesArg = ConfigValueArgument("binaries", 'b', "specifies the paths of the binaries", { "path" });
binariesArg.setRequiredValueCount(Argument::varValueCount);
parser.setMainArguments({ &packagesArg, &binariesArg, &parser.helpArg() });
parser.setDefaultArgument(&parser.helpArg()); parser.setDefaultArgument(&parser.helpArg());
parser.parseArgs(argc, argv); parser.parseArgs(argc, argv);
if (parser.helpArg().isPresent()) {
return EXIT_SUCCESS;
}
auto packages = std::vector<std::shared_ptr<LibPkg::Package>>(); auto res = PacparseResults();
auto packageMutex = std::mutex(); auto packageMutex = std::mutex();
auto binaryMutex = std::mutex();
auto returnCode = std::atomic<int>(EXIT_SUCCESS);
auto pi = std::vector<const char *>::const_iterator(); auto pi = std::vector<const char *>::const_iterator();
auto pend = std::vector<const char *>::const_iterator(); auto pend = std::vector<const char *>::const_iterator();
auto piMutex = std::mutex(); auto bi = std::vector<const char *>::const_iterator();
auto bend = std::vector<const char *>::const_iterator();
auto imutex = std::mutex();
if (packagesArg.isPresent()) { if (packagesArg.isPresent()) {
const auto &packagePaths = packagesArg.values(); const auto &packagePaths = packagesArg.values();
pi = packagePaths.begin(); pi = packagePaths.begin();
pend = packagePaths.end(); pend = packagePaths.end();
packages.reserve(packagePaths.size()); res.packages.reserve(packagePaths.size());
}
if (binariesArg.isPresent()) {
const auto &binaryPaths = binariesArg.values();
bi = binaryPaths.begin();
bend = binaryPaths.end();
res.binaries.reserve(binaryPaths.size());
} }
const auto processPackage = [&] { const auto processPackage = [&] {
for (;;) { for (;;) {
// get next package path // get next package path
auto piLock = std::unique_lock<std::mutex>(piMutex); const char *path = nullptr;
if (pi == pend) { auto isBinary = false;
auto ilock = std::unique_lock<std::mutex>(imutex);
if (pi != pend) {
path = *pi++;
} else if (bi != bend) {
isBinary = true;
path = *bi++;
} else {
return; return;
} }
auto packagePath = *(pi++); ilock.unlock();
piLock.unlock();
// parse package // parse package
try { try {
auto package = LibPkg::Package::fromPkgFile(packagePath); if (isBinary) {
auto packageLock = std::unique_lock<std::mutex>(packageMutex); auto binary = LibPkg::Binary();
packages.emplace_back(std::move(package)); binary.load(path);
auto binaryLock = std::unique_lock<std::mutex>(binaryMutex);
auto &binaryInfo = res.binaries.emplace_back();
binaryInfo.prefix = binary.addPrefix(std::string_view());
binaryInfo.name = std::move(binary.name);
binaryInfo.architecture = std::move(binary.architecture);
binaryInfo.isBigEndian = binary.isBigEndian;
binaryInfo.rpath = std::move(binary.rpath);
binaryInfo.symbols = std::move(binary.symbols);
binaryInfo.requiredLibs = std::move(binary.requiredLibs);
} else {
auto package = LibPkg::Package::fromPkgFile(path);
auto binaryLock = std::unique_lock<std::mutex>(packageMutex);
res.packages.emplace_back(std::move(package));
}
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
std::cerr << "Unable to parse \"" << packagePath << "\": " << e.what() << '\n'; std::cerr << "Unable to parse \"" << path << "\": " << e.what() << '\n';
returnCode = EXIT_FAILURE;
} }
} }
}; };
auto threads auto threads = std::vector<std::thread>(
= std::vector<std::thread>(std::max<std::size_t>(std::min<std::size_t>(std::thread::hardware_concurrency(), packages.capacity()), 1u) - 1); std::max<std::size_t>(std::min<std::size_t>(std::thread::hardware_concurrency(), res.packages.capacity() + res.binaries.capacity()), 1u) - 1);
for (auto &t : threads) { for (auto &t : threads) {
t = std::thread(processPackage); t = std::thread(processPackage);
} }
@ -76,7 +128,9 @@ int main(int argc, const char *argv[])
t.join(); t.join();
} }
const auto json = ReflectiveRapidJSON::JsonReflector::toJson(packages); const auto json = ReflectiveRapidJSON::JsonReflector::toJson(res);
std::cout << std::string_view(json.GetString(), json.GetSize()); std::cout << std::string_view(json.GetString(), json.GetSize());
return 0; return returnCode;
} }
#include "reflection/main.h"