blob: 924e91ccb1b559e02c1dece378f5adbaf6d64fdf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* @author Mikhail Y. Fursov
*/
#include "MTable.h"
#include <assert.h>
#include <algorithm>
#include "open/vm_method_access.h"
#include "open/vm_class_manipulation.h"
MTable::~MTable() {
for (FiltersQueue::const_iterator it = methodFilters.begin(), end = methodFilters.end(); it!=end; ++it) {
MethodFilter* filter = *it;
delete filter;
}
methodFilters.clear();
}
bool isNum(const std::string& str) {
return str.size() > 0 && str.size() < 10
&& *std::min_element(str.begin(), str.end()) >= '0'
&& *std::max_element(str.begin(), str.end()) <= '9';
}
bool MTable::addMethodFilter(const std::string& configLine) {
assert(!configLine.empty());
bool accept = configLine[0]!='-';
std::string filterString = configLine[0]=='+'||configLine[0]=='-' ? configLine.substr(1): configLine;
if (filterString[0] >= '0' && filterString[0]<='9') {
//bytecode size filter or method num filter
size_t divPos = filterString.find("..");
std::string start;
std::string end;
if (divPos == std::string::npos){
start = filterString;
end = filterString;
} else {;
start = filterString.substr(0, divPos);
end = filterString.substr(divPos + 2);
}
bool bcFilter = false;
if (*start.rbegin()=='b' || *start.rbegin()=='B') {
if (*end.rbegin()!='b' && *end.rbegin()!='B') {
return false;
}
start = start.substr(0, start.length()-1);
end = end.substr(0, end.length()-1);
bcFilter = true;
}
if (!isNum(start) || !isNum(end)) {
return false;
}
size_t _start = atoi(start.c_str());
size_t _end= atoi(end.c_str());
if (_start > _end) {
return false;
}
if (bcFilter) {
addBCSizeMethodFilter(accept, _start, _end);
} else {
addNumRangeMethodFilter(accept, _start, _end);
}
} else {
std::string className, methodName, signature;
size_t separatorWidth=1;
size_t classEndPos = filterString.find(".");
if (classEndPos == std::string::npos) {
separatorWidth = 2;
classEndPos = filterString.find("::");
}
if (classEndPos == std::string::npos) {
className = filterString;
} else {
className = filterString.substr(0, classEndPos);
size_t methodEndPos = filterString.find("(", classEndPos+separatorWidth);
if (methodEndPos==std::string::npos) {
methodName = filterString.substr(classEndPos+separatorWidth);
} else {
methodName = filterString.substr(classEndPos+separatorWidth, methodEndPos - (classEndPos+separatorWidth));
signature = filterString.substr(methodEndPos);
}
}
addNameMethodFilter(accept, className, methodName, signature);
}
return true;
}
void MTable::addNumRangeMethodFilter(bool accept, size_t start, size_t end) {
assert(start <= end);
MethodFilter::Mode mode = accept?MethodFilter::MODE_ACCEPT : MethodFilter::MODE_DENY;
MethodFilter* filter = new NumRangeMethodFilter(mode, start, end);
methodFilters.push_back(filter);
}
void MTable::addBCSizeMethodFilter(bool accept, size_t start, size_t end) {
assert(start <= end);
MethodFilter::Mode mode = accept?MethodFilter::MODE_ACCEPT : MethodFilter::MODE_DENY;
MethodFilter* filter = new BCSizeMethodFilter(mode, start, end);
methodFilters.push_back(filter);
}
void MTable::addNameMethodFilter(bool accept, const std::string& className,
const std::string& methodName, const std::string& signature)
{
MethodFilter::Mode mode = accept?MethodFilter::MODE_ACCEPT : MethodFilter::MODE_DENY;
MethodFilter* filter = new NameMethodFilter(mode, className, methodName, signature);
methodFilters.push_back(filter);
}
bool MTable::acceptMethod(Method_Handle mh, size_t num) const {
if (!methodFilters.empty()) {
MethodInfo mInfo(mh, num);
for (FiltersQueue::const_iterator it = methodFilters.begin(), end = methodFilters.end(); it!=end; ++it) {
MethodFilter* filter = *it;
bool matched = filter->matchMethod(mInfo);
if (!matched) {
continue;
}
return filter->getMode() == MethodFilter::MODE_ACCEPT ? true : false;
}
}
return true;
}
MTable::MethodInfo::MethodInfo(Method_Handle _mh, size_t _num) {
num = _num;
mh = _mh;
Class_Handle ch = method_get_class(mh);
className = class_get_name(ch);
methodName = method_get_name(mh);
signature = method_get_descriptor(mh);
assert(!className.empty() && !methodName.empty() && !signature.empty());
}
bool MTable::NumRangeMethodFilter::matchMethod(const MTable::MethodInfo& mInfo) const {
bool matched = mInfo.num >= start && mInfo.num <=end;
return matched;
}
bool MTable::BCSizeMethodFilter::matchMethod(const MTable::MethodInfo& mInfo) const {
size_t size = method_get_bytecode_length(mInfo.mh);
bool matched = size >=start && size<=end;
return matched;
}
bool startsWith(const std::string& str, const std::string& prefix) {
if (str.length() < prefix.length()) {
return false;
}
return std::equal(prefix.begin(), prefix.end(), str.begin());
}
bool MTable::NameMethodFilter::matchMethod(const MTable::MethodInfo& mInfo) const {
bool matched = true;
if (!className.empty()) {
matched = startsWith(mInfo.className, className);
}
if (matched && !methodName.empty()) {
matched = startsWith(mInfo.methodName, methodName);
}
if (matched && !signature.empty()) {
matched = startsWith(mInfo.signature, signature);
}
return matched;
}