def check(ret_part, name_part, params_part, after_part='', name_without_templates=None): if name_without_templates is None: name_without_templates = re.sub(r'<.*?>', '<>', name_part) + after_part signature = ''.join((name_part, params_part, after_part)) got_full_name, got_template_name, got_name = ( function_signature.Parse(signature)) self.assertEqual(name_without_templates, got_name) self.assertEqual(name_part + after_part, got_template_name) self.assertEqual(name_part + params_part + after_part, got_full_name) if ret_part: signature = ''.join( (ret_part, name_part, params_part, after_part)) got_full_name, got_template_name, got_name = ( function_signature.Parse(signature)) self.assertEqual(name_without_templates, got_name) self.assertEqual(name_part + after_part, got_template_name) self.assertEqual(name_part + params_part + after_part, got_full_name)
def check(ret_part, name_part, params_part, after_part=''): signature = ''.join((name_part, params_part, after_part)) got_full, got_name = function_signature.Parse(signature) self.assertEqual(name_part + after_part, got_name) self.assertEqual(name_part + params_part + after_part, got_full) if ret_part: signature = ''.join( (ret_part, name_part, params_part, after_part)) got_full, got_name = function_signature.Parse(signature) self.assertEqual(name_part + after_part, got_name) self.assertEqual(name_part + params_part + after_part, got_full)
def _NormalizeNames(symbol_group): """Ensures that all names are formatted in a useful way. This includes: - Assigning of |full_name|. - Stripping of return types in |full_name| and |name| (for functions). - Stripping parameters from |name|. - Moving "vtable for" and the like to be suffixes rather than prefixes. """ found_prefixes = set() for symbol in symbol_group: if symbol.name.startswith('*'): # See comment in _RemoveDuplicatesAndCalculatePadding() about when this # can happen. continue # E.g.: vtable for FOO idx = symbol.name.find(' for ', 0, 30) if idx != -1: found_prefixes.add(symbol.name[:idx + 4]) symbol.name = symbol.name[idx + 5:] + ' [' + symbol.name[:idx] + ']' # E.g.: virtual thunk to FOO idx = symbol.name.find(' to ', 0, 30) if idx != -1: found_prefixes.add(symbol.name[:idx + 3]) symbol.name = symbol.name[idx + 4:] + ' [' + symbol.name[:idx] + ']' # Strip out return type, and identify where parameter list starts. if symbol.section == 't': symbol.full_name, symbol.name = function_signature.Parse( symbol.name) # Remove anonymous namespaces (they just harm clustering). non_anonymous = symbol.name.replace('(anonymous namespace)::', '') if symbol.name != non_anonymous: symbol.is_anonymous = True symbol.name = non_anonymous symbol.full_name = symbol.full_name.replace( '(anonymous namespace)::', '') if symbol.section != 't' and '(' in symbol.name: # Pretty rare. Example: # blink::CSSValueKeywordsHash::findValueImpl(char const*)::value_word_list symbol.full_name = symbol.name symbol.name = re.sub(r'\(.*\)', '', symbol.full_name) # Don't bother storing both if they are the same. if symbol.full_name == symbol.name: symbol.full_name = '' logging.debug('Found name prefixes of: %r', found_prefixes)
def testParseFunctionSignature(self): def check(ret_part, name_part, params_part, after_part='', name_without_templates=None): if name_without_templates is None: name_without_templates = re.sub(r'<.*?>', '<>', name_part) + after_part signature = ''.join((name_part, params_part, after_part)) got_full_name, got_template_name, got_name = ( function_signature.Parse(signature)) self.assertEqual(name_without_templates, got_name) self.assertEqual(name_part + after_part, got_template_name) self.assertEqual(name_part + params_part + after_part, got_full_name) if ret_part: signature = ''.join( (ret_part, name_part, params_part, after_part)) got_full_name, got_template_name, got_name = ( function_signature.Parse(signature)) self.assertEqual(name_without_templates, got_name) self.assertEqual(name_part + after_part, got_template_name) self.assertEqual(name_part + params_part + after_part, got_full_name) check('bool ', 'foo::Bar<unsigned int, int>::Do<unsigned int>', '(unsigned int)') check('base::internal::CheckedNumeric<int>& ', 'base::internal::CheckedNumeric<int>::operator+=<int>', '(int)') check('base::internal::CheckedNumeric<int>& ', 'b::i::CheckedNumeric<int>::MathOp<b::i::CheckedAddOp, int>', '(int)') check('', '(anonymous namespace)::GetBridge', '(long long)') check('', 'operator delete', '(void*)') check( '', 'b::i::DstRangeRelationToSrcRangeImpl<long long, long long, ' 'std::__ndk1::numeric_limits, (b::i::Integer)1>::Check', '(long long)') check('', 'cc::LayerIterator::operator cc::LayerIteratorPosition const', '()', ' const') check('decltype ({parm#1}((SkRecords::NoOp)())) ', 'SkRecord::Record::visit<SkRecords::Draw&>', '(SkRecords::Draw&)', ' const') check('', 'base::internal::BindStateBase::BindStateBase', '(void (*)(), void (*)(base::internal::BindStateBase const*))') check('int ', 'std::__ndk1::__c11_atomic_load<int>', '(std::__ndk1::<int> volatile*, std::__ndk1::memory_order)') check('std::basic_ostream<char, std::char_traits<char> >& ', 'std::operator<< <std::char_traits<char> >', '(std::basic_ostream<char, std::char_traits<char> >&, char)', name_without_templates='std::operator<< <>') check('', 'std::basic_istream<char, std::char_traits<char> >' '::operator>>', '(unsigned int&)', name_without_templates='std::basic_istream<>::operator>>') check('', 'std::operator><std::allocator<char> >', '()', name_without_templates='std::operator><>') check('', 'std::operator>><std::allocator<char> >', '(std::basic_istream<char, std::char_traits<char> >&)', name_without_templates='std::operator>><>') check('', 'std::basic_istream<char>::operator>', '(unsigned int&)', name_without_templates='std::basic_istream<>::operator>') check( 'v8::internal::SlotCallbackResult ', 'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget' '<v8::PointerUpdateJobTraits<(v8::Direction)1>::Foo(v8::Heap*, ' 'v8::MemoryChunk*)::{lambda(v8::SlotType, unsigned char*)#2}::' 'operator()(v8::SlotType, unsigned char*, unsigned char*) ' 'const::{lambda(v8::Object**)#1}>', '(v8::RelocInfo, v8::Foo<(v8::PointerDirection)1>::Bar(v8::Heap*)::' '{lambda(v8::SlotType)#2}::operator()(v8::SlotType) const::' '{lambda(v8::Object**)#1})', name_without_templates=( 'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget<>')) check( '', 'WTF::StringAppend<WTF::String, WTF::String>::operator WTF::String', '()', ' const') # Make sure []s are not removed from the name part. check('', 'Foo', '()', ' [virtual thunk]') # Template function that accepts an anonymous lambda. check( '', 'blink::FrameView::ForAllNonThrottledFrameViews<blink::FrameView::Pre' 'Paint()::{lambda(FrameView&)#2}>', '(blink::FrameView::PrePaint()::{lambda(FrameView&)#2} const&)', '') # Test with multiple template args. check('int ', 'Foo<int()>::bar<a<b> >', '()', name_without_templates='Foo<>::bar<>') # SkArithmeticImageFilter.cpp has class within function body. e.g.: # ArithmeticFP::onCreateGLSLInstance() looks like: # class ArithmeticFP { # GrGLSLFragmentProcessor* onCreateGLSLInstance() const { # class GLSLFP { # void emitCode(EmitArgs& args) { ... } # }; # ... # } # }; SIG = '(anonymous namespace)::Foo::Baz() const::GLSLFP::onData(Foo, Bar)' got_full_name, got_template_name, got_name = ( function_signature.Parse(SIG)) self.assertEqual('(anonymous namespace)::Foo::Baz', got_name) self.assertEqual('(anonymous namespace)::Foo::Baz', got_template_name) self.assertEqual(SIG, got_full_name) # Top-level lambda. # Note: Inline lambdas do not seem to be broken into their own symbols. SIG = 'cc::{lambda(cc::PaintOp*)#63}::_FUN(cc::PaintOp*)' got_full_name, got_template_name, got_name = ( function_signature.Parse(SIG)) self.assertEqual('cc::$lambda#63', got_name) self.assertEqual('cc::$lambda#63', got_template_name) self.assertEqual('cc::$lambda#63(cc::PaintOp*)', got_full_name) SIG = 'cc::$_63::__invoke(cc::PaintOp*)' got_full_name, got_template_name, got_name = ( function_signature.Parse(SIG)) self.assertEqual('cc::$lambda#63', got_name) self.assertEqual('cc::$lambda#63', got_template_name) self.assertEqual('cc::$lambda#63(cc::PaintOp*)', got_full_name) # Data members check('', 'blink::CSSValueKeywordsHash::findValueImpl', '(char const*)', '::value_word_list') check('', 'foo::Bar<Z<Y> >::foo<bar>', '(abc)', '::var<baz>', name_without_templates='foo::Bar<>::foo<>::var<>')
def testParseFunctionSignature(self): def check(ret_part, name_part, params_part, after_part=''): signature = ''.join((name_part, params_part, after_part)) got_full, got_name = function_signature.Parse(signature) self.assertEqual(name_part + after_part, got_name) self.assertEqual(name_part + params_part + after_part, got_full) if ret_part: signature = ''.join( (ret_part, name_part, params_part, after_part)) got_full, got_name = function_signature.Parse(signature) self.assertEqual(name_part + after_part, got_name) self.assertEqual(name_part + params_part + after_part, got_full) check('bool ', 'foo::Bar<unsigned int, int>::Do<unsigned int>', '(unsigned int)') check('base::internal::CheckedNumeric<int>& ', 'base::internal::CheckedNumeric<int>::operator+=<int>', '(int)') check('base::internal::CheckedNumeric<int>& ', 'b::i::CheckedNumeric<int>::MathOp<b::i::CheckedAddOp, int>', '(int)') check('', '(anonymous namespace)::GetBridge', '(long long)') check('', 'operator delete', '(void*)') check( '', 'b::i::DstRangeRelationToSrcRangeImpl<long long, long long, ' 'std::__ndk1::numeric_limits, (b::i::Integer)1>::Check', '(long long)') check('', 'cc::LayerIterator::operator cc::LayerIteratorPosition const', '()', ' const') check('decltype ({parm#1}((SkRecords::NoOp)())) ', 'SkRecord::Record::visit<SkRecords::Draw&>', '(SkRecords::Draw&)', ' const') check('', 'base::internal::BindStateBase::BindStateBase', '(void (*)(), void (*)(base::internal::BindStateBase const*))') check('int ', 'std::__ndk1::__c11_atomic_load<int>', '(std::__ndk1::<int> volatile*, std::__ndk1::memory_order)') check('std::basic_ostream<char, std::char_traits<char> >& ', 'std::operator<< <std::char_traits<char> >', '(std::basic_ostream<char, std::char_traits<char> >&, char)') check( 'v8::internal::SlotCallbackResult ', 'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget' '<v8::PointerUpdateJobTraits<(v8::Direction)1>::Foo(v8::Heap*, ' 'v8::MemoryChunk*)::{lambda(v8::SlotType, unsigned char*)#2}::' 'operator()(v8::SlotType, unsigned char*, unsigned char*) ' 'const::{lambda(v8::Object**)#1}>', '(v8::RelocInfo, v8::Foo<(v8::PointerDirection)1>::Bar(v8::Heap*)::' '{lambda(v8::SlotType)#2}::operator()(v8::SlotType) const::' '{lambda(v8::Object**)#1})') check( '', 'WTF::StringAppend<WTF::String, WTF::String>::operator WTF::String', '()', ' const') # Make sure []s are not removed from the name part. check('', 'Foo', '()', ' [virtual thunk]') # SkArithmeticImageFilter.cpp has class within function body. e.g.: # ArithmeticFP::onCreateGLSLInstance() looks like: # class ArithmeticFP { # GrGLSLFragmentProcessor* onCreateGLSLInstance() const { # class GLSLFP { # void emitCode(EmitArgs& args) { ... } # }; # ... # } # }; SIG = '(anonymous namespace)::Foo::Baz() const::GLSLFP::onData(Foo, Bar)' got_full, got_name = function_signature.Parse(SIG) self.assertEqual('(anonymous namespace)::Foo::Baz', got_name) self.assertEqual(SIG, got_full)
def _NormalizeNames(raw_symbols): """Ensures that all names are formatted in a useful way. This includes: - Deriving |name| and |template_name| from |full_name|. - Stripping of return types (for functions). - Moving "vtable for" and the like to be suffixes rather than prefixes. """ found_prefixes = set() for symbol in raw_symbols: full_name = symbol.full_name if full_name.startswith('*'): # See comment in _CalculatePadding() about when this # can happen. symbol.template_name = full_name symbol.name = full_name continue # Remove [clone] suffix, and set flag accordingly. # Search from left-to-right, as multiple [clone]s can exist. # Example name suffixes: # [clone .part.322] # GCC # [clone .isra.322] # GCC # [clone .constprop.1064] # GCC # [clone .11064] # clang # http://unix.stackexchange.com/questions/223013/function-symbol-gets-part-suffix-after-compilation idx = full_name.find(' [clone ') if idx != -1: full_name = full_name[:idx] symbol.flags |= models.FLAG_CLONE # Clones for C symbols. if symbol.section == 't': idx = full_name.rfind('.') if idx != -1 and full_name[idx + 1:].isdigit(): new_name = full_name[:idx] # Generated symbols that end with .123 but are not clones. # Find these via: # size_info.symbols.WhereInSection('t').WhereIsGroup().SortedByCount() if new_name not in ('__tcf_0', 'startup'): full_name = new_name symbol.flags |= models.FLAG_CLONE # Remove .part / .isra / .constprop. idx = full_name.rfind('.', 0, idx) if idx != -1: full_name = full_name[:idx] # E.g.: vtable for FOO idx = full_name.find(' for ', 0, 30) if idx != -1: found_prefixes.add(full_name[:idx + 4]) full_name = '{} [{}]'.format(full_name[idx + 5:], full_name[:idx]) # E.g.: virtual thunk to FOO idx = full_name.find(' to ', 0, 30) if idx != -1: found_prefixes.add(full_name[:idx + 3]) full_name = '{} [{}]'.format(full_name[idx + 4:], full_name[:idx]) # Strip out return type, and split out name, template_name. # Function parsing also applies to non-text symbols. E.g. Function statics. symbol.full_name, symbol.template_name, symbol.name = ( function_signature.Parse(full_name)) # Remove anonymous namespaces (they just harm clustering). symbol.template_name = symbol.template_name.replace( '(anonymous namespace)::', '') symbol.full_name = symbol.full_name.replace( '(anonymous namespace)::', '') non_anonymous_name = symbol.name.replace('(anonymous namespace)::', '') if symbol.name != non_anonymous_name: symbol.flags |= models.FLAG_ANONYMOUS symbol.name = non_anonymous_name # Allow using "is" to compare names (and should help with RAM). function_signature.InternSameNames(symbol) logging.debug('Found name prefixes of: %r', found_prefixes)