blob: 2bc78845d7926d04e079ed6cec8020dc0c86b3bf [file] [log] [blame]
// Copyright 2016 The Tulsi Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <assert.h>
#include <stdio.h>
#include <list>
#include <vector>
#include "covmap_patcher.h"
#include "dwarf_string_patcher.h"
#include "mach_o_container.h"
#include "mach_o_file.h"
using post_processor::CovmapPatcher;
using post_processor::DWARFStringPatcher;
using post_processor::MachOContainer;
using post_processor::MachOFile;
using post_processor::ReturnCode;
namespace {
struct PatchSettings {
std::string filename; // The path of the file to act on.
std::string old_prefix; // The path prefix to be replaced.
std::string new_prefix; // The new path prefix to replace old_prefix.
bool patch_dwarf_symbols; // Whether or not to patch DWARF paths.
bool patch_coverage_maps; // Whether or not to patch LLVM coverage maps.
bool verbose; // Enables verbose output.
};
void PrintUsage(const char *executable_name);
ReturnCode Patch(MachOFile *, const PatchSettings &);
} // namespace
int main(int argc, const char* argv[]) {
if (argc < 4) {
PrintUsage(argv[0]);
return 127;
}
PatchSettings patch_settings;
patch_settings.patch_coverage_maps = false;
patch_settings.patch_dwarf_symbols = false;
patch_settings.verbose = false;
std::vector<std::string> filenames;
for (int i = 1; i < argc - 2; ++i) {
const char *arg = argv[i];
if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose")) {
patch_settings.verbose = true;
continue;
}
if (!strcmp(arg, "-c") || !strcmp(arg, "--covmap")) {
patch_settings.patch_coverage_maps = true;
continue;
}
if (!strcmp(arg, "-d") || !strcmp(arg, "--dwarf")) {
patch_settings.patch_dwarf_symbols = true;
continue;
}
if (arg[0] == '-') {
fprintf(stderr, "Unknown option %s\n", arg);
return 127;
}
filenames.push_back(arg);
}
if (!patch_settings.verbose &&
!patch_settings.patch_dwarf_symbols &&
!patch_settings.patch_coverage_maps) {
PrintUsage(argv[0]);
return 127;
}
patch_settings.old_prefix = argv[argc - 2];
patch_settings.new_prefix = argv[argc - 1];
for (auto &filename : filenames) {
patch_settings.filename = filename;
MachOContainer f(filename, patch_settings.verbose);
ReturnCode retval = f.Read();
if (retval != post_processor::ERR_OK) {
fprintf(stderr,
"ERROR: Failed to read Mach-O content from %s.\n",
filename.c_str());
return retval;
}
if (f.Has32Bit()) {
retval = Patch(&f.GetMachOFile32(), patch_settings);
if (retval != post_processor::ERR_OK) {
return retval;
}
}
if (f.Has64Bit()) {
retval = Patch(&f.GetMachOFile64(), patch_settings);
if (retval != post_processor::ERR_OK) {
return retval;
}
}
retval = f.PerformDeferredWrites();
if (retval != post_processor::ERR_OK) {
return retval;
}
}
if (patch_settings.verbose) {
printf("Patching completed successfully.\n");
}
return 0;
}
namespace {
void PrintUsage(const char *executable_name) {
printf("Usage: %s <mode_options> <object_file> <old_path> <new_path>\n",
executable_name);
printf("Modifies the contents of the LLVM coverage map in the given "
"object_file by replacing any paths that start with \"old_path\" "
"with \"new_path\".\n");
printf("\nMode options (at least one is required):\n"
"\t-v, --verbose:\n"
"\t Print out verbose information during Mach parsing.\n"
"\t-c, --covmap:\n"
"\t Patch paths in LLVM coverage maps.\n"
"\t-d, --dwarf:\n"
"\t Patch paths in DWARF symbols.\n");
}
ReturnCode Patch(MachOFile *f, const PatchSettings &settings) {
if (settings.patch_coverage_maps) {
CovmapPatcher patcher(settings.old_prefix,
settings.new_prefix,
settings.verbose);
ReturnCode retval = patcher.Patch(f);
if (retval != post_processor::ERR_OK &&
retval != post_processor::ERR_WRITE_DEFERRED) {
return retval;
}
}
if (settings.patch_dwarf_symbols) {
DWARFStringPatcher patcher(settings.old_prefix,
settings.new_prefix,
settings.verbose);
ReturnCode retval = patcher.Patch(f);
if (retval != post_processor::ERR_OK &&
retval != post_processor::ERR_WRITE_DEFERRED) {
return retval;
}
}
return post_processor::ERR_OK;
}
} // namespace