/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * 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 "src/traced/probes/ftrace/ftrace_print_filter.h"

#include <string.h>

#include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
#include "src/traced/probes/ftrace/event_info_constants.h"

namespace perfetto {
namespace {
using ::perfetto::protos::gen::FtraceConfig;

bool PrefixMatches(const std::string& prefix, const char* start, size_t size) {
  if (prefix.size() > size) {
    return false;
  }
  return strncmp(prefix.c_str(), start, prefix.size()) == 0;
}

bool AtraceMessageMatches(const std::string& before_pid_part,
                          const std::string& after_pid_prefix,
                          const char* start,
                          size_t size) {
  base::StringView s(start, size);
  if (!s.StartsWith(base::StringView(before_pid_part))) {
    return false;
  }
  s = s.substr(before_pid_part.size());

  if (!s.StartsWith("|")) {
    return false;
  }
  s = s.substr(1);

  size_t skip_pid_count = 0;
  for (;; skip_pid_count++) {
    if (skip_pid_count == s.size()) {
      return false;
    }
    if (s.at(skip_pid_count) == '|') {
      break;
    }
    if (!isdigit(s.at(skip_pid_count))) {
      return false;
    }
  }
  skip_pid_count++;
  s = s.substr(skip_pid_count);

  return PrefixMatches(after_pid_prefix, s.data(), s.size());
}

}  // namespace

// static
bool FtracePrintFilter::RuleMatches(const Rule& rule,
                                    const char* start,
                                    size_t size) {
  switch (rule.type) {
    case Rule::Type::kAtraceMessage:
      return AtraceMessageMatches(rule.before_pid_part, rule.prefix, start,
                                  size);
    case Rule::Type::kPrefixMatch:
      break;
  }
  return PrefixMatches(rule.prefix, start, size);
}

FtracePrintFilter::FtracePrintFilter(const FtraceConfig::PrintFilter& conf) {
  rules_.reserve(conf.rules().size());
  for (const FtraceConfig::PrintFilter::Rule& conf_rule : conf.rules()) {
    Rule rule;
    rule.allow = conf_rule.allow();
    if (conf_rule.has_atrace_msg()) {
      rule.type = Rule::Type::kAtraceMessage;
      rule.before_pid_part = conf_rule.atrace_msg().type();
      rule.prefix = conf_rule.atrace_msg().prefix();
    } else {
      rule.type = Rule::Type::kPrefixMatch;
      rule.prefix = conf_rule.prefix();
    }
    rules_.push_back(std::move(rule));
  }
}

bool FtracePrintFilter::IsAllowed(const char* start, size_t size) const {
  for (const Rule& rule : rules_) {
    if (RuleMatches(rule, start, size)) {
      return rule.allow;
    }
  }
  return true;
}

// static
std::optional<FtracePrintFilterConfig> FtracePrintFilterConfig::Create(
    const protos::gen::FtraceConfig::PrintFilter& config,
    ProtoTranslationTable* table) {
  const Event* print_event = table->GetEvent(GroupAndName("ftrace", "print"));
  if (!print_event) {
    return std::nullopt;
  }
  const Field* buf_field = nullptr;
  for (const Field& field : print_event->fields) {
    if (strcmp(field.ftrace_name, "buf") == 0) {
      buf_field = &field;
      break;
    }
  }
  if (!buf_field) {
    return std::nullopt;
  }

  if (buf_field->strategy != kCStringToString) {
    return std::nullopt;
  }
  FtracePrintFilterConfig ret{FtracePrintFilter{config}};
  ret.event_id_ = print_event->ftrace_event_id;
  ret.event_size_ = print_event->size;
  ret.buf_field_offset_ = buf_field->ftrace_offset;
  return std::move(ret);
}

FtracePrintFilterConfig::FtracePrintFilterConfig(FtracePrintFilter filter)
    : filter_(filter) {}

bool FtracePrintFilterConfig::IsEventInteresting(const uint8_t* start,
                                                 const uint8_t* end) const {
  PERFETTO_DCHECK(start < end);
  const size_t length = static_cast<size_t>(end - start);

  // If the end of the buffer is before the end of the event, give up.
  if (event_size_ >= length) {
    PERFETTO_DFATAL("Buffer overflowed.");
    return true;
  }

  const uint8_t* field_start = start + buf_field_offset_;
  return filter_.IsAllowed(reinterpret_cast<const char*>(field_start),
                           static_cast<size_t>(end - field_start));
}

}  // namespace perfetto
