�ɲɾ�����ӯ�����һ��ˣ��������С���˴��ͣ�������P���ҹ��ñ˽��ά�Բ��������˸߸ԣ�������ơ��ҹ��ñ�����ά�Բ���ˡ���˳^�ӣ������ӡ� ���ͯj�ӣ��ƺ���ӣ� ? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!PK1]3,xexe6libstdcxx/v6/__pycache__/printers.cpython-36.opt-1.pycnu[3 h@sddlZddlZddlZddlZddlZddlZejddkrXeZe Z e Z e ZejjZn6GdddZddlm Z m Z GdddejZeZday ddlZWnek rd aYnXd ayddlZeejd rdaWnek rYnXeed rejZneZd d ZdaddZddZ ddZ!ddZ"ddZ#ddZ$ddZ%ddZ&Gdd d eZ'Gd!d"d"eZ(d#d$Z)d%d&Z*d'd(Z+Gd)d*d*eZ,d+d,Z-d-d.Z.Gd/d0d0eZ/Gd1d2d2eZ0Gd3d4d4e0Z1Gd5d6d6e0Z2Gd7d8d8eZ3Gd9d:d:eZ4Gd;d<dd>eZ6Gd?d@d@eZ7GdAdBdBeZ8GdCdDdDeZ9GdEdFdFeZ:GdGdHdHeZ;dIdJZdOdPZ?GdQdRdReZ@GdSdTdTeZAGdUdVdVeZBGdWdXdXeZCGdYdZdZeZDGd[d\d\eZEd]d^ZFGd_d`d`eZGGdadbdbeZHGdcddddeZIGdedfdfeZJGdgdhdheZKGdidjdjeZLGdkdldleZMGdmdndneZNdodpZOGdqdrdreNZPGdsdtdteNZQGdudvdveNZRGdwdxdxeNZSGdydzdzeZTGd{d|d|eZUGd}d~d~eZVGdddeZWGdddeZXGdddeZYGdddeZZGdddeZ[GdddeZ\GdddeZ]GdddeZ^GdddeZ_GdddeZ`GdddeZadddddddddddddg ZbddddddddgZcGdddeZdGdddeZeGdddeZfGdddeZgGdddeZhGdddeZiGdddeZjGdddeZkGdddeZlGdddeZmdanGdddeZoddZpGdddeZqdddÄZrddńZsddDŽZtddɄZueudS)Nc@seZdZdZddZdS)Iteratora:Compatibility mixin for iterators Instead of writing next() methods for iterators, write __next__() methods and use this mixin to make them work in Python 2 as well as Python 3. Idea stolen from the "six" documentation: cCs|jS)N)__next__)selfr0/usr/share/gcc-8/python/libstdcxx/v6/printers.pynext?sz Iterator.nextN)__name__ __module__ __qualname____doc__rrrrrr4s r)imapizipc@s(eZdZdZddZddZddZdS) UTCz5Concrete tzinfo class representing the UTC time zone.cCs tjdS)Nr)datetime timedelta)rdtrrr utcoffsetIsz UTC.utcoffsetcCsdS)Nrr)rrrrrtznameLsz UTC.tznamecCs tjdS)Nr)rr)rrrrrdstOszUTC.dstN)r r r r rrrrrrrrFsrTFZ TypePrinter ValuePrinterc Csz|j}xld|j|f}y tj|Stk r6YnX|j}t|r^|djr^|dj}q t dt ||fq WdS)Nz%s::%srzCannot find type %s::%s) strip_typedefstaggdb lookup_type RuntimeErrorfieldslen is_base_classtype ValueErrorstr)Zorignametypsearchrrrr find_typens  r%z__8::cGsdj|djdd|D}y tj|Stjk r}zFt|krv|jddtd}y tj|Stjk rtYnX|WYdd}~XnXdS)z8 Lookup template specialization templ. z{}<{}>z, cSsg|] }t|qSr)r!).0arrr sz%lookup_templ_spec..z::N)formatjoinrrerror_versioned_namespacereplace)Ztemplargsterrrlookup_templ_specs  r2cCsd|krd|}yt|d}Wn|jd}YnX|j}y t||Stjk rt|drt|dddr|jdd d }y t||Stjk rYnXd SXd S) a Lookup specialization of template nodename corresponding to containertype. nodename - The name of a class template, as a String containertype - The container, as a gdb.Type Return a gdb.Type for the corresponding specialization of nodename, or None if the type cannot be found. e.g. lookup_node_type('_List_node', gdb.lookup_type('std::list')) will return a gdb.Type for the type std::_List_node. z::zstd:: value_typerZstdzstd::__cxx1998z std::__debugZ __gnu_debugz ::__cxx1998::r)N)r%template_argumentrr2rr,is_member_of_namespacer.)nodenameZ containertypevaltyperrrlookup_node_types&   r8cGs@t|tjrt|}t|}x|D]}|j|dr"dSq"WdS)z Test whether a type is a member of one of the specified namespaces. The type can be specified as a string or a gdb.Type object. z::TF) isinstancerTyper!strip_versioned_namespace startswith)r#Z namespaces namespacerrrr5s  r5cCs2t|tjr|j}dt|f}tjd||dk S)z Test whether a type is a specialization of the named class template. The type can be specified as a string or a gdb.Type object. The template should be the name of a class template as a string, without any 'std' qualification. z(%s)?%sz ^std::%s<.*>$N)r9rr:rr-rematch)x template_namerrris_specialization_ofs  rBcCs |jtdS)N)r.r-)typenamerrrr;sr;cCs<d}d}tjddkr&tj|||dStj|||ddSdS)zCRemove "fundamentals_vN" inline namespace from qualified type name.z&^std::experimental::fundamentals_v\d::zstd::experimental::rrr))countN)sys version_infor>sub)r#patternreplrrrstrip_fundts_namespaces rKcCsVt|}|jdd}d}x d D]}|j||d|}qW|d}|j|d|}|S) zARemove known inline namespaces from the canonical name of a type.zstd::__cxx11::zstd::zstd::experimental::fundamentals_v1fundamentals_v2z::z filesystem::zv1::)rLrM)r;r.)type_strZexpt_nsZlfts_nsZfs_nsrrrstrip_inline_namespacess  rOc Cs:d}g}x,y|j|j|Wn |S|d7}q WdS)z-Return a type's template arguments as a list.rr)N)appendr4)type_objn template_argsrrrget_template_arg_listsrTc@s(eZdZdZddZddZddZdS) SmartPtrIteratorz@An iterator for smart pointer types with a single 'child' value.cCs ||_dS)N)_val)rvalrrr__init__szSmartPtrIterator.__init__cCs|S)Nr)rrrr__iter__szSmartPtrIterator.__iter__cCs$|jdkrtd|j|_}d|fS)Nzget())rV StopIteration)rrWrrrr s zSmartPtrIterator.__next__N)r r r r rXrYrrrrrrUsrUc@s0eZdZdZddZddZddZdd Zd S) SharedPointerPrinterzP Print a shared_ptr, weak_ptr, atomic, or atomic. cCst||_||_|d|_dS)N_M_ptr)r; _typenamerV_pointer)rrDrWrrrrXs zSharedPointerPrinter.__init__cCs t|jS)N)rUr^)rrrrchildrenszSharedPointerPrinter.childrencCsR|jdkrD|jddd}||d}t|jdjd}|j|S|jddS)Nz std::atomicZ _M_refcountZ_M_val_M_irpointerZ_M_pi)r]rVr%rcast)rZptr_valZptr_typerrr_get_refcountss    z#SharedPointerPrinter._get_refcountscCspd}|j}|jjjd}tt|}|dkr`|d}|d}|dkrPd|}nd||df}d|j||fS) NemptyrZ _M_use_countZ _M_weak_countzexpired, weak count %dzuse count %d, weak count %dr)z %s<%s> (%s))rcrVrr4r;r!r])rstateZ refcountstargZusecountZ weakcountrrr to_string(s  zSharedPointerPrinter.to_stringN)r r r r rXr_rcrgrrrrr[s  r[cCs|jj}|djs&tdt|j|j|dj}|jj}t|dkr^tdt|j|djdkrt|dS|djr|j|djStdt|jdS)zBReturn the tuple element stored in a _Tuple_impl base class.r)z-Unsupported implementation for std::tuple: %sr _M_head_implNri)rrrr r!rbrr")rWbasesZ head_baserrrr_tuple_impl_get9s     rkcCshtt|j}||krtd|j|jjdj}x*|dkr^|j|jjdj}|d8}q6Wt|S)z6Return the result of std::get(val) on a std::tuple.z0Out of range index for std::get on std::tuplerr))rrTrr rbrrk)rRrWZ tuple_sizenoderrr tuple_getQs  rmcCsd|jjdjj}t|ds(t|dr6|dd}n$t|drJ|d}ntdt|td|S)z4Return the result of val.get() on a std::unique_ptr.rZ__uniq_ptr_dataZ__uniq_ptr_impl_M_ttuplez-Unsupported implementation for unique_ptr: %s)rrrrBr r!rm)rWZ impl_typeZ tuple_memberrrrunique_ptr_get_s    rpc@s(eZdZdZddZddZddZdS) UniquePointerPrinterzPrint a unique_ptr.cCs ||_dS)N)rV)rrDrWrrrrXtszUniquePointerPrinter.__init__cCstt|jS)N)rUrprV)rrrrr_wszUniquePointerPrinter.childrencCs|jjjd}djt|S)Nrzstd::unique_ptr<{}>)rVrr4r*r!)rr0rrrrgzszUniquePointerPrinter.to_stringN)r r r r rXr_rgrrrrrqqsrqcCs|djj|jjS)z7Return the value held in a __gnu_cxx::__aligned_membuf. _M_storage)addressrbra dereference)Zbufr7rrrget_value_from_aligned_membufsruc CsjyF|jjdj}|dkr"|dS|dkrD|jjd}t|d|SWn YnXtdt|jdS)z-Return the value held in an _List_node<_Val>.r)_M_datarrrz!Unsupported implementation for %sN)rrr"r4rur r!)rlmemberr7rrrget_value_from_list_nodes rxc@s8eZdZdZGdddeZddZddZdd Zd S) StdListPrinterzPrint a std::list.c@s$eZdZddZddZddZdS)zStdListPrinter._iteratorcCs"||_|d|_|j|_d|_dS)N_M_nextr) _nodetype_basers_head_count)rnodetypeheadrrrrXs z!StdListPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz!StdListPrinter._iterator.__iter__cCsR|j|jkrt|jj|jj}|d|_|j}|jd|_t|}d||fS)Nrzr)z[%d])r|r}rZrbr{rtr~rx)reltrErWrrrrs   z!StdListPrinter._iterator.__next__N)r r r rXrYrrrrr _iteratorsrcCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zStdListPrinter.__init__cCs(td|jjj}|j||jddS)N _List_node_M_impl_M_node)r8rVrrar)rrrrrr_szStdListPrinter.childrencCs0|jdd}|d|jkr&d|jSd|jS)Nrrrzzempty %sz%s)rVrsr])rZheadnoderrrrgs zStdListPrinter.to_stringN) r r r r rrrXr_rgrrrrrys ryc@seZdZddZddZdS)NodeIteratorPrintercCs$||_||_||_t||j|_dS)N)rVr] _contnamer8rr{)rrDrWZcontnamer6rrrrXszNodeIteratorPrinter.__init__cCs:|jdsd|jS|jdj|jjj}tt|S)Nrz(non-dereferenceable iterator for std::%s)rVrrbr{rartr!rx)rrlrrrrgs    zNodeIteratorPrinter.to_stringN)r r r rXrgrrrrrsrc@seZdZdZddZdS)StdListIteratorPrinterzPrint std::list::iterator.cCstj|||dddS)Nlistr)rrX)rrDrWrrrrXszStdListIteratorPrinter.__init__N)r r r r rXrrrrrsrc@seZdZdZddZdS)StdFwdListIteratorPrinterz"Print std::forward_list::iterator.cCstj|||dddS)N forward_list_Fwd_list_node)rrX)rrDrWrrrrXs z"StdFwdListIteratorPrinter.__init__N)r r r r rXrrrrrsrc@s8eZdZdZGdddeZddZddZdd Zd S) StdSlistPrinterzPrint a __gnu_cxx::slist.c@s$eZdZddZddZddZdS)zStdSlistPrinter._iteratorcCs||_|dd|_d|_dS)N_M_headrzr)r{r|r~)rrrrrrrXsz"StdSlistPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz"StdSlistPrinter._iterator.__iter__cCsL|jdkrt|jj|jj}|d|_|j}|jd|_d||dfS)Nrrzr)z[%d]rv)r|rZrbr{rtr~)rrrErrrrs   z"StdSlistPrinter._iterator.__next__N)r r r rXrYrrrrrrsrcCs ||_dS)N)rV)rrDrWrrrrXszStdSlistPrinter.__init__cCs td|jj}|j|j|jS)Nz__gnu_cxx::_Slist_node)r8rVrrra)rrrrrr_szStdSlistPrinter.childrencCs|jdddkrdSdS)Nrrzrzempty __gnu_cxx::slistz__gnu_cxx::slist)rV)rrrrrgszStdSlistPrinter.to_stringN) r r r r rrrXr_rgrrrrrs rc@s eZdZdZddZddZdS)StdSlistIteratorPrinterz!Print __gnu_cxx::slist::iterator.cCs ||_dS)N)rV)rrDrWrrrrXsz StdSlistIteratorPrinter.__init__cCs<|jdsdStd|jjj}t|jdj|jdS)Nrz1non-dereferenceable iterator for __gnu_cxx::slistz__gnu_cxx::_Slist_noderv)rVr8rrar!rbrt)rrrrrrgs  z!StdSlistIteratorPrinter.to_stringN)r r r r rXrgrrrrrsrc@s@eZdZdZGdddeZddZddZdd Zd d Z d S) StdVectorPrinterzPrint a std::vector.c@s$eZdZddZddZddZdS)zStdVectorPrinter._iteratorcCs^||_|rH|d|_d|_|d|_|d|_|jjj}d|j|_n ||_||_d|_ dS)N_M_pr _M_offset) _bitvec_item_so_finish_fortrsizeof_isizer~)rstartfinishZbitvecityperrrrX s    z#StdVectorPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz#StdVectorPrinter._iterator.__iter__cCs|j}|jd|_|jr|j|jkr4|j|jkr4tt|jjd|j>@}|jd|_|j|j krv|jd|_d|_d||fS|j|jkrt|jj}|jd|_d||fSdS)Nr)rz[%d]) r~rrrrrrZboolrtr)rrErrrrrs         z#StdVectorPrinter._iterator.__next__N)r r r rXrYrrrrrr srcCs*t||_||_|jjdjtjk|_dS)Nr) r;r]rVrr4coderTYPE_CODE_BOOL_is_bool)rrDrWrrrrX0s zStdVectorPrinter.__init__cCs$|j|jdd|jdd|jS)Nr_M_start _M_finish)rrVr)rrrrr_6s zStdVectorPrinter.childrenc Cs|jdd}|jdd}|jdd}|jr|jddd}|jddd}|jddd}|jj}d|j}||||}|||}d|jt|t|fSd |jt||t||fSdS) NrrrZ_M_end_of_storagerrrz"%s of length %d, capacity %dz%s of length %d, capacity %d)rVrrtrrr]int) rrrendZforZbllengthZcapacityrrrrg;s   zStdVectorPrinter.to_stringcCsdS)Narrayr)rrrr display_hintMszStdVectorPrinter.display_hintN) r r r r rrrXr_rgrrrrrrs %rc@s eZdZdZddZddZdS)StdVectorIteratorPrinterzPrint std::vector::iterator.cCs ||_dS)N)rV)rrDrWrrrrXTsz!StdVectorIteratorPrinter.__init__cCs |jdsdSt|jdjS)NZ _M_currentz,non-dereferenceable iterator for std::vector)rVr!rt)rrrrrgWs z"StdVectorIteratorPrinter.to_stringN)r r r r rXrgrrrrrQsrc@s eZdZdZddZddZdS)StdBitIteratorPrinterz@Print std::vector's _Bit_iterator and _Bit_const_iterator.cCs ||_dS)N)rV)rrDrWrrrrX`szStdBitIteratorPrinter.__init__cCs.|jdsdSt|jdjd|jd>@S)Nrz2non-dereferenceable iterator for std::vectorr)r)rVrrt)rrrrrgcs zStdBitIteratorPrinter.to_stringN)r r r r rXrgrrrrr]src@s eZdZdZddZddZdS)StdBitReferencePrinterz#Print std::vector::reference.cCs ||_dS)N)rV)rrDrWrrrrXmszStdBitReferencePrinter.__init__cCs*|jdsdSt|jdj|jd@S)Nrz$invalid std::vector::referenceZ_M_mask)rVrrt)rrrrrgps z StdBitReferencePrinter.to_stringN)r r r r rXrgrrrrrjsrc@s8eZdZdZGdddeZddZddZdd Zd S) StdTuplePrinterzPrint a std::tuple.c@s0eZdZeddZddZddZddZd S) zStdTuplePrinter._iteratorcCsNt|dkr"t|djdrBdSn t|dkr2dSt|dkrBdStddS)Nrr)Z __tuple_baseTrFz4Top of tuple tree does not consist of a single node.)rrBrr )nodesrrr_is_nonempty_tuple}s   z,StdTuplePrinter._iterator._is_nonempty_tuplecCs:||_|jjj}|j|r0|jj|dj|_d|_dS)Nr)r}rrrrbr~)rrrrrrrXs   z"StdTuplePrinter._iterator.__init__cCs|S)Nr)rrrrrYsz"StdTuplePrinter._iterator.__iter__cCs|js t|jjj}t|dkr&tt|dkr:tdt|dkr`|jj|dj}d|_n&|jj|dj}|jj|dj|_|jd|_|jj}t|dks|djdkrd|jd|fSd|jd|dfSdS)Nrrz/Cannot parse more than 2 nodes in a tuple tree.r)rhz[%d]) r}rZrrrr rbr~r")rrimplrrrrrs$       z"StdTuplePrinter._iterator.__next__N)r r r staticmethodrrXrYrrrrrr|s  rcCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zStdTuplePrinter.__init__cCs |j|jS)N)rrV)rrrrr_szStdTuplePrinter.childrencCs(t|jjjdkrd|jSd|jS)Nrzempty %sz %s containing)rrVrrr])rrrrrgs zStdTuplePrinter.to_stringN) r r r r rrrXr_rgrrrrrys Erc@s0eZdZdZddZddZddZdd Zd S) StdStackOrQueuePrinterz!Print a std::stack or std::queue.cCst||_tj|d|_dS)Nc)r;r]rdefault_visualizer _visualizer)rrDrWrrrrXs zStdStackOrQueuePrinter.__init__cCs |jjS)N)rr_)rrrrr_szStdStackOrQueuePrinter.childrencCsd|j|jjfS)Nz%s wrapping: %s)r]rrg)rrrrrgsz StdStackOrQueuePrinter.to_stringcCst|jdr|jjSdS)Nr)hasattrrr)rrrrrs  z#StdStackOrQueuePrinter.display_hintN)r r r r rXr_rgrrrrrrs rc@s0eZdZdZddZddZddZdd Zd S) RbtreeIteratorzf Turn an RB-tree-based container (std::map, std::set etc.) into a Python iterable object. cCs2|ddd|_|dddd|_d|_dS)NrnrZ _M_node_countZ _M_header_M_leftr)_size_noder~)rZrbtreerrrrXszRbtreeIterator.__init__cCs|S)Nr)rrrrrYszRbtreeIterator.__iter__cCs t|jS)N)rr)rrrr__len__szRbtreeIterator.__len__cCs|j|jkrt|j}|jd|_|j|jkr|j}|jdrl|jd}xd|jdrh|jd}qNWnF|jd}x$||jdkr|}|jd}qzW|jd|kr|}||_|S)Nr)Z_M_rightrZ _M_parent)r~rrZrrt)rresultrlparentrrrrs$      zRbtreeIterator.__next__N)r r r r rXrYrrrrrrrs rc CsjyF|jjdj}|dkr"|dS|dkrD|jjd}t|d|SWn YnXtdt|jdS)z0Return the value held in an _Rb_tree_node<_Val>.r)Z_M_value_fieldrrrz!Unsupported implementation for %sN)rrr"r4rur r!)rlrwr7rrrget_value_from_Rb_tree_node s rc@s eZdZdZddZddZdS)StdRbtreeIteratorPrinterz2Print std::map::iterator, std::set::iterator, etc.cCs"||_td|jj}|j|_dS)N _Rb_tree_node)rVr8rra _link_type)rrDrWrrrrrX!sz!StdRbtreeIteratorPrinter.__init__cCs0|jdsdS|jdj|jj}tt|S)Nrz6non-dereferenceable iterator for associative container)rVrbrrtr!r)rrlrrrrg&s z"StdRbtreeIteratorPrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdDebugIteratorPrinterz-Print a debug enabled version of an iterator.cCs ||_dS)N)rV)rrDrWrrrrX0sz StdDebugIteratorPrinter.__init__cCsbtjd}|jjjd}|jj|d}|std||_nd|_dS)Nrir)) r;r]rVrr4Z_elttyperrr)rrDrWsizerrrrXs zStdDequePrinter.__init__cCsx|jdd}|jdd}|d|dd}|d|d}|d|d}|j|||}d |jtt|fS) Nrrrrr)_M_last_M_cur_M_firstz %s with %s)rVrr]rlong)rrrZdelta_nZdelta_sZdelta_errrrrgszStdDequePrinter.to_stringcCs@|jdd}|jdd}|j|d|d|d|d|jS)Nrrrrrr)rVrr)rrrrrrr_szStdDequePrinter.childrencCsdS)Nrr)rrrrrszStdDequePrinter.display_hintN) r r r r rrrXrgr_rrrrrrs   rc@s eZdZdZddZddZdS)StdDequeIteratorPrinterzPrint std::deque::iterator.cCs ||_dS)N)rV)rrDrWrrrrXsz StdDequeIteratorPrinter.__init__cCs |jdsdSt|jdjS)Nrz+non-dereferenceable iterator for std::deque)rVr!rt)rrrrrg s z!StdDequeIteratorPrinter.to_stringN)r r r r rXrgrrrrrsrc@s(eZdZdZddZddZddZdS) StdStringPrinterz'Print a std::basic_string of some kind.cCs||_|jddk|_dS)Nz::__cxx11::basic_stringr)ri)rVfind _new_string)rrDrWrrrrXszStdStringPrinter.__init__cCs|jj}|jtjkr|j}|jdd}|jrL|jd}|j|jj}n<|j j}tj t |dj }|j|d}|j d}t|dr|j|dS|j|dS) NZ _M_dataplusrZ_M_string_lengthz::_Repr)Z _M_length lazy_string)r)rVrrr TYPE_CODE_REFrrrbr unqualifiedrr!rartrrstring)rrptrrZrealtypeZreptypeheaderrrrrgs      zStdStringPrinter.to_stringcCsdS)Nrr)rrrrr-szStdStringPrinter.display_hintN)r r r r rXrgrrrrrrsrcCs"|d}|d}|d}|||fS)z'Access the streambuf put area pointers.Z _M_out_begZ _M_out_curZ _M_in_endr) streambufpbasepptregptrrrraccess_streambuf_ptrs1src@s(eZdZdZddZddZddZdS) StdStringBufPrinterzPrint a std::basic_stringbuf.cCs ||_dS)N)rV)r_rWrrrrX<szStdStringBufPrinter.__init__cCsLt|j\}}}|rB| s"||kr2|j||dS|j||dS|jdS)N)rZ _M_string)rrVr)rrrrrrrrg?s zStdStringBufPrinter.to_stringcCsdS)Nrr)rrrrrIsz StdStringBufPrinter.display_hintN)r r r r rXrgrrrrrr9s rc@s(eZdZdZddZddZddZdS) StdStringStreamPrinterz Print a std::basic_stringstream.cCsZ||_||_dd|jjDd}tjd|j|jtjd|_ |j |djk|_ dS)NcSsg|]}|jr|jqSr)rr)r&frrrr(Xsz3StdStringStreamPrinter.__init__..rZ__streamz$__stream->rdbuf() _M_stringbuf) rVr]rrrZset_convenience_variablerbrsparse_and_eval _streambuf_was_redirected)rrDrWZbasetyperrrrXPs  zStdStringStreamPrinter.__init__cCs$|jrd|j|jjfS|jdS)Nz%s redirected to %sr)rr]rrtrV)rrrrrg]sz StdStringStreamPrinter.to_stringcCs|jr dSdS)Nr)r)rrrrrcsz#StdStringStreamPrinter.display_hintN)r r r r rXrgrrrrrrMs rc@s$eZdZddZddZddZdS)Tr1HashtableIteratorcCsj|d|_d|_|d|_t|jdj|_d|_x2|j|jkrd|j|j|_|jrVP|jd|_q4WdS)NZ _M_bucketsrZ_M_bucket_countZ_Noder))_buckets_bucket _bucket_countr%rra _node_typer)r hashtablerrrrXjs  zTr1HashtableIterator.__init__cCs|S)Nr)rrrrrYvszTr1HashtableIterator.__iter__cCs|jdkrt|jj|j}|jd}|jd|_|jdkr|jd|_x2|j|jkr~|j|j|_|jrpP|jd|_qNW|S)NrZ_M_vrzr))rrZrbrrtrrr)rrlrrrrrys    zTr1HashtableIterator.__next__N)r r r rXrYrrrrrris rc@s$eZdZddZddZddZdS)StdHashtableIteratorcCsR|dd|_|jjd}|jjdjd}tdt||r>dnd}|j|_dS) NZ_M_before_begin_M_nxtr) rzstd::__detail::_Hash_nodetrueZfalse)rrr4r2r!rar)rrr7cachedZ node_typerrrrXs   zStdHashtableIterator.__init__cCs|S)Nr)rrrrrYszStdHashtableIterator.__iter__cCsR|jdkrt|jj|jj}|d|_|dj}|j|jjdj}|jS)Nrrrr) rrZrbrrtrsrr4ra)rrvalptrrrrrs   zStdHashtableIterator.__next__N)r r r rXrYrrrrrrsrc@s<eZdZdZddZddZddZedd Zd d Z d S) Tr1UnorderedSetPrinterz1Print a std::unordered_set or tr1::unordered_set.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zTr1UnorderedSetPrinter.__init__cCs|jjdr|jS|jdS)Nzstd::tr1_M_h)r]r<rV)rrrr _hashtables z!Tr1UnorderedSetPrinter._hashtablecCs|jd}d|jt|fS)N_M_element_countz %s with %s)rr]r)rrErrrrgs z Tr1UnorderedSetPrinter.to_stringcCsd|S)Nz[%d]r)irrr _format_countsz$Tr1UnorderedSetPrinter._format_countcCs@t|jtj}|jjdr.t|t|jSt|t |jS)Nzstd::tr1) r r itertoolsrEr]r<rrrr)rcounterrrrr_s zTr1UnorderedSetPrinter.childrenN) r r r r rXrrgrrr_rrrrrs  rc@s\eZdZdZddZddZddZedd Zed d Z ed d Z ddZ ddZ dS)Tr1UnorderedMapPrinterz1Print a std::unordered_map or tr1::unordered_map.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zTr1UnorderedMapPrinter.__init__cCs|jjdr|jS|jdS)Nzstd::tr1r)r]r<rV)rrrrrs z!Tr1UnorderedMapPrinter._hashtablecCs|jd}d|jt|fS)Nrz %s with %s)rr]r)rrErrrrgs z Tr1UnorderedMapPrinter.to_stringccs&x |D]}x|D] }|VqWqWdS)Nr)rrrrrr_flattens  zTr1UnorderedMapPrinter._flattencCs|d|dfS)Nrrr)rrrr _format_onesz"Tr1UnorderedMapPrinter._format_onecCsd|S)Nz[%d]r)rrrrrsz$Tr1UnorderedMapPrinter._format_countcCsdt|jtj}|jjdr@|jt|jt|j }t ||S|jt|jt |j }t ||S)Nzstd::tr1) r rrrEr]r<r r rrrr)rr datarrrr_s  zTr1UnorderedMapPrinter.childrencCsdS)Nrr)rrrrrsz#Tr1UnorderedMapPrinter.display_hintN) r r r r rXrrgrr r rr_rrrrrr s    r c@s8eZdZdZGdddeZddZddZdd Zd S) StdForwardListPrinterzPrint a std::forward_list.c@s$eZdZddZddZddZdS)zStdForwardListPrinter._iteratorcCs||_|d|_d|_dS)Nrzr)r{r|r~)rrrrrrrXs z(StdForwardListPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz(StdForwardListPrinter._iterator.__iter__cCsl|jdkrt|jj|jj}|d|_|j}|jd|_|dj}|j|jjdj }d||jfS)Nrrzr)rrz[%d]) r|rZrbr{rtr~rsrr4ra)rrrErrrrrs    z(StdForwardListPrinter._iterator.__next__N)r r r rXrYrrrrrrsrcCs||_t||_dS)N)rVr;r])rrDrWrrrrXszStdForwardListPrinter.__init__cCs(td|jjj}|j||jddS)Nrrr)r8rVrrar)rrrrrr_szStdForwardListPrinter.childrencCs*|jddddkr d|jSd|jS)Nrrrzrzempty %sz%s)rVr])rrrrrgs zStdForwardListPrinter.to_stringN) r r r r rrrXr_rgrrrrrs rc@sBeZdZdZd ddZddZGdddeZd d Zd d Z dS)SingleObjContainerPrinterz8Base class for printers of containers of single objects.NcCs||_||_||_dS)N)_contained_valuer_hint)rrWZvizZhintrrrrXsz"SingleObjContainerPrinter.__init__cCs(ts t|Stjjtjj|p&t|S)z5Return type as a string after applying type printers.)_use_type_printingr!rtypesapply_type_recognizersget_type_recognizers)rrrrr _recognizesz$SingleObjContainerPrinter._recognizec@s$eZdZddZddZddZdS)z$SingleObjContainerPrinter._containedcCs ||_dS)N)rV)rrWrrrrXsz-SingleObjContainerPrinter._contained.__init__cCs|S)Nr)rrrrrY"sz-SingleObjContainerPrinter._contained.__iter__cCs"|jdkrt|j}d|_d|fS)Nz[contained value])rVrZ)rZretvalrrrr%s  z-SingleObjContainerPrinter._contained.__next__N)r r r rXrYrrrrr _containedsrcCs6|jdkr|jdSt|jdr*|jjS|j|jS)Nr_)rrrrr_)rrrrr_,s     z"SingleObjContainerPrinter.childrencCs(t|jdr"t|jdr"|jjS|jS)Nr_r)rrrr)rrrrr3s   z&SingleObjContainerPrinter.display_hint)N) r r r r rXrrrr_rrrrrrs  rc CsH|jj}tjddkr"t|}nt|}ytj|jj SdSdS)z{Find the name of the function referred to by the gdb.Value f, which should contain a function pointer from the program.rrN) rtrsrFrGrrrZ block_for_pcfunctionr")rrrrfunction_pointer_to_name;s  rcs4eZdZdZfddZddZeddZZS)StdExpAnyPrinterz+Print a std::any or std::experimental::any.c st||_t|j|_||_d|_d}d}|jd}|dkrt|}|sXtd|jdj|}tj ||}|std|j|j d} d| kr g} xPt j D]D} y(tj d| |j d} | jtj| Wqtjk rYqXqWt| dkrtd | d} n tj| } | jd|_d}d | kr@|jd d j}n(d | krZ|jd d}ntd|j|j|jjj}tj|}tt |j||dS)NZ _M_managerrzInvalid function pointer in %szi({0}::_Manager_\w+<.*>)::_S_manage\((enum )?{0}::_Op, (const {0}|{0} const) ?\*, (union )?{0}::_Arg ?\*\)zUnknown manager function in %sr)z std::stringzstd::string(?!\w)z;Cannot uniquely determine std::string type used in std::anyz::_Manager_internalrrZ _M_bufferz::_Manager_externalr\)r;r]rKrV_contained_typerr r*r>r?groupr _string_typesrHrPrrr,rr4rsrbrartrsuperrX)rrDrWcontained_value visualizerZmgrfuncZrxmZmgrnameZmgrtypessr@Zmgrtyper) __class__rrrXVsX                 zStdExpAnyPrinter.__init__cCsT|jdkrd|jSd|j}t|jdr8||jjS|j|j}|tt|S)Nz%s [no contained value]z%s containing r_)rr]rrrgrr;r!)rdescr7rrrrgs     zStdExpAnyPrinter.to_stringcs@ttjdjh}ddddtg}|fdd|DO}|S)Nz std::stringzAbasic_string, std::allocator >zstd::zstd::__cxx11::csh|] }|qSrr)r&q)r#rr sz1StdExpAnyPrinter._string_types..)r!rrrr-)ZstringsZqualsr)r#rrs  zStdExpAnyPrinter._string_types) r r r r rXrgrr __classcell__rr)r$rrSs D rcs(eZdZdZfddZddZZS)StdExpOptionalPrinterz5Print a std::optional or std::experimental::optional.c st||_t|j|_|d}|jjdr8|d}|}n*|d}|d}y |d}Wn YnXtj|}|std}tt|j||dS)N _M_payloadzstd::experimental _M_engaged_M_value) r;r]rKr<rrrr)rX)rrDrWZpayloadZengagedrr )r$rrrXs"      zStdExpOptionalPrinter.__init__cCs:|jdkrd|jSt|jdr4d|j|jjfS|jS)Nz%s [no contained value]r_z%s containing %s)rr]rrrg)rrrrrgs    zStdExpOptionalPrinter.to_string)r r r r rXrgr(rr)r$rr)s r)cs(eZdZdZfddZddZZS)StdVariantPrinterzPrint a std::variant.cst|j}t||_|d|_|jt|krz[%s])rrrZrtr~r7r@r=)rrrEr?r0rrrrRs    z$StdExpPathPrinter._iterator.__next__N)r r r rXrYrrrrrrHsrcCs|j|jd|jS)Nr8)rrVr])rrrrr__szStdExpPathPrinter.childrenN) r r r r rXr=rgrrr_rrrrr7.s r7c@s@eZdZdZddZddZddZGdd d eZd d Z d S) StdPathPrinterzPrint a std::filesystem::path.cCsP||_||_t|jdd}|jtjdd@|_|jdkrF||_nd|_dS)Nr8rZ uintptr_tr)rVr]rprbrrr_impl)rrDrWrrrrrXfs zStdPathPrinter.__init__cCsHt|jjtj|jd}|dddkr0dS|d ddkrDdSdS) Nz::_Typerr:zroot-directoryr;r<z root-nameii)r!rrbrrr])rr0rrrr=ps zStdPathPrinter._path_typecCs8d|jd}|jdkr0|j}|r0d||f}d|S)Nz%sr>rz%s [%s]zfilesystem::path %s)rVrr=)rr?r0rrrrgxs   zStdPathPrinter.to_stringc@s$eZdZddZddZddZdS)zStdPathPrinter._iteratorc Cs||_|rtjd}tj|d}tjd}|j|j}|j}ttjdrbtd|j |j }n d|j }|j|j|}|j|j|_ |j ||_ d|_ n d|_ d|_ dS)Nrz::_Cmptcharalignofrr)r@rrrbrartrr:maxrrFrrr~) rrrAZint_typeZ cmpt_type char_typerZ sizeof_ImplbeginrrrrXs      z!StdPathPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz!StdPathPrinter._iterator.__iter__cCsd|j|jkrt|jj}|j}|jd|_|jd|_|d}t|j|j}|sX|}d||fS)Nr)r>z[%s])rrrZrtr~rBr@r=)rrrEr?r0rrrrs    z!StdPathPrinter._iterator.__next__N)r r r rXrYrrrrrrsrcCs|j|j|jS)N)rrDr])rrrrr_szStdPathPrinter.childrenN) r r r r rXr=rgrrr_rrrrrBcs  (rBc@s8eZdZdZddZGdddeZddZdd Zd S) StdPairPrinterz@Print a std::pair object, with 'first' and 'second' as children.cCs ||_dS)N)rV)rrDrWrrrrXszStdPairPrinter.__init__c@s(eZdZdZddZddZddZdS) zStdPairPrinter._iterz?An iterator for std::pair types. Returns 'first' then 'second'.cCs||_d|_dS)Nr)rV_which)rrWrrrrXszStdPairPrinter._iter.__init__cCs|S)Nr)rrrrrYszStdPairPrinter._iter.__iter__cCs8|jdkrt|j}|dkr$d|_nd|_||j|fS)Nrr)rKrZrV)rZwhichrrrrs zStdPairPrinter._iter.__next__N)r r r r rXrYrrrrrrsrcCs |j|jS)N)rrV)rrrrr_szStdPairPrinter.childrencCsdS)Nr)rrrrrgszStdPairPrinter.to_stringN) r r r r rXrrr_rgrrrrrJs rJc@s eZdZdZddZddZdS)StdCmpCatPrinterz#Print a comparison category object.cCs&||jddd|_|d|_dS)N:r)r,)rfindr]rV)rrDrWrrrrXszStdCmpCatPrinter.__init__cCsJ|jdkr|jdkrd}n"ddd ddddd i}|t|j}d j|j|S) Nstrong_orderingrZequalrZ unorderedr)ZlessZ equivalentZgreaterz std::{}::{}ri)r]rVrr*)rr"namesrrrrgs zStdCmpCatPrinter.to_stringN)r r r r rXrgrrrrrLsrLc@s`eZdZdZdZddZeddZeddZ ed d Z ed d Z ed dZ ddZ dS)StdErrorCodePrinterz0Print a std::error_code or std::error_condition.Nc CsL||_t||_tjdkrHyddl}dt_Wntk rFdt_YnXdS)NrTF)rVr;r]rQ_system_is_posixposix ImportError)rrDrWrSrrrrXs   zStdErrorCodePrinter.__init__cCs&tj|}|dk r"|jtjkr"|SdS)N)rrrZTYPE_CODE_ENUM)r"r#rrr_find_errc_enums z#StdErrorCodePrinter._find_errc_enumc CsBxs(     zStdErrorCodePrinter.to_string)r r r r rRrXrrU classmethodrXr]rdrfrgrrrrrQs   + rQc@s eZdZdZddZddZdS)StdRegexStatePrinterz/Print a state node in the NFA for a std::regex.cCs||_||_dS)N)rVr])rrDrWrrrrX[szStdRegexStatePrinter.__init__cCst|jd}|r|dd}|jd}dddddddddddddd }||}d j||}|dk r|jd |dk rd j|||jd |}d |S) NZ _M_opcoderzZaltZsubexprnegZ backref_index) repeat alternativeZ subexpr_beginZ subexpr_endZline_begin_assertionZline_end_assertionZ word_boundaryZsubexpr_lookaheadZbackrefr?ZacceptZdummyunknownzopcode={}, next={}Z_M_z {}, {}={}z{%s})r!rVr*)rZopcodeZnext_idZvariantsvr#rrrrg_s     zStdRegexStatePrinter.to_stringN)r r r r rXrgrrrrrlXsrlc@s@eZdZdZGdddeZddZddZdd Zd d Z d S) StdSpanPrinterzPrint a std::span.c@s$eZdZddZddZddZdS)zStdSpanPrinter._iteratorcCsd|_||_||_dS)Nr)r~_beginr)rrIrrrrrXysz!StdSpanPrinter._iterator.__init__cCs|S)Nr)rrrrrY~sz!StdSpanPrinter._iterator.__iter__cCs8|j|jkrt|j}|jd|_d||j|jfS)Nr)z[%d])r~rrZrtrt)rrErrrrs   z!StdSpanPrinter._iterator.__next__N)r r r rXrYrrrrrrxsrcCsLt||_||_tjd}|jjd|kr:|dd|_n|jjd|_dS)Nzstatic_cast(-1)r)Z _M_extentZ_M_extent_value)r;r]rVrrrr4r)rrDrWZsize_maxrrrrXs   zStdSpanPrinter.__init__cCsd|j|jfS)Nz%s of length %d)r]r)rrrrrgszStdSpanPrinter.to_stringcCs|j|jd|jS)Nr\)rrVr)rrrrr_szStdSpanPrinter.childrencCsdS)Nrr)rrrrrszStdSpanPrinter.display_hintN) r r r r rrrXrgr_rrrrrrsus  rsc@s0eZdZdZddZddZddZdd Zd S) StdInitializerListPrinterzPrint a std::initializer_list.cCs||_||_|d|_dS)Nr6)r]rVr)rrDrWrrrrXsz"StdInitializerListPrinter.__init__cCsd|j|jfS)Nz%s of length %d)r]r)rrrrrgsz#StdInitializerListPrinter.to_stringcCstj|jd|jS)NZ_M_array)rsrrVr)rrrrr_sz"StdInitializerListPrinter.childrencCsdS)Nrr)rrrrrsz&StdInitializerListPrinter.display_hintN)r r r r rXrgr_rrrrrrus ruc@s(eZdZdZddZddZddZdS) StdAtomicPrinterzPrint a std:atomic.cCsrt||_||_d|_|jjjd|_|jjdk rnt|jj}|jdsR|jdrn|d}t |||_|j |_ dS)Nrzstd::shared_ptr = { %s }) rwrgr1rrZ TYPE_CODE_INTrV TYPE_CODE_FLT TYPE_CODE_PTRrr]r!)rrWrrrrgs     zStdAtomicPrinter.to_stringN)r r r r rXrxrgrrrrrvs rvc@s eZdZdZddZddZdS)StdFormatArgsPrinterzPrint a std::basic_format_args.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zStdFormatArgsPrinter.__init__cCst|jj}t|dd}|tjdkr0d}n|tjdkrDd}nd}|jd}|dkrbd |S|dkrt|jd }d ||fS) Nrr)rEzstd::format_argswchar_tzstd::wformat_argszstd::basic_format_argsZ_M_packed_sizez%s with 1 argumentZ_M_unpacked_sizez%s with %d arguments)rTrVrrr)rZtargsrHr#rrrrrgs   zStdFormatArgsPrinter.to_stringN)r r r r rXrgrrrrr{sr{c@s0eZdZdZddZddZddZdd Zd S) StdChronoDurationPrinterzPrint a std::chrono::duration.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z!StdChronoDurationPrinter.__init__cCs*|jjjd}|jd}|jd}||fS)Nr)r)rVrr4)rZperiodrdenrrr_ratios  zStdChronoDurationPrinter._ratiocCs|j\}}|dkrF|dkr dS|dkr,dS|dkr8dS|dkr|dSn6|dkr||d krZd S|d krfd S|d krrdSdj|Sdj||S)Nr)r#iZmsi@Busiʚ;rW<minihiQdz[{}]sz[{}/{}]s)rr*)rrr~rrr_suffixs&  z StdChronoDurationPrinter._suffixcCs4|jd}|jjjtjkr$d|}dj||jS)N__rz%gz"std::chrono::duration = {{ {}{} }})rVrrrrryr*r)rrrrrrgs z"StdChronoDurationPrinter.to_stringN)r r r r rXrrrgrrrrr}s r}c@s*eZdZdZddZddZd ddZd S) StdChronoTimePointPrinterz Print a std::chrono::time_point.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z"StdChronoTimePointPrinter.__init__cCsv|jjjd}t|j}|dks(|dkr,dS|dkr8dS|dkrDdS|d krPdS|d kr\dS|dkrhdSdj|dfS)Nrzstd::chrono::_V2::system_clockzstd::chrono::system_clockstd::chrono::sys_timezstd::chrono::utc_clockstd::chrono::utc_timezstd::chrono::gps_clockstd::chrono::gps_timezstd::chrono::tai_clockstd::chrono::tai_timezstd::filesystem::__file_clockstd::chrono::file_timeumzstd::chrono::local_tstd::chrono::local_timez {} time_point)rr)rN)rN)rN)rr)rr)rVrr4r;r"r*)rclockr"rrr_clocks  z StdChronoTimePointPrinter._clockFc Cs|j\}}|jd}|d}t|jj|}|j}d}|dk r|j\} } || | |} ytjj| t } dj | }Wn YnXd|||f} |r| Sd|| fS)NZ__drrCz [{:%Y-%m-%d %H:%M:%S}]z%d%s%sz %s = { %s }) rrVr}rr"rrrZ fromtimestamp _utc_timezoner*)rZabbrevroffsetrrprintersuffixtimerr~Zsecsrr#rrrrg1s$   z#StdChronoTimePointPrinter.to_stringN)F)r r r r rXrrgrrrrrsrc@s eZdZdZddZddZdS)StdChronoZonedTimePrinterz Print a std::chrono::zoned_time.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXIs z"StdChronoZonedTimePrinter.__init__cCs@|jdjd}|jd}t|jj|}|jd}dj||S)NZ_M_zone_M_nameZ_M_tpTz%std::chrono::zoned_time = {{ {} {} }})rVrtrrr"rgr*)rZzonerrrrrrgMs   z#StdChronoZonedTimePrinter.to_stringN)r r r r rXrgrrrrrFsrZJanuaryZFebruaryZMarchZAprilZMayZJuneZJulyZAugustZ SeptemberZOctoberZNovemberZDecemberZSundayZMondayZTuesdayZ WednesdayZThursdayZFridayZSaturdayc@s eZdZdZddZddZdS)StdChronoCalendarPrinterzDPrint a std::chrono::day, std::chrono::month, std::chrono::year etc.cCst||_||_dS)N)r;r]rV)rrDrWrrrrX_s z!StdChronoCalendarPrinter.__init__c Csv|j}|j}d|kr$|dkr$|d}|jdr6|d}|dkrPdjt|dS|d kr||d ksl|ttkrtd |St|S|dkrd j|S|d kr|d}|dks|ttkrd|Sdjt|S|dkrdj|dt|dS|dkrdj|dS|dkrdj||dS|dkr,dj|S|dkrFdj||dS|dkr`dj||dS|dkrvdj||S|dkrd j|||dS|dkrdj||d!S|d"krd j|||dS|d#krd j|||dS|jd$rrd%}|d&dkr"d'jt|d(d)t|d&}t|d*d+}t|dd+}t|d,d+}|d-rb| }d.j||||SdS)/Nmonthz std::chrono::year_month_day_lastZ_M_mzstd::chrono::yearZ_M_yzstd::chrono::dayz{}Z_M_dzstd::chrono::monthr)z%d is not a valid monthz{}yzstd::chrono::weekdayZ_M_wdrz%d is not a valid weekdayzstd::chrono::weekday_indexedz{}[{}]r.zstd::chrono::weekday_lastz{}[last]zstd::chrono::month_dayz{}/{}zstd::chrono::month_day_lastz{}/lastzstd::chrono::month_weekdayZ_M_wdizstd::chrono::month_weekday_lastZ_M_wdlzstd::chrono::year_monthzstd::chrono::year_month_dayz{}/{}/{}Z_M_mdlzstd::chrono::year_month_weekdayz$std::chrono::year_month_weekday_lastzstd::chrono::hh_mm_ssrCZfractional_widthz.{:0{}d}Z_M_ssZ_M_rrr_M_sZ _M_is_negz{:02}:{:02}:{:02}{})rVr]r<r*rrmonthsweekdays) rrWr#r"yZwdZfractrr#rrrrgcsh               z"StdChronoCalendarPrinter.to_stringN)r r r r rXrgrrrrr\src@s eZdZdZddZddZdS)StdChronoTimeZonePrinterz4Print a chrono::time_zone or chrono::time_zone_link.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z!StdChronoTimeZonePrinter.__init__cCs6d|j|jdf}|jjdr2|d|jd7}|S)Nz%s = %srZ_linkz -> %sZ _M_target)r]rVrb)rr!rrrrgs z"StdChronoTimeZonePrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdChronoLeapSecondPrinterzPrint a chrono::leap_second.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z#StdChronoLeapSecondPrinter.__init__cCs.|jdd}d|dk}d|jt||fS)Nrrz+-rz %s %d (%c))rVr]abs)rZdaternrrrrgs z$StdChronoLeapSecondPrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdChronoTzdbPrinterzPrint a chrono::tzdb.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zStdChronoTzdbPrinter.__init__cCsd|j|jdfS)Nz%s %sversion)r]rV)rrrrrgszStdChronoTzdbPrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdChronoTimeZoneRulePrinterzPrint a chrono::time_zone rule.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z%StdChronoTimeZoneRulePrinter.__init__c Cs|jd}|d}t|d}dddddddd}|d}d j||j|d }|d krdd j||}nVt|d }|dkrdj||}n4|dkrd} nd} |d}dj| d || d||}dj|jd|jd|jd|S)NonkindrstZndZrd)r)rrCZ day_of_monthz{}{}Zthrz{} {}Z day_of_weekr)z last {} in {}rr<=r>=z{} {} {} {} {}z.time_zone rule {} from {} to {} starting on {}r"fromZto)rr)rr)rVrr*getr) rrrrsuffixesdayZ ordinal_dayrweekday directionrrrrgs*    z&StdChronoTimeZoneRulePrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdLocalePrinterzPrint a std::locale.cCs||_||_dS)N)rVr])rrDrWrrrrXszStdLocalePrinter.__init__csx|jdd}d}|ddkr&d}nFtj|jd}tj|jd}|dj}|dj}dj||}||i}d } xN| |kr|| dkr|| j}|| j}d j|||}|||<| d } qxWt|j} t| d kr|}nt| d krl| \} } t |j} d| j | d kr$| }| n| j | d kr<| }| dk rlt fd d |j D}dj|}dj||S)NrZ_M_namesrCr*z::_S_categoriesz::_S_categories_sizez{}={}r)z{};{}={}rc3s|]\}}|kr|VqdS)Nr)r&rrR)otherrr sz-StdLocalePrinter.to_string..z with "{}={}"zstd::locale = "{}"{}) rVrrr]rr*r4valuesrrrEritems)rrPmodr"ZcatsZncatrRr[Z cat_namesrZ uniq_namesZn1Zn2Z name_listr)rrrgsD            zStdLocalePrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdIntegralConstantPrinterz*Print a std::true_type or std::false_type.cCs||_||_dS)N)rVr])rrDrWrrrrX sz#StdIntegralConstantPrinter.__init__cCsL|jjjd}|jjjd}|jtjkr4|r0dSdSt|j}dj|||S)Nrr)zstd::true_typezstd::false_typez {}<{}, {}>) rVrr4rrrr;r]r*)rr3rZrDrrrrg s  z$StdIntegralConstantPrinter.to_stringN)r r r r rXrgrrrrr src@s eZdZdZddZddZdS)StdTextEncodingPrinterzPrint a std::text_encoding.cCs||_||_dS)N)rVr])rrDrWrrrrX$ szStdTextEncodingPrinter.__init__cCs<|jdj}|ddkr$|jdS|ddkr4dS|dS)NZ_M_repZ_M_idr)rrrq)rVrt)rZreprrrrg( s    z StdTextEncodingPrinter.to_stringN)r r r r rXrgrrrrr! srcs$eZdZfddZddZZS) RxPrintercs$tt|j||_||_d|_dS)NT)rrrXr" _functionenabled)rr"r)r$rrrX3 szRxPrinter.__init__cCs:|js dS|jjtjkr,ttjdr,|j}|j|j |S)Nreferenced_value) rrrrrrValuerrr")rrZrrrinvoke9 s  zRxPrinter.invoke)r r r rXrr(rr)r$rr2 s rcsHeZdZfddZddZddZddZed d Zd d Z Z S) Printercs6tt|j||_g|_i|_d|_tjd|_ dS)NTz^([a-zA-Z0-9_:]+)(<.*>)?$) rrrXr" _subprinters_lookuprr>compile _compiled_rx)rr")r$rrrXH s zPrinter.__init__cCs<|jj|std|t||}|jj|||j|<dS)Nz0libstdc++ programming error: "%s" does not match)rr?r rrrPr)rr"rrrrraddP s     z Printer.addcCs>|j|||d|kr:tjddt|}|j|||dS)N__cxx11z^(std|__gnu_cxx)::z\g<0>%s)rr>rHr-)rbaser"rZvbaserrr add_version[ s  zPrinter.add_versioncCs$|j||||j|d||dS)Nz __cxx1998::)r)rrr"rrrr add_containerc szPrinter.add_containercCs&|jtjkr|j}|jj}|jS)N)rrrrrrr)rrrrget_basic_typeg s  zPrinter.get_basic_typecCsr|j|j}|sdS|jj|}|s(dS|jd}|jjtjkrTttj drT|j }||j krn|j |j |SdS)Nr)r) rrrr?rrrrrrrrr)rrWrDr?basenamerrr__call__r s     zPrinter.__call__) r r r rXrrrrrrr(rr)r$rrG s    rc@s0eZdZdZddZGdddeZddZdS) TemplateTypePrinteral A type printer for class templates with default template arguments. Recognizes specializations of class templates and prints them without any template arguments that use a default template argument. Type printers are recursively applied to the template arguments. e.g. replace 'std::vector >' with 'std::vector'. cCs||_||_d|_dS)NT)r"_defargsr)rr"defargsrrrrX szTemplateTypePrinter.__init__c@s(eZdZdZddZddZddZdS) zTemplateTypePrinter._recognizerz-The recognizer class for TemplateTypePrinter.cCs||_||_dS)N)r"r)rr"rrrrrX sz(TemplateTypePrinter._recognizer.__init__c Cs|jdkrdS|jj|js dSt|}g}d}xtt|D]}||}|jj|}|dk r|j|}y|t j |kr|dSWn$t j k r|j|krdSYnXd}q>|rdS|j |j |q>W|jd|jjd}t|}|ddj|dS)a If type_obj is a specialization of self.name that uses all the default template arguments for the class template, then return a string representation of the type without default arguments. Otherwise, return None. NFTr)rr<r"rTrangerrrr*rrr,rP_recognize_subtyperrOr+) rrQrSZdisplayed_argsZrequire_defaultedrRrfZdefargrArrr recognize s2     z)TemplateTypePrinter._recognizer.recognizecCs|jtjkr|j|jdS|jtjkrj|j|j}t|jjdrR|dSd||j ddfS|jtj kr|j|jdSt tdr|jtj kr|j|jdStj jtj j|}|r|St|S)zxConvert a gdb.Type to a string by applying recognizers, or if that fails then simply converting to a string.rz[]z%s[%d]r)&TYPE_CODE_RVALUE_REFz&&)rrrzrrrr!rrbrrrrrrr)rrQrNrrrr s"     z2TemplateTypePrinter._recognizer._recognize_subtypeN)r r r r rXrrrrrr _recognizer s1rcCs|j|j|jS)z1Return a recognizer object for this type printer.)rr"r)rrrr instantiate szTemplateTypePrinter.instantiateN)r r r r rXobjectrrrrrrr s Prcstd||}tjj||td||}tjj||d|krdttfdd|jD}t||}tjj||td||}tjj||dS)a Add a type printer for a class template with default template arguments. Args: name (str): The template-name of the class template. defargs (dict int:string) The default template arguments. Types in defargs can refer to the Nth template-argument using {N} (with zero-based indices). e.g. 'unordered_map' has these defargs: { 2: 'std::hash<{0}>', 3: 'std::equal_to<{0}>', 4: 'std::allocator >' } zstd::zstd::__debug::rc3s"|]\}}||jdfVqdS)zstd::N)r.)r&rRr)rWrrr sz0add_one_template_type_printer..N)rrrregister_type_printerr-dictr)objr"rrr)rWradd_one_template_type_printer s rc@s2eZdZdZd ddZGdddeZddZdS) FilteringTypePrintera A type printer that uses typedef names for common template specializations. Args: template (str): The class template to recognize. name (str): The typedef-name that will be used instead. targ1 (str, optional): The first template argument. Defaults to None. Checks if a specialization of the class template 'template' is the same type as the typedef 'name', and prints it as 'name' instead. e.g. if an instantiation of std::basic_istream is the same type as std::istream then print it as std::istream. If targ1 is provided (not None), match only template specializations with this type as the first template argument, e.g. if template='basic_string' and targ1='char' then only match 'basic_string' and not 'basic_string'. This rejects non-matching specializations more quickly, without needing to do GDB type lookups. NcCs||_||_||_d|_dS)NT) _templater"_targ1r)rtemplater"targ1rrrrX- szFilteringTypePrinter.__init__c@s eZdZdZddZddZdS)z FilteringTypePrinter._recognizerz.The recognizer class for FilteringTypePrinter.cCs||_||_||_d|_dS)N)rr"r _type_obj)rrr"rrrrrX6 sz)FilteringTypePrinter._recognizer.__init__c Cs|jdkrdS|jdkrz|jdk rDdj|j|j}|jj|sVdSn|jj|jsVdSytj|jj |_Wn YnX|jdkrdStj j |j}tj j |}||krt |jS|jj dddkr|jjjdd}|jjdd}||krt |jSdS) z If type_obj starts with self._template and is the same type as self.name then return self.name, otherwise None. Nz{}<{}z::r) basic_stringz __cxx11::rCri)rrrr*rr<rrr"rrrrOrer.)rrQr#Zt1Zt2s1s2rrrr< s4        z*FilteringTypePrinter._recognizer.recognizeN)r r r r rXrrrrrr3 srcCs|j|j|j|jS)z1Return a recognizer object for this type printer.)rrr"r)rrrrrf sz FilteringTypePrinter.instantiate)N)r r r r rXrrrrrrrr s 3rcCsXtd|d||}tjj||d|krTdt}t|||||}tjj||dS)Nzstd::r)rrrrr-)rrr"rrrWrrradd_one_type_printerk s rc CsdtsdSxxdgD]p}t|d |d d |dt|d|d d |dt|dd|d d |dt|d|d d|dqWxdjD]|}x*dkD]"}t|d||d ||dqWxJdlD]B}t|d||d ||dt|d!||d ||dqWqWxdmD]}x0dpD](}t||d"||d d#|dqWxNdqD]F}t||d(||d)x&drD]}t||||||qlWqJWqWt|d-d.xdsD]}t|d9d:|qWt|d;d<t|d;d=t|d>d?t|d>d@t|dAdBt|dAdCt|dDdEt|dDdFt|dGdHdI}x0dyD](}t||d||d d|dqdequezstd::allocator<{0}>rrz __cxx11::listvectorrzstd::less<{0}>z)std::allocator>)rrCmultimapr4)r)rmultiset unordered_mapzstd::hash<{0}>zstd::equal_to<{0}>)rrCunordered_multimap unordered_set)r)rrCunordered_multisetrCrErr|rrrrrr)rrrrrrCrErr|)rr) rrrrrrrrr)rrrr)rCrrCrErr|)rr )rr#rr)rrr) rrrrr r r r r rrCrErr|rrrrrr)r!r"r#r$r%)rrr)rZchr@abiZdurrWrrrregister_type_printerst s "(     *                   r'cCs8trtjj|tn|dkr t}|jjtt|dS)z4Register libstdc++ pretty-printers with objfile Obj.N) _use_gdb_pprZprintingZregister_pretty_printerlibstdcxx_printerZpretty_printersrPr')rrrrregister_libstdcxx_printers s  r*cCsXtdatjddttjddttjddttjddttjddttjddttjddttjdd ttjdd t tjdd t tjdd t tjdd t tjddt tjddt tjddt tjddt tjddttjddtttjdr.tjddttjddttjdttjdttjdttjdttjdttjdt tjdt tjdttjddttjdd ttjdd!ttjdd"ttjdd#ttjdd$ttjdd%ttjd&dttjd&d ttjd&d!ttjd&d"ttjd&d#ttjd&d$ttjdd'ttjdd(ttjdd)ttjdd)tx2doD]*}tjdd-|ttjdd-|tqWtjd.d/ttjd.d0ttjdd1ttjd2d3t tjd4ttjd5ttjd6ttjd7ttjd8ttjd9d:t!tjd9d;t"tjd9dt$tjd?d>t$tjd@d>t%tjdAd>t%tjdd:t!tjdd;t"tjddrFrirrGrrrr ziprrrZtimezoneZutcrZtzinforr(Z gdb.printingrTrZ gdb.typesrrrZ printer_baser%r-r2r8r5rBr;rKrOrTrUr[rkrmrprqrurxryrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrr)r-r0r5r7rBrJrLrQrlrsrurvr{r}rrrrrrrrrrrrrrr)rrrrr'r*r;rrrrs      %   (&"I  U(*$/A " /%-^!,5I!{'$*/ ?  ",Ce%T oTPK1]e0libstdcxx/v6/__pycache__/xmethods.cpython-36.pycnu[3 hq@sddlZddlZddlZdZddZddZdZdd ZGd d d ejj Z Gd d d ejj Z Gddde Z Gddde ZGddde ZGddde ZGddde ZGddde ZGdddejjZGdddejj ZGdddeZGd d!d!eZGd"d#d#eZGd$d%d%eZGd&d'd'eZGd(d)d)eZGd*d+d+ejjZGd,d-d-ejjZGd.d/d/eZGd0d1d1eZGd2d3d3ejjZ Gd4d5d5ejj Z!Gd6d7d7e!Z"Gd8d9d9e!Z#Gd:d;d;e!Z$Gdd?d?ejjZ&Gd@dAdAejj Z'GdBdCdCe'Z(GdDdEdEe'Z)GdFdGdGe'Z*GdHdIdIe'Z+GdJdKdKe'Z,GdLdMdMe'Z-GdNdOdOejjZ.GdPdQdQejj Z/GdRdSdSe/Z0GdTdUdUe/Z1GdVdWdWejjZ2GdXdYdYejj Z3GdZd[d[e3Z4Gd\d]d]e3Z5Gd^d_d_ejjZ6Gd`dadaejj Z7Gdbdcdce7Z8Gdddedee7Z9Gdfdgdgejj Z:Gdhdidie:Z;GdjdkdkejjZ$N) isinstancerZTypetag_versioned_namespacerematch)xZ template_namerrris_specialization_of!s  rc@seZdZddZdS)LibStdCxxXMethodcCstjjj||||_dS)N)rxmethodXMethod__init__ worker_class)selfnamerrrrr.szLibStdCxxXMethod.__init__N)__name__ __module__ __qualname__rrrrrr-src@seZdZddZddZdS)ArrayWorkerBasecCs||_||_dS)N) _val_type_size)rval_typesizerrrr6szArrayWorkerBase.__init__cCstjd}|j|jjjS)Nz (void *) 0)rZparse_and_evalcastrpointer dereference)rZnullptrrrr null_value:s zArrayWorkerBase.null_valueN)rrrrr"rrrrr5src@s,eZdZddZddZddZddZd S) ArraySizeWorkercCstj|||dS)N)rr)rrrrrrr@szArraySizeWorker.__init__cCsdS)Nr)rrrr get_arg_typesCszArraySizeWorker.get_arg_typescCstS)N)r)robjrrrget_result_typeFszArraySizeWorker.get_result_typecCs|jS)N)r)rr%rrr__call__IszArraySizeWorker.__call__N)rrrrr$r&r'rrrrr#?sr#c@s,eZdZddZddZddZddZd S) ArrayEmptyWorkercCstj|||dS)N)rr)rrrrrrrNszArrayEmptyWorker.__init__cCsdS)Nr)rrrrr$QszArrayEmptyWorker.get_arg_typescCstS)N)r)rr%rrrr&Tsz ArrayEmptyWorker.get_result_typecCst|jdkS)Nr)intr)rr%rrrr'WszArrayEmptyWorker.__call__N)rrrrr$r&r'rrrrr(Msr(c@s,eZdZddZddZddZddZd S) ArrayFrontWorkercCstj|||dS)N)rr)rrrrrrr\szArrayFrontWorker.__init__cCsdS)Nr)rrrrr$_szArrayFrontWorker.get_arg_typescCs|jS)N)r)rr%rrrr&bsz ArrayFrontWorker.get_result_typecCs&t|jdkr|ddS|jSdS)Nr_M_elems)r)rr")rr%rrrr'es zArrayFrontWorker.__call__N)rrrrr$r&r'rrrrr*[sr*c@s,eZdZddZddZddZddZd S) ArrayBackWorkercCstj|||dS)N)rr)rrrrrrrmszArrayBackWorker.__init__cCsdS)Nr)rrrrr$pszArrayBackWorker.get_arg_typescCs|jS)N)r)rr%rrrr&sszArrayBackWorker.get_result_typecCs,t|jdkr |d|jdS|jSdS)Nrr+)r)rr")rr%rrrr'vszArrayBackWorker.__call__N)rrrrr$r&r'rrrrr,lsr,c@s,eZdZddZddZddZddZd S) ArrayAtWorkercCstj|||dS)N)rr)rrrrrrr~szArrayAtWorker.__init__cCstS)N)r)rrrrr$szArrayAtWorker.get_arg_typescCs|jS)N)r)rr%indexrrrr&szArrayAtWorker.get_result_typecCs4t|t|jkr(tdt||jf|d|S)Nz%Array index "%d" should not be >= %d.r+)r)r IndexError)rr%r/rrrr'szArrayAtWorker.__call__N)rrrrr$r&r'rrrrr.}sr.c@s,eZdZddZddZddZddZd S) ArraySubscriptWorkercCstj|||dS)N)rr)rrrrrrrszArraySubscriptWorker.__init__cCstS)N)r)rrrrr$sz"ArraySubscriptWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&sz$ArraySubscriptWorker.get_result_typecCs&t|jdkr|d|S|jSdS)Nrr+)r)rr")rr%r/rrrr's zArraySubscriptWorker.__call__N)rrrrr$r&r'rrrrr1sr1c@seZdZddZddZdS)ArrayMethodsMatchercsftjjjtdtdttdttdttdt tdt tdt d_ fd d j D_ dS) Narrayremptyfrontbackatz operator[])rr4r5r6r7z operator[]csg|]}j|qSr) _method_dict).0m)rrr sz0ArrayMethodsMatcher.__init__..)rrXMethodMatcherrmatcher_name_prefixrr#r(r*r,r.r1r8methods)rr)rrrs  zArrayMethodsMatcher.__init__c Cs^t|dsdS|jj|}|dks*|j r.dSy|jd}|jd}Wn dS|j||S)Nr3rr-)rr8getenabledtemplate_argumentr)r class_type method_namemethodZ value_typerrrrr s   zArrayMethodsMatcher.matchN)rrrrr rrrrr2s r2c@s$eZdZddZddZddZdS)DequeWorkerBasecCs||_d|jpd|_dS)Nir-)rsizeof_bufsize)rrrrrrszDequeWorkerBase.__init__cCsf|dd}|dd}|d|dkr,dS|j|d|dd|d|d|d |dS) N_M_impl_M_start _M_finish_M_curr_M_noder-_M_first_M_last)rG)rr%startfinishrrrrs   zDequeWorkerBase.sizecCs`|dd}|d|d}||kr0|d|S||}|ddt||j}|||jS)NrHrIrNrKrLr-)r)rG)rr%idxrOZfirst_node_sizeZ index_noderrrr/s  zDequeWorkerBase.indexN)rrrrrr/rrrrrEs rEc@s$eZdZddZddZddZdS)DequeEmptyWorkercCsdS)Nr)rrrrr$szDequeEmptyWorker.get_arg_typescCstS)N)r)rr%rrrr&sz DequeEmptyWorker.get_result_typecCs |ddd|dddkS)NrHrIrKrJr)rr%rrrr'szDequeEmptyWorker.__call__N)rrrr$r&r'rrrrrRsrRc@s$eZdZddZddZddZdS)DequeSizeWorkercCsdS)Nr)rrrrr$szDequeSizeWorker.get_arg_typescCstS)N)r)rr%rrrr&szDequeSizeWorker.get_result_typecCs |j|S)N)r)rr%rrrr'szDequeSizeWorker.__call__N)rrrr$r&r'rrrrrSsrSc@s$eZdZddZddZddZdS)DequeFrontWorkercCsdS)Nr)rrrrr$szDequeFrontWorker.get_arg_typescCs|jS)N)r)rr%rrrr&sz DequeFrontWorker.get_result_typecCs|ddddS)NrHrIrKrr)rr%rrrr'szDequeFrontWorker.__call__N)rrrr$r&r'rrrrrTsrTc@s$eZdZddZddZddZdS)DequeBackWorkercCsdS)Nr)rrrrr$szDequeBackWorker.get_arg_typescCs|jS)N)r)rr%rrrr&szDequeBackWorker.get_result_typecCs^|ddd|dddkrF|dddd}|d|jdS|ddddSdS) NrHrJrKrMrLr-r)rG)rr% prev_noderrrr's zDequeBackWorker.__call__N)rrrr$r&r'rrrrrUsrUc@s$eZdZddZddZddZdS)DequeSubscriptWorkercCstS)N)r)rrrrr$ sz"DequeSubscriptWorker.get_arg_typescCs|jS)N)r)rr% subscriptrrrr& sz$DequeSubscriptWorker.get_result_typecCs |j||S)N)r/)rr%rYrrrr'szDequeSubscriptWorker.__call__N)rrrr$r&r'rrrrrX srXc@s$eZdZddZddZddZdS) DequeAtWorkercCstS)N)r)rrrrr$szDequeAtWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&szDequeAtWorker.get_result_typecCs@t|j|}t||kr0tdt||fn |j||SdS)Nz%Deque index "%d" should not be >= %d.)r)rr0r/)rr%r/Z deque_sizerrrr's  zDequeAtWorker.__call__N)rrrr$r&r'rrrrrZsrZc@seZdZddZddZdS)DequeMethodsMatchercsftjjjtdtdttdttdttdt tdt tdt d_ fd d j D_ dS) Ndequer4rr5r6z operator[]r7)r4rr5r6z operator[]r7csg|]}j|qSr)r8)r9r:)rrrr;0sz0DequeMethodsMatcher.__init__..)rrr<rr=rrRrSrTrUrXrZr8r>)rr)rrr%s  zDequeMethodsMatcher.__init__cCs>t|dsdS|jj|}|dks*|j r.dS|j|jdS)Nr\r)rr8r?r@rrA)rrBrCrDrrrr 2s   zDequeMethodsMatcher.matchN)rrrrr rrrrr[$s r[c@seZdZddZddZdS)ForwardListWorkerBasecCs||_||_dS)N)r _node_type)rr node_typerrrr>szForwardListWorkerBase.__init__cCsdS)Nr)rrrrr$Bsz#ForwardListWorkerBase.get_arg_typesN)rrrrr$rrrrr]=sr]c@seZdZddZddZdS)ForwardListEmptyWorkercCstS)N)r)rr%rrrr&Gsz&ForwardListEmptyWorker.get_result_typecCs|ddddkS)NrH_M_head_M_nextrr)rr%rrrr'JszForwardListEmptyWorker.__call__N)rrrr&r'rrrrr`Fsr`c@seZdZddZddZdS)ForwardListFrontWorkercCs|jS)N)r)rr%rrrr&Osz&ForwardListFrontWorker.get_result_typecCs:|dddj|j}|ddj}|j|jjjS)NrHrarb _M_storage)rr^addressrr r!)rr%nodeZ val_addressrrrr'RszForwardListFrontWorker.__call__N)rrrr&r'rrrrrcNsrcc@seZdZddZddZdS)ForwardListMethodsMatchercsJtd}tjjj|tdttdtd_fddjD_ dS)N forward_listr4r5)r4r5csg|]}j|qSr)r8)r9r:)rrrr;`sz6ForwardListMethodsMatcher.__init__..) r=rrr<rrr`rcr8r>)rZ matcher_namer)rrrYs z"ForwardListMethodsMatcher.__init__cCsZt|dsdS|jj|}|dks*|j r.dS|jd}tjt|dj}|j ||S)Nrhrz::_Node) rr8r?r@rArrstrr r)rrBrCrDrr_rrrr bs   zForwardListMethodsMatcher.matchN)rrrrr rrrrrgXs rgc@s$eZdZddZddZddZdS)ListWorkerBasecCs||_||_dS)N)rr^)rrr_rrrrpszListWorkerBase.__init__cCsdS)Nr)rrrrr$tszListWorkerBase.get_arg_typescCsB|j}|jjdjdkr$|dS|dj}|j|jjjS)Nr-Z_M_datard)r!typefieldsrrerrr )rrfZaddrrrrget_value_from_nodews  z"ListWorkerBase.get_value_from_nodeN)rrrrr$rmrrrrrjosrjc@seZdZddZddZdS)ListEmptyWorkercCstS)N)r)rr%rrrr&szListEmptyWorker.get_result_typecCs&|dd}|d|jkrdSdSdS)NrHrLrbTF)re)rr%Z base_noderrrr's zListEmptyWorker.__call__N)rrrr&r'rrrrrnsrnc@seZdZddZddZdS)ListSizeWorkercCstS)N)r)rr%rrrr&szListSizeWorker.get_result_typecCsD|ddd}|ddj}d}x||kr>|d}|d7}q$W|S)NrHrLrbrr-)re)rr%Z begin_nodeZend_noderrrrr's  zListSizeWorker.__call__N)rrrr&r'rrrrrosroc@seZdZddZddZdS)ListFrontWorkercCs|jS)N)r)rr%rrrr&szListFrontWorker.get_result_typecCs"|dddj|j}|j|S)NrHrLrb)rr^rm)rr%rfrrrr'szListFrontWorker.__call__N)rrrr&r'rrrrrpsrpc@seZdZddZddZdS)ListBackWorkercCs|jS)N)r)rr%rrrr&szListBackWorker.get_result_typecCs"|dddj|j}|j|S)NrHrLZ_M_prev)rr^rm)rr%rWrrrr'szListBackWorker.__call__N)rrrr&r'rrrrrqsrqc@seZdZddZddZdS)ListMethodsMatchercsVtjjjtdtdttdttdttdt d_ fddj D_ dS) Nlistr4rr5r6)r4rr5r6csg|]}j|qSr)r8)r9r:)rrrr;sz/ListMethodsMatcher.__init__..) rrr<rr=rrnrorprqr8r>)rr)rrrs  zListMethodsMatcher.__init__cCsZt|dsdS|jj|}|dks*|j r.dS|jd}tjt|dj}|j ||S)Nz(__cxx11::)?listrz::_Node) rr8r?r@rArrrir r)rrBrCrDrr_rrrr s   zListMethodsMatcher.matchN)rrrrr rrrrrrs rrc@s$eZdZddZddZddZdS)VectorWorkerBasecCs ||_dS)N)r)rrrrrrszVectorWorkerBase.__init__cCsz|jjtjkr^|ddd}|ddd}|ddd}|jjjd}||||S|dd|ddSdS)NrHrI_M_prJZ _M_offset)rcoderTYPE_CODE_BOOLr!rkrF)rr%rOrPZ finish_offsetbit_sizerrrrszVectorWorkerBase.sizecCsj|jjtjkrV|ddd}|jjjd}|||}||}|jd|>@dkS|dd|SdS)NrHrIrurvr-r)rrwrrxr!rkrF)rr%r/rOryZvalpoffsetrrrr?s zVectorWorkerBase.getN)rrrrrr?rrrrrts rtc@s$eZdZddZddZddZdS)VectorEmptyWorkercCsdS)Nr)rrrrr$szVectorEmptyWorker.get_arg_typescCstS)N)r)rr%rrrr&sz!VectorEmptyWorker.get_result_typecCst|j|dkS)Nr)r)r)rr%rrrr'szVectorEmptyWorker.__call__N)rrrr$r&r'rrrrr{sr{c@s$eZdZddZddZddZdS)VectorSizeWorkercCsdS)Nr)rrrrr$szVectorSizeWorker.get_arg_typescCstS)N)r)rr%rrrr&sz VectorSizeWorker.get_result_typecCs |j|S)N)r)rr%rrrr'szVectorSizeWorker.__call__N)rrrr$r&r'rrrrr|sr|c@s$eZdZddZddZddZdS)VectorFrontWorkercCsdS)Nr)rrrrr$szVectorFrontWorker.get_arg_typescCs|jS)N)r)rr%rrrr&sz!VectorFrontWorker.get_result_typecCs |j|dS)Nr)r?)rr%rrrr'szVectorFrontWorker.__call__N)rrrr$r&r'rrrrr}sr}c@s$eZdZddZddZddZdS)VectorBackWorkercCsdS)Nr)rrrrr$szVectorBackWorker.get_arg_typescCs|jS)N)r)rr%rrrr&sz VectorBackWorker.get_result_typecCs|j|t|j|dS)Nr-)r?r)r)rr%rrrr'szVectorBackWorker.__call__N)rrrr$r&r'rrrrr~sr~c@s$eZdZddZddZddZdS)VectorAtWorkercCstS)N)r)rrrrr$ szVectorAtWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&szVectorAtWorker.get_result_typecCs>t|j|}t||kr.tdt||f|j|t|S)Nz&Vector index "%d" should not be >= %d.)r)rr0r?)rr%r/rrrrr's  zVectorAtWorker.__call__N)rrrr$r&r'rrrrr src@s$eZdZddZddZddZdS)VectorSubscriptWorkercCstS)N)r)rrrrr$sz#VectorSubscriptWorker.get_arg_typescCs|jS)N)r)rr%rYrrrr&sz%VectorSubscriptWorker.get_result_typecCs|j|t|S)N)r?r))rr%rYrrrr'!szVectorSubscriptWorker.__call__N)rrrr$r&r'rrrrrsrc@seZdZddZddZdS)VectorMethodsMatchercsftjjjtdtdttdttdttdt tdt tdt d_ fd d j D_ dS) Nvectorrr4r5r6r7z operator[])rr4r5r6r7z operator[]csg|]}j|qSr)r8)r9r:)rrrr;2sz1VectorMethodsMatcher.__init__..)rrr<rr=rr|r{r}r~rrr8r>)rr)rrr&s   zVectorMethodsMatcher.__init__cCs>t|dsdS|jj|}|dks*|j r.dS|j|jdS)Nrr)rr8r?r@rrA)rrBrCrDrrrr 4s   zVectorMethodsMatcher.matchN)rrrrr rrrrr%src@s$eZdZddZddZddZdS)AssociativeContainerWorkerBasecCs ||_dS)N) _unordered)r unorderedrrrr@sz'AssociativeContainerWorkerBase.__init__cCs&|jr|ddS|dddSdS)NZ_M_hZ_M_element_count_M_trHZ _M_node_count)r)rr%rrr node_countCs z)AssociativeContainerWorkerBase.node_countcCsdS)Nr)rrrrr$Isz,AssociativeContainerWorkerBase.get_arg_typesN)rrrrrr$rrrrr?src@seZdZddZddZdS)AssociativeContainerEmptyWorkercCstS)N)r)rr%rrrr&Nsz/AssociativeContainerEmptyWorker.get_result_typecCst|j|dkS)Nr)r)r)rr%rrrr'Qsz(AssociativeContainerEmptyWorker.__call__N)rrrr&r'rrrrrMsrc@seZdZddZddZdS)AssociativeContainerSizeWorkercCstS)N)r)rr%rrrr&Vsz.AssociativeContainerSizeWorker.get_result_typecCs |j|S)N)r)rr%rrrr'Ysz'AssociativeContainerSizeWorker.__call__N)rrrr&r'rrrrrUsrc@seZdZddZddZdS)"AssociativeContainerMethodsMatchercsLtjjjt||_tdttdtd_ fddj D_ dS)Nrr4)rr4csg|]}j|qSr)r8)r9r:)rrrr;gsz?AssociativeContainerMethodsMatcher.__init__..) rrr<rr=_namerrrr8r>)rrr)rrr^s   z+AssociativeContainerMethodsMatcher.__init__cCsDt||jsdS|jj|}|dks,|j r0dSd|jk}|j|S)Nr)rrr8r?r@r)rrBrCrDrrrrr is   z(AssociativeContainerMethodsMatcher.matchN)rrrrr rrrrr]s rc@s8eZdZdZddZddZddZdd Zd d Zd S) UniquePtrGetWorkerzS Implement std::unique_ptr::get() and std::unique_ptr::operator->(). cCs*|jtjk|_|jr |j|_n||_dS)N)rwrTYPE_CODE_ARRAY _is_arraytarget _elem_type)r elem_typerrrrzs zUniquePtrGetWorker.__init__cCsdS)Nr)rrrrr$sz UniquePtrGetWorker.get_arg_typescCs |jjS)N)rr )rr%rrrr&sz"UniquePtrGetWorker.get_result_typecCs|dkp|j S)Nr?)r)rrCrrr _supportsszUniquePtrGetWorker._supportscCs|jjjdjj}t|dr.|dd}nt|drB|d}ndS|jjdj}|jdj}|jd}|jdkr|j|dS|jr|j|jSdSdS)Nrz__uniq_ptr_(data|impl)rtupler-Z _M_head_impl)r!rkrlr rrrZ is_base_class)rr%Z impl_typeZ tuple_memberZtuple_impl_typeZtuple_head_typeZ head_fieldrrrr's      zUniquePtrGetWorker.__call__N) rrr__doc__rr$r&rr'rrrrrus rc@s0eZdZdZddZddZddZdd Zd S) UniquePtrDerefWorkerz*Implement std::unique_ptr::operator*().cCstj||dS)N)rr)rrrrrrszUniquePtrDerefWorker.__init__cCs|jS)N)r)rr%rrrr&sz$UniquePtrDerefWorker.get_result_typecCs|j S)N)r)rrCrrrrszUniquePtrDerefWorker._supportscCstj||jS)N)rr'r!)rr%rrrr'szUniquePtrDerefWorker.__call__N)rrrrrr&rr'rrrrrs rc@s8eZdZdZddZddZddZdd Zd d Zd S) UniquePtrSubscriptWorkerz1Implement std::unique_ptr::operator[](size_t).cCstj||dS)N)rr)rrrrrrsz!UniquePtrSubscriptWorker.__init__cCstS)N)r)rrrrr$sz&UniquePtrSubscriptWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&sz(UniquePtrSubscriptWorker.get_result_typecCs|jS)N)r)rrCrrrrsz"UniquePtrSubscriptWorker._supportscCstj|||S)N)rr')rr%r/rrrr'sz!UniquePtrSubscriptWorker.__call__N) rrrrrr$r&rr'rrrrrs rc@seZdZddZddZdS)UniquePtrMethodsMatchercsVtjjjtdtdttdttdttdtd_ fddj D_ dS) N unique_ptrr?z operator->z operator*z operator[])r?z operator->z operator*z operator[]csg|]}j|qSr)r8)r9r:)rrrr;sz4UniquePtrMethodsMatcher.__init__..) rrr<rr=rrrrr8r>)rr)rrrs  z UniquePtrMethodsMatcher.__init__cCsPt|dsdS|jj|}|dks*|j r.dS|j|jd}|j|rL|SdS)Nrr)rr8r?r@rrAr)rrBrCrDworkerrrrr s   zUniquePtrMethodsMatcher.matchN)rrrrr rrrrrs rc@s8eZdZdZddZddZddZdd Zd d Zd S) SharedPtrGetWorkerzT Implements std::shared_ptr::get() and std::shared_ptr::operator->(). cCs*|jtjk|_|jr |j|_n||_dS)N)rwrrrrr)rrrrrrs zSharedPtrGetWorker.__init__cCsdS)Nr)rrrrr$sz SharedPtrGetWorker.get_arg_typescCs |jjS)N)rr )rr%rrrr&sz"SharedPtrGetWorker.get_result_typecCs|dkp|j S)Nr?)r)rrCrrrrszSharedPtrGetWorker._supportscCs|dS)NZ_M_ptrr)rr%rrrr'szSharedPtrGetWorker.__call__N) rrrrrr$r&rr'rrrrrs rc@s0eZdZdZddZddZddZdd Zd S) SharedPtrDerefWorkerz*Implement std::shared_ptr::operator*().cCstj||dS)N)rr)rrrrrrszSharedPtrDerefWorker.__init__cCs|jS)N)r)rr%rrrr&sz$SharedPtrDerefWorker.get_result_typecCs|j S)N)r)rrCrrrrszSharedPtrDerefWorker._supportscCstj||jS)N)rr'r!)rr%rrrr'szSharedPtrDerefWorker.__call__N)rrrrrr&rr'rrrrrs rc@s8eZdZdZddZddZddZdd Zd d Zd S) SharedPtrSubscriptWorkerz1Implement std::shared_ptr::operator[](size_t).cCstj||dS)N)rr)rrrrrr sz!SharedPtrSubscriptWorker.__init__cCstS)N)r)rrrrr$sz&SharedPtrSubscriptWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&sz(SharedPtrSubscriptWorker.get_result_typecCs|jS)N)r)rrCrrrrsz"SharedPtrSubscriptWorker._supportscCsZtjdt|j}|rJ|t|jdkrJtd|jt|t|jdftj|||S)Nz .*\[(\d+)]$r-z.shared_ptr<%s> index "%d" should not be >= %d.) r r rirr)groupr0rr')rr%r/r:rrrr's z!SharedPtrSubscriptWorker.__call__N) rrrrrr$r&rr'rrrrr s rc@s8eZdZdZddZddZddZdd Zd d Zd S) SharedPtrUseCountWorkerz*Implement std::shared_ptr::use_count().cCsdS)Nr)rrrrrr%sz SharedPtrUseCountWorker.__init__cCsdS)Nr)rrrrr$(sz%SharedPtrUseCountWorker.get_arg_typescCs tjdS)NZlong)rr)rr%rrrr&+sz'SharedPtrUseCountWorker.get_result_typecCsdS)NTr)rrCrrrr.sz!SharedPtrUseCountWorker._supportscCs|dd}|r|dSdS)NZ _M_refcountZ_M_piZ _M_use_countrr)rr%Z refcountsrrrr'1s z SharedPtrUseCountWorker.__call__N) rrrrrr$r&rr'rrrrr"s rc@s(eZdZdZddZddZddZdS) SharedPtrUniqueWorkerz'Implement std::shared_ptr::unique().cCstj||dS)N)rr)rrrrrr9szSharedPtrUniqueWorker.__init__cCs tjdS)Nr)rr)rr%rrrr&<sz%SharedPtrUniqueWorker.get_result_typecCstj||dkS)Nr-)rr')rr%rrrr'?szSharedPtrUniqueWorker.__call__N)rrrrrr&r'rrrrr6src@seZdZddZddZdS)SharedPtrMethodsMatchercsftjjjtdtdttdttdttdttdt tdt d_ fd d j D_ dS) N shared_ptrr?z operator->z operator*z operator[] use_countunique)r?z operator->z operator*z operator[]rrcsg|]}j|qSr)r8)r9r:)rrrr;Osz4SharedPtrMethodsMatcher.__init__..) rrr<rr=rrrrrrr8r>)rr)rrrDs  z SharedPtrMethodsMatcher.__init__cCsPt|dsdS|jj|}|dks*|j r.dS|j|jd}|j|rL|SdS)Nrr)rr8r?r@rrAr)rrBrCrDrrrrr Qs   zSharedPtrMethodsMatcher.matchN)rrrrr rrrrrCs rcCstjj|ttjj|ttjj|ttjj|ttjj|ttjj|tdtjj|tdtjj|tdtjj|tdtjj|tdtjj|tdtjj|tdtjj|tdtjj|t tjj|t dS) NsetmapZmultisetZmultimapZ unordered_setZ unordered_mapZunordered_multisetZunordered_multimap) rrZregister_xmethod_matcherr2rgr[rrrrrr)Zlocusrrrregister_libstdcxx_xmethods]s.        r)>rZ gdb.xmethodr r=rrr rrrrZ XMethodWorkerrr#r(r*r,r.r1r<r2rErRrSrTrUrXrZr[r]r`rcrgrjrnrorprqrrrtr{r|r}r~rrrrrrrrrrrrrrrrrrrrrrsr                * PK1] B666libstdcxx/v6/__pycache__/__init__.cpython-36.opt-1.pycnu[3 h}@sddZddZdS)c Cs&y ddl}dStk r dSXdS)NTF)Z gdb.xmethod ImportError)Zgdbr0/usr/share/gcc-8/python/libstdcxx/v6/__init__.pygdb_has_xmethodss rcCs2ddlm}||tr.ddlm}||dS)N)register_libstdcxx_printers)register_libstdcxx_xmethods)ZprintersrrZxmethodsr)objrrrrrrs   rN)rrrrrrsPK1]3,xexe0libstdcxx/v6/__pycache__/printers.cpython-36.pycnu[3 h@sddlZddlZddlZddlZddlZddlZejddkrXeZe Z e Z e ZejjZn6GdddZddlm Z m Z GdddejZeZday ddlZWnek rd aYnXd ayddlZeejd rdaWnek rYnXeed rejZneZd d ZdaddZddZ ddZ!ddZ"ddZ#ddZ$ddZ%ddZ&Gdd d eZ'Gd!d"d"eZ(d#d$Z)d%d&Z*d'd(Z+Gd)d*d*eZ,d+d,Z-d-d.Z.Gd/d0d0eZ/Gd1d2d2eZ0Gd3d4d4e0Z1Gd5d6d6e0Z2Gd7d8d8eZ3Gd9d:d:eZ4Gd;d<dd>eZ6Gd?d@d@eZ7GdAdBdBeZ8GdCdDdDeZ9GdEdFdFeZ:GdGdHdHeZ;dIdJZdOdPZ?GdQdRdReZ@GdSdTdTeZAGdUdVdVeZBGdWdXdXeZCGdYdZdZeZDGd[d\d\eZEd]d^ZFGd_d`d`eZGGdadbdbeZHGdcddddeZIGdedfdfeZJGdgdhdheZKGdidjdjeZLGdkdldleZMGdmdndneZNdodpZOGdqdrdreNZPGdsdtdteNZQGdudvdveNZRGdwdxdxeNZSGdydzdzeZTGd{d|d|eZUGd}d~d~eZVGdddeZWGdddeZXGdddeZYGdddeZZGdddeZ[GdddeZ\GdddeZ]GdddeZ^GdddeZ_GdddeZ`GdddeZadddddddddddddg ZbddddddddgZcGdddeZdGdddeZeGdddeZfGdddeZgGdddeZhGdddeZiGdddeZjGdddeZkGdddeZlGdddeZmdanGdddeZoddZpGdddeZqdddÄZrddńZsddDŽZtddɄZueudS)Nc@seZdZdZddZdS)Iteratora:Compatibility mixin for iterators Instead of writing next() methods for iterators, write __next__() methods and use this mixin to make them work in Python 2 as well as Python 3. Idea stolen from the "six" documentation: cCs|jS)N)__next__)selfr0/usr/share/gcc-8/python/libstdcxx/v6/printers.pynext?sz Iterator.nextN)__name__ __module__ __qualname____doc__rrrrrr4s r)imapizipc@s(eZdZdZddZddZddZdS) UTCz5Concrete tzinfo class representing the UTC time zone.cCs tjdS)Nr)datetime timedelta)rdtrrr utcoffsetIsz UTC.utcoffsetcCsdS)Nrr)rrrrrtznameLsz UTC.tznamecCs tjdS)Nr)rr)rrrrrdstOszUTC.dstN)r r r r rrrrrrrrFsrTFZ TypePrinter ValuePrinterc Csz|j}xld|j|f}y tj|Stk r6YnX|j}t|r^|djr^|dj}q t dt ||fq WdS)Nz%s::%srzCannot find type %s::%s) strip_typedefstaggdb lookup_type RuntimeErrorfieldslen is_base_classtype ValueErrorstr)Zorignametypsearchrrrr find_typens  r%z__8::cGsdj|djdd|D}y tj|Stjk r}zFt|krv|jddtd}y tj|Stjk rtYnX|WYdd}~XnXdS)z8 Lookup template specialization templ. z{}<{}>z, cSsg|] }t|qSr)r!).0arrr sz%lookup_templ_spec..z::N)formatjoinrrerror_versioned_namespacereplace)Ztemplargsterrrlookup_templ_specs  r2cCsd|krd|}yt|d}Wn|jd}YnX|j}y t||Stjk rt|drt|dddr|jdd d }y t||Stjk rYnXd SXd S) a Lookup specialization of template nodename corresponding to containertype. nodename - The name of a class template, as a String containertype - The container, as a gdb.Type Return a gdb.Type for the corresponding specialization of nodename, or None if the type cannot be found. e.g. lookup_node_type('_List_node', gdb.lookup_type('std::list')) will return a gdb.Type for the type std::_List_node. z::zstd:: value_typerZstdzstd::__cxx1998z std::__debugZ __gnu_debugz ::__cxx1998::r)N)r%template_argumentrr2rr,is_member_of_namespacer.)nodenameZ containertypevaltyperrrlookup_node_types&   r8cGs@t|tjrt|}t|}x|D]}|j|dr"dSq"WdS)z Test whether a type is a member of one of the specified namespaces. The type can be specified as a string or a gdb.Type object. z::TF) isinstancerTyper!strip_versioned_namespace startswith)r#Z namespaces namespacerrrr5s  r5cCs2t|tjr|j}dt|f}tjd||dk S)z Test whether a type is a specialization of the named class template. The type can be specified as a string or a gdb.Type object. The template should be the name of a class template as a string, without any 'std' qualification. z(%s)?%sz ^std::%s<.*>$N)r9rr:rr-rematch)x template_namerrris_specialization_ofs  rBcCs |jtdS)N)r.r-)typenamerrrr;sr;cCs<d}d}tjddkr&tj|||dStj|||ddSdS)zCRemove "fundamentals_vN" inline namespace from qualified type name.z&^std::experimental::fundamentals_v\d::zstd::experimental::rrr))countN)sys version_infor>sub)r#patternreplrrrstrip_fundts_namespaces rKcCsVt|}|jdd}d}x d D]}|j||d|}qW|d}|j|d|}|S) zARemove known inline namespaces from the canonical name of a type.zstd::__cxx11::zstd::zstd::experimental::fundamentals_v1fundamentals_v2z::z filesystem::zv1::)rLrM)r;r.)type_strZexpt_nsZlfts_nsZfs_nsrrrstrip_inline_namespacess  rOc Cs:d}g}x,y|j|j|Wn |S|d7}q WdS)z-Return a type's template arguments as a list.rr)N)appendr4)type_objn template_argsrrrget_template_arg_listsrTc@s(eZdZdZddZddZddZdS) SmartPtrIteratorz@An iterator for smart pointer types with a single 'child' value.cCs ||_dS)N)_val)rvalrrr__init__szSmartPtrIterator.__init__cCs|S)Nr)rrrr__iter__szSmartPtrIterator.__iter__cCs$|jdkrtd|j|_}d|fS)Nzget())rV StopIteration)rrWrrrr s zSmartPtrIterator.__next__N)r r r r rXrYrrrrrrUsrUc@s0eZdZdZddZddZddZdd Zd S) SharedPointerPrinterzP Print a shared_ptr, weak_ptr, atomic, or atomic. cCst||_||_|d|_dS)N_M_ptr)r; _typenamerV_pointer)rrDrWrrrrXs zSharedPointerPrinter.__init__cCs t|jS)N)rUr^)rrrrchildrenszSharedPointerPrinter.childrencCsR|jdkrD|jddd}||d}t|jdjd}|j|S|jddS)Nz std::atomicZ _M_refcountZ_M_val_M_irpointerZ_M_pi)r]rVr%rcast)rZptr_valZptr_typerrr_get_refcountss    z#SharedPointerPrinter._get_refcountscCspd}|j}|jjjd}tt|}|dkr`|d}|d}|dkrPd|}nd||df}d|j||fS) NemptyrZ _M_use_countZ _M_weak_countzexpired, weak count %dzuse count %d, weak count %dr)z %s<%s> (%s))rcrVrr4r;r!r])rstateZ refcountstargZusecountZ weakcountrrr to_string(s  zSharedPointerPrinter.to_stringN)r r r r rXr_rcrgrrrrr[s  r[cCs|jj}|djs&tdt|j|j|dj}|jj}t|dkr^tdt|j|djdkrt|dS|djr|j|djStdt|jdS)zBReturn the tuple element stored in a _Tuple_impl base class.r)z-Unsupported implementation for std::tuple: %sr _M_head_implNri)rrrr r!rbrr")rWbasesZ head_baserrrr_tuple_impl_get9s     rkcCshtt|j}||krtd|j|jjdj}x*|dkr^|j|jjdj}|d8}q6Wt|S)z6Return the result of std::get(val) on a std::tuple.z0Out of range index for std::get on std::tuplerr))rrTrr rbrrk)rRrWZ tuple_sizenoderrr tuple_getQs  rmcCsd|jjdjj}t|ds(t|dr6|dd}n$t|drJ|d}ntdt|td|S)z4Return the result of val.get() on a std::unique_ptr.rZ__uniq_ptr_dataZ__uniq_ptr_impl_M_ttuplez-Unsupported implementation for unique_ptr: %s)rrrrBr r!rm)rWZ impl_typeZ tuple_memberrrrunique_ptr_get_s    rpc@s(eZdZdZddZddZddZdS) UniquePointerPrinterzPrint a unique_ptr.cCs ||_dS)N)rV)rrDrWrrrrXtszUniquePointerPrinter.__init__cCstt|jS)N)rUrprV)rrrrr_wszUniquePointerPrinter.childrencCs|jjjd}djt|S)Nrzstd::unique_ptr<{}>)rVrr4r*r!)rr0rrrrgzszUniquePointerPrinter.to_stringN)r r r r rXr_rgrrrrrqqsrqcCs|djj|jjS)z7Return the value held in a __gnu_cxx::__aligned_membuf. _M_storage)addressrbra dereference)Zbufr7rrrget_value_from_aligned_membufsruc CsjyF|jjdj}|dkr"|dS|dkrD|jjd}t|d|SWn YnXtdt|jdS)z-Return the value held in an _List_node<_Val>.r)_M_datarrrz!Unsupported implementation for %sN)rrr"r4rur r!)rlmemberr7rrrget_value_from_list_nodes rxc@s8eZdZdZGdddeZddZddZdd Zd S) StdListPrinterzPrint a std::list.c@s$eZdZddZddZddZdS)zStdListPrinter._iteratorcCs"||_|d|_|j|_d|_dS)N_M_nextr) _nodetype_basers_head_count)rnodetypeheadrrrrXs z!StdListPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz!StdListPrinter._iterator.__iter__cCsR|j|jkrt|jj|jj}|d|_|j}|jd|_t|}d||fS)Nrzr)z[%d])r|r}rZrbr{rtr~rx)reltrErWrrrrs   z!StdListPrinter._iterator.__next__N)r r r rXrYrrrrr _iteratorsrcCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zStdListPrinter.__init__cCs(td|jjj}|j||jddS)N _List_node_M_impl_M_node)r8rVrrar)rrrrrr_szStdListPrinter.childrencCs0|jdd}|d|jkr&d|jSd|jS)Nrrrzzempty %sz%s)rVrsr])rZheadnoderrrrgs zStdListPrinter.to_stringN) r r r r rrrXr_rgrrrrrys ryc@seZdZddZddZdS)NodeIteratorPrintercCs$||_||_||_t||j|_dS)N)rVr] _contnamer8rr{)rrDrWZcontnamer6rrrrXszNodeIteratorPrinter.__init__cCs:|jdsd|jS|jdj|jjj}tt|S)Nrz(non-dereferenceable iterator for std::%s)rVrrbr{rartr!rx)rrlrrrrgs    zNodeIteratorPrinter.to_stringN)r r r rXrgrrrrrsrc@seZdZdZddZdS)StdListIteratorPrinterzPrint std::list::iterator.cCstj|||dddS)Nlistr)rrX)rrDrWrrrrXszStdListIteratorPrinter.__init__N)r r r r rXrrrrrsrc@seZdZdZddZdS)StdFwdListIteratorPrinterz"Print std::forward_list::iterator.cCstj|||dddS)N forward_list_Fwd_list_node)rrX)rrDrWrrrrXs z"StdFwdListIteratorPrinter.__init__N)r r r r rXrrrrrsrc@s8eZdZdZGdddeZddZddZdd Zd S) StdSlistPrinterzPrint a __gnu_cxx::slist.c@s$eZdZddZddZddZdS)zStdSlistPrinter._iteratorcCs||_|dd|_d|_dS)N_M_headrzr)r{r|r~)rrrrrrrXsz"StdSlistPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz"StdSlistPrinter._iterator.__iter__cCsL|jdkrt|jj|jj}|d|_|j}|jd|_d||dfS)Nrrzr)z[%d]rv)r|rZrbr{rtr~)rrrErrrrs   z"StdSlistPrinter._iterator.__next__N)r r r rXrYrrrrrrsrcCs ||_dS)N)rV)rrDrWrrrrXszStdSlistPrinter.__init__cCs td|jj}|j|j|jS)Nz__gnu_cxx::_Slist_node)r8rVrrra)rrrrrr_szStdSlistPrinter.childrencCs|jdddkrdSdS)Nrrzrzempty __gnu_cxx::slistz__gnu_cxx::slist)rV)rrrrrgszStdSlistPrinter.to_stringN) r r r r rrrXr_rgrrrrrs rc@s eZdZdZddZddZdS)StdSlistIteratorPrinterz!Print __gnu_cxx::slist::iterator.cCs ||_dS)N)rV)rrDrWrrrrXsz StdSlistIteratorPrinter.__init__cCs<|jdsdStd|jjj}t|jdj|jdS)Nrz1non-dereferenceable iterator for __gnu_cxx::slistz__gnu_cxx::_Slist_noderv)rVr8rrar!rbrt)rrrrrrgs  z!StdSlistIteratorPrinter.to_stringN)r r r r rXrgrrrrrsrc@s@eZdZdZGdddeZddZddZdd Zd d Z d S) StdVectorPrinterzPrint a std::vector.c@s$eZdZddZddZddZdS)zStdVectorPrinter._iteratorcCs^||_|rH|d|_d|_|d|_|d|_|jjj}d|j|_n ||_||_d|_ dS)N_M_pr _M_offset) _bitvec_item_so_finish_fortrsizeof_isizer~)rstartfinishZbitvecityperrrrX s    z#StdVectorPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz#StdVectorPrinter._iterator.__iter__cCs|j}|jd|_|jr|j|jkr4|j|jkr4tt|jjd|j>@}|jd|_|j|j krv|jd|_d|_d||fS|j|jkrt|jj}|jd|_d||fSdS)Nr)rz[%d]) r~rrrrrrZboolrtr)rrErrrrrs         z#StdVectorPrinter._iterator.__next__N)r r r rXrYrrrrrr srcCs*t||_||_|jjdjtjk|_dS)Nr) r;r]rVrr4coderTYPE_CODE_BOOL_is_bool)rrDrWrrrrX0s zStdVectorPrinter.__init__cCs$|j|jdd|jdd|jS)Nr_M_start _M_finish)rrVr)rrrrr_6s zStdVectorPrinter.childrenc Cs|jdd}|jdd}|jdd}|jr|jddd}|jddd}|jddd}|jj}d|j}||||}|||}d|jt|t|fSd |jt||t||fSdS) NrrrZ_M_end_of_storagerrrz"%s of length %d, capacity %dz%s of length %d, capacity %d)rVrrtrrr]int) rrrendZforZbllengthZcapacityrrrrg;s   zStdVectorPrinter.to_stringcCsdS)Narrayr)rrrr display_hintMszStdVectorPrinter.display_hintN) r r r r rrrXr_rgrrrrrrs %rc@s eZdZdZddZddZdS)StdVectorIteratorPrinterzPrint std::vector::iterator.cCs ||_dS)N)rV)rrDrWrrrrXTsz!StdVectorIteratorPrinter.__init__cCs |jdsdSt|jdjS)NZ _M_currentz,non-dereferenceable iterator for std::vector)rVr!rt)rrrrrgWs z"StdVectorIteratorPrinter.to_stringN)r r r r rXrgrrrrrQsrc@s eZdZdZddZddZdS)StdBitIteratorPrinterz@Print std::vector's _Bit_iterator and _Bit_const_iterator.cCs ||_dS)N)rV)rrDrWrrrrX`szStdBitIteratorPrinter.__init__cCs.|jdsdSt|jdjd|jd>@S)Nrz2non-dereferenceable iterator for std::vectorr)r)rVrrt)rrrrrgcs zStdBitIteratorPrinter.to_stringN)r r r r rXrgrrrrr]src@s eZdZdZddZddZdS)StdBitReferencePrinterz#Print std::vector::reference.cCs ||_dS)N)rV)rrDrWrrrrXmszStdBitReferencePrinter.__init__cCs*|jdsdSt|jdj|jd@S)Nrz$invalid std::vector::referenceZ_M_mask)rVrrt)rrrrrgps z StdBitReferencePrinter.to_stringN)r r r r rXrgrrrrrjsrc@s8eZdZdZGdddeZddZddZdd Zd S) StdTuplePrinterzPrint a std::tuple.c@s0eZdZeddZddZddZddZd S) zStdTuplePrinter._iteratorcCsNt|dkr"t|djdrBdSn t|dkr2dSt|dkrBdStddS)Nrr)Z __tuple_baseTrFz4Top of tuple tree does not consist of a single node.)rrBrr )nodesrrr_is_nonempty_tuple}s   z,StdTuplePrinter._iterator._is_nonempty_tuplecCs:||_|jjj}|j|r0|jj|dj|_d|_dS)Nr)r}rrrrbr~)rrrrrrrXs   z"StdTuplePrinter._iterator.__init__cCs|S)Nr)rrrrrYsz"StdTuplePrinter._iterator.__iter__cCs|js t|jjj}t|dkr&tt|dkr:tdt|dkr`|jj|dj}d|_n&|jj|dj}|jj|dj|_|jd|_|jj}t|dks|djdkrd|jd|fSd|jd|dfSdS)Nrrz/Cannot parse more than 2 nodes in a tuple tree.r)rhz[%d]) r}rZrrrr rbr~r")rrimplrrrrrs$       z"StdTuplePrinter._iterator.__next__N)r r r staticmethodrrXrYrrrrrr|s  rcCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zStdTuplePrinter.__init__cCs |j|jS)N)rrV)rrrrr_szStdTuplePrinter.childrencCs(t|jjjdkrd|jSd|jS)Nrzempty %sz %s containing)rrVrrr])rrrrrgs zStdTuplePrinter.to_stringN) r r r r rrrXr_rgrrrrrys Erc@s0eZdZdZddZddZddZdd Zd S) StdStackOrQueuePrinterz!Print a std::stack or std::queue.cCst||_tj|d|_dS)Nc)r;r]rdefault_visualizer _visualizer)rrDrWrrrrXs zStdStackOrQueuePrinter.__init__cCs |jjS)N)rr_)rrrrr_szStdStackOrQueuePrinter.childrencCsd|j|jjfS)Nz%s wrapping: %s)r]rrg)rrrrrgsz StdStackOrQueuePrinter.to_stringcCst|jdr|jjSdS)Nr)hasattrrr)rrrrrs  z#StdStackOrQueuePrinter.display_hintN)r r r r rXr_rgrrrrrrs rc@s0eZdZdZddZddZddZdd Zd S) RbtreeIteratorzf Turn an RB-tree-based container (std::map, std::set etc.) into a Python iterable object. cCs2|ddd|_|dddd|_d|_dS)NrnrZ _M_node_countZ _M_header_M_leftr)_size_noder~)rZrbtreerrrrXszRbtreeIterator.__init__cCs|S)Nr)rrrrrYszRbtreeIterator.__iter__cCs t|jS)N)rr)rrrr__len__szRbtreeIterator.__len__cCs|j|jkrt|j}|jd|_|j|jkr|j}|jdrl|jd}xd|jdrh|jd}qNWnF|jd}x$||jdkr|}|jd}qzW|jd|kr|}||_|S)Nr)Z_M_rightrZ _M_parent)r~rrZrrt)rresultrlparentrrrrs$      zRbtreeIterator.__next__N)r r r r rXrYrrrrrrrs rc CsjyF|jjdj}|dkr"|dS|dkrD|jjd}t|d|SWn YnXtdt|jdS)z0Return the value held in an _Rb_tree_node<_Val>.r)Z_M_value_fieldrrrz!Unsupported implementation for %sN)rrr"r4rur r!)rlrwr7rrrget_value_from_Rb_tree_node s rc@s eZdZdZddZddZdS)StdRbtreeIteratorPrinterz2Print std::map::iterator, std::set::iterator, etc.cCs"||_td|jj}|j|_dS)N _Rb_tree_node)rVr8rra _link_type)rrDrWrrrrrX!sz!StdRbtreeIteratorPrinter.__init__cCs0|jdsdS|jdj|jj}tt|S)Nrz6non-dereferenceable iterator for associative container)rVrbrrtr!r)rrlrrrrg&s z"StdRbtreeIteratorPrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdDebugIteratorPrinterz-Print a debug enabled version of an iterator.cCs ||_dS)N)rV)rrDrWrrrrX0sz StdDebugIteratorPrinter.__init__cCsbtjd}|jjjd}|jj|d}|std||_nd|_dS)Nrir)) r;r]rVrr4Z_elttyperrr)rrDrWsizerrrrXs zStdDequePrinter.__init__cCsx|jdd}|jdd}|d|dd}|d|d}|d|d}|j|||}d |jtt|fS) Nrrrrr)_M_last_M_cur_M_firstz %s with %s)rVrr]rlong)rrrZdelta_nZdelta_sZdelta_errrrrgszStdDequePrinter.to_stringcCs@|jdd}|jdd}|j|d|d|d|d|jS)Nrrrrrr)rVrr)rrrrrrr_szStdDequePrinter.childrencCsdS)Nrr)rrrrrszStdDequePrinter.display_hintN) r r r r rrrXrgr_rrrrrrs   rc@s eZdZdZddZddZdS)StdDequeIteratorPrinterzPrint std::deque::iterator.cCs ||_dS)N)rV)rrDrWrrrrXsz StdDequeIteratorPrinter.__init__cCs |jdsdSt|jdjS)Nrz+non-dereferenceable iterator for std::deque)rVr!rt)rrrrrg s z!StdDequeIteratorPrinter.to_stringN)r r r r rXrgrrrrrsrc@s(eZdZdZddZddZddZdS) StdStringPrinterz'Print a std::basic_string of some kind.cCs||_|jddk|_dS)Nz::__cxx11::basic_stringr)ri)rVfind _new_string)rrDrWrrrrXszStdStringPrinter.__init__cCs|jj}|jtjkr|j}|jdd}|jrL|jd}|j|jj}n<|j j}tj t |dj }|j|d}|j d}t|dr|j|dS|j|dS) NZ _M_dataplusrZ_M_string_lengthz::_Repr)Z _M_length lazy_string)r)rVrrr TYPE_CODE_REFrrrbr unqualifiedrr!rartrrstring)rrptrrZrealtypeZreptypeheaderrrrrgs      zStdStringPrinter.to_stringcCsdS)Nrr)rrrrr-szStdStringPrinter.display_hintN)r r r r rXrgrrrrrrsrcCs"|d}|d}|d}|||fS)z'Access the streambuf put area pointers.Z _M_out_begZ _M_out_curZ _M_in_endr) streambufpbasepptregptrrrraccess_streambuf_ptrs1src@s(eZdZdZddZddZddZdS) StdStringBufPrinterzPrint a std::basic_stringbuf.cCs ||_dS)N)rV)r_rWrrrrX<szStdStringBufPrinter.__init__cCsLt|j\}}}|rB| s"||kr2|j||dS|j||dS|jdS)N)rZ _M_string)rrVr)rrrrrrrrg?s zStdStringBufPrinter.to_stringcCsdS)Nrr)rrrrrIsz StdStringBufPrinter.display_hintN)r r r r rXrgrrrrrr9s rc@s(eZdZdZddZddZddZdS) StdStringStreamPrinterz Print a std::basic_stringstream.cCsZ||_||_dd|jjDd}tjd|j|jtjd|_ |j |djk|_ dS)NcSsg|]}|jr|jqSr)rr)r&frrrr(Xsz3StdStringStreamPrinter.__init__..rZ__streamz$__stream->rdbuf() _M_stringbuf) rVr]rrrZset_convenience_variablerbrsparse_and_eval _streambuf_was_redirected)rrDrWZbasetyperrrrXPs  zStdStringStreamPrinter.__init__cCs$|jrd|j|jjfS|jdS)Nz%s redirected to %sr)rr]rrtrV)rrrrrg]sz StdStringStreamPrinter.to_stringcCs|jr dSdS)Nr)r)rrrrrcsz#StdStringStreamPrinter.display_hintN)r r r r rXrgrrrrrrMs rc@s$eZdZddZddZddZdS)Tr1HashtableIteratorcCsj|d|_d|_|d|_t|jdj|_d|_x2|j|jkrd|j|j|_|jrVP|jd|_q4WdS)NZ _M_bucketsrZ_M_bucket_countZ_Noder))_buckets_bucket _bucket_countr%rra _node_typer)r hashtablerrrrXjs  zTr1HashtableIterator.__init__cCs|S)Nr)rrrrrYvszTr1HashtableIterator.__iter__cCs|jdkrt|jj|j}|jd}|jd|_|jdkr|jd|_x2|j|jkr~|j|j|_|jrpP|jd|_qNW|S)NrZ_M_vrzr))rrZrbrrtrrr)rrlrrrrrys    zTr1HashtableIterator.__next__N)r r r rXrYrrrrrris rc@s$eZdZddZddZddZdS)StdHashtableIteratorcCsR|dd|_|jjd}|jjdjd}tdt||r>dnd}|j|_dS) NZ_M_before_begin_M_nxtr) rzstd::__detail::_Hash_nodetrueZfalse)rrr4r2r!rar)rrr7cachedZ node_typerrrrXs   zStdHashtableIterator.__init__cCs|S)Nr)rrrrrYszStdHashtableIterator.__iter__cCsR|jdkrt|jj|jj}|d|_|dj}|j|jjdj}|jS)Nrrrr) rrZrbrrtrsrr4ra)rrvalptrrrrrs   zStdHashtableIterator.__next__N)r r r rXrYrrrrrrsrc@s<eZdZdZddZddZddZedd Zd d Z d S) Tr1UnorderedSetPrinterz1Print a std::unordered_set or tr1::unordered_set.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zTr1UnorderedSetPrinter.__init__cCs|jjdr|jS|jdS)Nzstd::tr1_M_h)r]r<rV)rrrr _hashtables z!Tr1UnorderedSetPrinter._hashtablecCs|jd}d|jt|fS)N_M_element_countz %s with %s)rr]r)rrErrrrgs z Tr1UnorderedSetPrinter.to_stringcCsd|S)Nz[%d]r)irrr _format_countsz$Tr1UnorderedSetPrinter._format_countcCs@t|jtj}|jjdr.t|t|jSt|t |jS)Nzstd::tr1) r r itertoolsrEr]r<rrrr)rcounterrrrr_s zTr1UnorderedSetPrinter.childrenN) r r r r rXrrgrrr_rrrrrs  rc@s\eZdZdZddZddZddZedd Zed d Z ed d Z ddZ ddZ dS)Tr1UnorderedMapPrinterz1Print a std::unordered_map or tr1::unordered_map.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zTr1UnorderedMapPrinter.__init__cCs|jjdr|jS|jdS)Nzstd::tr1r)r]r<rV)rrrrrs z!Tr1UnorderedMapPrinter._hashtablecCs|jd}d|jt|fS)Nrz %s with %s)rr]r)rrErrrrgs z Tr1UnorderedMapPrinter.to_stringccs&x |D]}x|D] }|VqWqWdS)Nr)rrrrrr_flattens  zTr1UnorderedMapPrinter._flattencCs|d|dfS)Nrrr)rrrr _format_onesz"Tr1UnorderedMapPrinter._format_onecCsd|S)Nz[%d]r)rrrrrsz$Tr1UnorderedMapPrinter._format_countcCsdt|jtj}|jjdr@|jt|jt|j }t ||S|jt|jt |j }t ||S)Nzstd::tr1) r rrrEr]r<r r rrrr)rr datarrrr_s  zTr1UnorderedMapPrinter.childrencCsdS)Nrr)rrrrrsz#Tr1UnorderedMapPrinter.display_hintN) r r r r rXrrgrr r rr_rrrrrr s    r c@s8eZdZdZGdddeZddZddZdd Zd S) StdForwardListPrinterzPrint a std::forward_list.c@s$eZdZddZddZddZdS)zStdForwardListPrinter._iteratorcCs||_|d|_d|_dS)Nrzr)r{r|r~)rrrrrrrXs z(StdForwardListPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz(StdForwardListPrinter._iterator.__iter__cCsl|jdkrt|jj|jj}|d|_|j}|jd|_|dj}|j|jjdj }d||jfS)Nrrzr)rrz[%d]) r|rZrbr{rtr~rsrr4ra)rrrErrrrrs    z(StdForwardListPrinter._iterator.__next__N)r r r rXrYrrrrrrsrcCs||_t||_dS)N)rVr;r])rrDrWrrrrXszStdForwardListPrinter.__init__cCs(td|jjj}|j||jddS)Nrrr)r8rVrrar)rrrrrr_szStdForwardListPrinter.childrencCs*|jddddkr d|jSd|jS)Nrrrzrzempty %sz%s)rVr])rrrrrgs zStdForwardListPrinter.to_stringN) r r r r rrrXr_rgrrrrrs rc@sBeZdZdZd ddZddZGdddeZd d Zd d Z dS)SingleObjContainerPrinterz8Base class for printers of containers of single objects.NcCs||_||_||_dS)N)_contained_valuer_hint)rrWZvizZhintrrrrXsz"SingleObjContainerPrinter.__init__cCs(ts t|Stjjtjj|p&t|S)z5Return type as a string after applying type printers.)_use_type_printingr!rtypesapply_type_recognizersget_type_recognizers)rrrrr _recognizesz$SingleObjContainerPrinter._recognizec@s$eZdZddZddZddZdS)z$SingleObjContainerPrinter._containedcCs ||_dS)N)rV)rrWrrrrXsz-SingleObjContainerPrinter._contained.__init__cCs|S)Nr)rrrrrY"sz-SingleObjContainerPrinter._contained.__iter__cCs"|jdkrt|j}d|_d|fS)Nz[contained value])rVrZ)rZretvalrrrr%s  z-SingleObjContainerPrinter._contained.__next__N)r r r rXrYrrrrr _containedsrcCs6|jdkr|jdSt|jdr*|jjS|j|jS)Nr_)rrrrr_)rrrrr_,s     z"SingleObjContainerPrinter.childrencCs(t|jdr"t|jdr"|jjS|jS)Nr_r)rrrr)rrrrr3s   z&SingleObjContainerPrinter.display_hint)N) r r r r rXrrrr_rrrrrrs  rc CsH|jj}tjddkr"t|}nt|}ytj|jj SdSdS)z{Find the name of the function referred to by the gdb.Value f, which should contain a function pointer from the program.rrN) rtrsrFrGrrrZ block_for_pcfunctionr")rrrrfunction_pointer_to_name;s  rcs4eZdZdZfddZddZeddZZS)StdExpAnyPrinterz+Print a std::any or std::experimental::any.c st||_t|j|_||_d|_d}d}|jd}|dkrt|}|sXtd|jdj|}tj ||}|std|j|j d} d| kr g} xPt j D]D} y(tj d| |j d} | jtj| Wqtjk rYqXqWt| dkrtd | d} n tj| } | jd|_d}d | kr@|jd d j}n(d | krZ|jd d}ntd|j|j|jjj}tj|}tt |j||dS)NZ _M_managerrzInvalid function pointer in %szi({0}::_Manager_\w+<.*>)::_S_manage\((enum )?{0}::_Op, (const {0}|{0} const) ?\*, (union )?{0}::_Arg ?\*\)zUnknown manager function in %sr)z std::stringzstd::string(?!\w)z;Cannot uniquely determine std::string type used in std::anyz::_Manager_internalrrZ _M_bufferz::_Manager_externalr\)r;r]rKrV_contained_typerr r*r>r?groupr _string_typesrHrPrrr,rr4rsrbrartrsuperrX)rrDrWcontained_value visualizerZmgrfuncZrxmZmgrnameZmgrtypessr@Zmgrtyper) __class__rrrXVsX                 zStdExpAnyPrinter.__init__cCsT|jdkrd|jSd|j}t|jdr8||jjS|j|j}|tt|S)Nz%s [no contained value]z%s containing r_)rr]rrrgrr;r!)rdescr7rrrrgs     zStdExpAnyPrinter.to_stringcs@ttjdjh}ddddtg}|fdd|DO}|S)Nz std::stringzAbasic_string, std::allocator >zstd::zstd::__cxx11::csh|] }|qSrr)r&q)r#rr sz1StdExpAnyPrinter._string_types..)r!rrrr-)ZstringsZqualsr)r#rrs  zStdExpAnyPrinter._string_types) r r r r rXrgrr __classcell__rr)r$rrSs D rcs(eZdZdZfddZddZZS)StdExpOptionalPrinterz5Print a std::optional or std::experimental::optional.c st||_t|j|_|d}|jjdr8|d}|}n*|d}|d}y |d}Wn YnXtj|}|std}tt|j||dS)N _M_payloadzstd::experimental _M_engaged_M_value) r;r]rKr<rrrr)rX)rrDrWZpayloadZengagedrr )r$rrrXs"      zStdExpOptionalPrinter.__init__cCs:|jdkrd|jSt|jdr4d|j|jjfS|jS)Nz%s [no contained value]r_z%s containing %s)rr]rrrg)rrrrrgs    zStdExpOptionalPrinter.to_string)r r r r rXrgr(rr)r$rr)s r)cs(eZdZdZfddZddZZS)StdVariantPrinterzPrint a std::variant.cst|j}t||_|d|_|jt|krz[%s])rrrZrtr~r7r@r=)rrrEr?r0rrrrRs    z$StdExpPathPrinter._iterator.__next__N)r r r rXrYrrrrrrHsrcCs|j|jd|jS)Nr8)rrVr])rrrrr__szStdExpPathPrinter.childrenN) r r r r rXr=rgrrr_rrrrr7.s r7c@s@eZdZdZddZddZddZGdd d eZd d Z d S) StdPathPrinterzPrint a std::filesystem::path.cCsP||_||_t|jdd}|jtjdd@|_|jdkrF||_nd|_dS)Nr8rZ uintptr_tr)rVr]rprbrrr_impl)rrDrWrrrrrXfs zStdPathPrinter.__init__cCsHt|jjtj|jd}|dddkr0dS|d ddkrDdSdS) Nz::_Typerr:zroot-directoryr;r<z root-nameii)r!rrbrrr])rr0rrrr=ps zStdPathPrinter._path_typecCs8d|jd}|jdkr0|j}|r0d||f}d|S)Nz%sr>rz%s [%s]zfilesystem::path %s)rVrr=)rr?r0rrrrgxs   zStdPathPrinter.to_stringc@s$eZdZddZddZddZdS)zStdPathPrinter._iteratorc Cs||_|rtjd}tj|d}tjd}|j|j}|j}ttjdrbtd|j |j }n d|j }|j|j|}|j|j|_ |j ||_ d|_ n d|_ d|_ dS)Nrz::_Cmptcharalignofrr)r@rrrbrartrr:maxrrFrrr~) rrrAZint_typeZ cmpt_type char_typerZ sizeof_ImplbeginrrrrXs      z!StdPathPrinter._iterator.__init__cCs|S)Nr)rrrrrYsz!StdPathPrinter._iterator.__iter__cCsd|j|jkrt|jj}|j}|jd|_|jd|_|d}t|j|j}|sX|}d||fS)Nr)r>z[%s])rrrZrtr~rBr@r=)rrrEr?r0rrrrs    z!StdPathPrinter._iterator.__next__N)r r r rXrYrrrrrrsrcCs|j|j|jS)N)rrDr])rrrrr_szStdPathPrinter.childrenN) r r r r rXr=rgrrr_rrrrrBcs  (rBc@s8eZdZdZddZGdddeZddZdd Zd S) StdPairPrinterz@Print a std::pair object, with 'first' and 'second' as children.cCs ||_dS)N)rV)rrDrWrrrrXszStdPairPrinter.__init__c@s(eZdZdZddZddZddZdS) zStdPairPrinter._iterz?An iterator for std::pair types. Returns 'first' then 'second'.cCs||_d|_dS)Nr)rV_which)rrWrrrrXszStdPairPrinter._iter.__init__cCs|S)Nr)rrrrrYszStdPairPrinter._iter.__iter__cCs8|jdkrt|j}|dkr$d|_nd|_||j|fS)Nrr)rKrZrV)rZwhichrrrrs zStdPairPrinter._iter.__next__N)r r r r rXrYrrrrrrsrcCs |j|jS)N)rrV)rrrrr_szStdPairPrinter.childrencCsdS)Nr)rrrrrgszStdPairPrinter.to_stringN) r r r r rXrrr_rgrrrrrJs rJc@s eZdZdZddZddZdS)StdCmpCatPrinterz#Print a comparison category object.cCs&||jddd|_|d|_dS)N:r)r,)rfindr]rV)rrDrWrrrrXszStdCmpCatPrinter.__init__cCsJ|jdkr|jdkrd}n"ddd ddddd i}|t|j}d j|j|S) Nstrong_orderingrZequalrZ unorderedr)ZlessZ equivalentZgreaterz std::{}::{}ri)r]rVrr*)rr"namesrrrrgs zStdCmpCatPrinter.to_stringN)r r r r rXrgrrrrrLsrLc@s`eZdZdZdZddZeddZeddZ ed d Z ed d Z ed dZ ddZ dS)StdErrorCodePrinterz0Print a std::error_code or std::error_condition.Nc CsL||_t||_tjdkrHyddl}dt_Wntk rFdt_YnXdS)NrTF)rVr;r]rQ_system_is_posixposix ImportError)rrDrWrSrrrrXs   zStdErrorCodePrinter.__init__cCs&tj|}|dk r"|jtjkr"|SdS)N)rrrZTYPE_CODE_ENUM)r"r#rrr_find_errc_enums z#StdErrorCodePrinter._find_errc_enumc CsBxs(     zStdErrorCodePrinter.to_string)r r r r rRrXrrU classmethodrXr]rdrfrgrrrrrQs   + rQc@s eZdZdZddZddZdS)StdRegexStatePrinterz/Print a state node in the NFA for a std::regex.cCs||_||_dS)N)rVr])rrDrWrrrrX[szStdRegexStatePrinter.__init__cCst|jd}|r|dd}|jd}dddddddddddddd }||}d j||}|dk r|jd |dk rd j|||jd |}d |S) NZ _M_opcoderzZaltZsubexprnegZ backref_index) repeat alternativeZ subexpr_beginZ subexpr_endZline_begin_assertionZline_end_assertionZ word_boundaryZsubexpr_lookaheadZbackrefr?ZacceptZdummyunknownzopcode={}, next={}Z_M_z {}, {}={}z{%s})r!rVr*)rZopcodeZnext_idZvariantsvr#rrrrg_s     zStdRegexStatePrinter.to_stringN)r r r r rXrgrrrrrlXsrlc@s@eZdZdZGdddeZddZddZdd Zd d Z d S) StdSpanPrinterzPrint a std::span.c@s$eZdZddZddZddZdS)zStdSpanPrinter._iteratorcCsd|_||_||_dS)Nr)r~_beginr)rrIrrrrrXysz!StdSpanPrinter._iterator.__init__cCs|S)Nr)rrrrrY~sz!StdSpanPrinter._iterator.__iter__cCs8|j|jkrt|j}|jd|_d||j|jfS)Nr)z[%d])r~rrZrtrt)rrErrrrs   z!StdSpanPrinter._iterator.__next__N)r r r rXrYrrrrrrxsrcCsLt||_||_tjd}|jjd|kr:|dd|_n|jjd|_dS)Nzstatic_cast(-1)r)Z _M_extentZ_M_extent_value)r;r]rVrrrr4r)rrDrWZsize_maxrrrrXs   zStdSpanPrinter.__init__cCsd|j|jfS)Nz%s of length %d)r]r)rrrrrgszStdSpanPrinter.to_stringcCs|j|jd|jS)Nr\)rrVr)rrrrr_szStdSpanPrinter.childrencCsdS)Nrr)rrrrrszStdSpanPrinter.display_hintN) r r r r rrrXrgr_rrrrrrsus  rsc@s0eZdZdZddZddZddZdd Zd S) StdInitializerListPrinterzPrint a std::initializer_list.cCs||_||_|d|_dS)Nr6)r]rVr)rrDrWrrrrXsz"StdInitializerListPrinter.__init__cCsd|j|jfS)Nz%s of length %d)r]r)rrrrrgsz#StdInitializerListPrinter.to_stringcCstj|jd|jS)NZ_M_array)rsrrVr)rrrrr_sz"StdInitializerListPrinter.childrencCsdS)Nrr)rrrrrsz&StdInitializerListPrinter.display_hintN)r r r r rXrgr_rrrrrrus ruc@s(eZdZdZddZddZddZdS) StdAtomicPrinterzPrint a std:atomic.cCsrt||_||_d|_|jjjd|_|jjdk rnt|jj}|jdsR|jdrn|d}t |||_|j |_ dS)Nrzstd::shared_ptr = { %s }) rwrgr1rrZ TYPE_CODE_INTrV TYPE_CODE_FLT TYPE_CODE_PTRrr]r!)rrWrrrrgs     zStdAtomicPrinter.to_stringN)r r r r rXrxrgrrrrrvs rvc@s eZdZdZddZddZdS)StdFormatArgsPrinterzPrint a std::basic_format_args.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zStdFormatArgsPrinter.__init__cCst|jj}t|dd}|tjdkr0d}n|tjdkrDd}nd}|jd}|dkrbd |S|dkrt|jd }d ||fS) Nrr)rEzstd::format_argswchar_tzstd::wformat_argszstd::basic_format_argsZ_M_packed_sizez%s with 1 argumentZ_M_unpacked_sizez%s with %d arguments)rTrVrrr)rZtargsrHr#rrrrrgs   zStdFormatArgsPrinter.to_stringN)r r r r rXrgrrrrr{sr{c@s0eZdZdZddZddZddZdd Zd S) StdChronoDurationPrinterzPrint a std::chrono::duration.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z!StdChronoDurationPrinter.__init__cCs*|jjjd}|jd}|jd}||fS)Nr)r)rVrr4)rZperiodrdenrrr_ratios  zStdChronoDurationPrinter._ratiocCs|j\}}|dkrF|dkr dS|dkr,dS|dkr8dS|dkr|dSn6|dkr||d krZd S|d krfd S|d krrdSdj|Sdj||S)Nr)r#iZmsi@Busiʚ;rW<minihiQdz[{}]sz[{}/{}]s)rr*)rrr~rrr_suffixs&  z StdChronoDurationPrinter._suffixcCs4|jd}|jjjtjkr$d|}dj||jS)N__rz%gz"std::chrono::duration = {{ {}{} }})rVrrrrryr*r)rrrrrrgs z"StdChronoDurationPrinter.to_stringN)r r r r rXrrrgrrrrr}s r}c@s*eZdZdZddZddZd ddZd S) StdChronoTimePointPrinterz Print a std::chrono::time_point.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z"StdChronoTimePointPrinter.__init__cCsv|jjjd}t|j}|dks(|dkr,dS|dkr8dS|dkrDdS|d krPdS|d kr\dS|dkrhdSdj|dfS)Nrzstd::chrono::_V2::system_clockzstd::chrono::system_clockstd::chrono::sys_timezstd::chrono::utc_clockstd::chrono::utc_timezstd::chrono::gps_clockstd::chrono::gps_timezstd::chrono::tai_clockstd::chrono::tai_timezstd::filesystem::__file_clockstd::chrono::file_timeumzstd::chrono::local_tstd::chrono::local_timez {} time_point)rr)rN)rN)rN)rr)rr)rVrr4r;r"r*)rclockr"rrr_clocks  z StdChronoTimePointPrinter._clockFc Cs|j\}}|jd}|d}t|jj|}|j}d}|dk r|j\} } || | |} ytjj| t } dj | }Wn YnXd|||f} |r| Sd|| fS)NZ__drrCz [{:%Y-%m-%d %H:%M:%S}]z%d%s%sz %s = { %s }) rrVr}rr"rrrZ fromtimestamp _utc_timezoner*)rZabbrevroffsetrrprintersuffixtimerr~Zsecsrr#rrrrg1s$   z#StdChronoTimePointPrinter.to_stringN)F)r r r r rXrrgrrrrrsrc@s eZdZdZddZddZdS)StdChronoZonedTimePrinterz Print a std::chrono::zoned_time.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXIs z"StdChronoZonedTimePrinter.__init__cCs@|jdjd}|jd}t|jj|}|jd}dj||S)NZ_M_zone_M_nameZ_M_tpTz%std::chrono::zoned_time = {{ {} {} }})rVrtrrr"rgr*)rZzonerrrrrrgMs   z#StdChronoZonedTimePrinter.to_stringN)r r r r rXrgrrrrrFsrZJanuaryZFebruaryZMarchZAprilZMayZJuneZJulyZAugustZ SeptemberZOctoberZNovemberZDecemberZSundayZMondayZTuesdayZ WednesdayZThursdayZFridayZSaturdayc@s eZdZdZddZddZdS)StdChronoCalendarPrinterzDPrint a std::chrono::day, std::chrono::month, std::chrono::year etc.cCst||_||_dS)N)r;r]rV)rrDrWrrrrX_s z!StdChronoCalendarPrinter.__init__c Csv|j}|j}d|kr$|dkr$|d}|jdr6|d}|dkrPdjt|dS|d kr||d ksl|ttkrtd |St|S|dkrd j|S|d kr|d}|dks|ttkrd|Sdjt|S|dkrdj|dt|dS|dkrdj|dS|dkrdj||dS|dkr,dj|S|dkrFdj||dS|dkr`dj||dS|dkrvdj||S|dkrd j|||dS|dkrdj||d!S|d"krd j|||dS|d#krd j|||dS|jd$rrd%}|d&dkr"d'jt|d(d)t|d&}t|d*d+}t|dd+}t|d,d+}|d-rb| }d.j||||SdS)/Nmonthz std::chrono::year_month_day_lastZ_M_mzstd::chrono::yearZ_M_yzstd::chrono::dayz{}Z_M_dzstd::chrono::monthr)z%d is not a valid monthz{}yzstd::chrono::weekdayZ_M_wdrz%d is not a valid weekdayzstd::chrono::weekday_indexedz{}[{}]r.zstd::chrono::weekday_lastz{}[last]zstd::chrono::month_dayz{}/{}zstd::chrono::month_day_lastz{}/lastzstd::chrono::month_weekdayZ_M_wdizstd::chrono::month_weekday_lastZ_M_wdlzstd::chrono::year_monthzstd::chrono::year_month_dayz{}/{}/{}Z_M_mdlzstd::chrono::year_month_weekdayz$std::chrono::year_month_weekday_lastzstd::chrono::hh_mm_ssrCZfractional_widthz.{:0{}d}Z_M_ssZ_M_rrr_M_sZ _M_is_negz{:02}:{:02}:{:02}{})rVr]r<r*rrmonthsweekdays) rrWr#r"yZwdZfractrr#rrrrgcsh               z"StdChronoCalendarPrinter.to_stringN)r r r r rXrgrrrrr\src@s eZdZdZddZddZdS)StdChronoTimeZonePrinterz4Print a chrono::time_zone or chrono::time_zone_link.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z!StdChronoTimeZonePrinter.__init__cCs6d|j|jdf}|jjdr2|d|jd7}|S)Nz%s = %srZ_linkz -> %sZ _M_target)r]rVrb)rr!rrrrgs z"StdChronoTimeZonePrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdChronoLeapSecondPrinterzPrint a chrono::leap_second.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z#StdChronoLeapSecondPrinter.__init__cCs.|jdd}d|dk}d|jt||fS)Nrrz+-rz %s %d (%c))rVr]abs)rZdaternrrrrgs z$StdChronoLeapSecondPrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdChronoTzdbPrinterzPrint a chrono::tzdb.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs zStdChronoTzdbPrinter.__init__cCsd|j|jdfS)Nz%s %sversion)r]rV)rrrrrgszStdChronoTzdbPrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdChronoTimeZoneRulePrinterzPrint a chrono::time_zone rule.cCst||_||_dS)N)r;r]rV)rrDrWrrrrXs z%StdChronoTimeZoneRulePrinter.__init__c Cs|jd}|d}t|d}dddddddd}|d}d j||j|d }|d krdd j||}nVt|d }|dkrdj||}n4|dkrd} nd} |d}dj| d || d||}dj|jd|jd|jd|S)NonkindrstZndZrd)r)rrCZ day_of_monthz{}{}Zthrz{} {}Z day_of_weekr)z last {} in {}rr<=r>=z{} {} {} {} {}z.time_zone rule {} from {} to {} starting on {}r"fromZto)rr)rr)rVrr*getr) rrrrsuffixesdayZ ordinal_dayrweekday directionrrrrgs*    z&StdChronoTimeZoneRulePrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdLocalePrinterzPrint a std::locale.cCs||_||_dS)N)rVr])rrDrWrrrrXszStdLocalePrinter.__init__csx|jdd}d}|ddkr&d}nFtj|jd}tj|jd}|dj}|dj}dj||}||i}d } xN| |kr|| dkr|| j}|| j}d j|||}|||<| d } qxWt|j} t| d kr|}nt| d krl| \} } t |j} d| j | d kr$| }| n| j | d kr<| }| dk rlt fd d |j D}dj|}dj||S)NrZ_M_namesrCr*z::_S_categoriesz::_S_categories_sizez{}={}r)z{};{}={}rc3s|]\}}|kr|VqdS)Nr)r&rrR)otherrr sz-StdLocalePrinter.to_string..z with "{}={}"zstd::locale = "{}"{}) rVrrr]rr*r4valuesrrrEritems)rrPmodr"ZcatsZncatrRr[Z cat_namesrZ uniq_namesZn1Zn2Z name_listr)rrrgsD            zStdLocalePrinter.to_stringN)r r r r rXrgrrrrrsrc@s eZdZdZddZddZdS)StdIntegralConstantPrinterz*Print a std::true_type or std::false_type.cCs||_||_dS)N)rVr])rrDrWrrrrX sz#StdIntegralConstantPrinter.__init__cCsL|jjjd}|jjjd}|jtjkr4|r0dSdSt|j}dj|||S)Nrr)zstd::true_typezstd::false_typez {}<{}, {}>) rVrr4rrrr;r]r*)rr3rZrDrrrrg s  z$StdIntegralConstantPrinter.to_stringN)r r r r rXrgrrrrr src@s eZdZdZddZddZdS)StdTextEncodingPrinterzPrint a std::text_encoding.cCs||_||_dS)N)rVr])rrDrWrrrrX$ szStdTextEncodingPrinter.__init__cCs<|jdj}|ddkr$|jdS|ddkr4dS|dS)NZ_M_repZ_M_idr)rrrq)rVrt)rZreprrrrg( s    z StdTextEncodingPrinter.to_stringN)r r r r rXrgrrrrr! srcs$eZdZfddZddZZS) RxPrintercs$tt|j||_||_d|_dS)NT)rrrXr" _functionenabled)rr"r)r$rrrX3 szRxPrinter.__init__cCs:|js dS|jjtjkr,ttjdr,|j}|j|j |S)Nreferenced_value) rrrrrrValuerrr")rrZrrrinvoke9 s  zRxPrinter.invoke)r r r rXrr(rr)r$rr2 s rcsHeZdZfddZddZddZddZed d Zd d Z Z S) Printercs6tt|j||_g|_i|_d|_tjd|_ dS)NTz^([a-zA-Z0-9_:]+)(<.*>)?$) rrrXr" _subprinters_lookuprr>compile _compiled_rx)rr")r$rrrXH s zPrinter.__init__cCs<|jj|std|t||}|jj|||j|<dS)Nz0libstdc++ programming error: "%s" does not match)rr?r rrrPr)rr"rrrrraddP s     z Printer.addcCs>|j|||d|kr:tjddt|}|j|||dS)N__cxx11z^(std|__gnu_cxx)::z\g<0>%s)rr>rHr-)rbaser"rZvbaserrr add_version[ s  zPrinter.add_versioncCs$|j||||j|d||dS)Nz __cxx1998::)r)rrr"rrrr add_containerc szPrinter.add_containercCs&|jtjkr|j}|jj}|jS)N)rrrrrrr)rrrrget_basic_typeg s  zPrinter.get_basic_typecCsr|j|j}|sdS|jj|}|s(dS|jd}|jjtjkrTttj drT|j }||j krn|j |j |SdS)Nr)r) rrrr?rrrrrrrrr)rrWrDr?basenamerrr__call__r s     zPrinter.__call__) r r r rXrrrrrrr(rr)r$rrG s    rc@s0eZdZdZddZGdddeZddZdS) TemplateTypePrinteral A type printer for class templates with default template arguments. Recognizes specializations of class templates and prints them without any template arguments that use a default template argument. Type printers are recursively applied to the template arguments. e.g. replace 'std::vector >' with 'std::vector'. cCs||_||_d|_dS)NT)r"_defargsr)rr"defargsrrrrX szTemplateTypePrinter.__init__c@s(eZdZdZddZddZddZdS) zTemplateTypePrinter._recognizerz-The recognizer class for TemplateTypePrinter.cCs||_||_dS)N)r"r)rr"rrrrrX sz(TemplateTypePrinter._recognizer.__init__c Cs|jdkrdS|jj|js dSt|}g}d}xtt|D]}||}|jj|}|dk r|j|}y|t j |kr|dSWn$t j k r|j|krdSYnXd}q>|rdS|j |j |q>W|jd|jjd}t|}|ddj|dS)a If type_obj is a specialization of self.name that uses all the default template arguments for the class template, then return a string representation of the type without default arguments. Otherwise, return None. NFTr)rr<r"rTrangerrrr*rrr,rP_recognize_subtyperrOr+) rrQrSZdisplayed_argsZrequire_defaultedrRrfZdefargrArrr recognize s2     z)TemplateTypePrinter._recognizer.recognizecCs|jtjkr|j|jdS|jtjkrj|j|j}t|jjdrR|dSd||j ddfS|jtj kr|j|jdSt tdr|jtj kr|j|jdStj jtj j|}|r|St|S)zxConvert a gdb.Type to a string by applying recognizers, or if that fails then simply converting to a string.rz[]z%s[%d]r)&TYPE_CODE_RVALUE_REFz&&)rrrzrrrr!rrbrrrrrrr)rrQrNrrrr s"     z2TemplateTypePrinter._recognizer._recognize_subtypeN)r r r r rXrrrrrr _recognizer s1rcCs|j|j|jS)z1Return a recognizer object for this type printer.)rr"r)rrrr instantiate szTemplateTypePrinter.instantiateN)r r r r rXobjectrrrrrrr s Prcstd||}tjj||td||}tjj||d|krdttfdd|jD}t||}tjj||td||}tjj||dS)a Add a type printer for a class template with default template arguments. Args: name (str): The template-name of the class template. defargs (dict int:string) The default template arguments. Types in defargs can refer to the Nth template-argument using {N} (with zero-based indices). e.g. 'unordered_map' has these defargs: { 2: 'std::hash<{0}>', 3: 'std::equal_to<{0}>', 4: 'std::allocator >' } zstd::zstd::__debug::rc3s"|]\}}||jdfVqdS)zstd::N)r.)r&rRr)rWrrr sz0add_one_template_type_printer..N)rrrregister_type_printerr-dictr)objr"rrr)rWradd_one_template_type_printer s rc@s2eZdZdZd ddZGdddeZddZdS) FilteringTypePrintera A type printer that uses typedef names for common template specializations. Args: template (str): The class template to recognize. name (str): The typedef-name that will be used instead. targ1 (str, optional): The first template argument. Defaults to None. Checks if a specialization of the class template 'template' is the same type as the typedef 'name', and prints it as 'name' instead. e.g. if an instantiation of std::basic_istream is the same type as std::istream then print it as std::istream. If targ1 is provided (not None), match only template specializations with this type as the first template argument, e.g. if template='basic_string' and targ1='char' then only match 'basic_string' and not 'basic_string'. This rejects non-matching specializations more quickly, without needing to do GDB type lookups. NcCs||_||_||_d|_dS)NT) _templater"_targ1r)rtemplater"targ1rrrrX- szFilteringTypePrinter.__init__c@s eZdZdZddZddZdS)z FilteringTypePrinter._recognizerz.The recognizer class for FilteringTypePrinter.cCs||_||_||_d|_dS)N)rr"r _type_obj)rrr"rrrrrX6 sz)FilteringTypePrinter._recognizer.__init__c Cs|jdkrdS|jdkrz|jdk rDdj|j|j}|jj|sVdSn|jj|jsVdSytj|jj |_Wn YnX|jdkrdStj j |j}tj j |}||krt |jS|jj dddkr|jjjdd}|jjdd}||krt |jSdS) z If type_obj starts with self._template and is the same type as self.name then return self.name, otherwise None. Nz{}<{}z::r) basic_stringz __cxx11::rCri)rrrr*rr<rrr"rrrrOrer.)rrQr#Zt1Zt2s1s2rrrr< s4        z*FilteringTypePrinter._recognizer.recognizeN)r r r r rXrrrrrr3 srcCs|j|j|j|jS)z1Return a recognizer object for this type printer.)rrr"r)rrrrrf sz FilteringTypePrinter.instantiate)N)r r r r rXrrrrrrrr s 3rcCsXtd|d||}tjj||d|krTdt}t|||||}tjj||dS)Nzstd::r)rrrrr-)rrr"rrrWrrradd_one_type_printerk s rc CsdtsdSxxdgD]p}t|d |d d |dt|d|d d |dt|dd|d d |dt|d|d d|dqWxdjD]|}x*dkD]"}t|d||d ||dqWxJdlD]B}t|d||d ||dt|d!||d ||dqWqWxdmD]}x0dpD](}t||d"||d d#|dqWxNdqD]F}t||d(||d)x&drD]}t||||||qlWqJWqWt|d-d.xdsD]}t|d9d:|qWt|d;d<t|d;d=t|d>d?t|d>d@t|dAdBt|dAdCt|dDdEt|dDdFt|dGdHdI}x0dyD](}t||d||d d|dqdequezstd::allocator<{0}>rrz __cxx11::listvectorrzstd::less<{0}>z)std::allocator>)rrCmultimapr4)r)rmultiset unordered_mapzstd::hash<{0}>zstd::equal_to<{0}>)rrCunordered_multimap unordered_set)r)rrCunordered_multisetrCrErr|rrrrrr)rrrrrrCrErr|)rr) rrrrrrrrr)rrrr)rCrrCrErr|)rr )rr#rr)rrr) rrrrr r r r r rrCrErr|rrrrrr)r!r"r#r$r%)rrr)rZchr@abiZdurrWrrrregister_type_printerst s "(     *                   r'cCs8trtjj|tn|dkr t}|jjtt|dS)z4Register libstdc++ pretty-printers with objfile Obj.N) _use_gdb_pprZprintingZregister_pretty_printerlibstdcxx_printerZpretty_printersrPr')rrrrregister_libstdcxx_printers s  r*cCsXtdatjddttjddttjddttjddttjddttjddttjddttjdd ttjdd t tjdd t tjdd t tjdd t tjddt tjddt tjddt tjddt tjddttjddtttjdr.tjddttjddttjdttjdttjdttjdttjdttjdt tjdt tjdttjddttjdd ttjdd!ttjdd"ttjdd#ttjdd$ttjdd%ttjd&dttjd&d ttjd&d!ttjd&d"ttjd&d#ttjd&d$ttjdd'ttjdd(ttjdd)ttjdd)tx2doD]*}tjdd-|ttjdd-|tqWtjd.d/ttjd.d0ttjdd1ttjd2d3t tjd4ttjd5ttjd6ttjd7ttjd8ttjd9d:t!tjd9d;t"tjd9dt$tjd?d>t$tjd@d>t%tjdAd>t%tjdd:t!tjdd;t"tjddrFrirrGrrrr ziprrrZtimezoneZutcrZtzinforr(Z gdb.printingrTrZ gdb.typesrrrZ printer_baser%r-r2r8r5rBr;rKrOrTrUr[rkrmrprqrurxryrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrr)r-r0r5r7rBrJrLrQrlrsrurvr{r}rrrrrrrrrrrrrrr)rrrrr'r*r;rrrrs      %   (&"I  U(*$/A " /%-^!,5I!{'$*/ ?  ",Ce%T oTPK1]e6libstdcxx/v6/__pycache__/xmethods.cpython-36.opt-1.pycnu[3 hq@sddlZddlZddlZdZddZddZdZdd ZGd d d ejj Z Gd d d ejj Z Gddde Z Gddde ZGddde ZGddde ZGddde ZGddde ZGdddejjZGdddejj ZGdddeZGd d!d!eZGd"d#d#eZGd$d%d%eZGd&d'd'eZGd(d)d)eZGd*d+d+ejjZGd,d-d-ejjZGd.d/d/eZGd0d1d1eZGd2d3d3ejjZ Gd4d5d5ejj Z!Gd6d7d7e!Z"Gd8d9d9e!Z#Gd:d;d;e!Z$Gdd?d?ejjZ&Gd@dAdAejj Z'GdBdCdCe'Z(GdDdEdEe'Z)GdFdGdGe'Z*GdHdIdIe'Z+GdJdKdKe'Z,GdLdMdMe'Z-GdNdOdOejjZ.GdPdQdQejj Z/GdRdSdSe/Z0GdTdUdUe/Z1GdVdWdWejjZ2GdXdYdYejj Z3GdZd[d[e3Z4Gd\d]d]e3Z5Gd^d_d_ejjZ6Gd`dadaejj Z7Gdbdcdce7Z8Gdddedee7Z9Gdfdgdgejj Z:Gdhdidie:Z;GdjdkdkejjZ$N) isinstancerZTypetag_versioned_namespacerematch)xZ template_namerrris_specialization_of!s  rc@seZdZddZdS)LibStdCxxXMethodcCstjjj||||_dS)N)rxmethodXMethod__init__ worker_class)selfnamerrrrr.szLibStdCxxXMethod.__init__N)__name__ __module__ __qualname__rrrrrr-src@seZdZddZddZdS)ArrayWorkerBasecCs||_||_dS)N) _val_type_size)rval_typesizerrrr6szArrayWorkerBase.__init__cCstjd}|j|jjjS)Nz (void *) 0)rZparse_and_evalcastrpointer dereference)rZnullptrrrr null_value:s zArrayWorkerBase.null_valueN)rrrrr"rrrrr5src@s,eZdZddZddZddZddZd S) ArraySizeWorkercCstj|||dS)N)rr)rrrrrrr@szArraySizeWorker.__init__cCsdS)Nr)rrrr get_arg_typesCszArraySizeWorker.get_arg_typescCstS)N)r)robjrrrget_result_typeFszArraySizeWorker.get_result_typecCs|jS)N)r)rr%rrr__call__IszArraySizeWorker.__call__N)rrrrr$r&r'rrrrr#?sr#c@s,eZdZddZddZddZddZd S) ArrayEmptyWorkercCstj|||dS)N)rr)rrrrrrrNszArrayEmptyWorker.__init__cCsdS)Nr)rrrrr$QszArrayEmptyWorker.get_arg_typescCstS)N)r)rr%rrrr&Tsz ArrayEmptyWorker.get_result_typecCst|jdkS)Nr)intr)rr%rrrr'WszArrayEmptyWorker.__call__N)rrrrr$r&r'rrrrr(Msr(c@s,eZdZddZddZddZddZd S) ArrayFrontWorkercCstj|||dS)N)rr)rrrrrrr\szArrayFrontWorker.__init__cCsdS)Nr)rrrrr$_szArrayFrontWorker.get_arg_typescCs|jS)N)r)rr%rrrr&bsz ArrayFrontWorker.get_result_typecCs&t|jdkr|ddS|jSdS)Nr_M_elems)r)rr")rr%rrrr'es zArrayFrontWorker.__call__N)rrrrr$r&r'rrrrr*[sr*c@s,eZdZddZddZddZddZd S) ArrayBackWorkercCstj|||dS)N)rr)rrrrrrrmszArrayBackWorker.__init__cCsdS)Nr)rrrrr$pszArrayBackWorker.get_arg_typescCs|jS)N)r)rr%rrrr&sszArrayBackWorker.get_result_typecCs,t|jdkr |d|jdS|jSdS)Nrr+)r)rr")rr%rrrr'vszArrayBackWorker.__call__N)rrrrr$r&r'rrrrr,lsr,c@s,eZdZddZddZddZddZd S) ArrayAtWorkercCstj|||dS)N)rr)rrrrrrr~szArrayAtWorker.__init__cCstS)N)r)rrrrr$szArrayAtWorker.get_arg_typescCs|jS)N)r)rr%indexrrrr&szArrayAtWorker.get_result_typecCs4t|t|jkr(tdt||jf|d|S)Nz%Array index "%d" should not be >= %d.r+)r)r IndexError)rr%r/rrrr'szArrayAtWorker.__call__N)rrrrr$r&r'rrrrr.}sr.c@s,eZdZddZddZddZddZd S) ArraySubscriptWorkercCstj|||dS)N)rr)rrrrrrrszArraySubscriptWorker.__init__cCstS)N)r)rrrrr$sz"ArraySubscriptWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&sz$ArraySubscriptWorker.get_result_typecCs&t|jdkr|d|S|jSdS)Nrr+)r)rr")rr%r/rrrr's zArraySubscriptWorker.__call__N)rrrrr$r&r'rrrrr1sr1c@seZdZddZddZdS)ArrayMethodsMatchercsftjjjtdtdttdttdttdt tdt tdt d_ fd d j D_ dS) Narrayremptyfrontbackatz operator[])rr4r5r6r7z operator[]csg|]}j|qSr) _method_dict).0m)rrr sz0ArrayMethodsMatcher.__init__..)rrXMethodMatcherrmatcher_name_prefixrr#r(r*r,r.r1r8methods)rr)rrrs  zArrayMethodsMatcher.__init__c Cs^t|dsdS|jj|}|dks*|j r.dSy|jd}|jd}Wn dS|j||S)Nr3rr-)rr8getenabledtemplate_argumentr)r class_type method_namemethodZ value_typerrrrr s   zArrayMethodsMatcher.matchN)rrrrr rrrrr2s r2c@s$eZdZddZddZddZdS)DequeWorkerBasecCs||_d|jpd|_dS)Nir-)rsizeof_bufsize)rrrrrrszDequeWorkerBase.__init__cCsf|dd}|dd}|d|dkr,dS|j|d|dd|d|d|d |dS) N_M_impl_M_start _M_finish_M_curr_M_noder-_M_first_M_last)rG)rr%startfinishrrrrs   zDequeWorkerBase.sizecCs`|dd}|d|d}||kr0|d|S||}|ddt||j}|||jS)NrHrIrNrKrLr-)r)rG)rr%idxrOZfirst_node_sizeZ index_noderrrr/s  zDequeWorkerBase.indexN)rrrrrr/rrrrrEs rEc@s$eZdZddZddZddZdS)DequeEmptyWorkercCsdS)Nr)rrrrr$szDequeEmptyWorker.get_arg_typescCstS)N)r)rr%rrrr&sz DequeEmptyWorker.get_result_typecCs |ddd|dddkS)NrHrIrKrJr)rr%rrrr'szDequeEmptyWorker.__call__N)rrrr$r&r'rrrrrRsrRc@s$eZdZddZddZddZdS)DequeSizeWorkercCsdS)Nr)rrrrr$szDequeSizeWorker.get_arg_typescCstS)N)r)rr%rrrr&szDequeSizeWorker.get_result_typecCs |j|S)N)r)rr%rrrr'szDequeSizeWorker.__call__N)rrrr$r&r'rrrrrSsrSc@s$eZdZddZddZddZdS)DequeFrontWorkercCsdS)Nr)rrrrr$szDequeFrontWorker.get_arg_typescCs|jS)N)r)rr%rrrr&sz DequeFrontWorker.get_result_typecCs|ddddS)NrHrIrKrr)rr%rrrr'szDequeFrontWorker.__call__N)rrrr$r&r'rrrrrTsrTc@s$eZdZddZddZddZdS)DequeBackWorkercCsdS)Nr)rrrrr$szDequeBackWorker.get_arg_typescCs|jS)N)r)rr%rrrr&szDequeBackWorker.get_result_typecCs^|ddd|dddkrF|dddd}|d|jdS|ddddSdS) NrHrJrKrMrLr-r)rG)rr% prev_noderrrr's zDequeBackWorker.__call__N)rrrr$r&r'rrrrrUsrUc@s$eZdZddZddZddZdS)DequeSubscriptWorkercCstS)N)r)rrrrr$ sz"DequeSubscriptWorker.get_arg_typescCs|jS)N)r)rr% subscriptrrrr& sz$DequeSubscriptWorker.get_result_typecCs |j||S)N)r/)rr%rYrrrr'szDequeSubscriptWorker.__call__N)rrrr$r&r'rrrrrX srXc@s$eZdZddZddZddZdS) DequeAtWorkercCstS)N)r)rrrrr$szDequeAtWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&szDequeAtWorker.get_result_typecCs@t|j|}t||kr0tdt||fn |j||SdS)Nz%Deque index "%d" should not be >= %d.)r)rr0r/)rr%r/Z deque_sizerrrr's  zDequeAtWorker.__call__N)rrrr$r&r'rrrrrZsrZc@seZdZddZddZdS)DequeMethodsMatchercsftjjjtdtdttdttdttdt tdt tdt d_ fd d j D_ dS) Ndequer4rr5r6z operator[]r7)r4rr5r6z operator[]r7csg|]}j|qSr)r8)r9r:)rrrr;0sz0DequeMethodsMatcher.__init__..)rrr<rr=rrRrSrTrUrXrZr8r>)rr)rrr%s  zDequeMethodsMatcher.__init__cCs>t|dsdS|jj|}|dks*|j r.dS|j|jdS)Nr\r)rr8r?r@rrA)rrBrCrDrrrr 2s   zDequeMethodsMatcher.matchN)rrrrr rrrrr[$s r[c@seZdZddZddZdS)ForwardListWorkerBasecCs||_||_dS)N)r _node_type)rr node_typerrrr>szForwardListWorkerBase.__init__cCsdS)Nr)rrrrr$Bsz#ForwardListWorkerBase.get_arg_typesN)rrrrr$rrrrr]=sr]c@seZdZddZddZdS)ForwardListEmptyWorkercCstS)N)r)rr%rrrr&Gsz&ForwardListEmptyWorker.get_result_typecCs|ddddkS)NrH_M_head_M_nextrr)rr%rrrr'JszForwardListEmptyWorker.__call__N)rrrr&r'rrrrr`Fsr`c@seZdZddZddZdS)ForwardListFrontWorkercCs|jS)N)r)rr%rrrr&Osz&ForwardListFrontWorker.get_result_typecCs:|dddj|j}|ddj}|j|jjjS)NrHrarb _M_storage)rr^addressrr r!)rr%nodeZ val_addressrrrr'RszForwardListFrontWorker.__call__N)rrrr&r'rrrrrcNsrcc@seZdZddZddZdS)ForwardListMethodsMatchercsJtd}tjjj|tdttdtd_fddjD_ dS)N forward_listr4r5)r4r5csg|]}j|qSr)r8)r9r:)rrrr;`sz6ForwardListMethodsMatcher.__init__..) r=rrr<rrr`rcr8r>)rZ matcher_namer)rrrYs z"ForwardListMethodsMatcher.__init__cCsZt|dsdS|jj|}|dks*|j r.dS|jd}tjt|dj}|j ||S)Nrhrz::_Node) rr8r?r@rArrstrr r)rrBrCrDrr_rrrr bs   zForwardListMethodsMatcher.matchN)rrrrr rrrrrgXs rgc@s$eZdZddZddZddZdS)ListWorkerBasecCs||_||_dS)N)rr^)rrr_rrrrpszListWorkerBase.__init__cCsdS)Nr)rrrrr$tszListWorkerBase.get_arg_typescCsB|j}|jjdjdkr$|dS|dj}|j|jjjS)Nr-Z_M_datard)r!typefieldsrrerrr )rrfZaddrrrrget_value_from_nodews  z"ListWorkerBase.get_value_from_nodeN)rrrrr$rmrrrrrjosrjc@seZdZddZddZdS)ListEmptyWorkercCstS)N)r)rr%rrrr&szListEmptyWorker.get_result_typecCs&|dd}|d|jkrdSdSdS)NrHrLrbTF)re)rr%Z base_noderrrr's zListEmptyWorker.__call__N)rrrr&r'rrrrrnsrnc@seZdZddZddZdS)ListSizeWorkercCstS)N)r)rr%rrrr&szListSizeWorker.get_result_typecCsD|ddd}|ddj}d}x||kr>|d}|d7}q$W|S)NrHrLrbrr-)re)rr%Z begin_nodeZend_noderrrrr's  zListSizeWorker.__call__N)rrrr&r'rrrrrosroc@seZdZddZddZdS)ListFrontWorkercCs|jS)N)r)rr%rrrr&szListFrontWorker.get_result_typecCs"|dddj|j}|j|S)NrHrLrb)rr^rm)rr%rfrrrr'szListFrontWorker.__call__N)rrrr&r'rrrrrpsrpc@seZdZddZddZdS)ListBackWorkercCs|jS)N)r)rr%rrrr&szListBackWorker.get_result_typecCs"|dddj|j}|j|S)NrHrLZ_M_prev)rr^rm)rr%rWrrrr'szListBackWorker.__call__N)rrrr&r'rrrrrqsrqc@seZdZddZddZdS)ListMethodsMatchercsVtjjjtdtdttdttdttdt d_ fddj D_ dS) Nlistr4rr5r6)r4rr5r6csg|]}j|qSr)r8)r9r:)rrrr;sz/ListMethodsMatcher.__init__..) rrr<rr=rrnrorprqr8r>)rr)rrrs  zListMethodsMatcher.__init__cCsZt|dsdS|jj|}|dks*|j r.dS|jd}tjt|dj}|j ||S)Nz(__cxx11::)?listrz::_Node) rr8r?r@rArrrir r)rrBrCrDrr_rrrr s   zListMethodsMatcher.matchN)rrrrr rrrrrrs rrc@s$eZdZddZddZddZdS)VectorWorkerBasecCs ||_dS)N)r)rrrrrrszVectorWorkerBase.__init__cCsz|jjtjkr^|ddd}|ddd}|ddd}|jjjd}||||S|dd|ddSdS)NrHrI_M_prJZ _M_offset)rcoderTYPE_CODE_BOOLr!rkrF)rr%rOrPZ finish_offsetbit_sizerrrrszVectorWorkerBase.sizecCsj|jjtjkrV|ddd}|jjjd}|||}||}|jd|>@dkS|dd|SdS)NrHrIrurvr-r)rrwrrxr!rkrF)rr%r/rOryZvalpoffsetrrrr?s zVectorWorkerBase.getN)rrrrrr?rrrrrts rtc@s$eZdZddZddZddZdS)VectorEmptyWorkercCsdS)Nr)rrrrr$szVectorEmptyWorker.get_arg_typescCstS)N)r)rr%rrrr&sz!VectorEmptyWorker.get_result_typecCst|j|dkS)Nr)r)r)rr%rrrr'szVectorEmptyWorker.__call__N)rrrr$r&r'rrrrr{sr{c@s$eZdZddZddZddZdS)VectorSizeWorkercCsdS)Nr)rrrrr$szVectorSizeWorker.get_arg_typescCstS)N)r)rr%rrrr&sz VectorSizeWorker.get_result_typecCs |j|S)N)r)rr%rrrr'szVectorSizeWorker.__call__N)rrrr$r&r'rrrrr|sr|c@s$eZdZddZddZddZdS)VectorFrontWorkercCsdS)Nr)rrrrr$szVectorFrontWorker.get_arg_typescCs|jS)N)r)rr%rrrr&sz!VectorFrontWorker.get_result_typecCs |j|dS)Nr)r?)rr%rrrr'szVectorFrontWorker.__call__N)rrrr$r&r'rrrrr}sr}c@s$eZdZddZddZddZdS)VectorBackWorkercCsdS)Nr)rrrrr$szVectorBackWorker.get_arg_typescCs|jS)N)r)rr%rrrr&sz VectorBackWorker.get_result_typecCs|j|t|j|dS)Nr-)r?r)r)rr%rrrr'szVectorBackWorker.__call__N)rrrr$r&r'rrrrr~sr~c@s$eZdZddZddZddZdS)VectorAtWorkercCstS)N)r)rrrrr$ szVectorAtWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&szVectorAtWorker.get_result_typecCs>t|j|}t||kr.tdt||f|j|t|S)Nz&Vector index "%d" should not be >= %d.)r)rr0r?)rr%r/rrrrr's  zVectorAtWorker.__call__N)rrrr$r&r'rrrrr src@s$eZdZddZddZddZdS)VectorSubscriptWorkercCstS)N)r)rrrrr$sz#VectorSubscriptWorker.get_arg_typescCs|jS)N)r)rr%rYrrrr&sz%VectorSubscriptWorker.get_result_typecCs|j|t|S)N)r?r))rr%rYrrrr'!szVectorSubscriptWorker.__call__N)rrrr$r&r'rrrrrsrc@seZdZddZddZdS)VectorMethodsMatchercsftjjjtdtdttdttdttdt tdt tdt d_ fd d j D_ dS) Nvectorrr4r5r6r7z operator[])rr4r5r6r7z operator[]csg|]}j|qSr)r8)r9r:)rrrr;2sz1VectorMethodsMatcher.__init__..)rrr<rr=rr|r{r}r~rrr8r>)rr)rrr&s   zVectorMethodsMatcher.__init__cCs>t|dsdS|jj|}|dks*|j r.dS|j|jdS)Nrr)rr8r?r@rrA)rrBrCrDrrrr 4s   zVectorMethodsMatcher.matchN)rrrrr rrrrr%src@s$eZdZddZddZddZdS)AssociativeContainerWorkerBasecCs ||_dS)N) _unordered)r unorderedrrrr@sz'AssociativeContainerWorkerBase.__init__cCs&|jr|ddS|dddSdS)NZ_M_hZ_M_element_count_M_trHZ _M_node_count)r)rr%rrr node_countCs z)AssociativeContainerWorkerBase.node_countcCsdS)Nr)rrrrr$Isz,AssociativeContainerWorkerBase.get_arg_typesN)rrrrrr$rrrrr?src@seZdZddZddZdS)AssociativeContainerEmptyWorkercCstS)N)r)rr%rrrr&Nsz/AssociativeContainerEmptyWorker.get_result_typecCst|j|dkS)Nr)r)r)rr%rrrr'Qsz(AssociativeContainerEmptyWorker.__call__N)rrrr&r'rrrrrMsrc@seZdZddZddZdS)AssociativeContainerSizeWorkercCstS)N)r)rr%rrrr&Vsz.AssociativeContainerSizeWorker.get_result_typecCs |j|S)N)r)rr%rrrr'Ysz'AssociativeContainerSizeWorker.__call__N)rrrr&r'rrrrrUsrc@seZdZddZddZdS)"AssociativeContainerMethodsMatchercsLtjjjt||_tdttdtd_ fddj D_ dS)Nrr4)rr4csg|]}j|qSr)r8)r9r:)rrrr;gsz?AssociativeContainerMethodsMatcher.__init__..) rrr<rr=_namerrrr8r>)rrr)rrr^s   z+AssociativeContainerMethodsMatcher.__init__cCsDt||jsdS|jj|}|dks,|j r0dSd|jk}|j|S)Nr)rrr8r?r@r)rrBrCrDrrrrr is   z(AssociativeContainerMethodsMatcher.matchN)rrrrr rrrrr]s rc@s8eZdZdZddZddZddZdd Zd d Zd S) UniquePtrGetWorkerzS Implement std::unique_ptr::get() and std::unique_ptr::operator->(). cCs*|jtjk|_|jr |j|_n||_dS)N)rwrTYPE_CODE_ARRAY _is_arraytarget _elem_type)r elem_typerrrrzs zUniquePtrGetWorker.__init__cCsdS)Nr)rrrrr$sz UniquePtrGetWorker.get_arg_typescCs |jjS)N)rr )rr%rrrr&sz"UniquePtrGetWorker.get_result_typecCs|dkp|j S)Nr?)r)rrCrrr _supportsszUniquePtrGetWorker._supportscCs|jjjdjj}t|dr.|dd}nt|drB|d}ndS|jjdj}|jdj}|jd}|jdkr|j|dS|jr|j|jSdSdS)Nrz__uniq_ptr_(data|impl)rtupler-Z _M_head_impl)r!rkrlr rrrZ is_base_class)rr%Z impl_typeZ tuple_memberZtuple_impl_typeZtuple_head_typeZ head_fieldrrrr's      zUniquePtrGetWorker.__call__N) rrr__doc__rr$r&rr'rrrrrus rc@s0eZdZdZddZddZddZdd Zd S) UniquePtrDerefWorkerz*Implement std::unique_ptr::operator*().cCstj||dS)N)rr)rrrrrrszUniquePtrDerefWorker.__init__cCs|jS)N)r)rr%rrrr&sz$UniquePtrDerefWorker.get_result_typecCs|j S)N)r)rrCrrrrszUniquePtrDerefWorker._supportscCstj||jS)N)rr'r!)rr%rrrr'szUniquePtrDerefWorker.__call__N)rrrrrr&rr'rrrrrs rc@s8eZdZdZddZddZddZdd Zd d Zd S) UniquePtrSubscriptWorkerz1Implement std::unique_ptr::operator[](size_t).cCstj||dS)N)rr)rrrrrrsz!UniquePtrSubscriptWorker.__init__cCstS)N)r)rrrrr$sz&UniquePtrSubscriptWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&sz(UniquePtrSubscriptWorker.get_result_typecCs|jS)N)r)rrCrrrrsz"UniquePtrSubscriptWorker._supportscCstj|||S)N)rr')rr%r/rrrr'sz!UniquePtrSubscriptWorker.__call__N) rrrrrr$r&rr'rrrrrs rc@seZdZddZddZdS)UniquePtrMethodsMatchercsVtjjjtdtdttdttdttdtd_ fddj D_ dS) N unique_ptrr?z operator->z operator*z operator[])r?z operator->z operator*z operator[]csg|]}j|qSr)r8)r9r:)rrrr;sz4UniquePtrMethodsMatcher.__init__..) rrr<rr=rrrrr8r>)rr)rrrs  z UniquePtrMethodsMatcher.__init__cCsPt|dsdS|jj|}|dks*|j r.dS|j|jd}|j|rL|SdS)Nrr)rr8r?r@rrAr)rrBrCrDworkerrrrr s   zUniquePtrMethodsMatcher.matchN)rrrrr rrrrrs rc@s8eZdZdZddZddZddZdd Zd d Zd S) SharedPtrGetWorkerzT Implements std::shared_ptr::get() and std::shared_ptr::operator->(). cCs*|jtjk|_|jr |j|_n||_dS)N)rwrrrrr)rrrrrrs zSharedPtrGetWorker.__init__cCsdS)Nr)rrrrr$sz SharedPtrGetWorker.get_arg_typescCs |jjS)N)rr )rr%rrrr&sz"SharedPtrGetWorker.get_result_typecCs|dkp|j S)Nr?)r)rrCrrrrszSharedPtrGetWorker._supportscCs|dS)NZ_M_ptrr)rr%rrrr'szSharedPtrGetWorker.__call__N) rrrrrr$r&rr'rrrrrs rc@s0eZdZdZddZddZddZdd Zd S) SharedPtrDerefWorkerz*Implement std::shared_ptr::operator*().cCstj||dS)N)rr)rrrrrrszSharedPtrDerefWorker.__init__cCs|jS)N)r)rr%rrrr&sz$SharedPtrDerefWorker.get_result_typecCs|j S)N)r)rrCrrrrszSharedPtrDerefWorker._supportscCstj||jS)N)rr'r!)rr%rrrr'szSharedPtrDerefWorker.__call__N)rrrrrr&rr'rrrrrs rc@s8eZdZdZddZddZddZdd Zd d Zd S) SharedPtrSubscriptWorkerz1Implement std::shared_ptr::operator[](size_t).cCstj||dS)N)rr)rrrrrr sz!SharedPtrSubscriptWorker.__init__cCstS)N)r)rrrrr$sz&SharedPtrSubscriptWorker.get_arg_typescCs|jS)N)r)rr%r/rrrr&sz(SharedPtrSubscriptWorker.get_result_typecCs|jS)N)r)rrCrrrrsz"SharedPtrSubscriptWorker._supportscCsZtjdt|j}|rJ|t|jdkrJtd|jt|t|jdftj|||S)Nz .*\[(\d+)]$r-z.shared_ptr<%s> index "%d" should not be >= %d.) r r rirr)groupr0rr')rr%r/r:rrrr's z!SharedPtrSubscriptWorker.__call__N) rrrrrr$r&rr'rrrrr s rc@s8eZdZdZddZddZddZdd Zd d Zd S) SharedPtrUseCountWorkerz*Implement std::shared_ptr::use_count().cCsdS)Nr)rrrrrr%sz SharedPtrUseCountWorker.__init__cCsdS)Nr)rrrrr$(sz%SharedPtrUseCountWorker.get_arg_typescCs tjdS)NZlong)rr)rr%rrrr&+sz'SharedPtrUseCountWorker.get_result_typecCsdS)NTr)rrCrrrr.sz!SharedPtrUseCountWorker._supportscCs|dd}|r|dSdS)NZ _M_refcountZ_M_piZ _M_use_countrr)rr%Z refcountsrrrr'1s z SharedPtrUseCountWorker.__call__N) rrrrrr$r&rr'rrrrr"s rc@s(eZdZdZddZddZddZdS) SharedPtrUniqueWorkerz'Implement std::shared_ptr::unique().cCstj||dS)N)rr)rrrrrr9szSharedPtrUniqueWorker.__init__cCs tjdS)Nr)rr)rr%rrrr&<sz%SharedPtrUniqueWorker.get_result_typecCstj||dkS)Nr-)rr')rr%rrrr'?szSharedPtrUniqueWorker.__call__N)rrrrrr&r'rrrrr6src@seZdZddZddZdS)SharedPtrMethodsMatchercsftjjjtdtdttdttdttdttdt tdt d_ fd d j D_ dS) N shared_ptrr?z operator->z operator*z operator[] use_countunique)r?z operator->z operator*z operator[]rrcsg|]}j|qSr)r8)r9r:)rrrr;Osz4SharedPtrMethodsMatcher.__init__..) rrr<rr=rrrrrrr8r>)rr)rrrDs  z SharedPtrMethodsMatcher.__init__cCsPt|dsdS|jj|}|dks*|j r.dS|j|jd}|j|rL|SdS)Nrr)rr8r?r@rrAr)rrBrCrDrrrrr Qs   zSharedPtrMethodsMatcher.matchN)rrrrr rrrrrCs rcCstjj|ttjj|ttjj|ttjj|ttjj|ttjj|tdtjj|tdtjj|tdtjj|tdtjj|tdtjj|tdtjj|tdtjj|tdtjj|t tjj|t dS) NsetmapZmultisetZmultimapZ unordered_setZ unordered_mapZunordered_multisetZunordered_multimap) rrZregister_xmethod_matcherr2rgr[rrrrrr)Zlocusrrrregister_libstdcxx_xmethods]s.        r)>rZ gdb.xmethodr r=rrr rrrrZ XMethodWorkerrr#r(r*r,r.r1r<r2rErRrSrTrUrXrZr[r]r`rcrgrjrnrorprqrrrtr{r|r}r~rrrrrrrrrrrrrrrrrrrrrrsr                * PK1] B660libstdcxx/v6/__pycache__/__init__.cpython-36.pycnu[3 h}@sddZddZdS)c Cs&y ddl}dStk r dSXdS)NTF)Z gdb.xmethod ImportError)Zgdbr0/usr/share/gcc-8/python/libstdcxx/v6/__init__.pygdb_has_xmethodss rcCs2ddlm}||tr.ddlm}||dS)N)register_libstdcxx_printers)register_libstdcxx_xmethods)ZprintersrrZxmethodsr)objrrrrrrs   rN)rrrrrrsPK1]qqlibstdcxx/v6/xmethods.pynu[# Xmethods for libstdc++. # Copyright (C) 2014-2025 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gdb import gdb.xmethod import re matcher_name_prefix = 'libstdc++::' def get_bool_type(): return gdb.lookup_type('bool') def get_std_size_type(): return gdb.lookup_type('std::size_t') _versioned_namespace = '__8::' def is_specialization_of(x, template_name): """ Test whether a type is a specialization of the named class template. The type can be specified as a string or a gdb.Type object. The template should be the name of a class template as a string, without any 'std' qualification. """ if isinstance(x, gdb.Type): x = x.tag template_name = '(%s)?%s' % (_versioned_namespace, template_name) return re.match(r'^std::(__\d::)?%s<.*>$' % template_name, x) is not None class LibStdCxxXMethod(gdb.xmethod.XMethod): def __init__(self, name, worker_class): gdb.xmethod.XMethod.__init__(self, name) self.worker_class = worker_class # Xmethods for std::array class ArrayWorkerBase(gdb.xmethod.XMethodWorker): def __init__(self, val_type, size): self._val_type = val_type self._size = size def null_value(self): nullptr = gdb.parse_and_eval('(void *) 0') return nullptr.cast(self._val_type.pointer()).dereference() class ArraySizeWorker(ArrayWorkerBase): def __init__(self, val_type, size): ArrayWorkerBase.__init__(self, val_type, size) def get_arg_types(self): return None def get_result_type(self, obj): return get_std_size_type() def __call__(self, obj): return self._size class ArrayEmptyWorker(ArrayWorkerBase): def __init__(self, val_type, size): ArrayWorkerBase.__init__(self, val_type, size) def get_arg_types(self): return None def get_result_type(self, obj): return get_bool_type() def __call__(self, obj): return (int(self._size) == 0) class ArrayFrontWorker(ArrayWorkerBase): def __init__(self, val_type, size): ArrayWorkerBase.__init__(self, val_type, size) def get_arg_types(self): return None def get_result_type(self, obj): return self._val_type def __call__(self, obj): if int(self._size) > 0: return obj['_M_elems'][0] else: return self.null_value() class ArrayBackWorker(ArrayWorkerBase): def __init__(self, val_type, size): ArrayWorkerBase.__init__(self, val_type, size) def get_arg_types(self): return None def get_result_type(self, obj): return self._val_type def __call__(self, obj): if int(self._size) > 0: return obj['_M_elems'][self._size - 1] else: return self.null_value() class ArrayAtWorker(ArrayWorkerBase): def __init__(self, val_type, size): ArrayWorkerBase.__init__(self, val_type, size) def get_arg_types(self): return get_std_size_type() def get_result_type(self, obj, index): return self._val_type def __call__(self, obj, index): if int(index) >= int(self._size): raise IndexError('Array index "%d" should not be >= %d.' % ((int(index), self._size))) return obj['_M_elems'][index] class ArraySubscriptWorker(ArrayWorkerBase): def __init__(self, val_type, size): ArrayWorkerBase.__init__(self, val_type, size) def get_arg_types(self): return get_std_size_type() def get_result_type(self, obj, index): return self._val_type def __call__(self, obj, index): if int(self._size) > 0: return obj['_M_elems'][index] else: return self.null_value() class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher): def __init__(self): gdb.xmethod.XMethodMatcher.__init__(self, matcher_name_prefix + 'array') self._method_dict = { 'size': LibStdCxxXMethod('size', ArraySizeWorker), 'empty': LibStdCxxXMethod('empty', ArrayEmptyWorker), 'front': LibStdCxxXMethod('front', ArrayFrontWorker), 'back': LibStdCxxXMethod('back', ArrayBackWorker), 'at': LibStdCxxXMethod('at', ArrayAtWorker), 'operator[]': LibStdCxxXMethod('operator[]', ArraySubscriptWorker), } self.methods = [self._method_dict[m] for m in self._method_dict] def match(self, class_type, method_name): if not is_specialization_of(class_type, 'array'): return None method = self._method_dict.get(method_name) if method is None or not method.enabled: return None try: value_type = class_type.template_argument(0) size = class_type.template_argument(1) except: return None return method.worker_class(value_type, size) # Xmethods for std::deque class DequeWorkerBase(gdb.xmethod.XMethodWorker): def __init__(self, val_type): self._val_type = val_type self._bufsize = 512 // val_type.sizeof or 1 def size(self, obj): start = obj['_M_impl']['_M_start'] finish = obj['_M_impl']['_M_finish'] if start['_M_cur'] == finish['_M_cur']: return 0 return (self._bufsize * (finish['_M_node'] - start['_M_node'] - 1) + (finish['_M_cur'] - finish['_M_first']) + (start['_M_last'] - start['_M_cur'])) def index(self, obj, idx): start = obj['_M_impl']['_M_start'] first_node_size = start['_M_last'] - start['_M_cur'] if idx < first_node_size: return start['_M_cur'][idx] idx = idx - first_node_size index_node = start['_M_node'][1 + int(idx) // self._bufsize] return index_node[idx % self._bufsize] class DequeEmptyWorker(DequeWorkerBase): def get_arg_types(self): return None def get_result_type(self, obj): return get_bool_type() def __call__(self, obj): return (obj['_M_impl']['_M_start']['_M_cur'] == obj['_M_impl']['_M_finish']['_M_cur']) class DequeSizeWorker(DequeWorkerBase): def get_arg_types(self): return None def get_result_type(self, obj): return get_std_size_type() def __call__(self, obj): return self.size(obj) class DequeFrontWorker(DequeWorkerBase): def get_arg_types(self): return None def get_result_type(self, obj): return self._val_type def __call__(self, obj): return obj['_M_impl']['_M_start']['_M_cur'][0] class DequeBackWorker(DequeWorkerBase): def get_arg_types(self): return None def get_result_type(self, obj): return self._val_type def __call__(self, obj): if (obj['_M_impl']['_M_finish']['_M_cur'] == obj['_M_impl']['_M_finish']['_M_first']): prev_node = obj['_M_impl']['_M_finish']['_M_node'] - 1 return prev_node[0][self._bufsize - 1] else: return obj['_M_impl']['_M_finish']['_M_cur'][-1] class DequeSubscriptWorker(DequeWorkerBase): def get_arg_types(self): return get_std_size_type() def get_result_type(self, obj, subscript): return self._val_type def __call__(self, obj, subscript): return self.index(obj, subscript) class DequeAtWorker(DequeWorkerBase): def get_arg_types(self): return get_std_size_type() def get_result_type(self, obj, index): return self._val_type def __call__(self, obj, index): deque_size = int(self.size(obj)) if int(index) >= deque_size: raise IndexError('Deque index "%d" should not be >= %d.' % (int(index), deque_size)) else: return self.index(obj, index) class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher): def __init__(self): gdb.xmethod.XMethodMatcher.__init__(self, matcher_name_prefix + 'deque') self._method_dict = { 'empty': LibStdCxxXMethod('empty', DequeEmptyWorker), 'size': LibStdCxxXMethod('size', DequeSizeWorker), 'front': LibStdCxxXMethod('front', DequeFrontWorker), 'back': LibStdCxxXMethod('back', DequeBackWorker), 'operator[]': LibStdCxxXMethod('operator[]', DequeSubscriptWorker), 'at': LibStdCxxXMethod('at', DequeAtWorker) } self.methods = [self._method_dict[m] for m in self._method_dict] def match(self, class_type, method_name): if not is_specialization_of(class_type, 'deque'): return None method = self._method_dict.get(method_name) if method is None or not method.enabled: return None return method.worker_class(class_type.template_argument(0)) # Xmethods for std::forward_list class ForwardListWorkerBase(gdb.xmethod.XMethodMatcher): def __init__(self, val_type, node_type): self._val_type = val_type self._node_type = node_type def get_arg_types(self): return None class ForwardListEmptyWorker(ForwardListWorkerBase): def get_result_type(self, obj): return get_bool_type() def __call__(self, obj): return obj['_M_impl']['_M_head']['_M_next'] == 0 class ForwardListFrontWorker(ForwardListWorkerBase): def get_result_type(self, obj): return self._val_type def __call__(self, obj): node = obj['_M_impl']['_M_head']['_M_next'].cast(self._node_type) val_address = node['_M_storage']['_M_storage'].address return val_address.cast(self._val_type.pointer()).dereference() class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher): def __init__(self): matcher_name = matcher_name_prefix + 'forward_list' gdb.xmethod.XMethodMatcher.__init__(self, matcher_name) self._method_dict = { 'empty': LibStdCxxXMethod('empty', ForwardListEmptyWorker), 'front': LibStdCxxXMethod('front', ForwardListFrontWorker) } self.methods = [self._method_dict[m] for m in self._method_dict] def match(self, class_type, method_name): if not is_specialization_of(class_type, 'forward_list'): return None method = self._method_dict.get(method_name) if method is None or not method.enabled: return None val_type = class_type.template_argument(0) node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer() return method.worker_class(val_type, node_type) # Xmethods for std::list class ListWorkerBase(gdb.xmethod.XMethodWorker): def __init__(self, val_type, node_type): self._val_type = val_type self._node_type = node_type def get_arg_types(self): return None def get_value_from_node(self, node): node = node.dereference() if node.type.fields()[1].name == '_M_data': # C++03 implementation, node contains the value as a member return node['_M_data'] # C++11 implementation, node stores value in __aligned_membuf addr = node['_M_storage'].address return addr.cast(self._val_type.pointer()).dereference() class ListEmptyWorker(ListWorkerBase): def get_result_type(self, obj): return get_bool_type() def __call__(self, obj): base_node = obj['_M_impl']['_M_node'] if base_node['_M_next'] == base_node.address: return True else: return False class ListSizeWorker(ListWorkerBase): def get_result_type(self, obj): return get_std_size_type() def __call__(self, obj): begin_node = obj['_M_impl']['_M_node']['_M_next'] end_node = obj['_M_impl']['_M_node'].address size = 0 while begin_node != end_node: begin_node = begin_node['_M_next'] size += 1 return size class ListFrontWorker(ListWorkerBase): def get_result_type(self, obj): return self._val_type def __call__(self, obj): node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type) return self.get_value_from_node(node) class ListBackWorker(ListWorkerBase): def get_result_type(self, obj): return self._val_type def __call__(self, obj): prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type) return self.get_value_from_node(prev_node) class ListMethodsMatcher(gdb.xmethod.XMethodMatcher): def __init__(self): gdb.xmethod.XMethodMatcher.__init__(self, matcher_name_prefix + 'list') self._method_dict = { 'empty': LibStdCxxXMethod('empty', ListEmptyWorker), 'size': LibStdCxxXMethod('size', ListSizeWorker), 'front': LibStdCxxXMethod('front', ListFrontWorker), 'back': LibStdCxxXMethod('back', ListBackWorker) } self.methods = [self._method_dict[m] for m in self._method_dict] def match(self, class_type, method_name): if not is_specialization_of(class_type, '(__cxx11::)?list'): return None method = self._method_dict.get(method_name) if method is None or not method.enabled: return None val_type = class_type.template_argument(0) node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer() return method.worker_class(val_type, node_type) # Xmethods for std::vector class VectorWorkerBase(gdb.xmethod.XMethodWorker): def __init__(self, val_type): self._val_type = val_type def size(self, obj): if self._val_type.code == gdb.TYPE_CODE_BOOL: start = obj['_M_impl']['_M_start']['_M_p'] finish = obj['_M_impl']['_M_finish']['_M_p'] finish_offset = obj['_M_impl']['_M_finish']['_M_offset'] bit_size = start.dereference().type.sizeof * 8 return (finish - start) * bit_size + finish_offset else: return obj['_M_impl']['_M_finish'] - obj['_M_impl']['_M_start'] def get(self, obj, index): if self._val_type.code == gdb.TYPE_CODE_BOOL: start = obj['_M_impl']['_M_start']['_M_p'] bit_size = start.dereference().type.sizeof * 8 valp = start + index // bit_size offset = index % bit_size return (valp.dereference() & (1 << offset)) > 0 else: return obj['_M_impl']['_M_start'][index] class VectorEmptyWorker(VectorWorkerBase): def get_arg_types(self): return None def get_result_type(self, obj): return get_bool_type() def __call__(self, obj): return int(self.size(obj)) == 0 class VectorSizeWorker(VectorWorkerBase): def get_arg_types(self): return None def get_result_type(self, obj): return get_std_size_type() def __call__(self, obj): return self.size(obj) class VectorFrontWorker(VectorWorkerBase): def get_arg_types(self): return None def get_result_type(self, obj): return self._val_type def __call__(self, obj): return self.get(obj, 0) class VectorBackWorker(VectorWorkerBase): def get_arg_types(self): return None def get_result_type(self, obj): return self._val_type def __call__(self, obj): return self.get(obj, int(self.size(obj)) - 1) class VectorAtWorker(VectorWorkerBase): def get_arg_types(self): return get_std_size_type() def get_result_type(self, obj, index): return self._val_type def __call__(self, obj, index): size = int(self.size(obj)) if int(index) >= size: raise IndexError('Vector index "%d" should not be >= %d.' % ((int(index), size))) return self.get(obj, int(index)) class VectorSubscriptWorker(VectorWorkerBase): def get_arg_types(self): return get_std_size_type() def get_result_type(self, obj, subscript): return self._val_type def __call__(self, obj, subscript): return self.get(obj, int(subscript)) class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher): def __init__(self): gdb.xmethod.XMethodMatcher.__init__(self, matcher_name_prefix + 'vector') self._method_dict = { 'size': LibStdCxxXMethod('size', VectorSizeWorker), 'empty': LibStdCxxXMethod('empty', VectorEmptyWorker), 'front': LibStdCxxXMethod('front', VectorFrontWorker), 'back': LibStdCxxXMethod('back', VectorBackWorker), 'at': LibStdCxxXMethod('at', VectorAtWorker), 'operator[]': LibStdCxxXMethod('operator[]', VectorSubscriptWorker), } self.methods = [self._method_dict[m] for m in self._method_dict] def match(self, class_type, method_name): if not is_specialization_of(class_type, 'vector'): return None method = self._method_dict.get(method_name) if method is None or not method.enabled: return None return method.worker_class(class_type.template_argument(0)) # Xmethods for associative containers class AssociativeContainerWorkerBase(gdb.xmethod.XMethodWorker): def __init__(self, unordered): self._unordered = unordered def node_count(self, obj): if self._unordered: return obj['_M_h']['_M_element_count'] else: return obj['_M_t']['_M_impl']['_M_node_count'] def get_arg_types(self): return None class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase): def get_result_type(self, obj): return get_bool_type() def __call__(self, obj): return int(self.node_count(obj)) == 0 class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase): def get_result_type(self, obj): return get_std_size_type() def __call__(self, obj): return self.node_count(obj) class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher): def __init__(self, name): gdb.xmethod.XMethodMatcher.__init__(self, matcher_name_prefix + name) self._name = name self._method_dict = { 'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker), 'empty': LibStdCxxXMethod('empty', AssociativeContainerEmptyWorker), } self.methods = [self._method_dict[m] for m in self._method_dict] def match(self, class_type, method_name): if not is_specialization_of(class_type, self._name): return None method = self._method_dict.get(method_name) if method is None or not method.enabled: return None unordered = 'unordered' in self._name return method.worker_class(unordered) # Xmethods for std::unique_ptr class UniquePtrGetWorker(gdb.xmethod.XMethodWorker): """ Implement std::unique_ptr::get() and std::unique_ptr::operator->(). """ def __init__(self, elem_type): self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY if self._is_array: self._elem_type = elem_type.target() else: self._elem_type = elem_type def get_arg_types(self): return None def get_result_type(self, obj): return self._elem_type.pointer() def _supports(self, method_name): # operator-> is not supported for unique_ptr return method_name == 'get' or not self._is_array def __call__(self, obj): impl_type = obj.dereference().type.fields()[0].type.tag # Check for new implementations first: if is_specialization_of(impl_type, '__uniq_ptr_(data|impl)'): tuple_member = obj['_M_t']['_M_t'] elif is_specialization_of(impl_type, 'tuple'): tuple_member = obj['_M_t'] else: return None tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl tuple_head_type = tuple_impl_type.fields()[1].type # _Head_base head_field = tuple_head_type.fields()[0] if head_field.name == '_M_head_impl': return tuple_member.cast(tuple_head_type)['_M_head_impl'] elif head_field.is_base_class: return tuple_member.cast(head_field.type) else: return None class UniquePtrDerefWorker(UniquePtrGetWorker): """Implement std::unique_ptr::operator*().""" def __init__(self, elem_type): UniquePtrGetWorker.__init__(self, elem_type) def get_result_type(self, obj): return self._elem_type def _supports(self, method_name): # operator* is not supported for unique_ptr return not self._is_array def __call__(self, obj): return UniquePtrGetWorker.__call__(self, obj).dereference() class UniquePtrSubscriptWorker(UniquePtrGetWorker): """Implement std::unique_ptr::operator[](size_t).""" def __init__(self, elem_type): UniquePtrGetWorker.__init__(self, elem_type) def get_arg_types(self): return get_std_size_type() def get_result_type(self, obj, index): return self._elem_type def _supports(self, method_name): # operator[] is only supported for unique_ptr return self._is_array def __call__(self, obj, index): return UniquePtrGetWorker.__call__(self, obj)[index] class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher): def __init__(self): gdb.xmethod.XMethodMatcher.__init__(self, matcher_name_prefix + 'unique_ptr') self._method_dict = { 'get': LibStdCxxXMethod('get', UniquePtrGetWorker), 'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker), 'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker), 'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker), } self.methods = [self._method_dict[m] for m in self._method_dict] def match(self, class_type, method_name): if not is_specialization_of(class_type, 'unique_ptr'): return None method = self._method_dict.get(method_name) if method is None or not method.enabled: return None worker = method.worker_class(class_type.template_argument(0)) if worker._supports(method_name): return worker return None # Xmethods for std::shared_ptr class SharedPtrGetWorker(gdb.xmethod.XMethodWorker): """ Implements std::shared_ptr::get() and std::shared_ptr::operator->(). """ def __init__(self, elem_type): self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY if self._is_array: self._elem_type = elem_type.target() else: self._elem_type = elem_type def get_arg_types(self): return None def get_result_type(self, obj): return self._elem_type.pointer() def _supports(self, method_name): # operator-> is not supported for shared_ptr return method_name == 'get' or not self._is_array def __call__(self, obj): return obj['_M_ptr'] class SharedPtrDerefWorker(SharedPtrGetWorker): """Implement std::shared_ptr::operator*().""" def __init__(self, elem_type): SharedPtrGetWorker.__init__(self, elem_type) def get_result_type(self, obj): return self._elem_type def _supports(self, method_name): # operator* is not supported for shared_ptr return not self._is_array def __call__(self, obj): return SharedPtrGetWorker.__call__(self, obj).dereference() class SharedPtrSubscriptWorker(SharedPtrGetWorker): """Implement std::shared_ptr::operator[](size_t).""" def __init__(self, elem_type): SharedPtrGetWorker.__init__(self, elem_type) def get_arg_types(self): return get_std_size_type() def get_result_type(self, obj, index): return self._elem_type def _supports(self, method_name): # operator[] is only supported for shared_ptr return self._is_array def __call__(self, obj, index): # Check bounds if _elem_type is an array of known bound m = re.match(r'.*\[(\d+)]$', str(self._elem_type)) if m and index >= int(m.group(1)): raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' % (self._elem_type, int(index), int(m.group(1)))) return SharedPtrGetWorker.__call__(self, obj)[index] class SharedPtrUseCountWorker(gdb.xmethod.XMethodWorker): """Implement std::shared_ptr::use_count().""" def __init__(self, elem_type): pass def get_arg_types(self): return None def get_result_type(self, obj): return gdb.lookup_type('long') def _supports(self, method_name): return True def __call__(self, obj): refcounts = obj['_M_refcount']['_M_pi'] return refcounts['_M_use_count'] if refcounts else 0 class SharedPtrUniqueWorker(SharedPtrUseCountWorker): """Implement std::shared_ptr::unique().""" def __init__(self, elem_type): SharedPtrUseCountWorker.__init__(self, elem_type) def get_result_type(self, obj): return gdb.lookup_type('bool') def __call__(self, obj): return SharedPtrUseCountWorker.__call__(self, obj) == 1 class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher): def __init__(self): gdb.xmethod.XMethodMatcher.__init__(self, matcher_name_prefix + 'shared_ptr') self._method_dict = { 'get': LibStdCxxXMethod('get', SharedPtrGetWorker), 'operator->': LibStdCxxXMethod('operator->', SharedPtrGetWorker), 'operator*': LibStdCxxXMethod('operator*', SharedPtrDerefWorker), 'operator[]': LibStdCxxXMethod('operator[]', SharedPtrSubscriptWorker), 'use_count': LibStdCxxXMethod('use_count', SharedPtrUseCountWorker), 'unique': LibStdCxxXMethod('unique', SharedPtrUniqueWorker), } self.methods = [self._method_dict[m] for m in self._method_dict] def match(self, class_type, method_name): if not is_specialization_of(class_type, 'shared_ptr'): return None method = self._method_dict.get(method_name) if method is None or not method.enabled: return None worker = method.worker_class(class_type.template_argument(0)) if worker._supports(method_name): return worker return None def register_libstdcxx_xmethods(locus): gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher()) gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher()) gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher()) gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher()) gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher()) gdb.xmethod.register_xmethod_matcher( locus, AssociativeContainerMethodsMatcher('set')) gdb.xmethod.register_xmethod_matcher( locus, AssociativeContainerMethodsMatcher('map')) gdb.xmethod.register_xmethod_matcher( locus, AssociativeContainerMethodsMatcher('multiset')) gdb.xmethod.register_xmethod_matcher( locus, AssociativeContainerMethodsMatcher('multimap')) gdb.xmethod.register_xmethod_matcher( locus, AssociativeContainerMethodsMatcher('unordered_set')) gdb.xmethod.register_xmethod_matcher( locus, AssociativeContainerMethodsMatcher('unordered_map')) gdb.xmethod.register_xmethod_matcher( locus, AssociativeContainerMethodsMatcher('unordered_multiset')) gdb.xmethod.register_xmethod_matcher( locus, AssociativeContainerMethodsMatcher('unordered_multimap')) gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher()) gdb.xmethod.register_xmethod_matcher(locus, SharedPtrMethodsMatcher()) PK1]ܯ}}libstdcxx/v6/__init__.pynu[# Copyright (C) 2014-2025 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Load the xmethods if GDB supports them. def gdb_has_xmethods(): try: import gdb.xmethod return True except ImportError: return False def register_libstdcxx_printers(obj): # Load the pretty-printers. from .printers import register_libstdcxx_printers register_libstdcxx_printers(obj) if gdb_has_xmethods(): from .xmethods import register_libstdcxx_xmethods register_libstdcxx_xmethods(obj) PK1]CBlibstdcxx/v6/printers.pynu[# Pretty-printers for libstdc++. # Copyright (C) 2008-2025 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gdb import itertools import re import sys import errno import datetime # Python 2 + Python 3 compatibility code # Resources about compatibility: # # * : Documentation of the "six" module # FIXME: The handling of e.g. std::basic_string (at least on char) # probably needs updating to work with Python 3's new string rules. # # In particular, Python 3 has a separate type (called byte) for # bytestrings, and a special b"" syntax for the byte literals; the old # str() type has been redefined to always store Unicode text. # # We probably can't do much about this until this GDB PR is addressed: # if sys.version_info[0] > 2: # Python 3 stuff Iterator = object # Python 3 folds these into the normal functions. imap = map izip = zip # Also, int subsumes long long = int _utc_timezone = datetime.timezone.utc else: # Python 2 stuff class Iterator: """Compatibility mixin for iterators Instead of writing next() methods for iterators, write __next__() methods and use this mixin to make them work in Python 2 as well as Python 3. Idea stolen from the "six" documentation: """ def next(self): return self.__next__() # In Python 2, we still need these from itertools from itertools import imap, izip # Python 2 does not provide the datetime.UTC singleton. class UTC(datetime.tzinfo): """Concrete tzinfo class representing the UTC time zone.""" def utcoffset(self, dt): return datetime.timedelta(0) def tzname(self, dt): return "UTC" def dst(self, dt): return datetime.timedelta(0) _utc_timezone = UTC() # Try to use the new-style pretty-printing if available. _use_gdb_pp = True try: import gdb.printing except ImportError: _use_gdb_pp = False # Try to install type-printers. _use_type_printing = False try: import gdb.types if hasattr(gdb.types, 'TypePrinter'): _use_type_printing = True except ImportError: pass # Use the base class if available. if hasattr(gdb, 'ValuePrinter'): printer_base = gdb.ValuePrinter else: printer_base = object # Starting with the type ORIG, search for the member type NAME. This # handles searching upward through superclasses. This is needed to # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615. def find_type(orig, name): typ = orig.strip_typedefs() while True: # Use Type.tag to ignore cv-qualifiers. PR 67440. search = '%s::%s' % (typ.tag, name) try: return gdb.lookup_type(search) except RuntimeError: pass # The type was not found, so try the superclass. We only need # to check the first superclass, so we don't bother with # anything fancier here. fields = typ.fields() if len(fields) and fields[0].is_base_class: typ = fields[0].type else: raise ValueError("Cannot find type %s::%s" % (str(orig), name)) _versioned_namespace = '__8::' def lookup_templ_spec(templ, *args): """ Lookup template specialization templ. """ t = '{}<{}>'.format(templ, ', '.join([str(a) for a in args])) try: return gdb.lookup_type(t) except gdb.error as e: # Type not found, try again in versioned namespace. global _versioned_namespace if _versioned_namespace not in templ: t = t.replace('::', '::' + _versioned_namespace, 1) try: return gdb.lookup_type(t) except gdb.error: # If that also fails, rethrow the original exception pass raise e # Use this to find container node types instead of find_type, # see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91997 for details. def lookup_node_type(nodename, containertype): """ Lookup specialization of template nodename corresponding to containertype. nodename - The name of a class template, as a String containertype - The container, as a gdb.Type Return a gdb.Type for the corresponding specialization of nodename, or None if the type cannot be found. e.g. lookup_node_type('_List_node', gdb.lookup_type('std::list')) will return a gdb.Type for the type std::_List_node. """ # If nodename is unqualified, assume it's in namespace std. if '::' not in nodename: nodename = 'std::' + nodename # Use either containertype's value_type or its first template argument. try: valtype = find_type(containertype, 'value_type') except: valtype = containertype.template_argument(0) valtype = valtype.strip_typedefs() try: return lookup_templ_spec(nodename, valtype) except gdb.error: # For debug mode containers the node is in std::__cxx1998. if is_member_of_namespace(nodename, 'std'): if is_member_of_namespace(containertype, 'std::__cxx1998', 'std::__debug', '__gnu_debug'): nodename = nodename.replace('::', '::__cxx1998::', 1) try: return lookup_templ_spec(nodename, valtype) except gdb.error: pass return None def is_member_of_namespace(typ, *namespaces): """ Test whether a type is a member of one of the specified namespaces. The type can be specified as a string or a gdb.Type object. """ if isinstance(typ, gdb.Type): typ = str(typ) typ = strip_versioned_namespace(typ) for namespace in namespaces: if typ.startswith(namespace + '::'): return True return False def is_specialization_of(x, template_name): """ Test whether a type is a specialization of the named class template. The type can be specified as a string or a gdb.Type object. The template should be the name of a class template as a string, without any 'std' qualification. """ global _versioned_namespace if isinstance(x, gdb.Type): x = x.tag template_name = '(%s)?%s' % (_versioned_namespace, template_name) return re.match('^std::%s<.*>$' % template_name, x) is not None def strip_versioned_namespace(typename): global _versioned_namespace return typename.replace(_versioned_namespace, '') def strip_fundts_namespace(typ): """Remove "fundamentals_vN" inline namespace from qualified type name.""" pattern = r'^std::experimental::fundamentals_v\d::' repl = 'std::experimental::' if sys.version_info[0] == 2: return re.sub(pattern, repl, typ, 1) else: # Technically this needs Python 3.1 but nobody should be using 3.0 return re.sub(pattern, repl, typ, count=1) def strip_inline_namespaces(type_str): """Remove known inline namespaces from the canonical name of a type.""" type_str = strip_versioned_namespace(type_str) type_str = type_str.replace('std::__cxx11::', 'std::') expt_ns = 'std::experimental::' for lfts_ns in ('fundamentals_v1', 'fundamentals_v2'): type_str = type_str.replace(expt_ns + lfts_ns + '::', expt_ns) fs_ns = expt_ns + 'filesystem::' type_str = type_str.replace(fs_ns + 'v1::', fs_ns) return type_str def get_template_arg_list(type_obj): """Return a type's template arguments as a list.""" n = 0 template_args = [] while True: try: template_args.append(type_obj.template_argument(n)) except: return template_args n += 1 class SmartPtrIterator(Iterator): """An iterator for smart pointer types with a single 'child' value.""" def __init__(self, val): self._val = val def __iter__(self): return self def __next__(self): if self._val is None: raise StopIteration self._val, val = None, self._val return ('get()', val) class SharedPointerPrinter(printer_base): """ Print a shared_ptr, weak_ptr, atomic, or atomic. """ def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val self._pointer = val['_M_ptr'] def children(self): return SmartPtrIterator(self._pointer) # Return the _Sp_counted_base<>* that holds the refcounts. def _get_refcounts(self): if self._typename == 'std::atomic': # A tagged pointer is stored as uintptr_t. ptr_val = self._val['_M_refcount']['_M_val']['_M_i'] ptr_val = ptr_val - (ptr_val % 2) # clear lock bit ptr_type = find_type(self._val['_M_refcount'].type, 'pointer') return ptr_val.cast(ptr_type) return self._val['_M_refcount']['_M_pi'] def to_string(self): state = 'empty' refcounts = self._get_refcounts() targ = self._val.type.template_argument(0) targ = strip_versioned_namespace(str(targ)) if refcounts != 0: usecount = refcounts['_M_use_count'] weakcount = refcounts['_M_weak_count'] if usecount == 0: state = 'expired, weak count %d' % weakcount else: state = 'use count %d, weak count %d' % ( usecount, weakcount - 1) return '%s<%s> (%s)' % (self._typename, targ, state) def _tuple_impl_get(val): """Return the tuple element stored in a _Tuple_impl base class.""" bases = val.type.fields() if not bases[-1].is_base_class: raise ValueError( "Unsupported implementation for std::tuple: %s" % str(val.type)) # Get the _Head_base base class: head_base = val.cast(bases[-1].type) fields = head_base.type.fields() if len(fields) == 0: raise ValueError( "Unsupported implementation for std::tuple: %s" % str(val.type)) if fields[0].name == '_M_head_impl': # The tuple element is the _Head_base::_M_head_impl data member. return head_base['_M_head_impl'] elif fields[0].is_base_class: # The tuple element is an empty base class of _Head_base. # Cast to that empty base class. return head_base.cast(fields[0].type) else: raise ValueError( "Unsupported implementation for std::tuple: %s" % str(val.type)) def tuple_get(n, val): """Return the result of std::get(val) on a std::tuple.""" tuple_size = len(get_template_arg_list(val.type)) if n > tuple_size: raise ValueError("Out of range index for std::get on std::tuple") # Get the first _Tuple_impl<0, T...> base class: node = val.cast(val.type.fields()[0].type) while n > 0: # Descend through the base classes until the Nth one. node = node.cast(node.type.fields()[0].type) n -= 1 return _tuple_impl_get(node) def unique_ptr_get(val): """Return the result of val.get() on a std::unique_ptr.""" # std::unique_ptr contains a std::tuple, # either as a direct data member _M_t (the old implementation) # or within a data member of type __uniq_ptr_data. impl_type = val.type.fields()[0].type.strip_typedefs() # Check for new implementations first: if is_specialization_of(impl_type, '__uniq_ptr_data') \ or is_specialization_of(impl_type, '__uniq_ptr_impl'): tuple_member = val['_M_t']['_M_t'] elif is_specialization_of(impl_type, 'tuple'): tuple_member = val['_M_t'] else: raise ValueError( "Unsupported implementation for unique_ptr: %s" % str(impl_type)) return tuple_get(0, tuple_member) class UniquePointerPrinter(printer_base): """Print a unique_ptr.""" def __init__(self, typename, val): self._val = val def children(self): return SmartPtrIterator(unique_ptr_get(self._val)) def to_string(self): t = self._val.type.template_argument(0) return 'std::unique_ptr<{}>'.format(str(t)) def get_value_from_aligned_membuf(buf, valtype): """Return the value held in a __gnu_cxx::__aligned_membuf.""" return buf['_M_storage'].address.cast(valtype.pointer()).dereference() def get_value_from_list_node(node): """Return the value held in an _List_node<_Val>.""" try: member = node.type.fields()[1].name if member == '_M_data': # C++03 implementation, node contains the value as a member return node['_M_data'] elif member == '_M_storage': # C++11 implementation, node stores value in __aligned_membuf valtype = node.type.template_argument(0) return get_value_from_aligned_membuf(node['_M_storage'], valtype) except: pass raise ValueError("Unsupported implementation for %s" % str(node.type)) class StdListPrinter(printer_base): """Print a std::list.""" class _iterator(Iterator): def __init__(self, nodetype, head): self._nodetype = nodetype self._base = head['_M_next'] self._head = head.address self._count = 0 def __iter__(self): return self def __next__(self): if self._base == self._head: raise StopIteration elt = self._base.cast(self._nodetype).dereference() self._base = elt['_M_next'] count = self._count self._count = self._count + 1 val = get_value_from_list_node(elt) return ('[%d]' % count, val) def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def children(self): nodetype = lookup_node_type('_List_node', self._val.type).pointer() return self._iterator(nodetype, self._val['_M_impl']['_M_node']) def to_string(self): headnode = self._val['_M_impl']['_M_node'] if headnode['_M_next'] == headnode.address: return 'empty %s' % (self._typename) return '%s' % (self._typename) class NodeIteratorPrinter(printer_base): def __init__(self, typename, val, contname, nodename): self._val = val self._typename = typename self._contname = contname self._nodetype = lookup_node_type(nodename, val.type) def to_string(self): if not self._val['_M_node']: return 'non-dereferenceable iterator for std::%s' % (self._contname) node = self._val['_M_node'].cast( self._nodetype.pointer()).dereference() return str(get_value_from_list_node(node)) class StdListIteratorPrinter(NodeIteratorPrinter): """Print std::list::iterator.""" def __init__(self, typename, val): NodeIteratorPrinter.__init__(self, typename, val, 'list', '_List_node') class StdFwdListIteratorPrinter(NodeIteratorPrinter): """Print std::forward_list::iterator.""" def __init__(self, typename, val): NodeIteratorPrinter.__init__(self, typename, val, 'forward_list', '_Fwd_list_node') class StdSlistPrinter(printer_base): """Print a __gnu_cxx::slist.""" class _iterator(Iterator): def __init__(self, nodetype, head): self._nodetype = nodetype self._base = head['_M_head']['_M_next'] self._count = 0 def __iter__(self): return self def __next__(self): if self._base == 0: raise StopIteration elt = self._base.cast(self._nodetype).dereference() self._base = elt['_M_next'] count = self._count self._count = self._count + 1 return ('[%d]' % count, elt['_M_data']) def __init__(self, typename, val): self._val = val def children(self): nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self._val.type) return self._iterator(nodetype.pointer(), self._val) def to_string(self): if self._val['_M_head']['_M_next'] == 0: return 'empty __gnu_cxx::slist' return '__gnu_cxx::slist' class StdSlistIteratorPrinter(printer_base): """Print __gnu_cxx::slist::iterator.""" def __init__(self, typename, val): self._val = val def to_string(self): if not self._val['_M_node']: return 'non-dereferenceable iterator for __gnu_cxx::slist' nodetype = lookup_node_type( '__gnu_cxx::_Slist_node', self._val.type).pointer() return str(self._val['_M_node'].cast(nodetype).dereference()['_M_data']) class StdVectorPrinter(printer_base): """Print a std::vector.""" class _iterator(Iterator): def __init__(self, start, finish, bitvec): self._bitvec = bitvec if bitvec: self._item = start['_M_p'] self._so = 0 self._finish = finish['_M_p'] self._fo = finish['_M_offset'] itype = self._item.dereference().type self._isize = 8 * itype.sizeof else: self._item = start self._finish = finish self._count = 0 def __iter__(self): return self def __next__(self): count = self._count self._count = self._count + 1 if self._bitvec: if self._item == self._finish and self._so >= self._fo: raise StopIteration elt = bool(self._item.dereference() & (1 << self._so)) self._so = self._so + 1 if self._so >= self._isize: self._item = self._item + 1 self._so = 0 return ('[%d]' % count, elt) else: if self._item == self._finish: raise StopIteration elt = self._item.dereference() self._item = self._item + 1 return ('[%d]' % count, elt) def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val self._is_bool = val.type.template_argument( 0).code == gdb.TYPE_CODE_BOOL def children(self): return self._iterator(self._val['_M_impl']['_M_start'], self._val['_M_impl']['_M_finish'], self._is_bool) def to_string(self): start = self._val['_M_impl']['_M_start'] finish = self._val['_M_impl']['_M_finish'] end = self._val['_M_impl']['_M_end_of_storage'] if self._is_bool: start = self._val['_M_impl']['_M_start']['_M_p'] finish = self._val['_M_impl']['_M_finish']['_M_p'] fo = self._val['_M_impl']['_M_finish']['_M_offset'] itype = start.dereference().type bl = 8 * itype.sizeof length = bl * (finish - start) + fo capacity = bl * (end - start) return ('%s of length %d, capacity %d' % (self._typename, int(length), int(capacity))) else: return ('%s of length %d, capacity %d' % (self._typename, int(finish - start), int(end - start))) def display_hint(self): return 'array' class StdVectorIteratorPrinter(printer_base): """Print std::vector::iterator.""" def __init__(self, typename, val): self._val = val def to_string(self): if not self._val['_M_current']: return 'non-dereferenceable iterator for std::vector' return str(self._val['_M_current'].dereference()) class StdBitIteratorPrinter(printer_base): """Print std::vector's _Bit_iterator and _Bit_const_iterator.""" def __init__(self, typename, val): self._val = val def to_string(self): if not self._val['_M_p']: return 'non-dereferenceable iterator for std::vector' return bool(self._val['_M_p'].dereference() & (1 << self._val['_M_offset'])) class StdBitReferencePrinter(printer_base): """Print std::vector::reference.""" def __init__(self, typename, val): self._val = val def to_string(self): if not self._val['_M_p']: # PR libstdc++/115098 removed the reference default constructor # that this case relates to. New code should never need this, # but we still handle it for compatibility with old binaries. return 'invalid std::vector::reference' return bool(self._val['_M_p'].dereference() & (self._val['_M_mask'])) class StdTuplePrinter(printer_base): """Print a std::tuple.""" class _iterator(Iterator): @staticmethod def _is_nonempty_tuple(nodes): if len(nodes) == 2: if is_specialization_of(nodes[1].type, '__tuple_base'): return True elif len(nodes) == 1: return True elif len(nodes) == 0: return False raise ValueError( "Top of tuple tree does not consist of a single node.") def __init__(self, head): self._head = head # Set the base class as the initial head of the # tuple. nodes = self._head.type.fields() if self._is_nonempty_tuple(nodes): # Set the actual head to the first pair. self._head = self._head.cast(nodes[0].type) self._count = 0 def __iter__(self): return self def __next__(self): # Check for further recursions in the inheritance tree. # For a GCC 5+ tuple self._head is None after visiting all nodes: if not self._head: raise StopIteration nodes = self._head.type.fields() # For a GCC 4.x tuple there is a final node with no fields: if len(nodes) == 0: raise StopIteration # Check that this iteration has an expected structure. if len(nodes) > 2: raise ValueError( "Cannot parse more than 2 nodes in a tuple tree.") if len(nodes) == 1: # This is the last node of a GCC 5+ std::tuple. impl = self._head.cast(nodes[0].type) self._head = None else: # Either a node before the last node, or the last node of # a GCC 4.x tuple (which has an empty parent). # - Left node is the next recursion parent. # - Right node is the actual class contained in the tuple. # Process right node. impl = self._head.cast(nodes[1].type) # Process left node and set it as head. self._head = self._head.cast(nodes[0].type) self._count = self._count + 1 # Finally, check the implementation. If it is # wrapped in _M_head_impl return that, otherwise return # the value "as is". fields = impl.type.fields() if len(fields) < 1 or fields[0].name != "_M_head_impl": return ('[%d]' % (self._count - 1), impl) else: return ('[%d]' % (self._count - 1), impl['_M_head_impl']) def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def children(self): return self._iterator(self._val) def to_string(self): if len(self._val.type.fields()) == 0: return 'empty %s' % (self._typename) return '%s containing' % (self._typename) class StdStackOrQueuePrinter(printer_base): """Print a std::stack or std::queue.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._visualizer = gdb.default_visualizer(val['c']) def children(self): return self._visualizer.children() def to_string(self): return '%s wrapping: %s' % (self._typename, self._visualizer.to_string()) def display_hint(self): if hasattr(self._visualizer, 'display_hint'): return self._visualizer.display_hint() return None class RbtreeIterator(Iterator): """ Turn an RB-tree-based container (std::map, std::set etc.) into a Python iterable object. """ def __init__(self, rbtree): self._size = rbtree['_M_t']['_M_impl']['_M_node_count'] self._node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left'] self._count = 0 def __iter__(self): return self def __len__(self): return int(self._size) def __next__(self): if self._count == self._size: raise StopIteration result = self._node self._count = self._count + 1 if self._count < self._size: # Compute the next node. node = self._node if node.dereference()['_M_right']: node = node.dereference()['_M_right'] while node.dereference()['_M_left']: node = node.dereference()['_M_left'] else: parent = node.dereference()['_M_parent'] while node == parent.dereference()['_M_right']: node = parent parent = parent.dereference()['_M_parent'] if node.dereference()['_M_right'] != parent: node = parent self._node = node return result def get_value_from_Rb_tree_node(node): """Return the value held in an _Rb_tree_node<_Val>.""" try: member = node.type.fields()[1].name if member == '_M_value_field': # C++03 implementation, node contains the value as a member return node['_M_value_field'] elif member == '_M_storage': # C++11 implementation, node stores value in __aligned_membuf valtype = node.type.template_argument(0) return get_value_from_aligned_membuf(node['_M_storage'], valtype) except: pass raise ValueError("Unsupported implementation for %s" % str(node.type)) # This is a pretty printer for std::_Rb_tree_iterator (which is # std::map::iterator), and has nothing to do with the RbtreeIterator # class above. class StdRbtreeIteratorPrinter(printer_base): """Print std::map::iterator, std::set::iterator, etc.""" def __init__(self, typename, val): self._val = val nodetype = lookup_node_type('_Rb_tree_node', self._val.type) self._link_type = nodetype.pointer() def to_string(self): if not self._val['_M_node']: return 'non-dereferenceable iterator for associative container' node = self._val['_M_node'].cast(self._link_type).dereference() return str(get_value_from_Rb_tree_node(node)) class StdDebugIteratorPrinter(printer_base): """Print a debug enabled version of an iterator.""" def __init__(self, typename, val): self._val = val # Just strip away the encapsulating __gnu_debug::_Safe_iterator # and return the wrapped iterator value. def to_string(self): base_type = gdb.lookup_type('__gnu_debug::_Safe_iterator_base') itype = self._val.type.template_argument(0) safe_seq = self._val.cast(base_type)['_M_sequence'] if not safe_seq: return str(self._val.cast(itype)) if self._val['_M_version'] != safe_seq['_M_version']: return "invalid iterator" return str(self._val.cast(itype)) def num_elements(num): """Return either "1 element" or "N elements" depending on the argument.""" return '1 element' if num == 1 else '%d elements' % num class StdMapPrinter(printer_base): """Print a std::map or std::multimap.""" # Turn an RbtreeIterator into a pretty-print iterator. class _iter(Iterator): def __init__(self, rbiter, type): self._rbiter = rbiter self._count = 0 self._type = type def __iter__(self): return self def __next__(self): if self._count % 2 == 0: n = next(self._rbiter) n = n.cast(self._type).dereference() n = get_value_from_Rb_tree_node(n) self._pair = n item = n['first'] else: item = self._pair['second'] result = ('[%d]' % self._count, item) self._count = self._count + 1 return result def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): return '%s with %s' % (self._typename, num_elements(len(RbtreeIterator(self._val)))) def children(self): node = lookup_node_type('_Rb_tree_node', self._val.type).pointer() return self._iter(RbtreeIterator(self._val), node) def display_hint(self): return 'map' class StdSetPrinter(printer_base): """Print a std::set or std::multiset.""" # Turn an RbtreeIterator into a pretty-print iterator. class _iter(Iterator): def __init__(self, rbiter, type): self._rbiter = rbiter self._count = 0 self._type = type def __iter__(self): return self def __next__(self): item = next(self._rbiter) item = item.cast(self._type).dereference() item = get_value_from_Rb_tree_node(item) # FIXME: this is weird ... what to do? # Maybe a 'set' display hint? result = ('[%d]' % self._count, item) self._count = self._count + 1 return result def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): return '%s with %s' % (self._typename, num_elements(len(RbtreeIterator(self._val)))) def children(self): node = lookup_node_type('_Rb_tree_node', self._val.type).pointer() return self._iter(RbtreeIterator(self._val), node) class StdBitsetPrinter(printer_base): """Print a std::bitset.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): # If template_argument handled values, we could print the # size. Or we could use a regexp on the type. return '%s' % (self._typename) def children(self): try: # An empty bitset may not have any members which will # result in an exception being thrown. words = self._val['_M_w'] except: return [] wtype = words.type # The _M_w member can be either an unsigned long, or an # array. This depends on the template specialization used. # If it is a single long, convert to a single element list. if wtype.code == gdb.TYPE_CODE_ARRAY: tsize = wtype.target().sizeof else: words = [words] tsize = wtype.sizeof nwords = wtype.sizeof / tsize result = [] byte = 0 while byte < nwords: w = words[byte] bit = 0 while w != 0: if (w & 1) != 0: # Another spot where we could use 'set'? result.append(('[%d]' % (byte * tsize * 8 + bit), 1)) bit = bit + 1 w = w >> 1 byte = byte + 1 return result class StdDequePrinter(printer_base): """Print a std::deque.""" class _iter(Iterator): def __init__(self, node, start, end, last, buffer_size): self._node = node self._p = start self._end = end self._last = last self._buffer_size = buffer_size self._count = 0 def __iter__(self): return self def __next__(self): if self._p == self._last: raise StopIteration result = ('[%d]' % self._count, self._p.dereference()) self._count = self._count + 1 # Advance the 'cur' pointer. self._p = self._p + 1 if self._p == self._end: # If we got to the end of this bucket, move to the # next bucket. self._node = self._node + 1 self._p = self._node[0] self._end = self._p + self._buffer_size return result def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val self._elttype = val.type.template_argument(0) size = self._elttype.sizeof if size < 512: self._buffer_size = int(512 / size) else: self._buffer_size = 1 def to_string(self): start = self._val['_M_impl']['_M_start'] end = self._val['_M_impl']['_M_finish'] delta_n = end['_M_node'] - start['_M_node'] - 1 delta_s = start['_M_last'] - start['_M_cur'] delta_e = end['_M_cur'] - end['_M_first'] size = self._buffer_size * delta_n + delta_s + delta_e return '%s with %s' % (self._typename, num_elements(long(size))) def children(self): start = self._val['_M_impl']['_M_start'] end = self._val['_M_impl']['_M_finish'] return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'], end['_M_cur'], self._buffer_size) def display_hint(self): return 'array' class StdDequeIteratorPrinter(printer_base): """Print std::deque::iterator.""" def __init__(self, typename, val): self._val = val def to_string(self): if not self._val['_M_cur']: return 'non-dereferenceable iterator for std::deque' return str(self._val['_M_cur'].dereference()) class StdStringPrinter(printer_base): """Print a std::basic_string of some kind.""" def __init__(self, typename, val): self._val = val self._new_string = typename.find("::__cxx11::basic_string") != -1 def to_string(self): # Make sure &string works, too. type = self._val.type if type.code == gdb.TYPE_CODE_REF: type = type.target() # Calculate the length of the string so that to_string returns # the string according to length, not according to first null # encountered. ptr = self._val['_M_dataplus']['_M_p'] if self._new_string: length = self._val['_M_string_length'] # https://sourceware.org/bugzilla/show_bug.cgi?id=17728 ptr = ptr.cast(ptr.type.strip_typedefs()) else: realtype = type.unqualified().strip_typedefs() reptype = gdb.lookup_type(str(realtype) + '::_Rep').pointer() header = ptr.cast(reptype) - 1 length = header.dereference()['_M_length'] if hasattr(ptr, "lazy_string"): return ptr.lazy_string(length=length) return ptr.string(length=length) def display_hint(self): return 'string' def access_streambuf_ptrs(streambuf): """Access the streambuf put area pointers.""" pbase = streambuf['_M_out_beg'] pptr = streambuf['_M_out_cur'] egptr = streambuf['_M_in_end'] return pbase, pptr, egptr class StdStringBufPrinter(printer_base): """Print a std::basic_stringbuf.""" def __init__(self, _, val): self._val = val def to_string(self): (pbase, pptr, egptr) = access_streambuf_ptrs(self._val) # Logic from basic_stringbuf::_M_high_mark() if pptr: if not egptr or pptr > egptr: return pbase.string(length=pptr - pbase) else: return pbase.string(length=egptr - pbase) return self._val['_M_string'] def display_hint(self): return 'string' class StdStringStreamPrinter(printer_base): """Print a std::basic_stringstream.""" def __init__(self, typename, val): self._val = val self._typename = typename # Check if the stream was redirected. This is essentially: # val['_M_streambuf'] != val['_M_stringbuf'].address # However, GDB can't resolve the virtual inheritance, so we do that # manually. basetype = [f.type for f in val.type.fields() if f.is_base_class][0] gdb.set_convenience_variable('__stream', val.cast(basetype).address) self._streambuf = gdb.parse_and_eval('$__stream->rdbuf()') self._was_redirected = self._streambuf != val['_M_stringbuf'].address def to_string(self): if self._was_redirected: return "%s redirected to %s" % ( self._typename, self._streambuf.dereference()) return self._val['_M_stringbuf'] def display_hint(self): if self._was_redirected: return None return 'string' class Tr1HashtableIterator(Iterator): def __init__(self, hashtable): self._buckets = hashtable['_M_buckets'] self._bucket = 0 self._bucket_count = hashtable['_M_bucket_count'] self._node_type = find_type(hashtable.type, '_Node').pointer() self._node = 0 while self._bucket != self._bucket_count: self._node = self._buckets[self._bucket] if self._node: break self._bucket = self._bucket + 1 def __iter__(self): return self def __next__(self): if self._node == 0: raise StopIteration node = self._node.cast(self._node_type) result = node.dereference()['_M_v'] self._node = node.dereference()['_M_next'] if self._node == 0: self._bucket = self._bucket + 1 while self._bucket != self._bucket_count: self._node = self._buckets[self._bucket] if self._node: break self._bucket = self._bucket + 1 return result class StdHashtableIterator(Iterator): def __init__(self, hashtable): self._node = hashtable['_M_before_begin']['_M_nxt'] valtype = hashtable.type.template_argument(1) cached = hashtable.type.template_argument(9).template_argument(0) node_type = lookup_templ_spec('std::__detail::_Hash_node', str(valtype), 'true' if cached else 'false') self._node_type = node_type.pointer() def __iter__(self): return self def __next__(self): if self._node == 0: raise StopIteration elt = self._node.cast(self._node_type).dereference() self._node = elt['_M_nxt'] valptr = elt['_M_storage'].address valptr = valptr.cast(elt.type.template_argument(0).pointer()) return valptr.dereference() class Tr1UnorderedSetPrinter(printer_base): """Print a std::unordered_set or tr1::unordered_set.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def _hashtable(self): if self._typename.startswith('std::tr1'): return self._val return self._val['_M_h'] def to_string(self): count = self._hashtable()['_M_element_count'] return '%s with %s' % (self._typename, num_elements(count)) @staticmethod def _format_count(i): return '[%d]' % i def children(self): counter = imap(self._format_count, itertools.count()) if self._typename.startswith('std::tr1'): return izip(counter, Tr1HashtableIterator(self._hashtable())) return izip(counter, StdHashtableIterator(self._hashtable())) class Tr1UnorderedMapPrinter(printer_base): """Print a std::unordered_map or tr1::unordered_map.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def _hashtable(self): if self._typename.startswith('std::tr1'): return self._val return self._val['_M_h'] def to_string(self): count = self._hashtable()['_M_element_count'] return '%s with %s' % (self._typename, num_elements(count)) @staticmethod def _flatten(list): for elt in list: for i in elt: yield i @staticmethod def _format_one(elt): return (elt['first'], elt['second']) @staticmethod def _format_count(i): return '[%d]' % i def children(self): counter = imap(self._format_count, itertools.count()) # Map over the hash table and flatten the result. if self._typename.startswith('std::tr1'): data = self._flatten( imap(self._format_one, Tr1HashtableIterator(self._hashtable()))) # Zip the two iterators together. return izip(counter, data) data = self._flatten( imap(self._format_one, StdHashtableIterator(self._hashtable()))) # Zip the two iterators together. return izip(counter, data) def display_hint(self): return 'map' class StdForwardListPrinter(printer_base): """Print a std::forward_list.""" class _iterator(Iterator): def __init__(self, nodetype, head): self._nodetype = nodetype self._base = head['_M_next'] self._count = 0 def __iter__(self): return self def __next__(self): if self._base == 0: raise StopIteration elt = self._base.cast(self._nodetype).dereference() self._base = elt['_M_next'] count = self._count self._count = self._count + 1 valptr = elt['_M_storage'].address valptr = valptr.cast(elt.type.template_argument(0).pointer()) return ('[%d]' % count, valptr.dereference()) def __init__(self, typename, val): self._val = val self._typename = strip_versioned_namespace(typename) def children(self): nodetype = lookup_node_type('_Fwd_list_node', self._val.type).pointer() return self._iterator(nodetype, self._val['_M_impl']['_M_head']) def to_string(self): if self._val['_M_impl']['_M_head']['_M_next'] == 0: return 'empty %s' % self._typename return '%s' % self._typename class SingleObjContainerPrinter(printer_base): """Base class for printers of containers of single objects.""" def __init__(self, val, viz, hint=None): self._contained_value = val self._visualizer = viz self._hint = hint def _recognize(self, type): """Return type as a string after applying type printers.""" global _use_type_printing if not _use_type_printing: return str(type) return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(), type) or str(type) class _contained(Iterator): def __init__(self, val): self._val = val def __iter__(self): return self def __next__(self): if self._val is None: raise StopIteration retval = self._val self._val = None return ('[contained value]', retval) def children(self): if self._contained_value is None: return self._contained(None) if hasattr(self._visualizer, 'children'): return self._visualizer.children() return self._contained(self._contained_value) def display_hint(self): if (hasattr(self._visualizer, 'children') and hasattr(self._visualizer, 'display_hint')): # If contained value is a map we want to display in the same way. return self._visualizer.display_hint() return self._hint def function_pointer_to_name(f): """Find the name of the function referred to by the gdb.Value f, which should contain a function pointer from the program.""" # Turn the function pointer into an actual address. # This is needed to unpack ppc64 function descriptors. f = f.dereference().address if sys.version_info[0] == 2: # Older versions of GDB need to use long for Python 2, # because int(f) on 64-bit big-endian values raises a # gdb.error saying "Cannot convert value to int." f = long(f) else: f = int(f) try: # If the function can't be found older versions of GDB raise a # RuntimeError saying "Cannot locate object file for block." return gdb.block_for_pc(f).function.name except: return None class StdExpAnyPrinter(SingleObjContainerPrinter): """Print a std::any or std::experimental::any.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._typename = strip_fundts_namespace(self._typename) self._val = val self._contained_type = None contained_value = None visualizer = None mgr = self._val['_M_manager'] if mgr != 0: func = function_pointer_to_name(mgr) if not func: raise ValueError( "Invalid function pointer in %s" % (self._typename)) # We want to use this regular expression: # T::_Manager_xxx<.*>::_S_manage\(T::_Op, const T\*, T::_Arg\*\) # where T is std::any or std::experimental::any. # But we need to account for variances in demangled names # between GDB versions, e.g. 'enum T::_Op' instead of 'T::_Op'. rx = ( r"({0}::_Manager_\w+<.*>)::_S_manage\(" r"(enum )?{0}::_Op, (const {0}|{0} const) ?\*, " r"(union )?{0}::_Arg ?\*\)" ).format(typename) m = re.match(rx, func) if not m: raise ValueError( "Unknown manager function in %s" % self._typename) mgrname = m.group(1) # FIXME need to expand 'std::string' so that gdb.lookup_type works if 'std::string' in mgrname: mgrtypes = [] for s in StdExpAnyPrinter._string_types(): try: x = re.sub(r"std::string(?!\w)", s, m.group(1)) # The following lookup might raise gdb.error if the # manager function was never instantiated for 's' in # the program, because there will be no such type. mgrtypes.append(gdb.lookup_type(x)) except gdb.error: pass if len(mgrtypes) != 1: # FIXME: this is unlikely in practice, but possible for # programs that use both old and new string types with # std::any in a single program. Can we do better? # Maybe find the address of each type's _S_manage and # compare to the address stored in _M_manager? raise ValueError( 'Cannot uniquely determine std::string type ' 'used in std::any' ) mgrtype = mgrtypes[0] else: mgrtype = gdb.lookup_type(mgrname) self._contained_type = mgrtype.template_argument(0) valptr = None if '::_Manager_internal' in mgrname: valptr = self._val['_M_storage']['_M_buffer'].address elif '::_Manager_external' in mgrname: valptr = self._val['_M_storage']['_M_ptr'] else: raise ValueError( "Unknown manager function in %s" % self._typename) contained_value = valptr.cast( self._contained_type.pointer()).dereference() visualizer = gdb.default_visualizer(contained_value) super(StdExpAnyPrinter, self).__init__(contained_value, visualizer) def to_string(self): if self._contained_type is None: return '%s [no contained value]' % self._typename desc = "%s containing " % self._typename if hasattr(self._visualizer, 'children'): return desc + self._visualizer.to_string() valtype = self._recognize(self._contained_type) return desc + strip_versioned_namespace(str(valtype)) @staticmethod def _string_types(): # This lookup for std::string might return the __cxx11 version, # but that's not necessarily the one used by the std::any # manager function we're trying to find. strings = {str(gdb.lookup_type('std::string').strip_typedefs())} # So also consider all the other possible std::string types! s = 'basic_string, std::allocator >' quals = ['std::', 'std::__cxx11::', 'std::' + _versioned_namespace] strings |= {q + s for q in quals} # set of unique strings return strings class StdExpOptionalPrinter(SingleObjContainerPrinter): """Print a std::optional or std::experimental::optional.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._typename = strip_fundts_namespace(self._typename) payload = val['_M_payload'] if self._typename.startswith('std::experimental'): engaged = val['_M_engaged'] contained_value = payload else: engaged = payload['_M_engaged'] contained_value = payload['_M_payload'] try: # Since GCC 9 contained_value = contained_value['_M_value'] except: pass visualizer = gdb.default_visualizer(contained_value) if not engaged: contained_value = None super(StdExpOptionalPrinter, self).__init__( contained_value, visualizer) def to_string(self): if self._contained_value is None: return "%s [no contained value]" % self._typename if hasattr(self._visualizer, 'children'): return "%s containing %s" % (self._typename, self._visualizer.to_string()) return self._typename class StdVariantPrinter(SingleObjContainerPrinter): """Print a std::variant.""" def __init__(self, typename, val): alternatives = get_template_arg_list(val.type) self._typename = strip_versioned_namespace(typename) self._index = val['_M_index'] if self._index >= len(alternatives): self._contained_type = None contained_value = None visualizer = None else: self._contained_type = alternatives[int(self._index)] addr = val['_M_u']['_M_first']['_M_storage'].address contained_value = addr.cast( self._contained_type.pointer()).dereference() visualizer = gdb.default_visualizer(contained_value) super(StdVariantPrinter, self).__init__( contained_value, visualizer, 'array') def to_string(self): if self._contained_value is None: return "%s [no contained value]" % self._typename if hasattr(self._visualizer, 'children'): return "%s [index %d] containing %s" % (self._typename, self._index, self._visualizer.to_string()) return "%s [index %d]" % (self._typename, self._index) class StdNodeHandlePrinter(SingleObjContainerPrinter): """Print a container node handle.""" def __init__(self, typename, val): self._value_type = val.type.template_argument(1) nodetype = val.type.template_argument(2).template_argument(0) self._is_rb_tree_node = is_specialization_of( nodetype.name, '_Rb_tree_node') self._is_map_node = val.type.template_argument(0) != self._value_type nodeptr = val['_M_ptr'] if nodeptr: if self._is_rb_tree_node: contained_value = get_value_from_Rb_tree_node( nodeptr.dereference()) else: contained_value = get_value_from_aligned_membuf(nodeptr['_M_storage'], self._value_type) visualizer = gdb.default_visualizer(contained_value) else: contained_value = None visualizer = None optalloc = val['_M_alloc'] self._alloc = optalloc['_M_payload'] if optalloc['_M_engaged'] else None super(StdNodeHandlePrinter, self).__init__(contained_value, visualizer, 'array') def to_string(self): desc = 'node handle for ' if not self._is_rb_tree_node: desc += 'unordered ' if self._is_map_node: desc += 'map' else: desc += 'set' if self._contained_value: desc += ' with element' if hasattr(self._visualizer, 'children'): return "%s = %s" % (desc, self._visualizer.to_string()) return desc else: return 'empty %s' % desc class StdExpStringViewPrinter(printer_base): """ Print a std::basic_string_view or std::experimental::basic_string_view """ def __init__(self, typename, val): self._val = val def to_string(self): ptr = self._val['_M_str'] len = self._val['_M_len'] if hasattr(ptr, "lazy_string"): return ptr.lazy_string(length=len) return ptr.string(length=len) def display_hint(self): return 'string' class StdExpPathPrinter(printer_base): """Print a std::experimental::filesystem::path.""" def __init__(self, typename, val): self._val = val self._typename = typename start = self._val['_M_cmpts']['_M_impl']['_M_start'] finish = self._val['_M_cmpts']['_M_impl']['_M_finish'] self._num_cmpts = int(finish - start) def _path_type(self): t = str(self._val['_M_type']) if t[-9:] == '_Root_dir': return "root-directory" if t[-10:] == '_Root_name': return "root-name" return None def to_string(self): path = "%s" % self._val['_M_pathname'] if self._num_cmpts == 0: t = self._path_type() if t: path = '%s [%s]' % (path, t) return "experimental::filesystem::path %s" % path class _iterator(Iterator): def __init__(self, cmpts, pathtype): self._pathtype = pathtype self._item = cmpts['_M_impl']['_M_start'] self._finish = cmpts['_M_impl']['_M_finish'] self._count = 0 def __iter__(self): return self def __next__(self): if self._item == self._finish: raise StopIteration item = self._item.dereference() count = self._count self._count = self._count + 1 self._item = self._item + 1 path = item['_M_pathname'] t = StdExpPathPrinter(self._pathtype, item)._path_type() if not t: t = count return ('[%s]' % t, path) def children(self): return self._iterator(self._val['_M_cmpts'], self._typename) class StdPathPrinter(printer_base): """Print a std::filesystem::path.""" def __init__(self, typename, val): self._val = val self._typename = typename impl = unique_ptr_get(self._val['_M_cmpts']['_M_impl']) self._type = impl.cast(gdb.lookup_type('uintptr_t')) & 3 if self._type == 0: self._impl = impl else: self._impl = None def _path_type(self): t = str(self._type.cast(gdb.lookup_type(self._typename + '::_Type'))) if t[-9:] == '_Root_dir': return "root-directory" if t[-10:] == '_Root_name': return "root-name" return None def to_string(self): path = "%s" % self._val['_M_pathname'] if self._type != 0: t = self._path_type() if t: path = '%s [%s]' % (path, t) return "filesystem::path %s" % path class _iterator(Iterator): def __init__(self, impl, pathtype): self._pathtype = pathtype if impl: # We can't access _Impl::_M_size because _Impl is incomplete # so cast to int* to access the _M_size member at offset zero, int_type = gdb.lookup_type('int') cmpt_type = gdb.lookup_type(pathtype + '::_Cmpt') char_type = gdb.lookup_type('char') impl = impl.cast(int_type.pointer()) size = impl.dereference() #self._capacity = (impl + 1).dereference() if hasattr(gdb.Type, 'alignof'): sizeof_Impl = max(2 * int_type.sizeof, cmpt_type.alignof) else: sizeof_Impl = 2 * int_type.sizeof begin = impl.cast(char_type.pointer()) + sizeof_Impl self._item = begin.cast(cmpt_type.pointer()) self._finish = self._item + size self._count = 0 else: self._item = None self._finish = None def __iter__(self): return self def __next__(self): if self._item == self._finish: raise StopIteration item = self._item.dereference() count = self._count self._count = self._count + 1 self._item = self._item + 1 path = item['_M_pathname'] t = StdPathPrinter(self._pathtype, item)._path_type() if not t: t = count return ('[%s]' % t, path) def children(self): return self._iterator(self._impl, self._typename) class StdPairPrinter(printer_base): """Print a std::pair object, with 'first' and 'second' as children.""" def __init__(self, typename, val): self._val = val class _iter(Iterator): """An iterator for std::pair types. Returns 'first' then 'second'.""" def __init__(self, val): self._val = val self._which = 'first' def __iter__(self): return self def __next__(self): if self._which is None: raise StopIteration which = self._which if which == 'first': self._which = 'second' else: self._which = None return (which, self._val[which]) def children(self): return self._iter(self._val) def to_string(self): return None class StdCmpCatPrinter(printer_base): """Print a comparison category object.""" def __init__(self, typename, val): self._typename = typename[typename.rfind(':') + 1:] self._val = val['_M_value'] def to_string(self): if self._typename == 'strong_ordering' and self._val == 0: name = 'equal' else: names = {2: 'unordered', -1: 'less', 0: 'equivalent', 1: 'greater'} name = names[int(self._val)] return 'std::{}::{}'.format(self._typename, name) class StdErrorCodePrinter(printer_base): """Print a std::error_code or std::error_condition.""" _system_is_posix = None # Whether std::system_category() use errno values. def __init__(self, typename, val): self._val = val self._typename = strip_versioned_namespace(typename) # Do this only once ... if StdErrorCodePrinter._system_is_posix is None: try: import posix StdErrorCodePrinter._system_is_posix = True except ImportError: StdErrorCodePrinter._system_is_posix = False @staticmethod def _find_errc_enum(name): typ = gdb.lookup_type(name) if typ is not None and typ.code == gdb.TYPE_CODE_ENUM: return typ return None @classmethod def _find_standard_errc_enum(cls, name): for ns in ['', _versioned_namespace]: try: qname = 'std::{}{}'.format(ns, name) return cls._find_errc_enum(qname) except RuntimeError: pass @classmethod def _match_net_ts_category(cls, cat): net_cats = ['stream', 'socket', 'ip::resolver'] for c in net_cats: func = c + '_category()' for ns in ['', _versioned_namespace]: ns = 'std::{}experimental::net::v1'.format(ns) sym = gdb.lookup_symbol('{}::{}::__c'.format(ns, func))[0] if sym is not None: if cat == sym.value().address: name = 'net::' + func enum = cls._find_errc_enum('{}::{}_errc'.format(ns, c)) return (name, enum) return (None, None) @classmethod def _category_info(cls, cat): """Return details of a std::error_category.""" name = None enum = None is_errno = False # Try these first, or we get "warning: RTTI symbol not found" when # using cat.dynamic_type on the local class types for Net TS # categories. func, enum = cls._match_net_ts_category(cat) if func is not None: return (None, func, enum, is_errno) # This might give a warning for a program-defined category defined as # a local class, but there doesn't seem to be any way to avoid that. typ = cat.dynamic_type.target() # Shortcuts for the known categories defined by libstdc++. if typ.tag.endswith('::generic_error_category'): name = 'generic' is_errno = True if typ.tag.endswith('::system_error_category'): name = 'system' is_errno = cls._system_is_posix if typ.tag.endswith('::future_error_category'): name = 'future' enum = cls._find_standard_errc_enum('future_errc') if typ.tag.endswith('::io_error_category'): name = 'io' enum = cls._find_standard_errc_enum('io_errc') if name is None: try: # Want to call std::error_category::name() override, but it's # unsafe: https://sourceware.org/bugzilla/show_bug.cgi?id=28856 # gdb.set_convenience_variable('__cat', cat) # return '"%s"' % gdb.parse_and_eval('$__cat->name()').string() pass except: pass return (name, typ.tag, enum, is_errno) @staticmethod def _unqualified_name(name): """ Strip any nested-name-specifier from name to give an unqualified name. """ return name.split('::')[-1] def to_string(self): value = self._val['_M_value'] cat = self._val['_M_cat'] name, alt_name, enum, is_errno = self._category_info(cat) if value == 0: default_cats = {'error_code': 'system', 'error_condition': 'generic'} if name == default_cats[self._unqualified_name(self._typename)]: return self._typename + ' = { }' # default-constructed value strval = str(value) if is_errno and value != 0: try: strval = errno.errorcode[int(value)] except: pass elif enum is not None: strval = self._unqualified_name(str(value.cast(enum))) if name is not None: name = '"%s"' % name else: name = alt_name return '%s = {%s: %s}' % (self._typename, name, strval) class StdRegexStatePrinter(printer_base): """Print a state node in the NFA for a std::regex.""" def __init__(self, typename, val): self._val = val self._typename = typename def to_string(self): opcode = str(self._val['_M_opcode']) if opcode: opcode = opcode[25:] next_id = self._val['_M_next'] variants = {'repeat': 'alt', 'alternative': 'alt', 'subexpr_begin': 'subexpr', 'subexpr_end': 'subexpr', 'line_begin_assertion': None, 'line_end_assertion': None, 'word_boundary': 'neg', 'subexpr_lookahead': 'neg', 'backref': 'backref_index', 'match': None, 'accept': None, 'dummy': None, 'unknown': None } v = variants[opcode] s = "opcode={}, next={}".format(opcode, next_id) if v is not None and self._val['_M_' + v] is not None: s = "{}, {}={}".format(s, v, self._val['_M_' + v]) return "{%s}" % (s) class StdSpanPrinter(printer_base): """Print a std::span.""" class _iterator(Iterator): def __init__(self, begin, size): self._count = 0 self._begin = begin self._size = size def __iter__(self): return self def __next__(self): if self._count == self._size: raise StopIteration count = self._count self._count = self._count + 1 return '[%d]' % count, (self._begin + count).dereference() def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val size_max = gdb.parse_and_eval('static_cast(-1)') if val.type.template_argument(1) == size_max: self._size = val['_M_extent']['_M_extent_value'] else: self._size = val.type.template_argument(1) def to_string(self): return '%s of length %d' % (self._typename, self._size) def children(self): return self._iterator(self._val['_M_ptr'], self._size) def display_hint(self): return 'array' class StdInitializerListPrinter(printer_base): """Print a std::initializer_list.""" def __init__(self, typename, val): self._typename = typename self._val = val self._size = val['_M_len'] def to_string(self): return '%s of length %d' % (self._typename, self._size) def children(self): return StdSpanPrinter._iterator(self._val['_M_array'], self._size) def display_hint(self): return 'array' class StdAtomicPrinter(printer_base): """Print a std:atomic.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val self._shptr_printer = None self._value_type = self._val.type.template_argument(0) if self._value_type.tag is not None: typ = strip_versioned_namespace(self._value_type.tag) if (typ.startswith('std::shared_ptr<') or typ.startswith('std::weak_ptr<')): impl = val['_M_impl'] self._shptr_printer = SharedPointerPrinter(typename, impl) self.children = self._shptr_children def _shptr_children(self): return SmartPtrIterator(self._shptr_printer._pointer) def to_string(self): if self._shptr_printer is not None: return self._shptr_printer.to_string() if self._value_type.code == gdb.TYPE_CODE_INT: val = self._val['_M_i'] elif self._value_type.code == gdb.TYPE_CODE_FLT: val = self._val['_M_fp'] elif self._value_type.code == gdb.TYPE_CODE_PTR: val = self._val['_M_b']['_M_p'] elif self._value_type.code == gdb.TYPE_CODE_BOOL: val = self._val['_M_base']['_M_i'] else: val = self._val['_M_i'] return '%s<%s> = { %s }' % (self._typename, str(self._value_type), val) class StdFormatArgsPrinter(printer_base): """Print a std::basic_format_args.""" # TODO: add printer for basic_format_arg and print out children. # TODO: add printer for __format::_ArgStore. def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): targs = get_template_arg_list(self._val.type) char_type = get_template_arg_list(targs[0])[1] if char_type == gdb.lookup_type('char'): typ = 'std::format_args' elif char_type == gdb.lookup_type('wchar_t'): typ = 'std::wformat_args' else: typ = 'std::basic_format_args' size = self._val['_M_packed_size'] if size == 1: return "%s with 1 argument" % (typ) if size == 0: size = self._val['_M_unpacked_size'] return "%s with %d arguments" % (typ, size) class StdChronoDurationPrinter(printer_base): """Print a std::chrono::duration.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def _ratio(self): # TODO use reduced period i.e. duration::period period = self._val.type.template_argument(1) num = period.template_argument(0) den = period.template_argument(1) return (num, den) def _suffix(self): num, den = self._ratio() if num == 1: if den == 1: return 's' if den == 1000: return 'ms' if den == 1000000: return 'us' if den == 1000000000: return 'ns' elif den == 1: if num == 60: return 'min' if num == 3600: return 'h' if num == 86400: return 'd' return '[{}]s'.format(num) return "[{}/{}]s".format(num, den) def to_string(self): r = self._val['__r'] if r.type.strip_typedefs().code == gdb.TYPE_CODE_FLT: r = "%g" % r return "std::chrono::duration = {{ {}{} }}".format(r, self._suffix()) class StdChronoTimePointPrinter(printer_base): """Print a std::chrono::time_point.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def _clock(self): clock = self._val.type.template_argument(0) name = strip_versioned_namespace(clock.name) if name == 'std::chrono::_V2::system_clock' \ or name == 'std::chrono::system_clock': return ('std::chrono::sys_time', 0) # XXX need to remove leap seconds from utc, gps, and tai if name == 'std::chrono::utc_clock': return ('std::chrono::utc_time', None) # XXX if name == 'std::chrono::gps_clock': return ('std::chrono::gps_time', None) # XXX 315964809 if name == 'std::chrono::tai_clock': return ('std::chrono::tai_time', None) # XXX -378691210 if name == 'std::filesystem::__file_clock': return ('std::chrono::file_time', 6437664000) if name == 'std::chrono::local_t': return ('std::chrono::local_time', 0) return ('{} time_point'.format(name), None) def to_string(self, abbrev=False): clock, offset = self._clock() d = self._val['__d'] r = d['__r'] printer = StdChronoDurationPrinter(d.type.name, d) suffix = printer._suffix() time = '' if offset is not None: num, den = printer._ratio() secs = (r * num / den) + offset try: dt = datetime.datetime.fromtimestamp(secs, _utc_timezone) time = ' [{:%Y-%m-%d %H:%M:%S}]'.format(dt) except: pass s = '%d%s%s' % (r, suffix, time) if abbrev: return s return '%s = { %s }' % (clock, s) class StdChronoZonedTimePrinter(printer_base): """Print a std::chrono::zoned_time.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): zone = self._val['_M_zone'].dereference()['_M_name'] time = self._val['_M_tp'] printer = StdChronoTimePointPrinter(time.type.name, time) time = printer.to_string(True) return 'std::chrono::zoned_time = {{ {} {} }}'.format(zone, time) months = [None, 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] class StdChronoCalendarPrinter(printer_base): """Print a std::chrono::day, std::chrono::month, std::chrono::year etc.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): val = self._val typ = self._typename if 'month' in typ and typ != 'std::chrono::year_month_day_last': m = val['_M_m'] if typ.startswith('std::chrono::year'): y = val['_M_y'] if typ == 'std::chrono::day': return '{}'.format(int(val['_M_d'])) if typ == 'std::chrono::month': if m < 1 or m >= len(months): return "%d is not a valid month" % m return months[m] if typ == 'std::chrono::year': return '{}y'.format(y) if typ == 'std::chrono::weekday': wd = val['_M_wd'] if wd < 0 or wd >= len(weekdays): return "%d is not a valid weekday" % wd return '{}'.format(weekdays[wd]) if typ == 'std::chrono::weekday_indexed': return '{}[{}]'.format(val['_M_wd'], int(val['_M_index'])) if typ == 'std::chrono::weekday_last': return '{}[last]'.format(val['_M_wd']) if typ == 'std::chrono::month_day': return '{}/{}'.format(m, val['_M_d']) if typ == 'std::chrono::month_day_last': return '{}/last'.format(m) if typ == 'std::chrono::month_weekday': return '{}/{}'.format(m, val['_M_wdi']) if typ == 'std::chrono::month_weekday_last': return '{}/{}'.format(m, val['_M_wdl']) if typ == 'std::chrono::year_month': return '{}/{}'.format(y, m) if typ == 'std::chrono::year_month_day': return '{}/{}/{}'.format(y, m, val['_M_d']) if typ == 'std::chrono::year_month_day_last': return '{}/{}'.format(y, val['_M_mdl']) if typ == 'std::chrono::year_month_weekday': return '{}/{}/{}'.format(y, m, val['_M_wdi']) if typ == 'std::chrono::year_month_weekday_last': return '{}/{}/{}'.format(y, m, val['_M_wdl']) if typ.startswith('std::chrono::hh_mm_ss'): fract = '' if val['fractional_width'] != 0: fract = '.{:0{}d}'.format(int(val['_M_ss']['_M_r']), int(val['fractional_width'])) h = int(val['_M_h']['__r']) m = int(val['_M_m']['__r']) s = int(val['_M_s']['__r']) if val['_M_is_neg']: h = -h return '{:02}:{:02}:{:02}{}'.format(h, m, s, fract) class StdChronoTimeZonePrinter(printer_base): """Print a chrono::time_zone or chrono::time_zone_link.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): str = '%s = %s' % (self._typename, self._val['_M_name']) if self._typename.endswith("_link"): str += ' -> %s' % (self._val['_M_target']) return str class StdChronoLeapSecondPrinter(printer_base): """Print a chrono::leap_second.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): date = self._val['_M_s']['__r'] neg = '+-'[date < 0] return '%s %d (%c)' % (self._typename, abs(date), neg) class StdChronoTzdbPrinter(printer_base): """Print a chrono::tzdb.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): return '%s %s' % (self._typename, self._val['version']) class StdChronoTimeZoneRulePrinter(printer_base): """Print a chrono::time_zone rule.""" def __init__(self, typename, val): self._typename = strip_versioned_namespace(typename) self._val = val def to_string(self): on = self._val['on'] kind = on['kind'] month = months[on['month']] suffixes = {1: 'st', 2: 'nd', 3: 'rd', 21: 'st', 22: 'nd', 23: 'rd', 31: 'st'} day = on['day_of_month'] ordinal_day = '{}{}'.format(day, suffixes.get(day, 'th')) if kind == 0: # DayOfMonth start = '{} {}'.format(month, ordinal_day) else: weekday = weekdays[on['day_of_week']] if kind == 1: # LastWeekDay start = 'last {} in {}'.format(weekday, month) else: if kind == 2: # LessEq direction = ('last', '<=') else: direction = ('first', '>=') day = on['day_of_month'] start = '{} {} {} {} {}'.format(direction[0], weekday, direction[1], month, ordinal_day) return 'time_zone rule {} from {} to {} starting on {}'.format( self._val['name'], self._val['from'], self._val['to'], start) class StdLocalePrinter(printer_base): """Print a std::locale.""" def __init__(self, typename, val): self._val = val self._typename = typename def to_string(self): names = self._val['_M_impl']['_M_names'] mod = '' if names[0] == 0: name = '*' else: cats = gdb.parse_and_eval(self._typename + '::_S_categories') ncat = gdb.parse_and_eval(self._typename + '::_S_categories_size') n = names[0].string() cat = cats[0].string() name = '{}={}'.format(cat, n) cat_names = {cat: n} i = 1 while i < ncat and names[i] != 0: n = names[i].string() cat = cats[i].string() name = '{};{}={}'.format(name, cat, n) cat_names[cat] = n i = i + 1 uniq_names = set(cat_names.values()) if len(uniq_names) == 1: name = n elif len(uniq_names) == 2: n1, n2 = (uniq_names) name_list = list(cat_names.values()) other = None if name_list.count(n1) == 1: name = n2 other = n1 elif name_list.count(n2) == 1: name = n1 other = n2 if other is not None: cat = next(c for c, n in cat_names.items() if n == other) mod = ' with "{}={}"'.format(cat, other) return 'std::locale = "{}"{}'.format(name, mod) class StdIntegralConstantPrinter(printer_base): """Print a std::true_type or std::false_type.""" def __init__(self, typename, val): self._val = val self._typename = typename def to_string(self): value_type = self._val.type.template_argument(0) value = self._val.type.template_argument(1) if value_type.code == gdb.TYPE_CODE_BOOL: if value: return "std::true_type" else: return "std::false_type" typename = strip_versioned_namespace(self._typename) return "{}<{}, {}>".format(typename, value_type, value) class StdTextEncodingPrinter(printer_base): """Print a std::text_encoding.""" def __init__(self, typename, val): self._val = val self._typename = typename def to_string(self): rep = self._val['_M_rep'].dereference() if rep['_M_id'] == 1: return self._val['_M_name'] if rep['_M_id'] == 2: return 'unknown' return rep['_M_name'] # A "regular expression" printer which conforms to the # "SubPrettyPrinter" protocol from gdb.printing. class RxPrinter(object): def __init__(self, name, function): super(RxPrinter, self).__init__() self.name = name self._function = function self.enabled = True def invoke(self, value): if not self.enabled: return None if value.type.code == gdb.TYPE_CODE_REF: if hasattr(gdb.Value, "referenced_value"): value = value.referenced_value() return self._function(self.name, value) # A pretty-printer that conforms to the "PrettyPrinter" protocol from # gdb.printing. It can also be used directly as an old-style printer. class Printer(object): def __init__(self, name): super(Printer, self).__init__() self.name = name self._subprinters = [] self._lookup = {} self.enabled = True self._compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$') def add(self, name, function): # A small sanity check. # FIXME if not self._compiled_rx.match(name): raise ValueError( 'libstdc++ programming error: "%s" does not match' % name) printer = RxPrinter(name, function) self._subprinters.append(printer) self._lookup[name] = printer # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION. def add_version(self, base, name, function): self.add(base + name, function) if '__cxx11' not in base: vbase = re.sub('^(std|__gnu_cxx)::', r'\g<0>%s' % _versioned_namespace, base) self.add(vbase + name, function) # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER. def add_container(self, base, name, function): self.add_version(base, name, function) self.add_version(base + '__cxx1998::', name, function) @staticmethod def get_basic_type(type): # If it points to a reference, get the reference. if type.code == gdb.TYPE_CODE_REF: type = type.target() # Get the unqualified type, stripped of typedefs. type = type.unqualified().strip_typedefs() return type.tag def __call__(self, val): typename = self.get_basic_type(val.type) if not typename: return None # All the types we match are template types, so we can use a # dictionary. match = self._compiled_rx.match(typename) if not match: return None basename = match.group(1) if val.type.code == gdb.TYPE_CODE_REF: if hasattr(gdb.Value, "referenced_value"): val = val.referenced_value() if basename in self._lookup: return self._lookup[basename].invoke(val) # Cannot find a pretty printer. Return None. return None libstdcxx_printer = None class TemplateTypePrinter(object): """ A type printer for class templates with default template arguments. Recognizes specializations of class templates and prints them without any template arguments that use a default template argument. Type printers are recursively applied to the template arguments. e.g. replace 'std::vector >' with 'std::vector'. """ def __init__(self, name, defargs): self.name = name self._defargs = defargs self.enabled = True class _recognizer(object): """The recognizer class for TemplateTypePrinter.""" def __init__(self, name, defargs): self.name = name self._defargs = defargs # self._type_obj = None def recognize(self, type_obj): """ If type_obj is a specialization of self.name that uses all the default template arguments for the class template, then return a string representation of the type without default arguments. Otherwise, return None. """ if type_obj.tag is None: return None if not type_obj.tag.startswith(self.name): return None template_args = get_template_arg_list(type_obj) displayed_args = [] require_defaulted = False for n in range(len(template_args)): # The actual template argument in the type: targ = template_args[n] # The default template argument for the class template: defarg = self._defargs.get(n) if defarg is not None: # Substitute other template arguments into the default: defarg = defarg.format(*template_args) # Fail to recognize the type (by returning None) # unless the actual argument is the same as the default. try: if targ != gdb.lookup_type(defarg): return None except gdb.error: # Type lookup failed, just use string comparison: if targ.tag != defarg: return None # All subsequent args must have defaults: require_defaulted = True elif require_defaulted: return None else: # Recursively apply recognizers to the template argument # and add it to the arguments that will be displayed: displayed_args.append(self._recognize_subtype(targ)) # This assumes no class templates in the nested-name-specifier: template_name = type_obj.tag[0:type_obj.tag.find('<')] template_name = strip_inline_namespaces(template_name) return template_name + '<' + ', '.join(displayed_args) + '>' def _recognize_subtype(self, type_obj): """Convert a gdb.Type to a string by applying recognizers, or if that fails then simply converting to a string.""" if type_obj.code == gdb.TYPE_CODE_PTR: return self._recognize_subtype(type_obj.target()) + '*' if type_obj.code == gdb.TYPE_CODE_ARRAY: type_str = self._recognize_subtype(type_obj.target()) if str(type_obj.strip_typedefs()).endswith('[]'): return type_str + '[]' # array of unknown bound return "%s[%d]" % (type_str, type_obj.range()[1] + 1) if type_obj.code == gdb.TYPE_CODE_REF: return self._recognize_subtype(type_obj.target()) + '&' if hasattr(gdb, 'TYPE_CODE_RVALUE_REF'): if type_obj.code == gdb.TYPE_CODE_RVALUE_REF: return self._recognize_subtype(type_obj.target()) + '&&' type_str = gdb.types.apply_type_recognizers( gdb.types.get_type_recognizers(), type_obj) if type_str: return type_str return str(type_obj) def instantiate(self): """Return a recognizer object for this type printer.""" return self._recognizer(self.name, self._defargs) def add_one_template_type_printer(obj, name, defargs): """ Add a type printer for a class template with default template arguments. Args: name (str): The template-name of the class template. defargs (dict int:string) The default template arguments. Types in defargs can refer to the Nth template-argument using {N} (with zero-based indices). e.g. 'unordered_map' has these defargs: { 2: 'std::hash<{0}>', 3: 'std::equal_to<{0}>', 4: 'std::allocator >' } """ printer = TemplateTypePrinter('std::' + name, defargs) gdb.types.register_type_printer(obj, printer) # Add type printer for same type in debug namespace: printer = TemplateTypePrinter('std::__debug::' + name, defargs) gdb.types.register_type_printer(obj, printer) if '__cxx11' not in name: # Add second type printer for same type in versioned namespace: ns = 'std::' + _versioned_namespace # PR 86112 Cannot use dict comprehension here: defargs = dict((n, d.replace('std::', ns)) for (n, d) in defargs.items()) printer = TemplateTypePrinter(ns + name, defargs) gdb.types.register_type_printer(obj, printer) # Add type printer for same type in debug namespace: printer = TemplateTypePrinter('std::__debug::' + name, defargs) gdb.types.register_type_printer(obj, printer) class FilteringTypePrinter(object): """ A type printer that uses typedef names for common template specializations. Args: template (str): The class template to recognize. name (str): The typedef-name that will be used instead. targ1 (str, optional): The first template argument. Defaults to None. Checks if a specialization of the class template 'template' is the same type as the typedef 'name', and prints it as 'name' instead. e.g. if an instantiation of std::basic_istream is the same type as std::istream then print it as std::istream. If targ1 is provided (not None), match only template specializations with this type as the first template argument, e.g. if template='basic_string' and targ1='char' then only match 'basic_string' and not 'basic_string'. This rejects non-matching specializations more quickly, without needing to do GDB type lookups. """ def __init__(self, template, name, targ1=None): self._template = template self.name = name self._targ1 = targ1 self.enabled = True class _recognizer(object): """The recognizer class for FilteringTypePrinter.""" def __init__(self, template, name, targ1): self._template = template self.name = name self._targ1 = targ1 self._type_obj = None def recognize(self, type_obj): """ If type_obj starts with self._template and is the same type as self.name then return self.name, otherwise None. """ if type_obj.tag is None: return None if self._type_obj is None: if self._targ1 is not None: s = '{}<{}'.format(self._template, self._targ1) if not type_obj.tag.startswith(s): # Filter didn't match. return None elif not type_obj.tag.startswith(self._template): # Filter didn't match. return None try: self._type_obj = gdb.lookup_type( self.name).strip_typedefs() except: pass if self._type_obj is None: return None t1 = gdb.types.get_basic_type(self._type_obj) t2 = gdb.types.get_basic_type(type_obj) if t1 == t2: return strip_inline_namespaces(self.name) # Workaround ambiguous typedefs matching both std:: and # std::__cxx11:: symbols. if self._template.split('::')[-1] == 'basic_string': s1 = self._type_obj.tag.replace('__cxx11::', '') s2 = type_obj.tag.replace('__cxx11::', '') if s1 == s2: return strip_inline_namespaces(self.name) return None def instantiate(self): """Return a recognizer object for this type printer.""" return self._recognizer(self._template, self.name, self._targ1) def add_one_type_printer(obj, template, name, targ1=None): printer = FilteringTypePrinter('std::' + template, 'std::' + name, targ1) gdb.types.register_type_printer(obj, printer) if '__cxx11' not in template: ns = 'std::' + _versioned_namespace printer = FilteringTypePrinter(ns + template, ns + name, targ1) gdb.types.register_type_printer(obj, printer) def register_type_printers(obj): global _use_type_printing if not _use_type_printing: return # Add type printers for typedefs std::string, std::wstring etc. for ch in (('', 'char'), ('w', 'wchar_t'), ('u8', 'char8_t'), ('u16', 'char16_t'), ('u32', 'char32_t')): add_one_type_printer(obj, 'basic_string', ch[0] + 'string', ch[1]) add_one_type_printer(obj, '__cxx11::basic_string', ch[0] + 'string', ch[1]) # Typedefs for __cxx11::basic_string used to be in namespace __cxx11: add_one_type_printer(obj, '__cxx11::basic_string', '__cxx11::' + ch[0] + 'string', ch[1]) add_one_type_printer(obj, 'basic_string_view', ch[0] + 'string_view', ch[1]) # Add type printers for typedefs std::istream, std::wistream etc. for ch in (('', 'char'), ('w', 'wchar_t')): for x in ('ios', 'streambuf', 'istream', 'ostream', 'iostream', 'filebuf', 'ifstream', 'ofstream', 'fstream'): add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1]) for x in ('stringbuf', 'istringstream', 'ostringstream', 'stringstream'): add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1]) # types are in __cxx11 namespace, but typedefs aren't: add_one_type_printer(obj, '__cxx11::basic_' + x, ch[0] + x, ch[1]) # Add type printers for typedefs regex, wregex, cmatch, wcmatch etc. for abi in ('', '__cxx11::'): for ch in (('', 'char'), ('w', 'wchar_t')): add_one_type_printer(obj, abi + 'basic_regex', abi + ch[0] + 'regex', ch[1]) for ch in ('c', 's', 'wc', 'ws'): add_one_type_printer( obj, abi + 'match_results', abi + ch + 'match') for x in ('sub_match', 'regex_iterator', 'regex_token_iterator'): add_one_type_printer(obj, abi + x, abi + ch + x) # Note that we can't have a printer for std::wstreampos, because # it is the same type as std::streampos. add_one_type_printer(obj, 'fpos', 'streampos') # Add type printers for typedefs. for dur in ('nanoseconds', 'microseconds', 'milliseconds', 'seconds', 'minutes', 'hours', 'days', 'weeks', 'years', 'months'): add_one_type_printer(obj, 'chrono::duration', 'chrono::' + dur) # Add type printers for typedefs. add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0') add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand') add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937') add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937_64') add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux24_base') add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux48_base') add_one_type_printer(obj, 'discard_block_engine', 'ranlux24') add_one_type_printer(obj, 'discard_block_engine', 'ranlux48') add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b') # Add type printers for experimental::basic_string_view typedefs. ns = 'experimental::fundamentals_v1::' for ch in (('', 'char'), ('w', 'wchar_t'), ('u8', 'char8_t'), ('u16', 'char16_t'), ('u32', 'char32_t')): add_one_type_printer(obj, ns + 'basic_string_view', ns + ch[0] + 'string_view', ch[1]) # Do not show defaulted template arguments in class templates. add_one_template_type_printer(obj, 'unique_ptr', {1: 'std::default_delete<{0}>'}) add_one_template_type_printer(obj, 'deque', {1: 'std::allocator<{0}>'}) add_one_template_type_printer( obj, 'forward_list', {1: 'std::allocator<{0}>'}) add_one_template_type_printer(obj, 'list', {1: 'std::allocator<{0}>'}) add_one_template_type_printer( obj, '__cxx11::list', {1: 'std::allocator<{0}>'}) add_one_template_type_printer(obj, 'vector', {1: 'std::allocator<{0}>'}) add_one_template_type_printer(obj, 'map', {2: 'std::less<{0}>', 3: 'std::allocator>'}) add_one_template_type_printer(obj, 'multimap', {2: 'std::less<{0}>', 3: 'std::allocator>'}) add_one_template_type_printer(obj, 'set', {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'}) add_one_template_type_printer(obj, 'multiset', {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'}) add_one_template_type_printer(obj, 'unordered_map', {2: 'std::hash<{0}>', 3: 'std::equal_to<{0}>', 4: 'std::allocator>'}) add_one_template_type_printer(obj, 'unordered_multimap', {2: 'std::hash<{0}>', 3: 'std::equal_to<{0}>', 4: 'std::allocator>'}) add_one_template_type_printer(obj, 'unordered_set', {1: 'std::hash<{0}>', 2: 'std::equal_to<{0}>', 3: 'std::allocator<{0}>'}) add_one_template_type_printer(obj, 'unordered_multiset', {1: 'std::hash<{0}>', 2: 'std::equal_to<{0}>', 3: 'std::allocator<{0}>'}) def register_libstdcxx_printers(obj): """Register libstdc++ pretty-printers with objfile Obj.""" global _use_gdb_pp global libstdcxx_printer if _use_gdb_pp: gdb.printing.register_pretty_printer(obj, libstdcxx_printer) else: if obj is None: obj = gdb obj.pretty_printers.append(libstdcxx_printer) register_type_printers(obj) def build_libstdcxx_dictionary(): global libstdcxx_printer libstdcxx_printer = Printer("libstdc++-v6") # libstdc++ objects requiring pretty-printing. # In order from: # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter) libstdcxx_printer.add_version( 'std::__cxx11::', 'basic_string', StdStringPrinter) libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter) libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter) libstdcxx_printer.add_container('std::', 'list', StdListPrinter) libstdcxx_printer.add_container('std::__cxx11::', 'list', StdListPrinter) libstdcxx_printer.add_container('std::', 'map', StdMapPrinter) libstdcxx_printer.add_container('std::', 'multimap', StdMapPrinter) libstdcxx_printer.add_container('std::', 'multiset', StdSetPrinter) libstdcxx_printer.add_version('std::', 'pair', StdPairPrinter) libstdcxx_printer.add_version('std::', 'priority_queue', StdStackOrQueuePrinter) libstdcxx_printer.add_version('std::', 'queue', StdStackOrQueuePrinter) libstdcxx_printer.add_version('std::', 'tuple', StdTuplePrinter) libstdcxx_printer.add_container('std::', 'set', StdSetPrinter) libstdcxx_printer.add_version('std::', 'stack', StdStackOrQueuePrinter) libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter) libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter) # vector libstdcxx_printer.add_version('std::', 'locale', StdLocalePrinter) if hasattr(gdb.Value, 'dynamic_type'): libstdcxx_printer.add_version('std::', 'error_code', StdErrorCodePrinter) libstdcxx_printer.add_version('std::', 'error_condition', StdErrorCodePrinter) # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG. libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter) libstdcxx_printer.add('std::__debug::deque', StdDequePrinter) libstdcxx_printer.add('std::__debug::list', StdListPrinter) libstdcxx_printer.add('std::__debug::map', StdMapPrinter) libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter) libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter) libstdcxx_printer.add('std::__debug::set', StdSetPrinter) libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter) # These are the TR1 and C++11 printers. # For array - the default GDB pretty-printer seems reasonable. libstdcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter) libstdcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter) libstdcxx_printer.add_container('std::', 'unordered_map', Tr1UnorderedMapPrinter) libstdcxx_printer.add_container('std::', 'unordered_set', Tr1UnorderedSetPrinter) libstdcxx_printer.add_container('std::', 'unordered_multimap', Tr1UnorderedMapPrinter) libstdcxx_printer.add_container('std::', 'unordered_multiset', Tr1UnorderedSetPrinter) libstdcxx_printer.add_container('std::', 'forward_list', StdForwardListPrinter) libstdcxx_printer.add_version( 'std::tr1::', 'shared_ptr', SharedPointerPrinter) libstdcxx_printer.add_version( 'std::tr1::', 'weak_ptr', SharedPointerPrinter) libstdcxx_printer.add_version('std::tr1::', 'unordered_map', Tr1UnorderedMapPrinter) libstdcxx_printer.add_version('std::tr1::', 'unordered_set', Tr1UnorderedSetPrinter) libstdcxx_printer.add_version('std::tr1::', 'unordered_multimap', Tr1UnorderedMapPrinter) libstdcxx_printer.add_version('std::tr1::', 'unordered_multiset', Tr1UnorderedSetPrinter) libstdcxx_printer.add_version('std::', 'initializer_list', StdInitializerListPrinter) libstdcxx_printer.add_version('std::', 'atomic', StdAtomicPrinter) libstdcxx_printer.add_version( 'std::', 'basic_stringbuf', StdStringBufPrinter) libstdcxx_printer.add_version( 'std::__cxx11::', 'basic_stringbuf', StdStringBufPrinter) for sstream in ('istringstream', 'ostringstream', 'stringstream'): libstdcxx_printer.add_version( 'std::', 'basic_' + sstream, StdStringStreamPrinter) libstdcxx_printer.add_version( 'std::__cxx11::', 'basic_' + sstream, StdStringStreamPrinter) libstdcxx_printer.add_version('std::chrono::', 'duration', StdChronoDurationPrinter) libstdcxx_printer.add_version('std::chrono::', 'time_point', StdChronoTimePointPrinter) libstdcxx_printer.add_version('std::', 'integral_constant', StdIntegralConstantPrinter) # std::regex components libstdcxx_printer.add_version('std::__detail::', '_State', StdRegexStatePrinter) # These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases. # The tr1 namespace containers do not have any debug equivalents, # so do not register printers for them. libstdcxx_printer.add('std::__debug::unordered_map', Tr1UnorderedMapPrinter) libstdcxx_printer.add('std::__debug::unordered_set', Tr1UnorderedSetPrinter) libstdcxx_printer.add('std::__debug::unordered_multimap', Tr1UnorderedMapPrinter) libstdcxx_printer.add('std::__debug::unordered_multiset', Tr1UnorderedSetPrinter) libstdcxx_printer.add('std::__debug::forward_list', StdForwardListPrinter) # Library Fundamentals TS components libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', 'any', StdExpAnyPrinter) libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', 'optional', StdExpOptionalPrinter) libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', 'basic_string_view', StdExpStringViewPrinter) # Filesystem TS components libstdcxx_printer.add_version('std::experimental::filesystem::v1::', 'path', StdExpPathPrinter) libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::', 'path', StdExpPathPrinter) libstdcxx_printer.add_version('std::filesystem::', 'path', StdPathPrinter) libstdcxx_printer.add_version('std::filesystem::__cxx11::', 'path', StdPathPrinter) # C++17 components libstdcxx_printer.add_version('std::', 'any', StdExpAnyPrinter) libstdcxx_printer.add_version('std::', 'optional', StdExpOptionalPrinter) libstdcxx_printer.add_version('std::', 'basic_string_view', StdExpStringViewPrinter) libstdcxx_printer.add_version('std::', 'variant', StdVariantPrinter) libstdcxx_printer.add_version('std::', '_Node_handle', StdNodeHandlePrinter) # C++20 components libstdcxx_printer.add_version( 'std::', 'partial_ordering', StdCmpCatPrinter) libstdcxx_printer.add_version('std::', 'weak_ordering', StdCmpCatPrinter) libstdcxx_printer.add_version('std::', 'strong_ordering', StdCmpCatPrinter) libstdcxx_printer.add_version('std::', 'span', StdSpanPrinter) libstdcxx_printer.add_version('std::', 'basic_format_args', StdFormatArgsPrinter) for c in ['day', 'month', 'year', 'weekday', 'weekday_indexed', 'weekday_last', 'month_day', 'month_day_last', 'month_weekday', 'month_weekday_last', 'year_month', 'year_month_day', 'year_month_day_last', 'year_month_weekday', 'year_month_weekday_last', 'hh_mm_ss']: libstdcxx_printer.add_version('std::chrono::', c, StdChronoCalendarPrinter) libstdcxx_printer.add_version('std::chrono::', 'time_zone', StdChronoTimeZonePrinter) libstdcxx_printer.add_version('std::chrono::', 'time_zone_link', StdChronoTimeZonePrinter) libstdcxx_printer.add_version('std::chrono::', 'zoned_time', StdChronoZonedTimePrinter) libstdcxx_printer.add_version('std::chrono::', 'leap_second', StdChronoLeapSecondPrinter) libstdcxx_printer.add_version( 'std::chrono::', 'tzdb', StdChronoTzdbPrinter) # libstdcxx_printer.add_version('std::chrono::(anonymous namespace)', 'Rule', # StdChronoTimeZoneRulePrinter) # C++26 components libstdcxx_printer.add_version('std::', 'text_encoding', StdTextEncodingPrinter) # Extensions. libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter) if True: # These shouldn't be necessary, if GDB "print *i" worked. # But it often doesn't, so here they are. libstdcxx_printer.add_container('std::', '_List_iterator', StdListIteratorPrinter) libstdcxx_printer.add_container('std::', '_List_const_iterator', StdListIteratorPrinter) libstdcxx_printer.add_version('std::', '_Rb_tree_iterator', StdRbtreeIteratorPrinter) libstdcxx_printer.add_version('std::', '_Rb_tree_const_iterator', StdRbtreeIteratorPrinter) libstdcxx_printer.add_container('std::', '_Deque_iterator', StdDequeIteratorPrinter) libstdcxx_printer.add_container('std::', '_Deque_const_iterator', StdDequeIteratorPrinter) libstdcxx_printer.add_version('__gnu_cxx::', '__normal_iterator', StdVectorIteratorPrinter) libstdcxx_printer.add_container('std::', '_Bit_iterator', StdBitIteratorPrinter) libstdcxx_printer.add_container('std::', '_Bit_const_iterator', StdBitIteratorPrinter) libstdcxx_printer.add_container('std::', '_Bit_reference', StdBitReferencePrinter) libstdcxx_printer.add_version('__gnu_cxx::', '_Slist_iterator', StdSlistIteratorPrinter) libstdcxx_printer.add_container('std::', '_Fwd_list_iterator', StdFwdListIteratorPrinter) libstdcxx_printer.add_container('std::', '_Fwd_list_const_iterator', StdFwdListIteratorPrinter) # Debug (compiled with -D_GLIBCXX_DEBUG) printer # registrations. libstdcxx_printer.add('__gnu_debug::_Safe_iterator', StdDebugIteratorPrinter) build_libstdcxx_dictionary() PK1]@JY3libstdcxx/__pycache__/__init__.cpython-36.opt-1.pycnu[3 h@sdS)Nrrr-/usr/share/gcc-8/python/libstdcxx/__init__.pysPK1]@JY-libstdcxx/__pycache__/__init__.cpython-36.pycnu[3 h@sdS)Nrrr-/usr/share/gcc-8/python/libstdcxx/__init__.pysPK1]2libstdcxx/__init__.pynu[ PKk1] z distro.pynu[#!/usr/bin/env python # Copyright 2015,2016,2017 Nir Cohen # # 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. """ The ``distro`` package (``distro`` stands for Linux Distribution) provides information about the Linux distribution it runs on, such as a reliable machine-readable distro ID, or version information. It is the recommended replacement for Python's original :py:func:`platform.linux_distribution` function, but it provides much more functionality. An alternative implementation became necessary because Python 3.5 deprecated this function, and Python 3.8 removed it altogether. Its predecessor function :py:func:`platform.dist` was already deprecated since Python 2.6 and removed in Python 3.8. Still, there are many cases in which access to OS distribution information is needed. See `Python issue 1322 `_ for more information. """ import argparse import json import logging import os import re import shlex import subprocess import sys import warnings from typing import ( Any, Callable, Dict, Iterable, Optional, Sequence, TextIO, Tuple, Type, ) try: from typing import TypedDict except ImportError: # Python 3.7 TypedDict = dict __version__ = "1.8.0" class VersionDict(TypedDict): major: str minor: str build_number: str class InfoDict(TypedDict): id: str version: str version_parts: VersionDict like: str codename: str _UNIXCONFDIR = os.environ.get("UNIXCONFDIR", "/etc") _UNIXUSRLIBDIR = os.environ.get("UNIXUSRLIBDIR", "/usr/lib") _OS_RELEASE_BASENAME = "os-release" #: Translation table for normalizing the "ID" attribute defined in os-release #: files, for use by the :func:`distro.id` method. #: #: * Key: Value as defined in the os-release file, translated to lower case, #: with blanks translated to underscores. #: #: * Value: Normalized value. NORMALIZED_OS_ID = { "ol": "oracle", # Oracle Linux "opensuse-leap": "opensuse", # Newer versions of OpenSuSE report as opensuse-leap } #: Translation table for normalizing the "Distributor ID" attribute returned by #: the lsb_release command, for use by the :func:`distro.id` method. #: #: * Key: Value as returned by the lsb_release command, translated to lower #: case, with blanks translated to underscores. #: #: * Value: Normalized value. NORMALIZED_LSB_ID = { "enterpriseenterpriseas": "oracle", # Oracle Enterprise Linux 4 "enterpriseenterpriseserver": "oracle", # Oracle Linux 5 "redhatenterpriseworkstation": "rhel", # RHEL 6, 7 Workstation "redhatenterpriseserver": "rhel", # RHEL 6, 7 Server "redhatenterprisecomputenode": "rhel", # RHEL 6 ComputeNode } #: Translation table for normalizing the distro ID derived from the file name #: of distro release files, for use by the :func:`distro.id` method. #: #: * Key: Value as derived from the file name of a distro release file, #: translated to lower case, with blanks translated to underscores. #: #: * Value: Normalized value. NORMALIZED_DISTRO_ID = { "redhat": "rhel", # RHEL 6.x, 7.x } # Pattern for content of distro release file (reversed) _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile( r"(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)" ) # Pattern for base file name of distro release file _DISTRO_RELEASE_BASENAME_PATTERN = re.compile(r"(\w+)[-_](release|version)$") # Base file names to be looked up for if _UNIXCONFDIR is not readable. _DISTRO_RELEASE_BASENAMES = [ "SuSE-release", "arch-release", "base-release", "centos-release", "fedora-release", "gentoo-release", "mageia-release", "mandrake-release", "mandriva-release", "mandrivalinux-release", "manjaro-release", "oracle-release", "redhat-release", "rocky-release", "sl-release", "slackware-version", ] # Base file names to be ignored when searching for distro release file _DISTRO_RELEASE_IGNORE_BASENAMES = ( "debian_version", "lsb-release", "oem-release", _OS_RELEASE_BASENAME, "system-release", "plesk-release", "iredmail-release", ) def linux_distribution(full_distribution_name: bool = True) -> Tuple[str, str, str]: """ .. deprecated:: 1.6.0 :func:`distro.linux_distribution()` is deprecated. It should only be used as a compatibility shim with Python's :py:func:`platform.linux_distribution()`. Please use :func:`distro.id`, :func:`distro.version` and :func:`distro.name` instead. Return information about the current OS distribution as a tuple ``(id_name, version, codename)`` with items as follows: * ``id_name``: If *full_distribution_name* is false, the result of :func:`distro.id`. Otherwise, the result of :func:`distro.name`. * ``version``: The result of :func:`distro.version`. * ``codename``: The extra item (usually in parentheses) after the os-release version number, or the result of :func:`distro.codename`. The interface of this function is compatible with the original :py:func:`platform.linux_distribution` function, supporting a subset of its parameters. The data it returns may not exactly be the same, because it uses more data sources than the original function, and that may lead to different data if the OS distribution is not consistent across multiple data sources it provides (there are indeed such distributions ...). Another reason for differences is the fact that the :func:`distro.id` method normalizes the distro ID string to a reliable machine-readable value for a number of popular OS distributions. """ warnings.warn( "distro.linux_distribution() is deprecated. It should only be used as a " "compatibility shim with Python's platform.linux_distribution(). Please use " "distro.id(), distro.version() and distro.name() instead.", DeprecationWarning, stacklevel=2, ) return _distro.linux_distribution(full_distribution_name) def id() -> str: """ Return the distro ID of the current distribution, as a machine-readable string. For a number of OS distributions, the returned distro ID value is *reliable*, in the sense that it is documented and that it does not change across releases of the distribution. This package maintains the following reliable distro ID values: ============== ========================================= Distro ID Distribution ============== ========================================= "ubuntu" Ubuntu "debian" Debian "rhel" RedHat Enterprise Linux "centos" CentOS "fedora" Fedora "sles" SUSE Linux Enterprise Server "opensuse" openSUSE "amzn" Amazon Linux "arch" Arch Linux "buildroot" Buildroot "cloudlinux" CloudLinux OS "exherbo" Exherbo Linux "gentoo" GenToo Linux "ibm_powerkvm" IBM PowerKVM "kvmibm" KVM for IBM z Systems "linuxmint" Linux Mint "mageia" Mageia "mandriva" Mandriva Linux "parallels" Parallels "pidora" Pidora "raspbian" Raspbian "oracle" Oracle Linux (and Oracle Enterprise Linux) "scientific" Scientific Linux "slackware" Slackware "xenserver" XenServer "openbsd" OpenBSD "netbsd" NetBSD "freebsd" FreeBSD "midnightbsd" MidnightBSD "rocky" Rocky Linux "aix" AIX "guix" Guix System ============== ========================================= If you have a need to get distros for reliable IDs added into this set, or if you find that the :func:`distro.id` function returns a different distro ID for one of the listed distros, please create an issue in the `distro issue tracker`_. **Lookup hierarchy and transformations:** First, the ID is obtained from the following sources, in the specified order. The first available and non-empty value is used: * the value of the "ID" attribute of the os-release file, * the value of the "Distributor ID" attribute returned by the lsb_release command, * the first part of the file name of the distro release file, The so determined ID value then passes the following transformations, before it is returned by this method: * it is translated to lower case, * blanks (which should not be there anyway) are translated to underscores, * a normalization of the ID is performed, based upon `normalization tables`_. The purpose of this normalization is to ensure that the ID is as reliable as possible, even across incompatible changes in the OS distributions. A common reason for an incompatible change is the addition of an os-release file, or the addition of the lsb_release command, with ID values that differ from what was previously determined from the distro release file name. """ return _distro.id() def name(pretty: bool = False) -> str: """ Return the name of the current OS distribution, as a human-readable string. If *pretty* is false, the name is returned without version or codename. (e.g. "CentOS Linux") If *pretty* is true, the version and codename are appended. (e.g. "CentOS Linux 7.1.1503 (Core)") **Lookup hierarchy:** The name is obtained from the following sources, in the specified order. The first available and non-empty value is used: * If *pretty* is false: - the value of the "NAME" attribute of the os-release file, - the value of the "Distributor ID" attribute returned by the lsb_release command, - the value of the "" field of the distro release file. * If *pretty* is true: - the value of the "PRETTY_NAME" attribute of the os-release file, - the value of the "Description" attribute returned by the lsb_release command, - the value of the "" field of the distro release file, appended with the value of the pretty version ("" and "" fields) of the distro release file, if available. """ return _distro.name(pretty) def version(pretty: bool = False, best: bool = False) -> str: """ Return the version of the current OS distribution, as a human-readable string. If *pretty* is false, the version is returned without codename (e.g. "7.0"). If *pretty* is true, the codename in parenthesis is appended, if the codename is non-empty (e.g. "7.0 (Maipo)"). Some distributions provide version numbers with different precisions in the different sources of distribution information. Examining the different sources in a fixed priority order does not always yield the most precise version (e.g. for Debian 8.2, or CentOS 7.1). Some other distributions may not provide this kind of information. In these cases, an empty string would be returned. This behavior can be observed with rolling releases distributions (e.g. Arch Linux). The *best* parameter can be used to control the approach for the returned version: If *best* is false, the first non-empty version number in priority order of the examined sources is returned. If *best* is true, the most precise version number out of all examined sources is returned. **Lookup hierarchy:** In all cases, the version number is obtained from the following sources. If *best* is false, this order represents the priority order: * the value of the "VERSION_ID" attribute of the os-release file, * the value of the "Release" attribute returned by the lsb_release command, * the version number parsed from the "" field of the first line of the distro release file, * the version number parsed from the "PRETTY_NAME" attribute of the os-release file, if it follows the format of the distro release files. * the version number parsed from the "Description" attribute returned by the lsb_release command, if it follows the format of the distro release files. """ return _distro.version(pretty, best) def version_parts(best: bool = False) -> Tuple[str, str, str]: """ Return the version of the current OS distribution as a tuple ``(major, minor, build_number)`` with items as follows: * ``major``: The result of :func:`distro.major_version`. * ``minor``: The result of :func:`distro.minor_version`. * ``build_number``: The result of :func:`distro.build_number`. For a description of the *best* parameter, see the :func:`distro.version` method. """ return _distro.version_parts(best) def major_version(best: bool = False) -> str: """ Return the major version of the current OS distribution, as a string, if provided. Otherwise, the empty string is returned. The major version is the first part of the dot-separated version string. For a description of the *best* parameter, see the :func:`distro.version` method. """ return _distro.major_version(best) def minor_version(best: bool = False) -> str: """ Return the minor version of the current OS distribution, as a string, if provided. Otherwise, the empty string is returned. The minor version is the second part of the dot-separated version string. For a description of the *best* parameter, see the :func:`distro.version` method. """ return _distro.minor_version(best) def build_number(best: bool = False) -> str: """ Return the build number of the current OS distribution, as a string, if provided. Otherwise, the empty string is returned. The build number is the third part of the dot-separated version string. For a description of the *best* parameter, see the :func:`distro.version` method. """ return _distro.build_number(best) def like() -> str: """ Return a space-separated list of distro IDs of distributions that are closely related to the current OS distribution in regards to packaging and programming interfaces, for example distributions the current distribution is a derivative from. **Lookup hierarchy:** This information item is only provided by the os-release file. For details, see the description of the "ID_LIKE" attribute in the `os-release man page `_. """ return _distro.like() def codename() -> str: """ Return the codename for the release of the current OS distribution, as a string. If the distribution does not have a codename, an empty string is returned. Note that the returned codename is not always really a codename. For example, openSUSE returns "x86_64". This function does not handle such cases in any special way and just returns the string it finds, if any. **Lookup hierarchy:** * the codename within the "VERSION" attribute of the os-release file, if provided, * the value of the "Codename" attribute returned by the lsb_release command, * the value of the "" field of the distro release file. """ return _distro.codename() def info(pretty: bool = False, best: bool = False) -> InfoDict: """ Return certain machine-readable information items about the current OS distribution in a dictionary, as shown in the following example: .. sourcecode:: python { 'id': 'rhel', 'version': '7.0', 'version_parts': { 'major': '7', 'minor': '0', 'build_number': '' }, 'like': 'fedora', 'codename': 'Maipo' } The dictionary structure and keys are always the same, regardless of which information items are available in the underlying data sources. The values for the various keys are as follows: * ``id``: The result of :func:`distro.id`. * ``version``: The result of :func:`distro.version`. * ``version_parts -> major``: The result of :func:`distro.major_version`. * ``version_parts -> minor``: The result of :func:`distro.minor_version`. * ``version_parts -> build_number``: The result of :func:`distro.build_number`. * ``like``: The result of :func:`distro.like`. * ``codename``: The result of :func:`distro.codename`. For a description of the *pretty* and *best* parameters, see the :func:`distro.version` method. """ return _distro.info(pretty, best) def os_release_info() -> Dict[str, str]: """ Return a dictionary containing key-value pairs for the information items from the os-release file data source of the current OS distribution. See `os-release file`_ for details about these information items. """ return _distro.os_release_info() def lsb_release_info() -> Dict[str, str]: """ Return a dictionary containing key-value pairs for the information items from the lsb_release command data source of the current OS distribution. See `lsb_release command output`_ for details about these information items. """ return _distro.lsb_release_info() def distro_release_info() -> Dict[str, str]: """ Return a dictionary containing key-value pairs for the information items from the distro release file data source of the current OS distribution. See `distro release file`_ for details about these information items. """ return _distro.distro_release_info() def uname_info() -> Dict[str, str]: """ Return a dictionary containing key-value pairs for the information items from the distro release file data source of the current OS distribution. """ return _distro.uname_info() def os_release_attr(attribute: str) -> str: """ Return a single named information item from the os-release file data source of the current OS distribution. Parameters: * ``attribute`` (string): Key of the information item. Returns: * (string): Value of the information item, if the item exists. The empty string, if the item does not exist. See `os-release file`_ for details about these information items. """ return _distro.os_release_attr(attribute) def lsb_release_attr(attribute: str) -> str: """ Return a single named information item from the lsb_release command output data source of the current OS distribution. Parameters: * ``attribute`` (string): Key of the information item. Returns: * (string): Value of the information item, if the item exists. The empty string, if the item does not exist. See `lsb_release command output`_ for details about these information items. """ return _distro.lsb_release_attr(attribute) def distro_release_attr(attribute: str) -> str: """ Return a single named information item from the distro release file data source of the current OS distribution. Parameters: * ``attribute`` (string): Key of the information item. Returns: * (string): Value of the information item, if the item exists. The empty string, if the item does not exist. See `distro release file`_ for details about these information items. """ return _distro.distro_release_attr(attribute) def uname_attr(attribute: str) -> str: """ Return a single named information item from the distro release file data source of the current OS distribution. Parameters: * ``attribute`` (string): Key of the information item. Returns: * (string): Value of the information item, if the item exists. The empty string, if the item does not exist. """ return _distro.uname_attr(attribute) try: from functools import cached_property except ImportError: # Python < 3.8 class cached_property: # type: ignore """A version of @property which caches the value. On access, it calls the underlying function and sets the value in `__dict__` so future accesses will not re-call the property. """ def __init__(self, f: Callable[[Any], Any]) -> None: self._fname = f.__name__ self._f = f def __get__(self, obj: Any, owner: Type[Any]) -> Any: assert obj is not None, f"call {self._fname} on an instance" ret = obj.__dict__[self._fname] = self._f(obj) return ret class LinuxDistribution: """ Provides information about a OS distribution. This package creates a private module-global instance of this class with default initialization arguments, that is used by the `consolidated accessor functions`_ and `single source accessor functions`_. By using default initialization arguments, that module-global instance returns data about the current OS distribution (i.e. the distro this package runs on). Normally, it is not necessary to create additional instances of this class. However, in situations where control is needed over the exact data sources that are used, instances of this class can be created with a specific distro release file, or a specific os-release file, or without invoking the lsb_release command. """ def __init__( self, include_lsb: Optional[bool] = None, os_release_file: str = "", distro_release_file: str = "", include_uname: Optional[bool] = None, root_dir: Optional[str] = None, include_oslevel: Optional[bool] = None, ) -> None: """ The initialization method of this class gathers information from the available data sources, and stores that in private instance attributes. Subsequent access to the information items uses these private instance attributes, so that the data sources are read only once. Parameters: * ``include_lsb`` (bool): Controls whether the `lsb_release command output`_ is included as a data source. If the lsb_release command is not available in the program execution path, the data source for the lsb_release command will be empty. * ``os_release_file`` (string): The path name of the `os-release file`_ that is to be used as a data source. An empty string (the default) will cause the default path name to be used (see `os-release file`_ for details). If the specified or defaulted os-release file does not exist, the data source for the os-release file will be empty. * ``distro_release_file`` (string): The path name of the `distro release file`_ that is to be used as a data source. An empty string (the default) will cause a default search algorithm to be used (see `distro release file`_ for details). If the specified distro release file does not exist, or if no default distro release file can be found, the data source for the distro release file will be empty. * ``include_uname`` (bool): Controls whether uname command output is included as a data source. If the uname command is not available in the program execution path the data source for the uname command will be empty. * ``root_dir`` (string): The absolute path to the root directory to use to find distro-related information files. Note that ``include_*`` parameters must not be enabled in combination with ``root_dir``. * ``include_oslevel`` (bool): Controls whether (AIX) oslevel command output is included as a data source. If the oslevel command is not available in the program execution path the data source will be empty. Public instance attributes: * ``os_release_file`` (string): The path name of the `os-release file`_ that is actually used as a data source. The empty string if no distro release file is used as a data source. * ``distro_release_file`` (string): The path name of the `distro release file`_ that is actually used as a data source. The empty string if no distro release file is used as a data source. * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. This controls whether the lsb information will be loaded. * ``include_uname`` (bool): The result of the ``include_uname`` parameter. This controls whether the uname information will be loaded. * ``include_oslevel`` (bool): The result of the ``include_oslevel`` parameter. This controls whether (AIX) oslevel information will be loaded. * ``root_dir`` (string): The result of the ``root_dir`` parameter. The absolute path to the root directory to use to find distro-related information files. Raises: * :py:exc:`ValueError`: Initialization parameters combination is not supported. * :py:exc:`OSError`: Some I/O issue with an os-release file or distro release file. * :py:exc:`UnicodeError`: A data source has unexpected characters or uses an unexpected encoding. """ self.root_dir = root_dir self.etc_dir = os.path.join(root_dir, "etc") if root_dir else _UNIXCONFDIR self.usr_lib_dir = ( os.path.join(root_dir, "usr/lib") if root_dir else _UNIXUSRLIBDIR ) if os_release_file: self.os_release_file = os_release_file else: etc_dir_os_release_file = os.path.join(self.etc_dir, _OS_RELEASE_BASENAME) usr_lib_os_release_file = os.path.join( self.usr_lib_dir, _OS_RELEASE_BASENAME ) # NOTE: The idea is to respect order **and** have it set # at all times for API backwards compatibility. if os.path.isfile(etc_dir_os_release_file) or not os.path.isfile( usr_lib_os_release_file ): self.os_release_file = etc_dir_os_release_file else: self.os_release_file = usr_lib_os_release_file self.distro_release_file = distro_release_file or "" # updated later is_root_dir_defined = root_dir is not None if is_root_dir_defined and (include_lsb or include_uname or include_oslevel): raise ValueError( "Including subprocess data sources from specific root_dir is disallowed" " to prevent false information" ) self.include_lsb = ( include_lsb if include_lsb is not None else not is_root_dir_defined ) self.include_uname = ( include_uname if include_uname is not None else not is_root_dir_defined ) self.include_oslevel = ( include_oslevel if include_oslevel is not None else not is_root_dir_defined ) def __repr__(self) -> str: """Return repr of all info""" return ( "LinuxDistribution(" "os_release_file={self.os_release_file!r}, " "distro_release_file={self.distro_release_file!r}, " "include_lsb={self.include_lsb!r}, " "include_uname={self.include_uname!r}, " "include_oslevel={self.include_oslevel!r}, " "root_dir={self.root_dir!r}, " "_os_release_info={self._os_release_info!r}, " "_lsb_release_info={self._lsb_release_info!r}, " "_distro_release_info={self._distro_release_info!r}, " "_uname_info={self._uname_info!r}, " "_oslevel_info={self._oslevel_info!r})".format(self=self) ) def linux_distribution( self, full_distribution_name: bool = True ) -> Tuple[str, str, str]: """ Return information about the OS distribution that is compatible with Python's :func:`platform.linux_distribution`, supporting a subset of its parameters. For details, see :func:`distro.linux_distribution`. """ return ( self.name() if full_distribution_name else self.id(), self.version(), self._os_release_info.get("release_codename") or self.codename(), ) def id(self) -> str: """Return the distro ID of the OS distribution, as a string. For details, see :func:`distro.id`. """ def normalize(distro_id: str, table: Dict[str, str]) -> str: distro_id = distro_id.lower().replace(" ", "_") return table.get(distro_id, distro_id) distro_id = self.os_release_attr("id") if distro_id: return normalize(distro_id, NORMALIZED_OS_ID) distro_id = self.lsb_release_attr("distributor_id") if distro_id: return normalize(distro_id, NORMALIZED_LSB_ID) distro_id = self.distro_release_attr("id") if distro_id: return normalize(distro_id, NORMALIZED_DISTRO_ID) distro_id = self.uname_attr("id") if distro_id: return normalize(distro_id, NORMALIZED_DISTRO_ID) return "" def name(self, pretty: bool = False) -> str: """ Return the name of the OS distribution, as a string. For details, see :func:`distro.name`. """ name = ( self.os_release_attr("name") or self.lsb_release_attr("distributor_id") or self.distro_release_attr("name") or self.uname_attr("name") ) if pretty: name = self.os_release_attr("pretty_name") or self.lsb_release_attr( "description" ) if not name: name = self.distro_release_attr("name") or self.uname_attr("name") version = self.version(pretty=True) if version: name = f"{name} {version}" return name or "" def version(self, pretty: bool = False, best: bool = False) -> str: """ Return the version of the OS distribution, as a string. For details, see :func:`distro.version`. """ versions = [ self.os_release_attr("version_id"), self.lsb_release_attr("release"), self.distro_release_attr("version_id"), self._parse_distro_release_content(self.os_release_attr("pretty_name")).get( "version_id", "" ), self._parse_distro_release_content( self.lsb_release_attr("description") ).get("version_id", ""), self.uname_attr("release"), ] if self.uname_attr("id").startswith("aix"): # On AIX platforms, prefer oslevel command output. versions.insert(0, self.oslevel_info()) elif self.id() == "debian" or "debian" in self.like().split(): # On Debian-like, add debian_version file content to candidates list. versions.append(self._debian_version) version = "" if best: # This algorithm uses the last version in priority order that has # the best precision. If the versions are not in conflict, that # does not matter; otherwise, using the last one instead of the # first one might be considered a surprise. for v in versions: if v.count(".") > version.count(".") or version == "": version = v else: for v in versions: if v != "": version = v break if pretty and version and self.codename(): version = f"{version} ({self.codename()})" return version def version_parts(self, best: bool = False) -> Tuple[str, str, str]: """ Return the version of the OS distribution, as a tuple of version numbers. For details, see :func:`distro.version_parts`. """ version_str = self.version(best=best) if version_str: version_regex = re.compile(r"(\d+)\.?(\d+)?\.?(\d+)?") matches = version_regex.match(version_str) if matches: major, minor, build_number = matches.groups() return major, minor or "", build_number or "" return "", "", "" def major_version(self, best: bool = False) -> str: """ Return the major version number of the current distribution. For details, see :func:`distro.major_version`. """ return self.version_parts(best)[0] def minor_version(self, best: bool = False) -> str: """ Return the minor version number of the current distribution. For details, see :func:`distro.minor_version`. """ return self.version_parts(best)[1] def build_number(self, best: bool = False) -> str: """ Return the build number of the current distribution. For details, see :func:`distro.build_number`. """ return self.version_parts(best)[2] def like(self) -> str: """ Return the IDs of distributions that are like the OS distribution. For details, see :func:`distro.like`. """ return self.os_release_attr("id_like") or "" def codename(self) -> str: """ Return the codename of the OS distribution. For details, see :func:`distro.codename`. """ try: # Handle os_release specially since distros might purposefully set # this to empty string to have no codename return self._os_release_info["codename"] except KeyError: return ( self.lsb_release_attr("codename") or self.distro_release_attr("codename") or "" ) def info(self, pretty: bool = False, best: bool = False) -> InfoDict: """ Return certain machine-readable information about the OS distribution. For details, see :func:`distro.info`. """ return dict( id=self.id(), version=self.version(pretty, best), version_parts=dict( major=self.major_version(best), minor=self.minor_version(best), build_number=self.build_number(best), ), like=self.like(), codename=self.codename(), ) def os_release_info(self) -> Dict[str, str]: """ Return a dictionary containing key-value pairs for the information items from the os-release file data source of the OS distribution. For details, see :func:`distro.os_release_info`. """ return self._os_release_info def lsb_release_info(self) -> Dict[str, str]: """ Return a dictionary containing key-value pairs for the information items from the lsb_release command data source of the OS distribution. For details, see :func:`distro.lsb_release_info`. """ return self._lsb_release_info def distro_release_info(self) -> Dict[str, str]: """ Return a dictionary containing key-value pairs for the information items from the distro release file data source of the OS distribution. For details, see :func:`distro.distro_release_info`. """ return self._distro_release_info def uname_info(self) -> Dict[str, str]: """ Return a dictionary containing key-value pairs for the information items from the uname command data source of the OS distribution. For details, see :func:`distro.uname_info`. """ return self._uname_info def oslevel_info(self) -> str: """ Return AIX' oslevel command output. """ return self._oslevel_info def os_release_attr(self, attribute: str) -> str: """ Return a single named information item from the os-release file data source of the OS distribution. For details, see :func:`distro.os_release_attr`. """ return self._os_release_info.get(attribute, "") def lsb_release_attr(self, attribute: str) -> str: """ Return a single named information item from the lsb_release command output data source of the OS distribution. For details, see :func:`distro.lsb_release_attr`. """ return self._lsb_release_info.get(attribute, "") def distro_release_attr(self, attribute: str) -> str: """ Return a single named information item from the distro release file data source of the OS distribution. For details, see :func:`distro.distro_release_attr`. """ return self._distro_release_info.get(attribute, "") def uname_attr(self, attribute: str) -> str: """ Return a single named information item from the uname command output data source of the OS distribution. For details, see :func:`distro.uname_attr`. """ return self._uname_info.get(attribute, "") @cached_property def _os_release_info(self) -> Dict[str, str]: """ Get the information items from the specified os-release file. Returns: A dictionary containing all information items. """ if os.path.isfile(self.os_release_file): with open(self.os_release_file, encoding="utf-8") as release_file: return self._parse_os_release_content(release_file) return {} @staticmethod def _parse_os_release_content(lines: TextIO) -> Dict[str, str]: """ Parse the lines of an os-release file. Parameters: * lines: Iterable through the lines in the os-release file. Each line must be a unicode string or a UTF-8 encoded byte string. Returns: A dictionary containing all information items. """ props = {} lexer = shlex.shlex(lines, posix=True) lexer.whitespace_split = True tokens = list(lexer) for token in tokens: # At this point, all shell-like parsing has been done (i.e. # comments processed, quotes and backslash escape sequences # processed, multi-line values assembled, trailing newlines # stripped, etc.), so the tokens are now either: # * variable assignments: var=value # * commands or their arguments (not allowed in os-release) # Ignore any tokens that are not variable assignments if "=" in token: k, v = token.split("=", 1) props[k.lower()] = v if "version" in props: # extract release codename (if any) from version attribute match = re.search(r"\((\D+)\)|,\s*(\D+)", props["version"]) if match: release_codename = match.group(1) or match.group(2) props["codename"] = props["release_codename"] = release_codename if "version_codename" in props: # os-release added a version_codename field. Use that in # preference to anything else Note that some distros purposefully # do not have code names. They should be setting # version_codename="" props["codename"] = props["version_codename"] elif "ubuntu_codename" in props: # Same as above but a non-standard field name used on older Ubuntus props["codename"] = props["ubuntu_codename"] return props @cached_property def _lsb_release_info(self) -> Dict[str, str]: """ Get the information items from the lsb_release command output. Returns: A dictionary containing all information items. """ if not self.include_lsb: return {} try: cmd = ("lsb_release", "-a") stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL) # Command not found or lsb_release returned error except (OSError, subprocess.CalledProcessError): return {} content = self._to_str(stdout).splitlines() return self._parse_lsb_release_content(content) @staticmethod def _parse_lsb_release_content(lines: Iterable[str]) -> Dict[str, str]: """ Parse the output of the lsb_release command. Parameters: * lines: Iterable through the lines of the lsb_release output. Each line must be a unicode string or a UTF-8 encoded byte string. Returns: A dictionary containing all information items. """ props = {} for line in lines: kv = line.strip("\n").split(":", 1) if len(kv) != 2: # Ignore lines without colon. continue k, v = kv props.update({k.replace(" ", "_").lower(): v.strip()}) return props @cached_property def _uname_info(self) -> Dict[str, str]: if not self.include_uname: return {} try: cmd = ("uname", "-rs") stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL) except OSError: return {} content = self._to_str(stdout).splitlines() return self._parse_uname_content(content) @cached_property def _oslevel_info(self) -> str: if not self.include_oslevel: return "" try: stdout = subprocess.check_output("oslevel", stderr=subprocess.DEVNULL) except (OSError, subprocess.CalledProcessError): return "" return self._to_str(stdout).strip() @cached_property def _debian_version(self) -> str: try: with open( os.path.join(self.etc_dir, "debian_version"), encoding="ascii" ) as fp: return fp.readline().rstrip() except FileNotFoundError: return "" @staticmethod def _parse_uname_content(lines: Sequence[str]) -> Dict[str, str]: if not lines: return {} props = {} match = re.search(r"^([^\s]+)\s+([\d\.]+)", lines[0].strip()) if match: name, version = match.groups() # This is to prevent the Linux kernel version from # appearing as the 'best' version on otherwise # identifiable distributions. if name == "Linux": return {} props["id"] = name.lower() props["name"] = name props["release"] = version return props @staticmethod def _to_str(bytestring: bytes) -> str: encoding = sys.getfilesystemencoding() return bytestring.decode(encoding) @cached_property def _distro_release_info(self) -> Dict[str, str]: """ Get the information items from the specified distro release file. Returns: A dictionary containing all information items. """ if self.distro_release_file: # If it was specified, we use it and parse what we can, even if # its file name or content does not match the expected pattern. distro_info = self._parse_distro_release_file(self.distro_release_file) basename = os.path.basename(self.distro_release_file) # The file name pattern for user-specified distro release files # is somewhat more tolerant (compared to when searching for the # file), because we want to use what was specified as best as # possible. match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) else: try: basenames = [ basename for basename in os.listdir(self.etc_dir) if basename not in _DISTRO_RELEASE_IGNORE_BASENAMES and os.path.isfile(os.path.join(self.etc_dir, basename)) ] # We sort for repeatability in cases where there are multiple # distro specific files; e.g. CentOS, Oracle, Enterprise all # containing `redhat-release` on top of their own. basenames.sort() except OSError: # This may occur when /etc is not readable but we can't be # sure about the *-release files. Check common entries of # /etc for information. If they turn out to not be there the # error is handled in `_parse_distro_release_file()`. basenames = _DISTRO_RELEASE_BASENAMES for basename in basenames: match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) if match is None: continue filepath = os.path.join(self.etc_dir, basename) distro_info = self._parse_distro_release_file(filepath) # The name is always present if the pattern matches. if "name" not in distro_info: continue self.distro_release_file = filepath break else: # the loop didn't "break": no candidate. return {} if match is not None: distro_info["id"] = match.group(1) # CloudLinux < 7: manually enrich info with proper id. if "cloudlinux" in distro_info.get("name", "").lower(): distro_info["id"] = "cloudlinux" return distro_info def _parse_distro_release_file(self, filepath: str) -> Dict[str, str]: """ Parse a distro release file. Parameters: * filepath: Path name of the distro release file. Returns: A dictionary containing all information items. """ try: with open(filepath, encoding="utf-8") as fp: # Only parse the first line. For instance, on SLES there # are multiple lines. We don't want them... return self._parse_distro_release_content(fp.readline()) except OSError: # Ignore not being able to read a specific, seemingly version # related file. # See https://github.com/python-distro/distro/issues/162 return {} @staticmethod def _parse_distro_release_content(line: str) -> Dict[str, str]: """ Parse a line from a distro release file. Parameters: * line: Line from the distro release file. Must be a unicode string or a UTF-8 encoded byte string. Returns: A dictionary containing all information items. """ matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(line.strip()[::-1]) distro_info = {} if matches: # regexp ensures non-None distro_info["name"] = matches.group(3)[::-1] if matches.group(2): distro_info["version_id"] = matches.group(2)[::-1] if matches.group(1): distro_info["codename"] = matches.group(1)[::-1] elif line: distro_info["name"] = line.strip() return distro_info _distro = LinuxDistribution() def main() -> None: logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) logger.addHandler(logging.StreamHandler(sys.stdout)) parser = argparse.ArgumentParser(description="OS distro info tool") parser.add_argument( "--json", "-j", help="Output in machine readable format", action="store_true" ) parser.add_argument( "--root-dir", "-r", type=str, dest="root_dir", help="Path to the root filesystem directory (defaults to /)", ) args = parser.parse_args() if args.root_dir: dist = LinuxDistribution( include_lsb=False, include_uname=False, include_oslevel=False, root_dir=args.root_dir, ) else: dist = _distro if args.json: logger.info(json.dumps(dist.info(), indent=4, sort_keys=True)) else: logger.info("Name: %s", dist.name(pretty=True)) distribution_version = dist.version(pretty=True) logger.info("Version: %s", distribution_version) distribution_codename = dist.codename() logger.info("Codename: %s", distribution_codename) if __name__ == "__main__": main() PKk1]:"8'__pycache__/kcsig_verify.cpython-36.pycnu[3 ;j\@s ddlZddlZddlZddlZddlZddlZddlZdgZdd1iZd Z e d Z e d Z e d Z Gd d d eZd2ddZddZd3ddZddZddZddZddZddZd d!Zejd"d#Zejd$d%Zd&d'Zd(d)Zd4d+d,Zd5d-d.Zd6d/d0Z dS)7NZrsa4096gpgtypekindroleserialkeyz/dev/shmc@s eZdZdS)ErrorN)__name__ __module__ __qualname__rr)/usr/libexec/kcare/python/kcsig_verify.pyr sr latin1cCsNt|}|tkr|S|tkr&|j|S|tkr:tt|Stdt|dS)NzUnsupported pae type )rbtypeutypeencodeintto_bytesstr ValueError)dataencodingdtyperrrrs  rcCs@t|}|tkr|S|tkr&|jdS|tkr8|jdStdS)Nzutf-8)rntyperdecoderrNotImplementedError)rrrrrnstr(s  rwc Cs8|d}t||}|j|WdQRXtj||dS)Nz.tmp)openwriteosrename)fnamecontentmode tmp_fnamefrrr atomic_write3s r)c Cst| }|jSQRXdS)N)r read)r$r(rrr read_file;s r+cCstjt|S)N)jsonloadsr+)r$rrr read_json@sr.cGs:dt|}x(|D] }t|}|dt||f7}qW|S)Ns%ds%d%s)lenr)partsresultpZbprrrpaeDs   r3cstfdd|DS)Ncsg|] }|qSrr).0r()rrr Oszpae_fields..)r3)rfieldsr)rr pae_fieldsMsr7cCst|t|dS)Nr)r7 PAE_FIELDS)rrrrpae_typeRsr9cCs$|dtkr tdt|ddS)Nrzinvalid key type: )r8rr)rrrr check_keyVs r:c csH|r |Vn8tjtdd$}|jt||j|jVWdQRXdS)Nz kcsig-data-)dirprefix)tempfileNamedTemporaryFileTMPDIRr!rflushname)r data_is_filer(rrr temp_datafile[s rCc cs*tj||d}z |VWdtj|XdS)N)r<r;)r=mkdtempshutilrmtree)r<r;Ztemp_dirrrrtemp_directoryfs rGcCs|ttddf}dd|d|dd|g}tj|tjtjtjd}|j|\}}|jd krntd t|d t|WdQRXdS) Nz kcsig-gpgtmp-)r;r<rz --homedirz --keyringz--verify-)stdinstdoutstderrrzVerify error:  ) rGr? subprocessPopenPIPE communicate returncode Exceptionr)keyfiledatafilesigdataZtmp_dircmdr2rJrKrrrrun_gpg_verifyos  rWcCsxt|tjtddX}|jtjt|d|jt ||"}tjt|}t |j ||WdQRXWdQRXdS)Nz kcsig-key-)r;r<r) r:r=r>r?r!base64 b64decoderr@rCrWrA) signaturerrrBkey_filerTrUrrr verify_keyys r\Fc Csd}i}xt|jD]h\}}||kr,d||<qyt|||||Wn.tk rp}zt|||<WYdd}~XqX|d7}qW||fS)Nrzno corresponding root key)itemsr\rRr) signatureskeysrrBcounterrorskeyidsigerrr verify_counts rfcCs|jdd}|jdd}i}|p"t}i}x|djD]\}} yXt| | d|krjdj| d|||<n*| d|krd j| d|||<n| ||<Wq6tk r} zt| ||<w6WYdd} ~ Xq6Xq6Wi} xN|jD]B\}} t| d |dt| d \} } | |kr| ||<q| | |<qWd } xl| jD]`\}} yt |d || |d dWn0tk r} zt| ||<WYdd} ~ Xn X| d7} q.W| st dt j |dS)N thresholdi' min_serialir`rz&invalid kind {0}, accepted list is {1}rz"invalid serial {0}, current is {1}r_)rrT)rrBr]z!Error validating file signature: ) getAVAILABLE_KINDSr^r:formatrRrrfr9r\r r,dumps)rUrT root_keyskindsrgrhrbZapplicable_keysrcrreZ verified_keysraZ root_errorsrrr_verifys>         rocCs$t|}t|}t||||ddS)N)rn)r.ro)ZsigfilerTZrootfilernrUrmrrrverifysrp)rrrrr)r)r)F)N)N)!rX contextlibr,r"rErMr=rjr8r?rrrrrRr rrr)r+r.r3r7r9r:contextmanagerrCrGrWr\rfrorprrrrs:        +PKk1]xS!__pycache__/distro.cpython-36.pycnu[3 ;j@s(dZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl m Z m Z m Z mZmZmZmZmZmZyddl mZWnek reZYnXdZGdddeZGdd d eZejjd d Zejjd d ZdZdddZddddddZ ddiZ!ej"dZ#ej"dZ$dddddddddd d!d"d#d$d%d&gZ%d'd(d)ed*d+d,fZ&dce'ee(e(e(fd.d/d0Z)e(d1d2d3Z*dde'e(d5d6d7Z+dee'e'e(d8d9d:Z,dfe'ee(e(e(fd;dd?Z.dhe'e(d;d@dAZ/die'e(d;dBdCZ0e(d1dDdEZ1e(d1dFdGZ2dje'e'ed8dHdIZ3e e(e(fd1dJdKZ4e e(e(fd1dLdMZ5e e(e(fd1dNdOZ6e e(e(fd1dPdQZ7e(e(dRdSdTZ8e(e(dRdUdVZ9e(e(dRdWdXZ:e(e(dRdYdZZ;ydd[le>Z?dd1d`daZ@eAdbkr$e@dS)ka The ``distro`` package (``distro`` stands for Linux Distribution) provides information about the Linux distribution it runs on, such as a reliable machine-readable distro ID, or version information. It is the recommended replacement for Python's original :py:func:`platform.linux_distribution` function, but it provides much more functionality. An alternative implementation became necessary because Python 3.5 deprecated this function, and Python 3.8 removed it altogether. Its predecessor function :py:func:`platform.dist` was already deprecated since Python 2.6 and removed in Python 3.8. Still, there are many cases in which access to OS distribution information is needed. See `Python issue 1322 `_ for more information. N) AnyCallableDictIterableOptionalSequenceTextIOTupleType) TypedDictz1.8.0c@seZdZUeeedS) VersionDictN)__name__ __module__ __qualname__strmajorminor build_numberrr#/usr/libexec/kcare/python/distro.pyr =s r c@s"eZdZUeeeee dS)InfoDictN) r rrridversionr version_partslikecodenamerrrrrCs rZ UNIXCONFDIRz/etcZ UNIXUSRLIBDIRz/usr/libz os-releaseZoracleZopensuse)Zolz opensuse-leapZrhel)ZenterpriseenterpriseasZenterpriseenterpriseserverZredhatenterpriseworkstationZredhatenterpriseserverZredhatenterprisecomputenoderedhatzA(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)z(\w+)[-_](release|version)$z SuSE-releasez arch-releasez base-releasezcentos-releasezfedora-releasezgentoo-releasezmageia-releasezmandrake-releasezmandriva-releasezmandrivalinux-releasezmanjaro-releasezoracle-releasezredhat-releasez rocky-releasez sl-releasezslackware-versiondebian_versionz lsb-releasez oem-releasezsystem-releasez plesk-releaseziredmail-releaseT)full_distribution_namereturncCstjdtddtj|S)a .. deprecated:: 1.6.0 :func:`distro.linux_distribution()` is deprecated. It should only be used as a compatibility shim with Python's :py:func:`platform.linux_distribution()`. Please use :func:`distro.id`, :func:`distro.version` and :func:`distro.name` instead. Return information about the current OS distribution as a tuple ``(id_name, version, codename)`` with items as follows: * ``id_name``: If *full_distribution_name* is false, the result of :func:`distro.id`. Otherwise, the result of :func:`distro.name`. * ``version``: The result of :func:`distro.version`. * ``codename``: The extra item (usually in parentheses) after the os-release version number, or the result of :func:`distro.codename`. The interface of this function is compatible with the original :py:func:`platform.linux_distribution` function, supporting a subset of its parameters. The data it returns may not exactly be the same, because it uses more data sources than the original function, and that may lead to different data if the OS distribution is not consistent across multiple data sources it provides (there are indeed such distributions ...). Another reason for differences is the fact that the :func:`distro.id` method normalizes the distro ID string to a reliable machine-readable value for a number of popular OS distributions. zdistro.linux_distribution() is deprecated. It should only be used as a compatibility shim with Python's platform.linux_distribution(). Please use distro.id(), distro.version() and distro.name() instead.) stacklevel)warningswarnDeprecationWarning_distrolinux_distribution)rrrrr&s !r&)rcCstjS)a Return the distro ID of the current distribution, as a machine-readable string. For a number of OS distributions, the returned distro ID value is *reliable*, in the sense that it is documented and that it does not change across releases of the distribution. This package maintains the following reliable distro ID values: ============== ========================================= Distro ID Distribution ============== ========================================= "ubuntu" Ubuntu "debian" Debian "rhel" RedHat Enterprise Linux "centos" CentOS "fedora" Fedora "sles" SUSE Linux Enterprise Server "opensuse" openSUSE "amzn" Amazon Linux "arch" Arch Linux "buildroot" Buildroot "cloudlinux" CloudLinux OS "exherbo" Exherbo Linux "gentoo" GenToo Linux "ibm_powerkvm" IBM PowerKVM "kvmibm" KVM for IBM z Systems "linuxmint" Linux Mint "mageia" Mageia "mandriva" Mandriva Linux "parallels" Parallels "pidora" Pidora "raspbian" Raspbian "oracle" Oracle Linux (and Oracle Enterprise Linux) "scientific" Scientific Linux "slackware" Slackware "xenserver" XenServer "openbsd" OpenBSD "netbsd" NetBSD "freebsd" FreeBSD "midnightbsd" MidnightBSD "rocky" Rocky Linux "aix" AIX "guix" Guix System ============== ========================================= If you have a need to get distros for reliable IDs added into this set, or if you find that the :func:`distro.id` function returns a different distro ID for one of the listed distros, please create an issue in the `distro issue tracker`_. **Lookup hierarchy and transformations:** First, the ID is obtained from the following sources, in the specified order. The first available and non-empty value is used: * the value of the "ID" attribute of the os-release file, * the value of the "Distributor ID" attribute returned by the lsb_release command, * the first part of the file name of the distro release file, The so determined ID value then passes the following transformations, before it is returned by this method: * it is translated to lower case, * blanks (which should not be there anyway) are translated to underscores, * a normalization of the ID is performed, based upon `normalization tables`_. The purpose of this normalization is to ensure that the ID is as reliable as possible, even across incompatible changes in the OS distributions. A common reason for an incompatible change is the addition of an os-release file, or the addition of the lsb_release command, with ID values that differ from what was previously determined from the distro release file name. )r%rrrrrrsPrF)prettyrcCs tj|S)ak Return the name of the current OS distribution, as a human-readable string. If *pretty* is false, the name is returned without version or codename. (e.g. "CentOS Linux") If *pretty* is true, the version and codename are appended. (e.g. "CentOS Linux 7.1.1503 (Core)") **Lookup hierarchy:** The name is obtained from the following sources, in the specified order. The first available and non-empty value is used: * If *pretty* is false: - the value of the "NAME" attribute of the os-release file, - the value of the "Distributor ID" attribute returned by the lsb_release command, - the value of the "" field of the distro release file. * If *pretty* is true: - the value of the "PRETTY_NAME" attribute of the os-release file, - the value of the "Description" attribute returned by the lsb_release command, - the value of the "" field of the distro release file, appended with the value of the pretty version ("" and "" fields) of the distro release file, if available. )r%name)r'rrrr(s$r()r'bestrcCs tj||S)aN Return the version of the current OS distribution, as a human-readable string. If *pretty* is false, the version is returned without codename (e.g. "7.0"). If *pretty* is true, the codename in parenthesis is appended, if the codename is non-empty (e.g. "7.0 (Maipo)"). Some distributions provide version numbers with different precisions in the different sources of distribution information. Examining the different sources in a fixed priority order does not always yield the most precise version (e.g. for Debian 8.2, or CentOS 7.1). Some other distributions may not provide this kind of information. In these cases, an empty string would be returned. This behavior can be observed with rolling releases distributions (e.g. Arch Linux). The *best* parameter can be used to control the approach for the returned version: If *best* is false, the first non-empty version number in priority order of the examined sources is returned. If *best* is true, the most precise version number out of all examined sources is returned. **Lookup hierarchy:** In all cases, the version number is obtained from the following sources. If *best* is false, this order represents the priority order: * the value of the "VERSION_ID" attribute of the os-release file, * the value of the "Release" attribute returned by the lsb_release command, * the version number parsed from the "" field of the first line of the distro release file, * the version number parsed from the "PRETTY_NAME" attribute of the os-release file, if it follows the format of the distro release files. * the version number parsed from the "Description" attribute returned by the lsb_release command, if it follows the format of the distro release files. )r%r)r'r)rrrrBs-r)r)rcCs tj|S)a Return the version of the current OS distribution as a tuple ``(major, minor, build_number)`` with items as follows: * ``major``: The result of :func:`distro.major_version`. * ``minor``: The result of :func:`distro.minor_version`. * ``build_number``: The result of :func:`distro.build_number`. For a description of the *best* parameter, see the :func:`distro.version` method. )r%r)r)rrrrrsrcCs tj|S)a5 Return the major version of the current OS distribution, as a string, if provided. Otherwise, the empty string is returned. The major version is the first part of the dot-separated version string. For a description of the *best* parameter, see the :func:`distro.version` method. )r% major_version)r)rrrr*s r*cCs tj|S)a6 Return the minor version of the current OS distribution, as a string, if provided. Otherwise, the empty string is returned. The minor version is the second part of the dot-separated version string. For a description of the *best* parameter, see the :func:`distro.version` method. )r% minor_version)r)rrrr+s r+cCs tj|S)a3 Return the build number of the current OS distribution, as a string, if provided. Otherwise, the empty string is returned. The build number is the third part of the dot-separated version string. For a description of the *best* parameter, see the :func:`distro.version` method. )r%r)r)rrrrs rcCstjS)a Return a space-separated list of distro IDs of distributions that are closely related to the current OS distribution in regards to packaging and programming interfaces, for example distributions the current distribution is a derivative from. **Lookup hierarchy:** This information item is only provided by the os-release file. For details, see the description of the "ID_LIKE" attribute in the `os-release man page `_. )r%rrrrrrsrcCstjS)a Return the codename for the release of the current OS distribution, as a string. If the distribution does not have a codename, an empty string is returned. Note that the returned codename is not always really a codename. For example, openSUSE returns "x86_64". This function does not handle such cases in any special way and just returns the string it finds, if any. **Lookup hierarchy:** * the codename within the "VERSION" attribute of the os-release file, if provided, * the value of the "Codename" attribute returned by the lsb_release command, * the value of the "" field of the distro release file. )r%rrrrrrsrcCs tj||S)a Return certain machine-readable information items about the current OS distribution in a dictionary, as shown in the following example: .. sourcecode:: python { 'id': 'rhel', 'version': '7.0', 'version_parts': { 'major': '7', 'minor': '0', 'build_number': '' }, 'like': 'fedora', 'codename': 'Maipo' } The dictionary structure and keys are always the same, regardless of which information items are available in the underlying data sources. The values for the various keys are as follows: * ``id``: The result of :func:`distro.id`. * ``version``: The result of :func:`distro.version`. * ``version_parts -> major``: The result of :func:`distro.major_version`. * ``version_parts -> minor``: The result of :func:`distro.minor_version`. * ``version_parts -> build_number``: The result of :func:`distro.build_number`. * ``like``: The result of :func:`distro.like`. * ``codename``: The result of :func:`distro.codename`. For a description of the *pretty* and *best* parameters, see the :func:`distro.version` method. )r%info)r'r)rrrr,s)r,cCstjS)z Return a dictionary containing key-value pairs for the information items from the os-release file data source of the current OS distribution. See `os-release file`_ for details about these information items. )r%os_release_inforrrrr-sr-cCstjS)z Return a dictionary containing key-value pairs for the information items from the lsb_release command data source of the current OS distribution. See `lsb_release command output`_ for details about these information items. )r%lsb_release_inforrrrr. sr.cCstjS)z Return a dictionary containing key-value pairs for the information items from the distro release file data source of the current OS distribution. See `distro release file`_ for details about these information items. )r%distro_release_inforrrrr/sr/cCstjS)z Return a dictionary containing key-value pairs for the information items from the distro release file data source of the current OS distribution. )r% uname_inforrrrr0sr0) attributercCs tj|S)a Return a single named information item from the os-release file data source of the current OS distribution. Parameters: * ``attribute`` (string): Key of the information item. Returns: * (string): Value of the information item, if the item exists. The empty string, if the item does not exist. See `os-release file`_ for details about these information items. )r%os_release_attr)r1rrrr2&sr2cCs tj|S)a Return a single named information item from the lsb_release command output data source of the current OS distribution. Parameters: * ``attribute`` (string): Key of the information item. Returns: * (string): Value of the information item, if the item exists. The empty string, if the item does not exist. See `lsb_release command output`_ for details about these information items. )r%lsb_release_attr)r1rrrr39sr3cCs tj|S)a Return a single named information item from the distro release file data source of the current OS distribution. Parameters: * ``attribute`` (string): Key of the information item. Returns: * (string): Value of the information item, if the item exists. The empty string, if the item does not exist. See `distro release file`_ for details about these information items. )r%distro_release_attr)r1rrrr4Msr4cCs tj|S)aZ Return a single named information item from the distro release file data source of the current OS distribution. Parameters: * ``attribute`` (string): Key of the information item. Returns: * (string): Value of the information item, if the item exists. The empty string, if the item does not exist. )r% uname_attr)r1rrrr5`sr5)cached_propertyc@s@eZdZdZeegefddddZeeeedddZdS) r6zA version of @property which caches the value. On access, it calls the underlying function and sets the value in `__dict__` so future accesses will not re-call the property. N)frcCs|j|_||_dS)N)r _fname_f)selfr7rrr__init__{szcached_property.__init__)objownerrcCs4|dk std|jd|j|}|j|j<|S)Nzcall z on an instance)AssertionErrorr8r9__dict__)r:r<r=retrrr__get__szcached_property.__get__) r rr__doc__rrr;r rArrrrr6usr6c @seZdZdZdUeeeeeeeeeeddddZeddd ZdVee eeefd d d Z edddZ dWeedddZ dXeeedddZ dYee eeefdddZdZeedddZd[eedddZd\eedddZedd d!Zedd"d#Zd]eeedd$d%Zeeefdd&d'Zeeefdd(d)Zeeefdd*d+Zeeefdd,d-Zedd.d/Zeed0d1d2Zeed0d3d4Zeed0d5d6Zeed0d7d8Ze eeefdd9d:Z!e"e#eeefd;dd?Z%e"e&eeeefd;d@dAZ'e eeefddBdCZ(e eddDdEZ)e eddFdGZ*e"e+eeeefd;dHdIZ,e"e-edJdKdLZ.e eeefddMdNZ/eeeefdOdPdQZ0e"eeeefdRdSdTZ1dS)^LinuxDistributiona  Provides information about a OS distribution. This package creates a private module-global instance of this class with default initialization arguments, that is used by the `consolidated accessor functions`_ and `single source accessor functions`_. By using default initialization arguments, that module-global instance returns data about the current OS distribution (i.e. the distro this package runs on). Normally, it is not necessary to create additional instances of this class. However, in situations where control is needed over the exact data sources that are used, instances of this class can be created with a specific distro release file, or a specific os-release file, or without invoking the lsb_release command. N) include_lsbos_release_filedistro_release_file include_unameroot_dirinclude_oslevelrc Cs||_|rtjj|dnt|_|r0tjj|dnt|_|rB||_nHtjj|jt }tjj|jt }tjj |s|tjj | r||_n||_|pd|_ |dk } | r|s|s|rt d|dk r|n| |_ |dk r|n| |_|dk r|n| |_dS)ah The initialization method of this class gathers information from the available data sources, and stores that in private instance attributes. Subsequent access to the information items uses these private instance attributes, so that the data sources are read only once. Parameters: * ``include_lsb`` (bool): Controls whether the `lsb_release command output`_ is included as a data source. If the lsb_release command is not available in the program execution path, the data source for the lsb_release command will be empty. * ``os_release_file`` (string): The path name of the `os-release file`_ that is to be used as a data source. An empty string (the default) will cause the default path name to be used (see `os-release file`_ for details). If the specified or defaulted os-release file does not exist, the data source for the os-release file will be empty. * ``distro_release_file`` (string): The path name of the `distro release file`_ that is to be used as a data source. An empty string (the default) will cause a default search algorithm to be used (see `distro release file`_ for details). If the specified distro release file does not exist, or if no default distro release file can be found, the data source for the distro release file will be empty. * ``include_uname`` (bool): Controls whether uname command output is included as a data source. If the uname command is not available in the program execution path the data source for the uname command will be empty. * ``root_dir`` (string): The absolute path to the root directory to use to find distro-related information files. Note that ``include_*`` parameters must not be enabled in combination with ``root_dir``. * ``include_oslevel`` (bool): Controls whether (AIX) oslevel command output is included as a data source. If the oslevel command is not available in the program execution path the data source will be empty. Public instance attributes: * ``os_release_file`` (string): The path name of the `os-release file`_ that is actually used as a data source. The empty string if no distro release file is used as a data source. * ``distro_release_file`` (string): The path name of the `distro release file`_ that is actually used as a data source. The empty string if no distro release file is used as a data source. * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. This controls whether the lsb information will be loaded. * ``include_uname`` (bool): The result of the ``include_uname`` parameter. This controls whether the uname information will be loaded. * ``include_oslevel`` (bool): The result of the ``include_oslevel`` parameter. This controls whether (AIX) oslevel information will be loaded. * ``root_dir`` (string): The result of the ``root_dir`` parameter. The absolute path to the root directory to use to find distro-related information files. Raises: * :py:exc:`ValueError`: Initialization parameters combination is not supported. * :py:exc:`OSError`: Some I/O issue with an os-release file or distro release file. * :py:exc:`UnicodeError`: A data source has unexpected characters or uses an unexpected encoding. etczusr/librDNzcIncluding subprocess data sources from specific root_dir is disallowed to prevent false information)rIospathjoin _UNIXCONFDIRetc_dir_UNIXUSRLIBDIRZ usr_lib_dirrF_OS_RELEASE_BASENAMEisfilerG ValueErrorrErHrJ) r:rErFrGrHrIrJZetc_dir_os_release_fileZusr_lib_os_release_fileZis_root_dir_definedrrrr;s(\  zLinuxDistribution.__init__)rcCs dj|dS)zReturn repr of all infoaLinuxDistribution(os_release_file={self.os_release_file!r}, distro_release_file={self.distro_release_file!r}, include_lsb={self.include_lsb!r}, include_uname={self.include_uname!r}, include_oslevel={self.include_oslevel!r}, root_dir={self.root_dir!r}, _os_release_info={self._os_release_info!r}, _lsb_release_info={self._lsb_release_info!r}, _distro_release_info={self._distro_release_info!r}, _uname_info={self._uname_info!r}, _oslevel_info={self._oslevel_info!r}))r:)format)r:rrr__repr__s zLinuxDistribution.__repr__T)rrcCs.|r |jn|j|j|jjdp*|jfS)z Return information about the OS distribution that is compatible with Python's :func:`platform.linux_distribution`, supporting a subset of its parameters. For details, see :func:`distro.linux_distribution`. release_codename)r(rr_os_release_infogetr)r:rrrrr&-s z$LinuxDistribution.linux_distributioncCs~ttttftddd}|jd}|r2||tS|jd}|rJ||tS|jd}|rb||tS|jd}|rz||tSdS)zoReturn the distro ID of the OS distribution, as a string. For details, see :func:`distro.id`. ) distro_idtablercSs|jjdd}|j||S)N _)lowerreplacerY)rZr[rrr normalizeCsz'LinuxDistribution.id..normalizerdistributor_idrD) rrr2NORMALIZED_OS_IDr3NORMALIZED_LSB_IDr4NORMALIZED_DISTRO_IDr5)r:r`rZrrrr=s        zLinuxDistribution.idF)r'rcCs~|jdp&|jdp&|jdp&|jd}|rv|jdp>|jd}|sv|jdpV|jd}|jdd}|rv|d|}|p|dS) zu Return the name of the OS distribution, as a string. For details, see :func:`distro.name`. r(ra pretty_name descriptionT)r'r\rD)r2r3r4r5r)r:r'r(rrrrr(Ys     zLinuxDistribution.name)r'r)rcCs|jd|jd|jd|j|jdjdd|j|jdjdd|jdg}|jdjdrr|jd|jn(|j d ksd |j j kr|j |j d}|rxJ|D]$}|jd |jd ks|dkr|}qWnx|D]}|dkr|}PqW|o|o|jr|d |jd }|S) z{ Return the version of the OS distribution, as a string. For details, see :func:`distro.version`. version_idreleasererDrfraixrdebian.z ())r2r3r4_parse_distro_release_contentrYr5 startswithinsert oslevel_inforrsplitappend_debian_versioncountr)r:r'r)versionsrvrrrrps2      zLinuxDistribution.version)r)rcCsL|j|d}|rHtjd}|j|}|rH|j\}}}||p>d|pDdfSdS)z Return the version of the OS distribution, as a tuple of version numbers. For details, see :func:`distro.version_parts`. )r)z(\d+)\.?(\d+)?\.?(\d+)?rD)rDrDrD)rrecompilematchgroups)r:r)Z version_strZ version_regexmatchesrrrrrrrs   zLinuxDistribution.version_partscCs|j|dS)z Return the major version number of the current distribution. For details, see :func:`distro.major_version`. r)r)r:r)rrrr*szLinuxDistribution.major_versioncCs|j|dS)z Return the minor version number of the current distribution. For details, see :func:`distro.minor_version`. )r)r:r)rrrr+szLinuxDistribution.minor_versioncCs|j|dS)z} Return the build number of the current distribution. For details, see :func:`distro.build_number`. r )r)r:r)rrrrszLinuxDistribution.build_numbercCs|jdp dS)z Return the IDs of distributions that are like the OS distribution. For details, see :func:`distro.like`. Zid_likerD)r2)r:rrrrszLinuxDistribution.likec Cs8y |jdStk r2|jdp0|jdp0dSXdS)zp Return the codename of the OS distribution. For details, see :func:`distro.codename`. rrDN)rXKeyErrorr3r4)r:rrrrs    zLinuxDistribution.codenamecCsBt|j|j||t|j||j||j|d|j|jdS)z Return certain machine-readable information about the OS distribution. For details, see :func:`distro.info`. )rrr)rrrrr)dictrrr*r+rrr)r:r'r)rrrr,s  zLinuxDistribution.infocCs|jS)z Return a dictionary containing key-value pairs for the information items from the os-release file data source of the OS distribution. For details, see :func:`distro.os_release_info`. )rX)r:rrrr-sz!LinuxDistribution.os_release_infocCs|jS)z Return a dictionary containing key-value pairs for the information items from the lsb_release command data source of the OS distribution. For details, see :func:`distro.lsb_release_info`. )_lsb_release_info)r:rrrr.sz"LinuxDistribution.lsb_release_infocCs|jS)z Return a dictionary containing key-value pairs for the information items from the distro release file data source of the OS distribution. For details, see :func:`distro.distro_release_info`. )_distro_release_info)r:rrrr/sz%LinuxDistribution.distro_release_infocCs|jS)z Return a dictionary containing key-value pairs for the information items from the uname command data source of the OS distribution. For details, see :func:`distro.uname_info`. ) _uname_info)r:rrrr0 szLinuxDistribution.uname_infocCs|jS)z5 Return AIX' oslevel command output. ) _oslevel_info)r:rrrrpszLinuxDistribution.oslevel_info)r1rcCs|jj|dS)z Return a single named information item from the os-release file data source of the OS distribution. For details, see :func:`distro.os_release_attr`. rD)rXrY)r:r1rrrr2sz!LinuxDistribution.os_release_attrcCs|jj|dS)z Return a single named information item from the lsb_release command output data source of the OS distribution. For details, see :func:`distro.lsb_release_attr`. rD)rrY)r:r1rrrr3#sz"LinuxDistribution.lsb_release_attrcCs|jj|dS)z Return a single named information item from the distro release file data source of the OS distribution. For details, see :func:`distro.distro_release_attr`. rD)rrY)r:r1rrrr4,sz%LinuxDistribution.distro_release_attrcCs|jj|dS)z Return a single named information item from the uname command output data source of the OS distribution. For details, see :func:`distro.uname_attr`. rD)rrY)r:r1rrrr55szLinuxDistribution.uname_attrc Cs2tjj|jr.t|jdd }|j|SQRXiS)z Get the information items from the specified os-release file. Returns: A dictionary containing all information items. zutf-8)encodingN)rLrMrSrFopen_parse_os_release_content)r:Z release_filerrrrX>sz"LinuxDistribution._os_release_info)linesrc Csi}tj|dd}d|_t|}x0|D](}d|kr&|jdd\}}|||j<q&Wd|krtjd|d}|r|jdp|jd}||d<|d <d |kr|d |d<nd |kr|d |d<|S) aD Parse the lines of an os-release file. Parameters: * lines: Iterable through the lines in the os-release file. Each line must be a unicode string or a UTF-8 encoded byte string. Returns: A dictionary containing all information items. T)posix=r|rz\((\D+)\)|,\s*(\D+)r rrWZversion_codenameZubuntu_codename)shlexwhitespace_splitlistrqr^rwsearchgroup) rpropslexertokenstokenkrvryrWrrrrKs$  z+LinuxDistribution._parse_os_release_contentc CsV|js iSyd}tj|tjd}Wnttjfk r<iSX|j|j}|j|S)z Get the information items from the lsb_release command output. Returns: A dictionary containing all information items. lsb_release-a)stderr)rr) rE subprocess check_outputDEVNULLOSErrorCalledProcessError_to_str splitlines_parse_lsb_release_content)r:cmdstdoutcontentrrrr}sz#LinuxDistribution._lsb_release_infocCs\i}xR|D]J}|jdjdd}t|dkr.q |\}}|j|jddj|jiq W|S)aM Parse the output of the lsb_release command. Parameters: * lines: Iterable through the lines of the lsb_release output. Each line must be a unicode string or a UTF-8 encoded byte string. Returns: A dictionary containing all information items.  :r|r r\r])striprqlenupdater_r^)rrlinekvrrvrrrrs  "z,LinuxDistribution._parse_lsb_release_contentc CsP|js iSyd}tj|tjd}Wntk r6iSX|j|j}|j|S)Nuname-rs)r)rr)rHrrrrrr_parse_uname_content)r:rrrrrrrszLinuxDistribution._uname_infoc CsH|js dSytjdtjd}Wnttjfk r8dSX|j|jS)NrDZoslevel)r)rJrrrrrrr)r:rrrrrszLinuxDistribution._oslevel_infocCsJy0ttjj|jddd}|jjSQRXWntk rDdSXdS)Nrascii)rrD)rrLrMrNrPreadlinerstripFileNotFoundError)r:fprrrrssz!LinuxDistribution._debian_versioncCs\|siSi}tjd|dj}|rX|j\}}|dkrsz:LinuxDistribution._distro_release_info..Nr(r|rZ cloudlinuxrD)rG_parse_distro_release_filerLrMr _DISTRO_RELEASE_BASENAME_PATTERNrylistdirrPsortr_DISTRO_RELEASE_BASENAMESrNrrYr^)r: distro_inforryZ basenamesfilepathr)r:rrs4        z&LinuxDistribution._distro_release_info)rrcCs@y&t|dd}|j|jSQRXWntk r:iSXdS)z Parse a distro release file. Parameters: * filepath: Path name of the distro release file. Returns: A dictionary containing all information items. zutf-8)rN)rrmrr)r:rrrrrrs z,LinuxDistribution._parse_distro_release_file)rrcCstj|jddd}i}|r~|jdddd |d<|jdrZ|jdddd |d<|jdr|jdddd |d<n|r|j|d<|S) a Parse a line from a distro release file. Parameters: * line: Line from the distro release file. Must be a unicode string or a UTF-8 encoded byte string. Returns: A dictionary containing all information items. Nr|r(r rgrrrr)(_DISTRO_RELEASE_CONTENT_REVERSED_PATTERNryrr)rr{rrrrrm1s    z/LinuxDistribution._parse_distro_release_content)NrDrDNNN)T)F)FF)F)F)F)F)FF)2r rrrBrboolrr;rVr r&rr(rrr*r+rrrrr,rr-r.r/r0rpr2r3r4r5r6rX staticmethodrrrrrrrrsrrbytesrrrrmrrrrrCsj}*         1   :rCcCstjt}|jtj|jtjtjt j dd}|j ddddd|j dd t d d d |j }|jr|td d d |jd}nt}|jr|jtj|jdddn@|jd|jdd|jdd}|jd||j}|jd|dS)NzOS distro info tool)rfz--jsonz-jz!Output in machine readable format store_true)helpactionz --root-dirz-rrIz5Path to the root filesystem directory (defaults to /))typedestrF)rErHrJrIT)indent sort_keyszName: %s)r'z Version: %sz Codename: %s)logging getLoggerr setLevelDEBUG addHandler StreamHandlerrrargparseArgumentParser add_argumentr parse_argsrIrCr%jsonr,dumpsr(rr)loggerparserargsdistZdistribution_versionZdistribution_codenamerrrmainNs6      r__main__)T)F)FF)F)F)F)F)FF)BrBrrrrLrwrrrr"Ztypingrrrrrrrr r r ImportErrorr~ __version__r renvironrYrOrQrRrbrcrdrxrrrrrrr&rr(rrr*r+rrrr,r-r.r/r0r2r3r4r5 functoolsr6rCr%rr rrrrs,      +S'0   ,   K( PKk1]k kcarectl/update_utils.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import functools import json import os import time from . import config, constants, log_utils, utils from .py23 import json_loads_nstr if False: # pragma: no cover from typing import Any, Callable, Dict # noqa: F401 STATUS_CHANGE_GAP_DELAY = 5 * 60 # 5 minute def touch_status_gap_file(filename='.kcarestatus'): status_filepath = os.path.join(constants.PATCH_CACHE, filename) utils.atomic_write(status_filepath, utils.timestamp_str()) def status_gap_passed(filename='.kcarestatus'): status_filepath = os.path.join(constants.PATCH_CACHE, filename) if os.path.isfile(status_filepath): with open(status_filepath, 'r') as sfile: try: timestamp = int(sfile.read()) if int(timestamp) + config.STATUS_CHANGE_GAP + STATUS_CHANGE_GAP_DELAY > time.time(): return False except Exception: pass return True def _check_component(component): # type: (str) -> None if component not in ('kernel', 'libcare'): raise ValueError('Unknown update status component: {0}'.format(component)) def _load_update_status(): # type: () -> Dict[str, Any] content = utils.read_file(constants.UPDATE_STATUS_PATH) if content is None: return {} try: result = json_loads_nstr(content) # type: Dict[str, Any] return result except (ValueError, TypeError): log_utils.kcarelog.warning('Failed to parse update status file') return {} def save_update_status(component, error): # type: (str, str) -> None _check_component(component) try: data = _load_update_status() data[component] = { 'error': error, 'timestamp': int(time.time()), } utils.atomic_write(constants.UPDATE_STATUS_PATH, json.dumps(data)) except Exception: log_utils.kcarelog.warning('Failed to save update status', exc_info=True) def _error_status(err): # type: (Exception) -> str # Prefer the short, fixed status label that KcareError subclasses set # (e.g. 'bad signature') for compact, groupable telemetry. When the status # is already echoed in the message (HTTPError's "HTTP Error 414: ...") the # message is the more useful value. When a numeric HTTP status is *not* in # the message, compose a readable "HTTP Error: " rather than a bare # code. str() also keeps an int status subscriptable on read-back. message = str(err) status = str(getattr(err, 'status', '')) if status and status not in message: if status.isdigit(): return 'HTTP Error: {0}'.format(status) return status return message def track_update_status(component): # type: (str) -> Callable[..., Any] _check_component(component) def decorator(fn): # type: (Callable[..., Any]) -> Callable[..., Any] @functools.wraps(fn) def inner(*args, **kwargs): # type: (Any, Any) -> Any try: result = fn(*args, **kwargs) except Exception as err: save_update_status(component, error=_error_status(err)) raise save_update_status(component, error='') return result return inner return decorator def read_update_error(component): # type: (str) -> str _check_component(component) try: data = _load_update_status() # str() guards against status files written by older clients that # persisted a non-string error (e.g. an int HTTP status like 414). error = data.get(component, {}).get('error', '') # type: Any return str(error)[: constants.UPDATE_ERROR_MAX_LENGTH] except Exception: log_utils.kcarelog.warning('Failed to read update status', exc_info=True) return '' PKk1]4ؓkcarectl/serverid.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import os from . import errors, utils from .py23 import json_loads_nstr SYSTEMID = '/etc/sysconfig/kcare/systemid' ALMA_SYSTEMID = '/etc/sysconfig/kcare/systemid.almacare' IM360_LICENSE_FILE = '/var/imunify360/license.json' if False: # pragma: no cover from typing import Optional # noqa: F401 def _systemid(): # type: () -> Optional[str] if not os.path.exists(SYSTEMID): return None with open(SYSTEMID, 'r') as fd: for line in fd: param, _, value = line.partition('=') if param.strip() == 'server_id': return value.strip() raise errors.KcareError('Unable to parse {0}.'.format(SYSTEMID), status='server id parse error') return None def _alma_systemid(): # type: () -> Optional[str] if not os.path.exists(ALMA_SYSTEMID): return None with open(ALMA_SYSTEMID, 'r') as f: return f.readline().strip() def _im360_systemid(): # type: () -> Optional[str] if not os.path.exists(IM360_LICENSE_FILE): return None data = {} with open(IM360_LICENSE_FILE) as f: content = f.read() if content: try: data = json_loads_nstr(content) except Exception: pass # we are not interested why lic file can't be parsed return data.get('id') @utils.cached def get_serverid(): # type: () -> Optional[str] """Get server_id or None if not present. Lookup order: SYSTEMID then IM360_LICENSE_FILE then ALMA_SYSTEMID """ return _systemid() or _im360_systemid() or _alma_systemid() def rm_serverid(): # type: () -> None os.unlink(SYSTEMID) def set_server_id(server_id): # type: (str) -> None utils.atomic_write(SYSTEMID, 'server_id={0}\n'.format(server_id)) PKk1]eSjkcarectl/capabilities.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT if False: # pragma: no cover from typing import List # noqa: F401 def get_kc_capabilites_bits(): # type: () -> int # a stub, will be encoded as int when we have some capabilities return 0 def get_lc_capabilites_bits(): # type: () -> int # a stub, will be encoded as int when we have some capabilities return 0 def has_kc_capabilities(required_capabilities): # type: (List[str]) -> bool # currently agent doesn't have any capabilities # so we fail this check if there are any required capabilities return not required_capabilities def has_lc_capabilities(required_capabilities): # type: (List[str]) -> bool # currently agent doesn't have any capabilities # so we fail this check if there are any required capabilities return not required_capabilities PKk1][7 _ _kcarectl/doctor.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT """Doctor v2 vitals collector (KPT-5984). Python port of the kcdoctor.sh (1.0-8) vitals collection: gathers the same data set into a DataPackage-based archive processed by the patch server generic uploads pipeline. Scalar and short values are consolidated into a single ``doctor.json`` (the eportal doctor precedent), one field each, instead of a tiny archive entry per value; bulk data (logs, command dumps, package lists, sysfs tunables, crash artifacts) stays as separate archive entries. The 1:1 inventory of collected items lives in docs/features/KPT-5984-doctor-v2/parity-inventory.md. """ import fnmatch import glob import os import re import socket from kcarectl import auth, config, delivery_kit, http_utils, kcare, log_utils, platform_utils, serverid, utils from kcarectl.process_utils import run_command from kcarectl.py23 import HTTPError, URLError, httplib if False: # pragma: no cover from typing import Any, Callable, Dict, List, Optional # noqa: F401 DOCTOR_VERSION = '2.0-1' GRUB2_CFG = '/boot/grub2/grub.cfg' KDUMP_CONF = '/etc/kdump.conf' DPKG_LOG = '/var/log/dpkg.log' APT_SOURCES_GLOB = '/etc/apt/sources.list*' YUM_REPOS_GLOB = '/etc/yum.repos.d/*' LIBCARE_LOGS_GLOB = '/var/log/libcare/*.log' LOG_TAIL_LINES = 10000 SYSFS_ROOT = '/sys' SYSFS_NAME_PATTERNS = ('enable*', 'nr_*', 'max_*', '*cnt*') # plain prefix match, mirroring the kcdoctor.sh get_sysfs_info_detail() # `! -path "*"` find filters SYSFS_EXCLUDE_PREFIXES = ( '/sys/kernel/debug/tracing/events', '/sys/kernel/tracing/events', '/sys/devices', ) CRASH_DUMP_PATTERNS = ('[0-9]*.log', 'kmsg*log') class KcarectlDoctorPackage(delivery_kit.DataPackage): data_type = 'kcarectl-doctor' upload_uri = '/upload/kcarectl-doctor/' @property def max_size(self): # type: () -> int return config.DOCTOR_REPORT_MAX_SIZE_BYTES # --- bulk items: one archive file each --- class CollectionSpec(object): """A single bulk vitals item ported from kcdoctor.sh. Collection failures are recorded in errors.log and never abort the report: an unhandled exception inside the package context manager would remove the whole archive. """ def __init__(self, arcname, collect): # type: (str, Callable[[delivery_kit.DataPackage, str], None]) -> None self.arcname = arcname self._collect = collect def apply(self, data_package): # type: (delivery_kit.DataPackage) -> None try: self._collect(data_package, self.arcname) except Exception as e: data_package.log_error('failed to collect {0}: {1}'.format(self.arcname, e)) def run_spec(arcname, cmd): # type: (str, str) -> CollectionSpec """`run ""` kcdoctor.sh helper (no shell features)""" def collect(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None data_package.add_stdout(arcname, cmd) return CollectionSpec(arcname, collect) def dump_spec(arcname, path): # type: (str, str) -> CollectionSpec """`dump ""` kcdoctor.sh helper for regular files""" def collect(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None data_package.add_file(arcname, src_path=path) return CollectionSpec(arcname, collect) def proc_dump_spec(arcname, path): # type: (str, str) -> CollectionSpec """`dump ""` for /proc and /sys files. tar reports them as 0-size so they are first read into memory (see the same approach in anomaly.prepare_kernel_anomaly_report). """ def collect(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None if not os.path.exists(path): data_package.log_error('file not found: {0}'.format(path)) return with open(path, 'rb') as f: data_package.add_file(arcname, data_bytes=f.read()) return CollectionSpec(arcname, collect) def callable_spec(arcname, fn): # type: (str, Callable[[delivery_kit.DataPackage, str], None]) -> CollectionSpec return CollectionSpec(arcname, fn) # --- scalar/short items: one doctor.json field each --- class FieldSpec(object): """A single doctor.json field ported from kcdoctor.sh. Collection failures are recorded in errors.log and never abort the report; a collector returning None omits the field (e.g. a distro-specific source file absent on this system). """ def __init__(self, key, collect): # type: (str, Callable[[], Any]) -> None self.key = key self._collect = collect def apply(self, data_package, report): # type: (delivery_kit.DataPackage, Dict[str, Any]) -> None try: value = self._collect() except Exception as e: data_package.log_error('failed to collect {0}: {1}'.format(self.key, e)) return if value is not None: report[self.key] = value def read_field(path): # type: (str) -> Callable[[], Optional[str]] """`dump ""` as a doctor.json string field. Read in binary (non-utf8 safe) and decoded leniently; an absent distro-specific source file simply omits the field (None). """ def collect(): # type: () -> Optional[str] if not os.path.exists(path): return None with open(path, 'rb') as f: return f.read().decode('utf-8', 'replace').strip() return collect def grep_field(path, pattern): # type: (str, str) -> Callable[[], Optional[List[str]]] """`grep ` as a doctor.json list-of-lines field. Match on bytes (like collect_apt_sources) so a non-utf8 byte cannot lose a line; the matched lines are decoded leniently for the JSON. """ regex = re.compile(utils.bstr(pattern)) def collect(): # type: () -> Optional[List[str]] if not os.path.exists(path): return None with open(path, 'rb') as f: lines = f.read().splitlines() return [line.decode('utf-8', 'replace') for line in lines if regex.search(line)] return collect def cmd_field(argv, as_lines=False): # type: (List[str], bool) -> Callable[[], Any] """`run ""` captured as a doctor.json field instead of a file.""" def collect(): # type: () -> Any _, stdout, _ = run_command(argv, catch_stdout=True, catch_stderr=True) text = (stdout or '').strip() return text.splitlines() if as_lines else text return collect def collect_doctor_version(): # type: () -> str return DOCTOR_VERSION @utils.cached def get_main_ip(): # type: () -> str """the public IP of the machine as seen by the patch server. Cached: the main_ip and server_id fields share one HTTP roundtrip per run. """ try: response = http_utils.urlopen(utils.get_patch_server_url('myip')) return utils.nstr(response.read()).strip() except Exception: return 'NA' def collect_server_id(): # type: () -> str server_id = serverid.get_serverid() if not server_id: # like kcdoctor.sh: fall back to the main IP with dots replaced server_id = get_main_ip().replace('.', '_') return utils.nstr(server_id) def collect_kernel_id(): # type: () -> str # kcdoctor.sh runs `sha1sum /proc/version`; get_kernel_hash() is the # same digest without the trailing file name return kcare.get_kernel_hash() def collect_uname(): # type: () -> Dict[str, str] result = {} # type: Dict[str, str] for flag in ('a', 'r', 'm', 'p', 'o'): _, stdout, _ = run_command(['uname', '-' + flag], catch_stdout=True, catch_stderr=True) result[flag] = (stdout or '').strip() return result def collect_grub2_entries(): # type: () -> Optional[List[str]] """`grep vmlinuz /boot/grub2/grub.cfg | sed 's/root=.*//'`""" if not os.path.exists(GRUB2_CFG): return None with open(GRUB2_CFG, 'rb') as f: text = f.read().decode('utf-8', 'replace') return [re.sub(r'root=.*', '', line) for line in text.splitlines() if 'vmlinuz' in line] def collect_yum_repos(): # type: () -> List[str] # `echo /etc/yum.repos.d/*`: the repo files present (empty when none) return sorted(glob.glob(YUM_REPOS_GLOB)) def collect_control_panel(): # type: () -> Dict[str, Any] """presence-only port of the kcdoctor.sh detect_cp() probes""" panels = [name for name, probe in platform_utils.CONTROL_PANEL_PROBES if probe()] return {'cp': panels, 'softaculous': platform_utils.has_softaculous()} # --- bulk collectors (one archive file each) --- def collect_ipcs(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None """`ipcs -m | sed -e s/-/=/g`""" _, stdout, _ = run_command(['ipcs', '-m'], catch_stdout=True, catch_stderr=True) data_package.add_file(arcname, data_bytes=utils.bstr((stdout or '').replace('-', '='), encoding='utf-8')) def collect_dpkg_install_log(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None """`grep ' install ' /var/log/dpkg.log`""" if not os.path.exists(DPKG_LOG): data_package.log_error('file not found: {0}'.format(DPKG_LOG)) return with open(DPKG_LOG, 'rb') as f: lines = [line for line in f.read().splitlines() if b' install ' in line] data_package.add_file(arcname, data_bytes=b'\n'.join(lines) + b'\n') def collect_packages(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None # same package list commands as anomaly.prepare_kernel_anomaly_report if os.path.exists('/usr/bin/rpm') or os.path.exists('/bin/rpm'): packages_cmd = r'rpm -q -a --queryformat="%{N}|%{V}-%{R}|%{arch}|%{INSTALLTIME:date}\n"' elif os.path.exists('/usr/bin/dpkg'): packages_cmd = r'/usr/bin/dpkg-query -W -f "${binary:Package}|${Version}|${Architecture}\n"' # an unreadable dpkg.log must not lose the package list below # (partial results, like the other multi-source collectors) try: collect_dpkg_install_log(data_package, 'dpkg.log') except Exception as e: data_package.log_error('failed to collect dpkg.log: {0}'.format(e)) else: packages_cmd = 'echo "unknown package manager"' data_package.add_stdout(arcname, packages_cmd) def collect_apt_sources(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None """`grep -rE '^(deb|URIs)' /etc/apt/sources.list*`""" regex = re.compile(br'^(deb|URIs)') files = [] # type: List[str] for path in sorted(glob.glob(APT_SOURCES_GLOB)): if os.path.isdir(path): for root, _, names in os.walk(path): files.extend(os.path.join(root, name) for name in sorted(names)) else: files.append(path) # like the shell `grep`: report the no-match case in errors.log # instead of storing an empty entry if not files: data_package.log_error('file not found: {0}'.format(APT_SOURCES_GLOB)) return lines = [] # type: List[bytes] for path in files: # an unreadable file must not lose the lines of the others try: with open(path, 'rb') as f: content = f.read() except Exception as e: data_package.log_error('failed to read {0}: {1}'.format(path, e)) continue prefix = utils.bstr('{0}:'.format(path), encoding='utf-8') lines.extend(prefix + line for line in content.splitlines() if regex.search(line)) data_package.add_file(arcname, data_bytes=b'\n'.join(lines) + b'\n') def collect_libcare_logs(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None """`tail -n10000 /var/log/libcare/*.log`""" paths = sorted(glob.glob(LIBCARE_LOGS_GLOB)) # like the shell `tail`: report the no-match case in errors.log # instead of storing an empty entry if not paths: data_package.log_error('file not found: {0}'.format(LIBCARE_LOGS_GLOB)) return chunks = [] # type: List[bytes] for path in paths: # an unreadable log must not lose the tails of the others try: with open(path, 'rb') as f: lines = f.read().splitlines()[-LOG_TAIL_LINES:] except Exception as e: data_package.log_error('failed to read {0}: {1}'.format(path, e)) continue header = utils.bstr('==> {0} <==\n'.format(path), encoding='utf-8') chunks.append(header + b'\n'.join(lines)) data_package.add_file(arcname, data_bytes=b'\n'.join(chunks) + b'\n') def collect_crash_dumps(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None """crashreporter artifacts from /var/cache/kcare/dumps""" if not os.path.isdir(config.KDUMPS_DIR): return data_package.add_stdout(arcname, 'ls -lR {0}'.format(config.KDUMPS_DIR)) for root, _, names in os.walk(config.KDUMPS_DIR): for name in sorted(names): if any(fnmatch.fnmatch(name, pattern) for pattern in CRASH_DUMP_PATTERNS): path = os.path.join(root, name) # keep the path relative to KDUMPS_DIR in the arcname so # same-named dumps from different subdirectories do not # overwrite each other in the archive rel_path = os.path.relpath(path, config.KDUMPS_DIR) data_package.add_file('crashreporter/{0}'.format(rel_path), src_path=path) def collect_kdump(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None # kcdoctor.sh gates kdump collection on `[ -e /etc/kdump.conf ]`; without # it get_kdump_root() defaults to /var/crash, so an unconfigured host with # a stale crash dir would otherwise be collected. if not os.path.exists(KDUMP_CONF): return kdump_root = kcare.get_kdump_root() if not os.path.isdir(kdump_root): return data_package.add_stdout(arcname, 'ls -lR {0}'.format(kdump_root)) for evt in sorted(glob.glob(os.path.join(kdump_root, '*'))): # only crash event directories can hold a vmcore-dmesg.txt; # skip regular files to keep errors.log free of noise if not os.path.isdir(evt): continue data_package.add_file( 'kdump/{0}/vmcore-dmesg.txt'.format(os.path.basename(evt)), src_path=os.path.join(evt, 'vmcore-dmesg.txt'), ) def collect_sysfs_config(data_package, arcname): # type: (delivery_kit.DataPackage, str) -> None """tunables gathered by the kcdoctor.sh get_sysfs_info() `find /sys` calls""" chunks = [] for root, dirs, names in os.walk(SYSFS_ROOT): if root.startswith(SYSFS_EXCLUDE_PREFIXES): dirs[:] = [] # do not descend into excluded subtrees continue for name in sorted(names): if any(fnmatch.fnmatch(name, pattern) for pattern in SYSFS_NAME_PATTERNS): path = os.path.join(root, name) try: with open(path, 'rb') as f: content = f.read() except Exception: content = b'' chunks.append(utils.bstr('cat {0}\n'.format(path)) + content + b'\n') data_package.add_file(arcname, data_bytes=b''.join(chunks)) # the full kcdoctor.sh (1.0-8) vitals set, in the script order; see # docs/features/KPT-5984-doctor-v2/parity-inventory.md for the mapping # scalar/short items, consolidated into doctor.json (one field each) FIELD_SPECS = [ FieldSpec('doctor_version', collect_doctor_version), FieldSpec('virt_what', cmd_field(['/usr/libexec/kcare/virt-what'], as_lines=True)), FieldSpec('main_ip', get_main_ip), FieldSpec('server_id', collect_server_id), FieldSpec('kernel_id', collect_kernel_id), FieldSpec('date', cmd_field(['date'])), FieldSpec('uname', collect_uname), FieldSpec('redhat_release', read_field('/etc/redhat-release')), FieldSpec('debian_version', read_field('/etc/debian_version')), FieldSpec('os_release', read_field('/etc/os-release')), FieldSpec('issue', read_field('/etc/issue')), FieldSpec('sysconfig_kernel', read_field('/etc/sysconfig/kernel')), FieldSpec('proc_uptime', read_field('/proc/uptime')), FieldSpec('proc_loadavg', read_field('/proc/loadavg')), FieldSpec('proc_cmdline', read_field('/proc/cmdline')), FieldSpec('proc_version', read_field('/proc/version')), FieldSpec('default_grub', grep_field('/etc/default/grub', 'DEFAULT')), FieldSpec('grub2_entries', collect_grub2_entries), FieldSpec('sshd_port', grep_field('/etc/ssh/sshd_config', 'Port')), FieldSpec('yum_repos_d', collect_yum_repos), FieldSpec('control_panel', collect_control_panel), ] # bulk items, one archive file each FILE_SPECS = [ run_spec('syslog', 'tail -n{0} /var/log/syslog'.format(LOG_TAIL_LINES)), run_spec('dmesg', 'dmesg'), run_spec('messages', 'tail -n{0} /var/log/messages'.format(LOG_TAIL_LINES)), run_spec('ls_var_cache_kcare', 'ls -lR /var/cache/kcare/'), dump_spec('kcare.conf', '/etc/sysconfig/kcare/kcare.conf'), run_spec('cpuinfo', 'cat /proc/cpuinfo'), proc_dump_spec('proc_vmstat', '/proc/vmstat'), proc_dump_spec('proc_devices', '/proc/devices'), proc_dump_spec('proc_diskstats', '/proc/diskstats'), proc_dump_spec('proc_mdstat', '/proc/mdstat'), proc_dump_spec('proc_meminfo', '/proc/meminfo'), proc_dump_spec('proc_swaps', '/proc/swaps'), proc_dump_spec('proc_filesystems', '/proc/filesystems'), proc_dump_spec('proc_mounts', '/proc/mounts'), proc_dump_spec('proc_interrupts', '/proc/interrupts'), dump_spec('grub.conf', '/boot/grub/grub.conf'), proc_dump_spec('proc_modules', '/proc/modules'), dump_spec('grub2.cfg', GRUB2_CFG), proc_dump_spec('proc_zoneinfo', '/proc/zoneinfo'), run_spec('ls_boot_configs', 'ls /etc/grub.conf /boot/grub/grub.conf /boot/grub/menu.lst'), run_spec('ls_boot', 'ls -l /boot'), run_spec('printenv', 'printenv'), run_spec('dmidecode', 'dmidecode'), callable_spec('ipcs', collect_ipcs), run_spec('sysctl', 'sysctl -a'), dump_spec('sysctl.conf', '/etc/sysctl.conf'), callable_spec('packages.list', collect_packages), run_spec('lspci', 'lspci -vv'), run_spec('dpkg_l', 'dpkg -l'), callable_spec('apt_sources', collect_apt_sources), dump_spec('yum.conf', '/etc/yum.conf'), run_spec('yum_repolist', 'yum repolist'), callable_spec('libcare_logs', collect_libcare_logs), run_spec('kcarectl.log', 'tail -n{0} /var/log/kcarectl.log'.format(LOG_TAIL_LINES)), dump_spec('kdump.conf', KDUMP_CONF), dump_spec('kcare-cron', '/etc/cron.d/kcare-cron'), callable_spec('crashreporter/ls', collect_crash_dumps), callable_spec('kdump/ls', collect_kdump), run_spec('aa_status', 'aa-status'), run_spec('sestatus', 'sestatus'), run_spec('kprobes_list', 'cat /sys/kernel/debug/kprobes/list'), callable_spec('sysfs_config', collect_sysfs_config), run_spec('lsblk', 'lsblk -f'), run_spec('df', 'df -h'), ] @utils.catch_errors(logger=log_utils.logwarn) def prepare_doctor_report(): # type: () -> Optional[KcarectlDoctorPackage] # None when collection fails (catch_errors): KPT-6064/KPT-6065 # callers must handle it data_package = KcarectlDoctorPackage() with data_package: report = {} # type: Dict[str, Any] for field in FIELD_SPECS: field.apply(data_package, report) data_package.add_json('doctor.json', report) for spec in FILE_SPECS: spec.apply(data_package) return data_package def send_doctor_report(fallback, force_fallback=False): # type: (Callable[[], None], bool) -> None """Collect and upload the doctor report via the generic uploads proxy. PUTs the archive to ``/upload/kcarectl-doctor/`` -- the same modern pipeline as ``kernel-anomaly`` -- which ePortal proxies transparently to the patch server, so no ePortal change is required. Any 2xx reply is success, including the ``REDUCED_REPORT`` ``204`` where the proxy intentionally drops the report (``send()`` returns without raising, so we do not fall back). Falls back to the legacy ``kcdoctor.sh`` flow (``fallback``) when: * ``force_fallback`` (the ``--doctor --fallback`` CLI flag) or ``config.FORCE_DOCTOR_FALLBACK`` is set -- the rollout kill-switch. ``--fallback`` is the one-off, per-invocation form; the config knob is settable per host in kcare.conf or pushed fleet-wide via the ``KC-Flag-Force-Doctor-Fallback`` feature flag. Either forces the legacy flow on every host, registered or not, before the new path is even considered; * the host is not registered, i.e. there is no auth string (OQ-4: the proxy upload requires auth, so the new path is not even attempted); * report collection failed (``prepare_doctor_report`` returned None); * the new route is unavailable on an older patch server / ePortal -- a 404 / 405 / 403, surfaced as ``HTTPError``, or a connection-level failure. ``send()`` drives ``http_utils.upload_file`` (raw ``httplib``, not ``urllib``), so transport failures surface as an ``OSError`` subclass -- ``socket.timeout``, ``ConnectionRefused``, ``socket.gaierror`` (DNS), ``ssl.SSLError`` -- or an ``httplib.HTTPException``, *not* ``URLError``; all of these mean the new path is unusable. ``upload_file`` raises only on status >= 400, so a redirect is not treated as a failure; the proxy and patch server never redirect uploads. :param fallback: legacy ``kcdoctor.sh`` runner, injected by the caller (KPT-6065) to keep this module free of an ``__init__`` import cycle. :param force_fallback: when True (``--doctor --fallback``), skip the v2 path and run ``fallback`` directly; the per-invocation form of ``config.FORCE_DOCTOR_FALLBACK``. """ if force_fallback or config.FORCE_DOCTOR_FALLBACK: src = '--fallback requested' if force_fallback else 'FORCE_DOCTOR_FALLBACK is set' log_utils.loginfo( 'doctor: {0}; using the legacy kcdoctor.sh flow'.format(src), print_msg=False, ) fallback() return if auth.get_http_auth_string() is None: log_utils.loginfo( 'doctor: host is not registered; using the legacy kcdoctor.sh flow', print_msg=False, ) fallback() return data_package = prepare_doctor_report() if data_package is None: log_utils.logwarn('doctor: report collection failed; using the legacy kcdoctor.sh flow') fallback() return try: upload_name = data_package.send() log_utils.loginfo('doctor: report uploaded as {0}'.format(upload_name), print_msg=False) # surface the uploaded filename to the user, the same way the eportal # --doctor does (kc.eportal make_doctor_report -> utils.print_wrapper) # so support can locate the report; the legacy kcdoctor.sh fallback # prints its own "Key:" line instead. print_wrapper (not loginfo) so # the line is shown unconditionally -- loginfo is gated by PRINT_LEVEL # and would be dropped under --quiet/--auto-update, whereas the legacy # kcdoctor.sh echo is not. utils.print_wrapper('Please provide this filename to support: {0}'.format(upload_name)) except (HTTPError, URLError, httplib.HTTPException, socket.error) as err: # upload_file drives httplib directly, so a transport failure # surfaces as socket.error (== OSError on py3: timeout, connection # refused, DNS, TLS) or httplib.HTTPException -- not URLError. An # HTTPError (route absent: 404 / 405 / 403) means the same thing: # the new path is unusable, so fall back to the legacy flow. log_utils.logwarn('doctor: report upload unavailable ({0}); using the legacy kcdoctor.sh flow'.format(err)) fallback() finally: data_package.remove_archive() PKk1] kcarectl/config.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT from . import constants if False: # pragma: no cover from typing import List # noqa: F401 AFTER_UPDATE_COMMAND = None AUTO_STICKY_PATCHSET = None AUTO_UPDATE = True AUTO_UPDATE_DELAY = None BEFORE_UPDATE_COMMAND = None BLACKLIST_FILE = 'kpatch.blacklist' CHECK_CLN_LICENSE_STATUS = True CHECK_SSL_CERTS = True FIXUPS_FILE = 'kpatch.fixups' FLAGS = ['keep-registration', 'manage-libcare'] FORCE_GID = None FORCE_JSON_SIG_V3 = True HTTP_TIMEOUT = 20 HTTP_UPLOAD_TIMEOUT = 240 IGNORE_UNKNOWN_KERNEL = False KPATCH_DEBUG = False # crash reporter ENABLE_CRASHREPORTER = False KDUMPS_DIR = constants.PATCH_CACHE + '/dumps' KMSG_OUTPUT = True KCORE_OUTPUT = True KCORE_OUTPUT_SIZE = 100 # 100Mb IGNORE_FEATURE_FLAGS = False LIBCARE_DISABLED = False LIBCARE_LIBS = ['libc', 'libssl', 'nscd', 'libm', 'libnss_dns'] # type: List[str] LIBCARE_PIDLOGS_MAX_TOTAL_SIZE_MB = 500 LIBCARE_SOCKET_TIMEOUT = 60 LIB_AUTO_UPDATE = True PATCH_BIN = 'kpatch.bin' PATCH_DONE = '.done' PATCH_INFO = 'kpatch.info' PATCH_LEVEL = None # a level to 'stick on' (if 0 then use latest level) PATCH_METHOD = '' PATCH_TYPE = '' PREFIX = '' PREV_PATCH_TYPE = 'default' PRINT_LEVEL = constants.PRINT_INFO REPORT_FQDN = False SEND_PERF_METRICS = False SILENCE_ERRORS = True STATUS_CHANGE_GAP = 4 * 60 * 60 + 5 * 60 # 4 hours STICKY_PATCH = False STICKY_PATCHSET = None UPDATE_DELAY = None UPDATE_FROM_LOCAL = False UPDATE_POLICY = constants.POLICY_REMOTE UPDATE_SYSCTL_CONFIG = True USERSPACE_PATCHES = None USE_CONTENT_FILE_V3 = True USE_SIGNATURE = True KERNEL_VERSION_FILE = '/proc/version' KCARE_UNAME_FILE = '/proc/kcare/effective_version' SUCCESS_TIMEOUT = 5 * 60 # anomaly reports KERNEL_ANOMALY_REPORT_ENABLE = False KERNEL_ANOMALY_REPORT_MAX_SIZE_BYTES = 500 * (1024**2) # 500MB # doctor reports DOCTOR_REPORT_MAX_SIZE_BYTES = 500 * (1024**2) # 500MB # force the legacy kcdoctor.sh flow instead of the v2 /upload proxy path -- a # rollout kill-switch, settable per host in kcare.conf or pushed fleet-wide via # the KC-Flag-Force-Doctor-Fallback feature flag FORCE_DOCTOR_FALLBACK = False # external services communication FORCE_IPV4 = False FORCE_IPV6 = False PATCH_SERVER = 'https://patches.kernelcare.com' PATCH_SERVER_IPV6 = 'https://ipv6.patches.kernelcare.com' REGISTRATION_URL = 'https://cln.cloudlinux.com/api/kcare' REGISTRATION_URL_IPV6 = 'https://ipv6.cln.cloudlinux.com/api/kcare' PKk1]Mqkcarectl/py23.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import json from . import constants if constants.PY2: # pragma: no py3 cover import httplib # isort: skip - skipped because isort incorrectly treats it as third-party from urllib import quote as urlquote from urllib import urlencode from ConfigParser import ConfigParser from urllib2 import HTTPError from urllib2 import Request as StdRequest from urllib2 import URLError from urllib2 import urlopen as std_urlopen from urlparse import urlparse # type: ignore class Request(StdRequest): def __init__(self, *args, **kwargs): method = kwargs.pop('method', None) StdRequest.__init__(self, *args, **kwargs) if method == 'HEAD': # Older versions of mypy supporting 2.x do not infer type of # the `method` variable correctly here. Cast to str explicitly. self.get_method = lambda: str(method) # type: ignore[assignment] # json.loads returns unicode strings and they can contaminate following # calls. Functions converts all unicode strings into native def _convert(data): dtype = type(data) if dtype is type(u''): return data.encode('utf-8') elif dtype is list: return [_convert(it) for it in data] elif dtype is dict: return dict((_convert(k), _convert(v)) for k, v in data.items()) return data def json_loads_nstr(json_str): return _convert(json.loads(json_str)) else: # pragma: no py2 cover from configparser import ConfigParser from http import client as httplib from urllib.error import HTTPError, URLError from urllib.parse import quote as urlquote from urllib.parse import urlencode, urlparse from urllib.request import Request from urllib.request import urlopen as std_urlopen json_loads_nstr = json.loads __all__ = [ "ConfigParser", "HTTPError", "Request", "URLError", "httplib", "json_loads_nstr", "std_urlopen", "urlencode", "urlparse", "urlquote", ] PKk1] ߬##kcarectl/__main__.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import os import sys from . import errors, log_utils, main, send_exc from .py23 import URLError # The scanner interface should skip us os.environ['KCARE_SCANNER_INTERFACE_DO_NOTHING'] = '1' if __name__ == '__main__': try: sys.exit(main()) except URLError as err: log_utils.logerror('{0}: {1}'.format(err, getattr(err, 'url', 'unknown'))) except errors.KcareError as err: log_utils.logerror(str(err)) sys.exit(1) except Exception as err: if isinstance(err, errors.SafeExceptionWrapper): log_utils.logexc(err.inner) else: log_utils.logexc(err) send_exc() sys.exit(1) PKk1]{8ڞkcarectl/fetch.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import hashlib import json import os import kcsig_verify # noqa: E402 from . import auth, config, constants, errors, http_utils, selinux, utils SIG_VERIFY_ORDER = [constants.SIG, constants.SIG_JSON] GPG_BIN = '/usr/bin/gpg' GPG_KEY_DIR = '/var/lib/kcare/gpg' CONTENT_FILE = 'release.content.json' def fetch_signature(url, dst, do_auth=False): urlopen_local = http_utils.urlopen if do_auth: urlopen_local = auth.urlopen_auth if config.FORCE_JSON_SIG_V3: sig_exts = SIG_VERIFY_ORDER[::-1] else: sig_exts = SIG_VERIFY_ORDER for sig_ext in sig_exts: try: signature = urlopen_local(url + sig_ext) break except errors.NotFound as nf: if sig_ext == sig_exts[-1]: raise nf # pragma: no cover sig_dst = dst + sig_ext # pragma: no cover utils.save_to_file(signature, sig_dst) return sig_dst def check_gpg_bin(): if not os.path.isfile(GPG_BIN): raise errors.KcareError('No {0} present. Please install gnupg'.format(GPG_BIN), status='gnupg not found') def check_gpg_signature(file_path, signature): # mocked: tests/unit """ Check a file signature using the gpg tool. If signature is wrong BadSignatureException will be raised. :param file_path: path to file which signature will be checked :param signature: a file with the signature :return: True in case of valid signature :raises: BadSignatureException """ check_gpg_bin() if signature.endswith(constants.SIG_JSON): root_keys = os.path.join(GPG_KEY_DIR, 'root-keys.json') try: kcsig_verify.verify(signature, file_path, root_keys) except kcsig_verify.Error as e: raise errors.BadSignatureException('Bad Signature: {0}: {1}'.format(file_path, str(e))) else: with open(signature, 'rb') as f: sigdata = f.read() keyring = os.path.join(GPG_KEY_DIR, 'kcare_pub.key') try: kcsig_verify.run_gpg_verify(keyring, file_path, sigdata) except Exception as e: raise errors.BadSignatureException('Bad Signature: {0}: {1}'.format(file_path, str(e))) # BadSignatureException is the only side effect of interrupted connection, # should retry file extraction in this case @utils.retry(errors.check_exc(errors.BadSignatureException), count=3, delay=0) def fetch_url(url, dst, check_signature=False, hash_checker=None): response = auth.urlopen_auth(url) tmp = selinux.selinux_safe_tmpname(dst) utils.save_to_file(response, tmp) if hash_checker: hash_checker.check(url, tmp) elif check_signature: signature = fetch_signature(url, tmp, do_auth=True) check_gpg_signature(tmp, signature) os.rename(tmp, dst) return response class HashChecker(object): def __init__(self, baseurl, content_file): self.content_file = content_file self.url_prefix = utils.get_patch_server_url(baseurl).rstrip('/') + '/' self.hashes = json.loads(utils.read_file(content_file))['files'] def check(self, url, fname): cfname = url[len(self.url_prefix) :] if cfname not in self.hashes: raise errors.KcareError( 'Invalid checksum: {0} not found in content file {1}'.format(cfname, self.content_file), status='invalid checksum', ) hsh = hashlib.sha256(utils.read_file_bin(fname)).hexdigest() expected_hsh = self.hashes[cfname]['sha256'] if hsh != expected_hsh: raise errors.BadSignatureException( 'Invalid checksum: {0} has invalid checksum {1}, expected {2}'.format(fname, hsh, expected_hsh) ) @utils.cached def get_hash_checker(level): if not config.USE_CONTENT_FILE_V3: return None if not level.baseurl: return None dst = level.cache_path(CONTENT_FILE) if not os.path.exists(dst): try: # here we also implicitly check content file signature fetch_url(utils.get_patch_server_url(level.baseurl, CONTENT_FILE), dst, config.USE_SIGNATURE) except errors.NotFound: return None return HashChecker(level.baseurl, dst) def wrap_with_cache_key(clbl): """Enrich request with a cache key, and save it if response had.""" def wrapper(*args, **kwargs): cache_key = utils.get_cache_key() if cache_key is not None: if 'headers' not in kwargs: kwargs['headers'] = {} kwargs['headers'][constants.CACHE_KEY_HEADER] = cache_key resp = clbl(*args, **kwargs) new_cache_key = resp.headers.get(constants.CACHE_KEY_HEADER) if new_cache_key is not None and new_cache_key != cache_key: utils.atomic_write(constants.CACHE_KEY_DUMP_PATH, new_cache_key) return resp return wrapper PKk1]gNgN*kcarectl/__pycache__/doctor.cpython-36.pycnu[3 ;j _.@s dZddlZddlZddlZddlZddlZddlmZmZm Z m Z m Z m Z m Z mZmZddlmZddlmZmZmZdZdZdZd Zd Zd Zd Zd ZdZdZdZ dZ!Gddde j"Z#Gddde$Z%ddZ&ddZ'd d!Z(d"d#Z)Gd$d%d%e$Z*d&d'Z+d(d)Z,dd+d,Z-d-d.Z.ej/d/d0Z0d1d2Z1d3d4Z2d5d6Z3d7d8Z4d9d:Z5d;d<Z6d=d>Z7d?d@Z8dAdBZ9dCdDZ:dEdFZ;dGdHZe*dMe.e*dNe-dOgdPdQe*dRe0e*dSe1e*dTe2e*dUe-dUge*dVe3e*dWe+dXe*dYe+dZe*d[e+d\e*d]e+d^e*d_e+d`e*dae+dbe*dce+dde*dee+dfe*dge+dhe*die,djdke*dle4e*dme,dndoe*dpe5e*dqe6gZ?e&drdsj@ee&dtdte&dudvj@ee&dwdxe'dydze&d{d|e(d}d~e(dde(dde(dde(dde(dde(dde(dde(dde'dde(dde'dee(dde&dde&dde&dde&dde)de7e&dde'dde)de9e&dde&dde)de:e'dde&dde)de;e&ddj@ee'dee'dde)de<e)de=e&dde&dde&dde)de>e&dde&ddg,ZAejBe jCdddZDdddZEdS)aODoctor v2 vitals collector (KPT-5984). Python port of the kcdoctor.sh (1.0-8) vitals collection: gathers the same data set into a DataPackage-based archive processed by the patch server generic uploads pipeline. Scalar and short values are consolidated into a single ``doctor.json`` (the eportal doctor precedent), one field each, instead of a tiny archive entry per value; bulk data (logs, command dumps, package lists, sysfs tunables, crash artifacts) stays as separate archive entries. The 1:1 inventory of collected items lives in docs/features/KPT-5984-doctor-v2/parity-inventory.md. N) authconfig delivery_kit http_utilskcare log_utilsplatform_utilsserveridutils) run_command) HTTPErrorURLErrorhttplibz2.0-1z/boot/grub2/grub.cfgz/etc/kdump.confz/var/log/dpkg.logz/etc/apt/sources.list*z/etc/yum.repos.d/*z/var/log/libcare/*.logi'z/sysenable*nr_*max_**cnt* /sys/kernel/debug/tracing/events/sys/kernel/tracing/events /sys/devices [0-9]*.logkmsg*logc@s eZdZdZdZeddZdS)KcarectlDoctorPackagezkcarectl-doctorz/upload/kcarectl-doctor/cCstjS)N)rDOCTOR_REPORT_MAX_SIZE_BYTES)selfr,/usr/libexec/kcare/python/kcarectl/doctor.pymax_size;szKcarectlDoctorPackage.max_sizeN)__name__ __module__ __qualname__ data_type upload_uripropertyrrrrrr7src@s eZdZdZddZddZdS)CollectionSpeczA single bulk vitals item ported from kcdoctor.sh. Collection failures are recorded in errors.log and never abort the report: an unhandled exception inside the package context manager would remove the whole archive. cCs||_||_dS)N)arcname_collect)rr%collectrrr__init__LszCollectionSpec.__init__cCsNy|j||jWn6tk rH}z|jdj|j|WYdd}~XnXdS)Nzfailed to collect {0}: {1})r&r% Exception log_errorformat)r data_packageerrrapplyQszCollectionSpec.applyN)rrr __doc__r(r.rrrrr$Dsr$csfdd}t||S)z4`run ""` kcdoctor.sh helper (no shell features)cs|j|dS)N) add_stdout)r,r%)cmdrrr']szrun_spec..collect)r$)r%r1r'r)r1rrun_specYs r2csfdd}t||S)z4`dump ""` kcdoctor.sh helper for regular filescs|j|ddS)N)src_path)add_file)r,r%)pathrrr'hszdump_spec..collect)r$)r%r5r'r)r5r dump_specds r6csfdd}t||S)z`dump ""` for /proc and /sys files. tar reports them as 0-size so they are first read into memory (see the same approach in anomaly.prepare_kernel_anomaly_report). c sLtjjs |jdjdStd}|j||jdWdQRXdS)Nzfile not found: {0}rb) data_bytes)osr5existsr*r+openr4read)r,r%f)r5rrr'ws   zproc_dump_spec..collect)r$)r%r5r'r)r5rproc_dump_specos r>cCs t||S)N)r$)r%fnrrr callable_specsr@c@s eZdZdZddZddZdS) FieldSpeczA single doctor.json field ported from kcdoctor.sh. Collection failures are recorded in errors.log and never abort the report; a collector returning None omits the field (e.g. a distro-specific source file absent on this system). cCs||_||_dS)N)keyr&)rrBr'rrrr(szFieldSpec.__init__cCsXy |j}Wn4tk r@}z|jdj|j|dSd}~XnX|dk rT|||j<dS)Nzfailed to collect {0}: {1})r&r)r*r+rB)rr,reportvaluer-rrrr.s zFieldSpec.applyN)rrr r/r(r.rrrrrAsrAcsfdd}|S)z`dump ""` as a doctor.json string field. Read in binary (non-utf8 safe) and decoded leniently; an absent distro-specific source file simply omits the field (None). c s:tjjsdStd}|jjddjSQRXdS)Nr7zutf-8replace)r9r5r:r;r<decodestrip)r=)r5rrr's  zread_field..collectr)r5r'r)r5r read_fields rHcs"tjtj|fdd}|S)z`grep ` as a doctor.json list-of-lines field. Match on bytes (like collect_apt_sources) so a non-utf8 byte cannot lose a line; the matched lines are decoded leniently for the JSON. c sDtjjsdStd}|jj}WdQRXfdd|DS)Nr7cs"g|]}j|r|jddqS)zutf-8rE)searchrF).0line)regexrr sz/grep_field..collect..)r9r5r:r;r< splitlines)r=lines)r5rLrrr's   zgrep_field..collect)recompiler bstr)r5patternr'r)r5rLr grep_fields rTFcsfdd}|S)z@`run ""` captured as a doctor.json field instead of a file.cs0tddd\}}}|pdj}r,|jS|S)NT) catch_stdout catch_stderr)r rGrN)_stdouttext)argvas_linesrrr's zcmd_field..collectr)r[r\r'r)r[r\r cmd_fieldsr]cCstS)N)DOCTOR_VERSIONrrrrcollect_doctor_versionsr_c Cs<y"tjtjd}tj|jjStk r6dSXdS)zthe public IP of the machine as seen by the patch server. Cached: the main_ip and server_id fields share one HTTP roundtrip per run. ZmyipZNAN)rurlopenr get_patch_server_urlnstrr<rGr))responserrr get_main_ips rdcCs$tj}|stjdd}tj|S)N.rX)r get_serveridrdrEr rb) server_idrrrcollect_server_idsrhcCstjS)N)rget_kernel_hashrrrrcollect_kernel_idsrjcCsBi}x8d D]0}tdd|gddd \}}}|p0d j||<q W|S) Narmpouname-T)rUrVrW)rkrlrmrnro)r rG)resultflagrXrYrrr collect_unames  rtc CsHtjjtsdSttd}|jjdd}WdQRXdd|jDS)z7`grep vmlinuz /boot/grub2/grub.cfg | sed 's/root=.*//'`Nr7zutf-8rEcSs"g|]}d|krtjdd|qS)Zvmlinuzzroot=.*rW)rPsub)rJrKrrrrMsz)collect_grub2_entries..)r9r5r: GRUB2_CFGr;r<rFrN)r=rZrrrcollect_grub2_entries s   rwcCsttjtS)N)sortedglobYUM_REPOS_GLOBrrrrcollect_yum_repossr{cCsddtjD}|tjdS)z8presence-only port of the kcdoctor.sh detect_cp() probescSsg|]\}}|r|qSrr)rJnameproberrrrMsz)collect_control_panel..)cpZ softaculous)rCONTROL_PANEL_PROBEShas_softaculous)Zpanelsrrrcollect_control_panelsrcCs@tddgddd\}}}|j|tj|p(djdddd d d S) z`ipcs -m | sed -e s/-/=/g`ipcsz-mT)rUrVrWrq=zutf-8)encoding)r8N)r r4r rRrE)r,r%rXrYrrr collect_ipcs%src Cshtjjts |jdjtdSttd}dd|jjD}WdQRX|j |dj |dddS)z$`grep ' install ' /var/log/dpkg.log`zfile not found: {0}Nr7cSsg|]}d|kr|qS)s install r)rJrKrrrrM4sz,collect_dpkg_install_log.. )r8) r9r5r:DPKG_LOGr*r+r;r<rNr4join)r,r%r=rOrrrcollect_dpkg_install_log,s    rcCstjjdstjjdrd}nXtjjdrrd}yt|dWqvtk rn}z|jdj|WYdd}~XqvXnd}|j||dS) Nz /usr/bin/rpmz/bin/rpmzFrpm -q -a --queryformat="%{N}|%{V}-%{R}|%{arch}|%{INSTALLTIME:date}\n"z /usr/bin/dpkgzJ/usr/bin/dpkg-query -W -f "${binary:Package}|${Version}|${Architecture}\n"zdpkg.logzfailed to collect dpkg.log: {0}zecho "unknown package manager")r9r5r:rr)r*r+r0)r,r% packages_cmdr-rrrcollect_packages9s $rc sFtjdg}xdttjtD]R}tjj|rfx@tj|D]&\}}|j fddt|Dq:Wq|j |qW|s|j dj tdSg}x|D]}y"t |d}|j}WdQRXWn6tk r} z|j dj || wWYdd} ~ XnXtjdj |d d |j fd d|jDqW|j|d j|d d dS)z/`grep -rE '^(deb|URIs)' /etc/apt/sources.list*`s ^(deb|URIs)c3s|]}tjj|VqdS)N)r9r5r)rJr|)rootrr Usz&collect_apt_sources..zfile not found: {0}Nr7zfailed to read {0}: {1}z{0}:zutf-8)rc3s |]}j|r|VqdS)N)rI)rJrK)prefixrLrrrjsr)r8)rPrQrxryAPT_SOURCES_GLOBr9r5isdirwalkextendappendr*r+r;r<r)r rRrNr4r) r,r%filesr5rXnamesrOr=contentr-r)rrLrrcollect_apt_sourcesLs*  "  "rc Csttjt}|s&|jdjtdSg}x|D]}y0t|d}|jjt d}WdQRXWn6t k r}z|jdj||w0WYdd}~XnXt j dj|dd}|j |dj |q0W|j|dj |dd dS) z%`tail -n10000 /var/log/libcare/*.log`zfile not found: {0}Nr7zfailed to read {0}: {1}z ==> {0} <== zutf-8)rr)r8)rxryLIBCARE_LOGS_GLOBr*r+r;r<rNLOG_TAIL_LINESr)r rRrrr4) r,r%pathschunksr5r=rOr-headerrrrcollect_libcare_logsos  $rcstjjtjsdS|j|djtjxttjtjD]d\}}}xXt|D]Lt fddt DrHtjj |}tjj |tj}|j dj||dqHWq4WdS)z3crashreporter artifacts from /var/cache/kcare/dumpsNz ls -lR {0}c3s|]}tj|VqdS)N)fnmatch)rJrS)r|rrrsz&collect_crash_dumps..zcrashreporter/{0})r3)r9r5rr KDUMPS_DIRr0r+rrxanyCRASH_DUMP_PATTERNSrrelpathr4)r,r%rrXrr5Zrel_pathr)r|rcollect_crash_dumpssrcCstjjtsdStj}tjj|s(dS|j|dj|xTt t j tjj |dD]8}tjj|sfqT|j djtjj |tjj |ddqTWdS)Nz ls -lR {0}*zkdump/{0}/vmcore-dmesg.txtzvmcore-dmesg.txt)r3)r9r5r: KDUMP_CONFrget_kdump_rootrr0r+rxryrr4basename)r,r% kdump_rootZevtrrr collect_kdumps   rc sg}xtjtD]\}}}|jtr2g|dd<qxt|D]tfddtDr.r7zcat {0} r)r8)r9r SYSFS_ROOT startswithSYSFS_EXCLUDE_PREFIXESrxrSYSFS_NAME_PATTERNSr5rr;r<r)rr rRr+r4) r,r%rrdirsrr5r=rr)r|rcollect_sysfs_configs    &rZdoctor_versionZ virt_whatz/usr/libexec/kcare/virt-whatT)r\Zmain_iprgZ kernel_iddaterpZredhat_releasez/etc/redhat-releaseZdebian_versionz/etc/debian_versionZ os_releasez/etc/os-releaseZissuez /etc/issueZsysconfig_kernelz/etc/sysconfig/kernelZ proc_uptimez /proc/uptimeZ proc_loadavgz /proc/loadavgZ proc_cmdlinez /proc/cmdline proc_versionz /proc/versionZ default_grubz/etc/default/grubDEFAULTZ grub2_entriesZ sshd_portz/etc/ssh/sshd_configZPortZ yum_repos_dZ control_panelsyslogztail -n{0} /var/log/syslogdmesgmessagesztail -n{0} /var/log/messagesls_var_cache_kcarezls -lR /var/cache/kcare/z kcare.confz/etc/sysconfig/kcare/kcare.confcpuinfozcat /proc/cpuinfoZ proc_vmstatz /proc/vmstatZ proc_devicesz /proc/devicesZproc_diskstatsz/proc/diskstatsZ proc_mdstatz /proc/mdstatZ proc_meminfoz /proc/meminfoZ proc_swapsz /proc/swapsZproc_filesystemsz/proc/filesystemsZ proc_mountsz /proc/mountsZproc_interruptsz/proc/interruptsz grub.confz/boot/grub/grub.conf proc_modulesz /proc/modulesz grub2.cfgZ proc_zoneinfoz/proc/zoneinfoZls_boot_configsz:ls /etc/grub.conf /boot/grub/grub.conf /boot/grub/menu.lstZls_bootz ls -l /bootZprintenvZ dmidecodersysctlz sysctl -az sysctl.confz/etc/sysctl.confz packages.listZlspciz lspci -vvZdpkg_lzdpkg -lZ apt_sourceszyum.confz /etc/yum.confZ yum_repolistz yum repolistZ libcare_logsz kcarectl.logz tail -n{0} /var/log/kcarectl.logz kdump.confz kcare-cronz/etc/cron.d/kcare-cronzcrashreporter/lszkdump/lsZ aa_statusz aa-statusZsestatusZ kprobes_listz"cat /sys/kernel/debug/kprobes/listZ sysfs_configZlsblkzlsblk -fZdfzdf -h)loggerc Cs\t}|Hi}xtD]}|j||qW|jd|xtD]}|j|q= 400, so a redirect is not treated as a failure; the proxy and patch server never redirect uploads. :param fallback: legacy ``kcdoctor.sh`` runner, injected by the caller (KPT-6065) to keep this module free of an ``__init__`` import cycle. :param force_fallback: when True (``--doctor --fallback``), skip the v2 path and run ``fallback`` directly; the per-invocation form of ``config.FORCE_DOCTOR_FALLBACK``. z--fallback requestedzFORCE_DOCTOR_FALLBACK is setz.doctor: {0}; using the legacy kcdoctor.sh flowF) print_msgNzAdoctor: host is not registered; using the legacy kcdoctor.sh flowzCdoctor: report collection failed; using the legacy kcdoctor.sh flowzdoctor: report uploaded as {0}z,Please provide this filename to support: {0}zJdoctor: report upload unavailable ({0}); using the legacy kcdoctor.sh flow)rFORCE_DOCTOR_FALLBACKrloginfor+rget_http_auth_stringrlogwarnsendr print_wrapperr r r HTTPExceptionsocketerrorremove_archive)fallbackforce_fallbacksrcr, upload_nameerrrrrsend_doctor_report-s4)    r)rrrr)rrr)rr)F)F)Fr/rryr9rPrkcarectlrrrrrrrr r Zkcarectl.process_utilsr Z kcarectl.py23r r rr^rvrrrrzrrrrrr DataPackagerobjectr$r2r6r>r@rArHrTr]r_cachedrdrhrjrtrwr{rrrrrrrrrrr+r catch_errorsrrrrrrrs,          #           PKk1]-kcarectl/__pycache__/constants.cpython-36.pycnu[3 ;j@sddlZddlZdZdZdZdZdZejddkZdZ ej j e dZ ej j e dZ d Zd Zd Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"dZ#dZ$dZ%dS)Nz/var/cache/kcarezfeature_flags.jsonzupdate_status.jsondz Kc-Cache-Keyz/etc/sysconfig/kcare/cache_keyZREMOTEZLOCALZ LOCAL_FIRST3z/var/log/kcarectl.logz.sigz .json-sigz Kc-Auth-Tokenz/etc/sysconfig/kcare/auth_tokenFz/usr/bin/systemctlZmanualautoZsmartzkcare.koz/usr/libexec/kcare/kpatch_ctlz 3.8-1.el8)&ossys PRINT_DEBUG PRINT_INFOZ PRINT_WARN PRINT_ERRORPRINT_CRITICAL version_infoZPY2 PATCH_CACHEpathjoinZFEATURE_FLAGS_CACHEZUPDATE_STATUS_PATHZUPDATE_ERROR_MAX_LENGTHZCACHE_KEY_HEADERZCACHE_KEY_DUMP_PATH POLICY_REMOTE POLICY_LOCALPOLICY_LOCAL_FIRSTZKC_PATCH_VERSIONLOG_FILESIGZSIG_JSONAUTH_TOKEN_HEADERAUTH_TOKEN_DUMP_PATHZ RETRY_DELAYZRETRY_MAX_DELAYZ RETRY_BACKOFFZ RETRY_COUNTZSKIP_SYSTEMCTL_CHECKZ SYSTEMCTLUPDATE_MODE_MANUALUPDATE_MODE_AUTOUPDATE_MODE_SMARTKMOD_BIN KPATCH_CTLVERSIONr!r!//usr/libexec/kcare/python/kcarectl/constants.pysDPKk1]B0kcarectl/__pycache__/ipv6_support.cpython-36.pycnu[3 ;j@sddlZddlZddlZddlZddlmZmZmZmZm Z m Z ddl m Z dZ dZdZejjejdZdZGd d d eZeZd d Zd dZddZddZddZdS)N)config constants http_utils log_utilsserveridutils)json_loads_nstrzipv6_preference.json<c@s,eZdZddZeddZeddZdS)IPProtoSelectorcCsbtjrtjddStjjds.tjddStjrBtjddSt}|dk rltjdj|r`dnd |Sd}|j tj stjd d}n2|j tjstjd d}nt j rtjd d}|dk rt ||S|jdd }|jdd }|tkrtjdd}nR|tkrtjdd}n8|tkr8tjdd}n|tkrRtjdd}nd}t ||S)ak Choose ipv6 if it is more suitable. Checks order: - check config values (it is faster) - eportal setup and FORCE_IPVx - then check each proto availability using HEAD requests - then check if we have server_id, it means we don't expect an ip license - and finally we need to check if there is an ip license z,decided to use ipv4 because of config valuesFzkernelcare.comz,decided to use ipv6 because of config valuesTNz%decided to use {0} from on-disk cacheipv6Zipv4z1decided to use ipv4 because ipv6 is not availablez1decided to use ipv6 because ipv4 is not availablez/decided to use ipv4 because server id was found)rz2decided to use ipv4 because ipv4 license was foundz2decided to use ipv6 because ipv6 license was foundz8decided to use ipv4 because ipv4 trial license was foundz8decided to use ipv6 because ipv6 trial license was found)r FORCE_IPV4rlogdebug PATCH_SERVERendswith FORCE_IPV6 _read_cacheformat_is_url_reachablePATCH_SERVER_IPV6r get_serverid _write_cache_get_cln_licenseCLN_VALID_LICENSECLN_TRIAL_ACTIVE_LICENSE)selfcachedresultZ ipv4_licenseZ ipv6_licenser 2/usr/libexec/kcare/python/kcarectl/ipv6_support.pyis_ipv6_preferredsV                    z!IPProtoSelector.is_ipv6_preferredcCsbtj|ddd}ytj|dddddStk r\}ztjdj|t|dSd}~XnXdS) NHEAD)method auth_string F)timeout retry_on_500 retry_countTz%error during HEAD request to {0}: {1})r http_requesturlopen Exceptionrrrstr)urlrequester r r!r`sz!IPProtoSelector._is_url_reachablec Cs|r tjntj}|d}tjtj|ddj}tj|}| sL|j d rbt j j dj |tSy t|dStk rtSXdS)Nz /check.plainF)r)codezUnexpected CLN response: {0})rREGISTRATION_URL_IPV6REGISTRATION_URLrnstrrr,read data_as_dictgetrkcarelogerrorrCLN_NO_LICENSEint ValueError)rZbase_urlr/contentinfor r r!rks  z IPProtoSelector._get_cln_licenseN)__name__ __module__ __qualname__r" staticmethodrrr r r r!r sA r c Cstjt}|sdSy t|}Wn,ttfk rJtjdj|dddSXt |t sntjdj|dddS|j d}t |t stjdj|dddS|j d}t |t j st |t rtjdj|dddStjt|}|d kp|tkr tjd j|tdS|S) Nz+ipv6 preference cache: malformed json {0!r}F) print_msgz/ipv6 preference cache: unexpected payload {0!r} prefer_ipv6z3ipv6 preference cache: unexpected prefer_ipv6 {0!r}tsz)ipv6 preference cache: malformed ts {0!r}rz;ipv6 preference cache: stale entry (age={0:.0f}s, ttl={1}s))r try_to_read CACHE_FILEr r= TypeErrorrlogwarnr isinstancedictr8boolnumbersZIntegraltimer<CACHE_TTL_SECONDSr)r>datarEZ cached_tsZager r r!rs0      rcCsl|ttjd}ytjttj|ddWn:ttfk rf}zt j dj |ddWYdd}~XnXdS)N)rErFT) ensure_dirz*failed to write ipv6 preference cache: {0}F)rD) r<rOr atomic_writerHjsondumpsOSErrorIOErrorrrJr)rrQr1r r r!rs rc Cs(ytjtWntk r"YnXdS)z'Drop the on-disk ipv6 preference cache.N)osunlinkrHrVr r r r! clear_cachesrZcCstjrtjStjS)N)ip_proto_selectorr"rrrr r r r!get_patch_serversr\cCstjrtjStjS)N)r[r"rr3r4r r r r!get_registration_urlsr]iiQ)rTrNrXrOrrrrrrpy23r rrr;pathjoin PATCH_CACHErHrPobjectr r[rrrZr\r]r r r r!s"  b'  PKk1]w˕||+kcarectl/__pycache__/anomaly.cpython-36.pycnu[3 ;j@sddlZddlZddlmZmZmZmZejejdddZ ddZ ejejddd Z ejejd d d d Z e dkre idS)N) delivery_kitkcare log_utilsutils)loggercCs|jS)aSend the DataPackage archive to the patch server. Upload errors are logged and swallowed (catch_errors), preserving the historical kernel-anomaly behavior. :param data_package: DataPackage instance to send :return: Upload name (package identifier) )send) data_packager -/usr/libexec/kcare/python/kcarectl/anomaly.pysend_data_packages r cCsTtj}xFtj|D]8\}}||dkr*Pdj||jdd}|j||dqWdS)zZadds recent files for the last hour to the given data package starting from the newest oneiz{0}/{1}/_)src_pathN)timerZsort_files_by_ctimeformatreplaceadd_file)filesrZarchive_prefixnowpathctimeZarcnamer r r copy_recent_filess  rc3Cstj}|tjjdr(|jddtjjdr@|jdd|jdd|jd d |jd d tjjd s|tjjd rd}n$tjjdrd}|jdddnd}|jd|td}|jdtj |j dWdQRXtd}|jdtj |j dWdQRX|jddd|j d||jddd|jd d!j t jytt j|d"Wn4tk r}z|jd#j |WYdd}~XnXytt j|d$Wn4tk r}z|jd%j |WYdd}~XnXWdQRX|S)&Nz/var/log/messagesmessagesztail -n10000 /var/log/messagesz/var/log/syslogZsyslogztail -n10000 /var/log/syslogz kcarectl.logz"tail -n10000 /var/log/kcarectl.logZdmesgZls_var_cache_kcarezls -lR /var/cache/kcare/z /usr/bin/rpmz/bin/rpmzFrpm -q -a --queryformat="%{N}|%{V}-%{R}|%{arch}|%{INSTALLTIME:date}\n"z /usr/bin/dpkgzJ/usr/bin/dpkg-query -W -f "${binary:Package}|${Version}|${Architecture}\n"zdpkg.logz/var/log/dpkg.log)rzecho "unknown package manager"z packages.listz /proc/versionZ proc_version)Z data_bytesz /proc/modulesZ proc_modulesz kcare.confz/etc/sysconfig/kcare/kcare.confzserver_info.jsonz kdump.confz/etc/kdump.confZls_kdumpz ls -lR {0}Zkdumpzfailed to copy kdumps: {0}Z crashreporterz+failed to copy crashreporter artifacts: {0})rZKernelAnomalyPackageosrexistsZ add_stdoutropenrbstrreadZadd_jsonrrZget_kdump_rootrZlist_kdump_txt_files ExceptionZ log_errorZlist_crashreporter_log_files) server_inforZ packages_cmdfer r r prepare_kernel_anomaly_report*sB          " " ",r"F)rZdefault_returnc Cs|d}t|d}t|jdp"d}t|d}|d}yt|dd}Wntttfk rld}YnX||||||g}t|sd Sd }d } d } |d kr|dkrd }|||ko||d knr|dkrd } ||krd } || | g} t| rtjdj|d Sd S)z3taken from eportal - anomalies::detect_agent_rebootreasonuptime patch_levelz-1 last_stoptsstaterFi,TiupdatezAgent anomaly detected: {0}) intgetKeyError TypeError ValueErrorallrloginfor) rr#r$r%r&r'Zstate_tsZfieldsZ first_update_after_reboot_markerZcrash_soon_after_update_markerZno_proper_shutdown_markermarkersr r r detect_anomaly_s8   , r4__main__)rrkcarectlrrrrZ catch_errorslogwarnr rr"r4__name__r r r r s 5-PKk1]6ՌII+kcarectl/__pycache__/libcare.cpython-36.pycnu[3 ;jb@s ddlZddlZddlZddlZddlZddlmZmZmZm Z m Z m Z m Z m Z mZmZmZmZmZmZddlmZmZmZdZdOZdZd Zd Zd d d d Zd dedgfddedgfgZej ddZ!ddZ"ddZ#ddZ$Gddde%Z&ddZ'dPddZ(dd Z)d!d"Z*d#d$Z+dQd&d'Z,d(d)Z-e$d*d+Z.e$d,d-Z/e$d.d/Z0d0d1Z1d2d3Z2d4d5Z3d6d7Z4d8d9Z5dRd:d;Z6e$e'ej7dd?Z9ej7ej:d@ej;e$e'e jdEdFZ?dGdHZ@dSdIdJZAdKdLZBdMdNZCdS)TN)auth capabilitiesconfigconfig_handlers constantserrorsfetch log_utilsplatform_utils process_utilsselinux server_info update_utilsutils) HTTPErrorjson_loads_nstrurlquotez!/usr/libexec/kcare/libcare-client/run/libcare/libcare.sock/var/run/libcare.sockz /var/cache/kcare/libcare_patchesz /var/cache/kcare/libcare_cvelistz&/etc/sysconfig/kcare/libcare.logrotatedb)mysqldmariadbdpostgresZubuntuz16. libnss_dnsz7.c sttj}ty tj}|dj}|d}Wn0tk r`xtD]\}}}|OqFWYn>X|d}x2tD]*\}}}|dks||krp|j |rp|PqpWfdd|DS)Nrr.csg|]}|kr|qSr).0lib) blacklistedr-/usr/libexec/kcare/python/kcarectl/libcare.py Rsz/_get_effective_libcare_libs..) listr LIBCARE_LIBSsetr get_distrolower ExceptionLIBCARE_LIBS_BLACKLIST startswith) libsZ distro_infodistroversion_Zbl_libsZversion_dottedZ bl_distroZ bl_versionr)rr _get_effective_libcare_libs;s   r.cCsdddgtdS)Nrrr)rr*)r.rrrr get_userspace_mapUsr/cGstjjtjd|f|S)N userspace)ospathjoinr PATCH_CACHE)libnamepartsrrr get_userspace_cache_path\sr7csfdd}|S)NcsVz ||Sy tdWn6tk rN}ztjdj|ddWYdd}~XnXXdS)N clearcachez$Libcare cache clearing failed: '{0}'F) print_msg)libcare_clientr'r logerrorformat)argskwargserr)clblrr wrapperas   z$clear_libcare_cache..wrapperr)r@rAr)r@r clear_libcare_cache`s rBcs0eZdZdfdd Zd ddZddZZS) UserspacePatchLevelNcst||j||S)N)super__new__)clsr5buildidlevelbaseurl) __class__rr rEoszUserspacePatchLevel.__new__cCs||_||_||_||_dS)N)rHr5rGrI)selfr5rGrHrIrrr __init__rszUserspacePatchLevel.__init__cGst|j|jt|f|S)N)r7r5rGstr)rKr6rrr cache_pathxszUserspacePatchLevel.cache_path)N)N)__name__ __module__ __qualname__rErLrN __classcell__rr)rJr rCns rCcsddfdd}|S)NcSsd \}}z|dkrt}i}g}x8t|D],}|jdd||jd<|j|jdgq*Wtj|dd}djd d |jD}djt|}Wdtj t |d d tj t |d d XdS)z(KPT-1543 Save info about applied patchesNzlatest-versionpackagepatchescve) cve_field cSsg|]}dj|qS) )r3)rrecrrr r!szLrefresh_applied_patches_list..save_current_state..T) ensure_dir)rSrS) _libcare_info_get_patches_infogetextendrextract_unique_cvesr3itemssorted atomic_writeLIBCARE_PATCHESLIBCARE_CVE_LIST)infoZversionsZcvesZpackagesZ all_patchesrZZcves_setrrr save_current_state}sz8refresh_applied_patches_list..save_current_statec s"d}z||}|S|XdS)Nr)r=r>rf)r@rgrr rAs  z-refresh_applied_patches_list..wrapperr)r@rAr)r@rgr refresh_applied_patches_list|srhc"Cstjpd}t|}t|j}tjtj|d|||d}|dtj d|7}tj|d}|rlt j j d||}i}|rd|i|d <y t jtj|fd d i|}Wntjk r|rtjd j||d d dStjt||ddYnLtk r4} z.| jdkr"|r"tjdj|ddWYdd} ~ XnXtj|jttj |j!} | jdg} t"j#| s|tj$dj|t%||| d| jd} t&| d} t||| d}t j j'| st j j(|dkr:tj| d}yt j)||tj*t j+| dWn<tk r8} z| jd(kr&tj,dWYdd} ~ XnXt||| }dd |d!|d"g}t-j.|ddd#\}}}|rtjd$j|||d%dt||d&}t j j/| rt j j0|rtj|t j1| |d't j2|d'|| S))Nmainuz latest.v1z?info=updater*tagsZStickyheaders check_licenseFz;No libcare patchset available for {0} at tag {1}, skipping.)r9T) ignore_errorsiz8Invalid sticky patch tag {0}: server rejected the value.zinvalid lib sticky patch)statusrzkLatest LibCare patchset for {0} is incompatible with the current kernecare package version, please upgrade.rHrIz patch.tar.gzrZ patch_url)check_signature hash_checkerzKC+ licence is requiredtarZxfz-Cz--no-same-owner) catch_stdout catch_stderrz(Patches unpacking error: '{0}' '{1}' {2}zpatches unpacking errorlatestz.tmp)rsrt)3rPREFIXrstriprget_patch_server_url LIBNAME_MAPr^rZencoded_server_lib_infor1r2r3r wrap_with_cache_keyr urlopen_authrNotFoundr loginfor<shutilrmtreer7rcode KcareErrorrset_feature_flags_from_headersrmrnstrreadrhas_lc_capabilitiesCapabilitiesMismatchrCrMexistsgetsize fetch_url USE_SIGNATUREget_hash_checkerNoLibcareLicenseExceptionr run_commandislinkisdirsymlinkrename)r5build_id patch_leveltagprefixurl cache_dstZ extra_kwargsresponseexmetarequired_capabilitiesrHplevelZ patch_pathdstcmdrstdoutstderrZ link_namerrr fetch_userspace_patchsr          "     rcCsL| t_|sttj|rdndd|r0ttjjd|r@dnddS)NFALSEYES)LIBCARE_DISABLEDzlibcare service is enableddisabled) rrlibcare_server_stopr update_configlibcare_server_startr kcarelogrf)rrrr set_libcare_statussrc Cstjstjjtjr^tjtjddgtjtjddgtjtjddgtjtjddgn6ytjdd ddg}Wnt k rdSXtj|dS) Nstopzlibcare.socketzlibcare.servicez reset-failedlibcareservice /usr/sbin//sbin/)rr) rSKIP_SYSTEMCTL_CHECKr1r2r SYSTEMCTLr rfind_cmdr')rrrr rsrc Cstjstjjtjrtjtjdddgddd\}}}|dkr@dStjtjddgtjtjddgtjtjd d gtjtjd dgtjtjd dgn@trdSytj d dd d g}Wnt k rdSXtj|dS)Nz is-activez--quietzlibcare.serviceT)rvrwrrzlibcare.socketz reset-failedrstartr /usr/sbin//sbin/)rr) rrr1r2rrr rlibcare_server_startedrr')rr-rrrr rs& rTcsdjddt|pgD}ddg}s6|dd|g7}y t|}Wn6tk rx}ztjdj|d d WYdd}~XnXg}x@|jd D]2}|ry|jt j |Wqt k rYqXqWd d |D}x.|D]&}t fdd|dj D|d<qW|S)N|css|]}djtj|VqdS)z({0})N)r<reescape)rprocrrr $sz _libcare_info..rfz-jz-lz-rz/Gathering userspace libraries info error: '{0}'zuserspace libs info error)rprXcSs$g|]}|jd|jd|dqS)commpid)rrr*)pop)rlinerrr r!:sz!_libcare_info..c3s(|] \}}d|ks r||fVqdS)patchlvlNr)rkv)patchedrr r=sr*)r3rbr:r'rrr<splitappendjsonloads ValueErrordictra)rlimitZregexprlinesr?resultrr)rr r\ s& &  &r\c Cst}x<|D]4}x.|djD]\}}|j|d|dfqWq Wg}t}xb|D]Z}xT|D]L\}} t||t| d} tjj| r^t | d} |j t j | WdQRXq^WqTW|S)Nr*rGrz info.jsonr) r$raaddr/r7rMr1r2isfileopenrrload) rfrUrZr-datarumaprrrZpatch_info_filenamefdrrr r]Bs    "r]cCs ttS)N)r]r\rrrr libcare_patch_info_basicRsrcCs"t}|stjdtjd|iS)NzNo patched processes.r)rr r;rdumps)rrrr libcare_patch_infoWs rcCs"t}|stjdtjd|iS)NzNo patched processes.r)r\r r;rr)rrrr libcare_info_s rcCs.i}x$tD]}|jdd||jd<q W|S)Nzlatest-versionrSrT)rr^)rrZrrr _libcare_versiongs rcCs*x$tjD]\}}|j|r |Sq WdS)NrS)rrar))r5rTr,rrr libcare_versionns rcCsdjdd|DdS)Ncss|]}tj|dVqdS)N)rbstr)rprrr rvsz(libcare_client_format..r)r3)paramsrrr libcare_client_formatusrcCs,xtD]}tjj|r|SqWtjddS)NzLibcare socket is not found.)LIBCARE_SOCKETr1r2rrr)Zlibcare_socketrrr get_available_libcare_socketys  rc Gstjrtjdtjtjtjd}|jdd}z||jt |jtj t |}t j dj|d|j|x|jd}|sP||7}qpW|jdd }t j d j|d |S|jXdS) NzLibcare is disabled.r rzLibcare socket send: {cmd})rizutf-8replacez!Libcare socket recieved: {result})r)rrrrsocketAF_UNIX SOCK_STREAM settimeoutconnectrLIBCARE_SOCKET_TIMEOUTrr logdebugr<sendallrecvdecodeclose)rsockresrrrrrr r:s(        r:cCs|rzxp|D]h}td||}tjj|s(q ytdd|Wq tk rp}ztjdj||ddWYdd}~Xq Xq WdSx|D]}ytdt|Wn6tk r}ztjdj|d dWYdd}~XnXy tdWqtk r}ztjd j|ddWYdd}~XqXqWdS) Nrlrkz --storagez3Userspace patch applying error (storage={0}): '{1}'zuserspace patch apply error)rpZstoragez(Userspace storage switching error: '{0}'zuserspace storage switch errorz%Userspace patch applying error: '{0}') r7r1r2rr:r'rrr<)rrrZ storage_pathr?rrr libcare_patch_applys*     & rcCsHy tdWn6tk rB}ztjdj|ddWYdd}~XnXdS)Nunloadz&Userspace patch unloading error: '{0}'zuserspace patch unload error)rp)r:r'rrr<)r?rrr libcare_unloads rcCsDy tdWn2tk r>}ztjdj|WYdd}~XnXdS)z;Reload libcare-server plugin without restarting the server.ZrepluginzUserspace replugin error: '{0}'N)r:r'rrr<)r?rrr libcare_replugins rrcCst|tjkrtj rdSt}|dkr6t|j}g}x|D]}|j|j |gq@W|srt j dj |dSt ||d\}}}} |rtjd|st j ddStjtjjtjdtyt||dWn>tjk r} zt jt| tjdWYdd} ~ XnXt} t| } ttd d | Ds.zPatched before: {before})beforezPatched after: {after})aftercss|]}|D] }|Vq qdS)Nr)rrarrrr r scss|]}|D] }|Vq qdS)Nr)rrarrrr r scss|]}t|VqdS)N)len)rrrrr rszThe patches have been successfully applied to {count} newly discovered processes. The overall amount of applied patches is {overall}.)countoverallz*Object `{0}` is patched for {1} processes.)"rotate_libcare_logsrUPDATE_MODE_AUTOrLIB_AUTO_UPDATEr/r"keysr_r^r rr<check_userspace_updatesrrr restore_selinux_contextr1r2r3r4rr;rMr\_get_userspace_procsanyrr$valuessumrra)moderrrZprocess_filterZuserspace_patchfailedsomething_foundr-rrZ data_afterrZuniq_procs_afterZuniq_procs_beforeZdiffrrrrrr do_userspace_updatesR    r cCs\z.yt\}}}}Wntjk r*dSXWdtX|r@dS|rHdStjddrXdSdS)Nrz.libcarestatus)filenamer)rrrrrstatus_gap_passed)r r-libs_not_patchedrrr get_userspace_update_statuss rcCsdi}xZ|D]R}xL|djD]<\}}|jdr||kr>g||<||j|d|dfqWq W|S)Nr*rrr)rar^r)rfrrr5rZrrr r.s  "rcCsNt}xB|D]:}x4|djD]$\}}|j||d|jddfqWq W|S)Nr*rGrr)r$rarr^)rfrrr5rZrrr _get_userspace_libs9s  $rcs\s$t}gfdd|jDtdd}t|}d}}d}xt|D]}|\} } } y2t| | | |d} |r|| dkr|wNd}| dkrd}WqNtjk r} zd}tj t | WYdd} ~ XqNtj tj fk rYqNtj k rYqNtjk r>}z,t|ddd krd}tjt |WYdd}~XqNXqNWtjd d ||||fS) Ncsg|]}j|qSr)r_)rr*)rrr r!Esz+check_userspace_updates..F)rrT)rrrpzinvalid lib sticky patchz.libcarestatus)r)r/rr\rrrrrr logwarnrMrrAlreadyTrialedExceptionrgetattrr;rtouch_status_gap_file)rrrZ data_beforerr r rrZr5rrrerr)rr rAs>   $ rc sfd}d}tjddd}|rytj|tgdd\}}}Wn.tk rd}zd}t|}WYdd}~XnX|rtjd j|dd ntj d dd d t j j sdSt jd}yt j}tjdfdd|D}dd|D}|jddd} xD|D]<\}} | t j j| 7} | |krt j| tjjd| qWWn$tk r`tjddd YnXdS)NrrSZ logrotateF) raise_excT)rwrz5failed to run logrotate for libcare logs, stderr: {0})r9zlogrotate utility wasn't foundz/var/log/libcare/irz ^\d+\.log.*cs$g|]}j|rtjj|qSr)matchr1r2r3)rfn)libcare_log_directory pidlog_rerr r!sz'rotate_libcare_logs..cSsg|]}tjj||fqSr)r1r2getctime)rfprrr r!s)reversez%Removed %s because of logs size limitz)Failed to cleanup libcare server logfilesi)r rrLIBCARE_LOGROTATE_CONFIGr'rMr r;r<rr1r2rr!LIBCARE_PIDLOGS_MAX_TOTAL_SIZE_MBlistdirrcompilesortrremoverrflogexc) rcrZlogrotate_pathr-rZmax_total_sizeZ log_filesZ pidlog_filesZpidlog_files_with_ctZ total_sizefilepathr)rrr rrs<       rc CsJytjdd ddg}Wntk r*dSXtj|ddd\}}}|d kS) zKAssume that whenever the service is not running, we did not patch anything.r /usr/sbin//sbin/rrpFT)rvrwr)r+r,)r rr'r)rrr-rrr rs r)rr)NN)TN)N)NN)Drr1rrrrSrrrrrrr r r r r rrrpy23rrrZLIBCARE_CLIENTrrdrer"r|r$r(cachedr.r/r7rBintrCrhrrrrr\r]rrrrrrrr:rlog_all_parent_processesrrtrack_update_statusskip_if_no_selinux_moduleUPDATE_MODE_MANUALr rrrrrrrrrr sh@  L  "    $ H   1*PKk1]Q(kcarectl/__pycache__/py23.cpython-36.pycnu[3 ;j @s"ddlZddlmZejrddlZddlmZddlmZddl m Z ddl m Z ddl m Z dd l mZdd l mZdd lmZGd d d e Z ddZddZnbddlm Z ddlmZddlm Z mZddlmZddlmZmZddlm Z dd lmZejZddd dddddddg ZdS)N) constants)quote) urlencode) ConfigParser) HTTPError)Request)URLError)urlopen)urlparsec@seZdZddZdS)rcs8|jddtj|f||dkr4fdd|_dS)NmethodHEADcstS)N)str)r r*/usr/libexec/kcare/python/kcarectl/py23.pysz"Request.__init__..)pop StdRequest__init__Z get_method)selfargskwargsr)r rrs zRequest.__init__N)__name__ __module__ __qualname__rrrrrrsrcCsVt|}|tdkr|jdS|tkr4dd|DS|tkrRtdd|jDS|S)Nzutf-8cSsg|] }t|qSr)_convert).0itrrr %sz_convert..css"|]\}}t|t|fVqdS)N)r)rkvrrr 'sz_convert..)typeencodelistdictitems)dataZdtyperrrr s  rcCsttj|S)N)rjsonloads)Zjson_strrrrjson_loads_nstr*sr+)client)rr )rr rrr httplib std_urlopenrr urlquote)r)rrPY2r-Zurllibrr/rrZurllib2rrrr r r.r rr+ configparserZhttpr,Z urllib.errorZ urllib.parseZurllib.requestr*__all__rrrrs@                PKk1]B,kcarectl/__pycache__/__main__.cpython-36.pycnu[3 ;j#@s*ddlZddlZddlmZmZmZmZddlmZdej d<e dkr&yej eWnek rZ z ej dje ee d d WYddZ [ Xnejk rZ zej ee ej dWYddZ [ XnXek r$Z z:ee ejreje jn eje eej dWYddZ [ XnXdS) N)errors log_utilsmainsend_exc)URLError1Z"KCARE_SCANNER_INTERFACE_DO_NOTHING__main__z{0}: {1}urlunknown)ossysrrrrpy23renviron__name__exiterrlogerrorformatgetattr KcareErrorstr Exception isinstanceSafeExceptionWrapperlogexcinnerrr./usr/libexec/kcare/python/kcarectl/__main__.pys$   *  PKk1] &&,kcarectl/__pycache__/serverid.cpython-36.pycnu[3 ;j@sjddlZddlmZmZddlmZdZdZdZdd Z d d Z d d Z ej ddZ ddZddZdS)N)errorsutils)json_loads_nstrz/etc/sysconfig/kcare/systemidz&/etc/sysconfig/kcare/systemid.almacarez/var/imunify360/license.jsonc CsptjjtsdSttdL}xD|D]<}|jd\}}}|jdkrJ|jStjdj tddq"WWdQRXdS)Nr= server_idzUnable to parse {0}.zserver id parse error)status) ospathexistsSYSTEMIDopen partitionstripr KcareErrorformat)fdlineparam_valuer./usr/libexec/kcare/python/kcarectl/serverid.py _systemids    "rc Cs2tjjtsdSttd}|jjSQRXdS)Nr)r r r ALMA_SYSTEMIDrreadliner)frrr_alma_systemid!s  rcCs`tjjtsdSi}tt4}|j}|rLy t|}Wntk rJYnXWdQRX|jdS)Nid) r r r IM360_LICENSE_FILErreadr Exceptionget)datarcontentrrr_im360_systemid)s   r&cCstptptS)zqGet server_id or None if not present. Lookup order: SYSTEMID then IM360_LICENSE_FILE then ALMA_SYSTEMID )rr&rrrrr get_serverid9sr'cCstjtdS)N)r unlinkr rrrr rm_serveridCsr)cCstjtdj|dS)Nzserver_id={0} )r atomic_writer r)rrrr set_server_idHsr+)r rrpy23rr rr rrr&cachedr'r)r+rrrrs  PKk1]{?++)kcarectl/__pycache__/kcare.cpython-36.pycnu[3 ;j)@sddlZddlZddlZddlZddlZddlZddlZddlZddlm Z m Z m Z m Z m Z ddlmZddlmZdZddZd d Zd d Zd dZddZddZddZGdddeZGdddeZGdddeZddZddZdd Z d!d"Z!d#d$Z"d%d&Z#d'd(Z$d)d*Z%e j&d+d,Z'e j&d-d.Z(e j&d/d0Z)d1d2Z*d3d4Z+d5d6Z,d7d8Z-d9d:Z.d;d<Z/e j&d=d>Z0d?d@Z1dAdBZ2dCdDZ3dEdFZ4dS)GN)config constants log_utils process_utilsutils)SafeExceptionWrapper)json_loads_nstrzuname: cCstj|p|dkS)Nz.-_+)strisalnum)cr +/usr/libexec/kcare/python/kcarectl/kcare.py is_uname_charsrcCsft}tt||tjdB}x:|jD].}|jtr&djt t |t tdj Sq&WWdQRXdS)Nr) get_kernel_hashopenget_cache_pathr PATCH_INFO readlines startswith UNAME_LABELjoinfilterrlenstrip) patch_levelkhashfliner r r parse_unames  .r!c CsJtjjtjrFy"ttjd}|j||jdStk rDYnXdS)NwTF) ospathexistsrKCARE_UNAME_FILErwriteclose Exception) new_versionrr r rkcare_update_effective_version%s  r+c Cs.ttjd}ztj|jjS|jXdS)Nrb)rrKERNEL_VERSION_FILEhashlibsha1read hexdigestr()rr r rr1s rcCstjjtjd}tjj|rt|dV}|jj}y t |Wn6t k rdt t tjj |St k rvdSX|SQRXdS)z:Returns timestamp from PATCH_CACHE/stoped.at if its exsitsz stopped.atrerrorNz-1)r#r$rr PATCH_CACHEr%rr0rstripint ValueErrorr getctimer))Zstopped_at_filenameZfhvaluer r r get_last_stop<s     r9cCsPtjpd}tjpd}dj||t||g}tjd|f}|rD||f7}tjj|S)Nnonedefault-patches) rPREFIX PATCH_TYPErr rr3r#r$)rplevelfnameprefixptypeZ patch_dirresultr r rrMs    rcGstjtjf|S)N)rget_patch_server_urlrr>)partsr r rget_kernel_prefixed_urlWsrGc@seZdZddZddZdS)BaseKernelPatchLevelcGst|jt|f|S)N)rrr )selfrFr r r cache_path\szBaseKernelPatchLevel.cache_pathcCs|j|j|j|jdS)N)levelrbaseurlrelease)rKrrLrM)rIr r ras_dict_szBaseKernelPatchLevel.as_dictN)__name__ __module__ __qualname__rJrNr r r rrH[srHcs8eZdZd fdd Zd ddZddZdd ZZS) KernelPatchLevelNcst||j||S)N)super__new__)clsrrKrLrM) __class__r rrTiszKernelPatchLevel.__new__cCs||_||_||_||_dS)N)rKrrLrM)rIrrKrLrMr r r__init__lszKernelPatchLevel.__init__cGstj|j|jf|S)N)rrErLr)rIrFr r rkmod_urlrszKernelPatchLevel.kmod_urlcGstj|j|jt|f|S)N)rrErLrr )rIrFr r rfile_urluszKernelPatchLevel.file_url)N)N)rOrPrQrTrWrXrY __classcell__r r )rVrrRhs rRcs<eZdZfddZddZddZddZd d ZZS) LegacyKernelPatchLevelcsByt||j||Stk r<}zt|WYdd}~XnXdS)N)rSrTr6r)rUrrKexc)rVr rrTzszLegacyKernelPatchLevel.__new__cCs||_||_d|_d|_dS)N)rKrrLrM)rIrrKr r rrWszLegacyKernelPatchLevel.__init__cGs0dtjkr t|jt|f|St|jf|S)Nzpatches.kernelcare.com)r PATCH_SERVERrGrr )rIrFr r rrXs zLegacyKernelPatchLevel.kmod_urlcGst|jt|f|S)N)rGrr )rIrFr r rrYszLegacyKernelPatchLevel.file_urlcCst|jt||S)N)rRrr5)rIrLr r rupgradeszLegacyKernelPatchLevel.upgrade) rOrPrQrTrWrXrYr^rZr r )rVrr[ys  r[cCs^y6ttjjtjdd}tj|j|WdQRXWn"t k rXt j dddYnXdS)Nzkernel_patch_level.jsonr"z!failed to dump kernel patch levelF) print_msg) rr#r$rrr3jsondumprNr)rlogexc)Zkernel_patch_levelrr r rdump_kernel_patch_levels rccCsTy,ttjjtjd}t|jSQRXWn"tk rNt j dddYnXdS)Nzkernel_patch_level.jsonz(failed to read dumped kernel patch levelF)r_) rr#r$rrr3r r0r)rrb)rr r rread_dumped_kernel_patch_levels rdcCstdd|DddddS)NcSsg|]}|tjj|fqSr )r#r$r7).0itr r r sz'sort_files_by_ctime..cSs|dS)Nrr )pairr r rsz%sort_files_by_ctime..T)keyreverse)sorted)Z files_listr r rsort_files_by_ctimes rmc Cs\d}tjjds|Std6}x.|D]&}|j}|jdr$|jdd\}}q$WWdQRX|S)Nz /var/crashz/etc/kdump.confzpath r)r#r$isfilerrrsplit)Z kdump_pathZ kdump_confr _r r rget_kdump_roots    rqcCs*t}tjj|sgStjtjj|dS)Nz*/vmcore)rqr#r$isdirglobr) kdump_rootr r rlist_kdump_vcore_filess rucCs*t}tjj|sgStjtjj|dS)Nz*/*.txt)rqr#r$rrrsr)rtr r rlist_kdump_txt_filess rvcCs(tjjtjsgStjtjjtjdS)Nz*.log)r#r$rrr KDUMPS_DIRrsrr r r rlist_crashreporter_log_filessrxcCs(tjjtjsgSddtjtjDS)NcSsg|]}tjjtj|qSr )r#r$rrrw)rerfr r rrgsz0list_crashreporter_artifacts..)r#r$rrrrwlistdirr r r rlist_crashreporter_artifactssrzcCst}|sdSt|ddS)Nrr)rurm)Zkdumpsr r rkdumps_latest_event_timestampsr{cCs>tjstjjtjr:tjtjddgddd\}}}|jSdS)Nz is-activekdumpT) catch_stdout catch_stderrzsystemd-absent) rSKIP_SYSTEMCTL_CHECKr#r$rn SYSTEMCTLr run_commandr)rpstdoutr r r kdump_statussrcCst}|sdSt|ddS)Nrr)rzrm)Z artifactsr r r$crashreporter_latest_event_timestampsrc Cs:d}tjj|sdSt|d}|jj}WdQRX|S)Nz/sys/module/kcare/versionr)r#r$r%rr0r)Zkmod_version_filerversionr r rget_current_kmod_versions   rcCs6t}|sdStjdddt||tjgj}||kS)NTz /sbin/modinfoz-Fr)rr check_outputrrKMOD_BINr)rr@Z old_versionr*r r ris_kmod_version_changeds rcCst}|stjSt|S)N)loaded_patch_levelplatformrMr!)rr r rkcare_uname_susrcCs,tjjtjr"ttjdjjStSdS)Nr) r#r$r%rr&rr0rrr r r r kcare_unamesrcCs`ttd}|r\y t|Wn0tk rN}zt|dtWYdd}~XnXtt|SdS)Nz patch-levelzUnexpected patch state)parse_patch_descriptionloaded_patch_descriptionr5r6r _patch_infor[r)pler r rrs  rcCsJytjtjdgddStjk rD}z|jtjkr6dSd}~XnXdS)NinfoT)checkr) rrr KPATCH_CTL subprocessCalledProcessError returncodeerrnoZEBUSY)rr r rr!s  rcCsRyddtdDSttfk rL}ztjdt|ddgSd}~XnXdS)NcSsg|]}|jdqS)r)ro)rer r r rrg-sz&get_loaded_modules..z /proc/modulesz#Error getting loaded modules list: F)r_)rOSErrorIOErrorrlogerrorr )exr r rget_loaded_modules*s rcCsdtkrdSttdS)Nkcarezkpatch-description)rget_patch_valuerr r r rr3s rcCstj|j|S)N)r data_as_dictget)rZlabelr r rr;src Csrddddd}|s|S|jd\}}}|jd\}}}|jd\}}}|pLd|d<|pXd|d<||d <||d <|S) Nr;r)z patch-levelz patch-typez last-updatezkernel-version;:r<z patch-levelz patch-typez last-updatezkernel-version) partition) descrDZlevel_type_timestamprpkernelZ level_type timestamprZ patch_typer r rr?s  rcCshtjjtjd}tjj|rdt|d8}y|j}tj |St t t t tfk rXYnXWdQRXdS)Nz kcare.stater)r#r$rrr3r%rr0astZ literal_eval SyntaxErrorrr6 TypeErrorUnicodeDecodeError)Z state_filerstater r r get_stateSs   r)5rrrsr.r`r#rrrrrrrrerrorsrpy23r rrr!r+rr9rrGr5rHrRr[rcrdrmrqrurvrxrzcachedr{rrrrrrrrrrrrrr r r rsV               PKk1]˫ 1kcarectl/__pycache__/process_utils.cpython-36.pycnu[3 ;j4@spddlZddlZddlZddlZddlmZmZejdddZddd Z dd d Z d d Z ddZ ddZ dS)N) log_utilsutilsTcCsR|pd}x*|D]"}tjj||}tjj|r|SqW|rJtdj||ndSdS)N /usr/sbin/sbin/usr/bin/binz{0} could not be found at {1})rrrr)ospathjoinisfile Exceptionformat)namepathsZ raise_excitfnamer3/usr/libexec/kcare/python/kcarectl/process_utils.pyfind_cmds  rFc Cs|r tjnd}|rtjnd}tj||||d}|j\}} |j} |dk rRtj|}|dk rdtj| } tjt j dj |j|| dj |d|r| rtj | |} || _| | _| | || fS)N)stdoutstderrshellz Call result for `{cmd}`: exit code {exit_code} === STDOUT === {stdout} === STDERR === {stderr} === END ===  )Z exit_coderrcmd) subprocessPIPEPopen communicate returncodernstrrlogdebugtextwrapdedentrr CalledProcessErroroutputr) command catch_stdout catch_stderrrcheckrrpZstdout_capturedZstderr_capturedcodeexcrrr run_commands&     r-cCst|d|d\}}}|S)NT)r'r))r-)argsr)_rrrr check_outputDsr0c Csydddddt|g}t|dd\}}}|rFtjdj|d d d dS|j}dddd dt|g}t|dd\}}}|rtjd j|d d d dS|j}t||fStk r}ztjdj||dd d dSd}~XnXdS)Npsz --no-headersz-oppidz-pT)r'z3Could not retrieve process parent PID for PID {pid})pidF) print_msgZcommz-Could not retrieve process name for PID {pid}zJCould not retrieve process name and parent PID for PID {pid}, error: {err})r3err)NN)NN)NN)strr-rloginforstripintr ) r3Zcmd_ppidr+rr/r2Zcmd_commrerrr _get_parent_pid_and_process_nameIs$ r;cstjfdd}|S)zMDecorator that logs parent process chain before calling the wrapped function.cst||S)N)_log_all_parent_processes)r.kwargs)funcrrwrapperfsz)log_all_parent_processes..wrapper) functoolswraps)r>r?r)r>rlog_all_parent_processescsrBcCsg}tj}x<|dkrH|dkrHt|\}}|j||f|dkrBP|}qWtjdddxJtt|D]:\}\}}d|d}tjdj||pd |pd d ddqfWdS) NrrzAgent parent processes chain:F)r4-z->z{prefix} "{name}" (pid: {pid})unknown)prefixrr3) r getpidr;appendrr7 enumeratereversedr)Z process_chainZ current_pidr2Z process_namelevelr3rrErrrr<ns  r<)NT)FFFF)F)r@r rr"rrcachedrr-r0r;rBr<rrrrs  %  PKk1]L'7 7 /kcarectl/__pycache__/server_info.cpython-36.pycnu[3 ;j@sddlZddlZddlZddlZddlZddlZddlmZmZm Z m Z m Z m Z m Z mZd ddZdddZdd d Zd d ZdS)N) capabilities constants http_utilskcareplatform_utilsserverid update_utilsutilsFc Cst}t|ptj|d<||d<tj|d<tj|d<tj|d<tj|d<tj|d<t j }|d|d <|d |d <t j |d <t jtj|d <t j|d<t j|d<t j|d<t j|d<tj|d<t jt j}|d|d<|d|d<|d|d<t jpd|d<t j|d<t j|d<tj|d<yt j|d<Wntk rdYnXt j!}|r|||d<t j"}|dk r||d <t#j$d!|d"<|rt j%|d#<|rt j&|d$<|S)%Ntsreasonmachine processorreleasesystemversionrdistrordistro_versionZeuname kcare_version last_stopnodeuptimevirtproxyz last-updateZ ltimestampz patch-level patch_levelz patch-type patch_typekmodZcrashreporter_ts kdump_statusrZkdump_ts server_idstatekernel update_errorZ secure_boot perf_metrics)'dictinttimeplatformr rrrrr get_distror kcare_unamer strip_version_timestamprVERSION get_last_stop get_hostname get_uptimeget_virtr proxy_is_usedparse_patch_descriptionloaded_patch_descriptionget_current_kmod_version$crashreporter_latest_event_timestamprrget_kc_capabilites_bitskdumps_latest_event_timestamp Exceptionr get_serverid get_stater read_update_errorsecure_boot_infoget_performance_metrics) r nowr;r#datar descriptionrr r@1/usr/libexec/kcare/python/kcarectl/server_info.py server_infosT                      rBcCst}t|ptj|d<||d<||d<tj}|d|d<|d|d<tj|d<tjt j |d <tj |d <tj |d <tj |d <tj|d <d}tjjdrtjjd}||d<tjd|d<|S)Nr r rrrrrr rrrrrgz/var/lib/libcare/stopstop_tslibcarer")r$r%r&rr(r'r r r*rr+r-r.r/rget_lc_capabilites_bitsospathexistsgetctimer r:)r rr=r>rrCr@r@rAserver_lib_infoIs&         rJcCst|||d}t|ddS)N)r rr=T) b64_encoding)rJencode_checkin_payload)r rr=infor@r@rAencoded_server_lib_infodsrNcCsP|r2tj|ddd}tjtjtjtj|dStjtj tjt |SdS)NF,:) ensure_ascii separatorszutf-8)rOrP) jsondumpsr nstrbase64urlsafe_b64encodezlibcompressbstr b16encodestr)r>rKZdata_strr@r@rArLisrL)NFF)N)N)rVrSrFr'r&rXrrrrrrrr r rBrJrNrLr@r@r@rAs( 7  PKk1]P;55)kcarectl/__pycache__/utils.cpython-36.pycnu[3 ;j[#@sdddlmZddlZddlZddlZddlZddlZddlZddlZddl Z ddl m Z ddl m Z ej dZdZedZed ZedZdddZd?ddZddZd@ddZdedfddZddZdd Zd!d"Zd#d$Zd%d&Zd'd(Z ed)d*Z!d+d,Z"dAd-d.Z#dBd/d0Z$d1d2Z%dCd4d5Z&d6d7Z'd8d9Z(de)fdfd:d;Z*dS)D)print_functionN)datetime) constantsz^(\d+[.]\d+[-]\d+)Fwc Cstjj|}|r(tjj| r(tj|ytj|j}Wntk rP|}YnXtj ||tjj |ddd<}tj |j ||j ||jtj|j |j}WdQRXtj|tj} ztj| Wdtj| Xtj||dS)N.F)modedirprefixdelete)ospathdirnameexistsmakedirsstatst_mode ExceptiontempfileNamedTemporaryFilebasenamefchmodfilenowriteflushfsyncnameopenO_RDONLYcloserename) fnamecontent ensure_dirr Z create_modeZdnamerfZ tmp_fnameZ folder_fdr)+/usr/libexec/kcare/python/kcarectl/utils.py atomic_write"s$      r+utf-8cCs4t|tkr|St|tkr&|j|S|j|SdS)N)typentypebtypedecodeencode)dataencodingr)r)r*nstr>s    r4latin1cCst|tkr|j|}|S)N)r-utyper1)r2r3r)r)r*bstrHs  r7cCst|tkr|j|}|S)N)r-r/r0)r2r3r)r)r*ustrOs  r8cs4itjfdd}|_j|_|_|S)Nc sH|tt|jf}y|Stk r0YnX||}|<|S)N)tuplesorteditemsKeyError)argskwargsZ cache_keyresult)cachefnr)r*innerZszcached..inner) functoolswrapsr@clearorig)rArBr))r@rAr*cachedVs  rGcsFdkrtjdkrtjdkr*tjifdd}|S)Ncsfdd}|S)Ncs}xltD]`}y ||Stk rJ}z|s:WYdd}~XnXtj|t|tjdtj}qWy ||Stk r}zt |dWYdd}~XnXdS)Nrattempts) rangertimesleepminrandomuniformrRETRY_MAX_DELAYsetattr)r=r>Zldelay_exZfinal_ex)backoff check_retrycountdelayrAstater)r*rBvs     z'retry..decorator..innerr))rArB)rSrTrUrVrW)rAr* decoratoruszretry..decorator)r RETRY_DELAY RETRY_COUNT RETRY_BACKOFF)rTrUrVrSrXr))rSrTrUrVrWr*retryjsr\c Cstjj|sdSg}tj|}|dk r2tj||}xD|D]<}tjj||}||krh|jtj|j |f|j ddq8WxF||dD]6\}} tjj | stjj | rtj | qtj| qWdS)NT)reverse)rrrlistdirfnmatchfilterjoinappendrst_mtimesortisfileislinkremoveshutilrmtree) Z directory exclude_pathkeep_npatternr2r;item full_pathrQentryr)r)r*clean_directorys     rpcCsNttjjtjdddttjjtjdddtjjtjrJtjtjdS)Nmodulesr)rkpatches) rprrrar PATCH_CACHErCACHE_KEY_DUMP_PATHunlinkr)r)r)r*clear_all_cachesrvc Cs^tjj|}tjj|s"tj|t|d(}tj|||jtj |j WdQRXdS)Nwb) rrrrrr!rh copyfileobjrrr)responsedstZ parent_dirr(r)r)r* save_to_files     r{cCstj|}|r|jdp|S)Nr) VERSION_REmatchgroup)versionr}r)r)r*strip_version_timestamps rcCs0|jd\}}}|s$|jd\}}}tj|dS)NT z%Y-%m-%d) partitionrstrptime)Zstr_rawZstr_dateseprQr)r)r*parse_response_datesrcGs0ddlm}djddtd|jf|DS)Nr) ipv6_support/css|]}|jdVqdS)rN)strip).0itr)r)r* sz'get_patch_server_url..)rrrar`get_patch_server)partsrr)r)r*get_patch_server_urls rc Cs0tjj|sdSt|}|jjSQRXdS)N)rrrr!readr)filenamer(r)r)r* try_to_reads  rcCs ttjS)N)rrrtr)r)r)r* get_cache_keysrc Cs.tjj|s|St|| }|jSQRXdS)N)rrrr!r)r%r defaultr(r)r)r* _read_files  rcCst|d|}|S)Nr)r)r%rr?r)r)r* read_files rcCst|d|}|S)Nrb)r)r%rr?r)r)r* read_file_bins rcCsBi}|j}x0|D](}|r|jd\}}}|r|j||<qW|S)N:) splitlinesrr)r2r?Z data_lineslinekey delimitervaluer)r)r* data_as_dicts rcvecCs0t}x$|D]}|j|}|r |j|q W|S)a Extract unique CVEs from a list of patches. Args: patches: List of patch dictionaries cve_field: Field name to extract CVE from (default 'cve' for userspace, 'kpatch-cve' for kernel) Returns: Set of unique CVE strings )setgetadd)rr cve_fieldZ unique_cvespatchrr)r)r*extract_unique_cvess   rcCstttjS)N)strintrJr)r)r)r* timestamp_strsrcGs t|dS)za workaround to fix T201N)print)valuesr)r)r* print_wrappersrcsfdd}|S)Ncs tjfdd}|S)Ncsny ||Sk rh}zBrZdd|Ddd|jD}djjdj||Sd}~XnXdS)NcSsg|] }t|qSr))r)rar)r)r* &szBcatch_errors..decorator..inner..cSsg|]\}}dj||qS)z{0}={1})format)rkvr)r)r*r&sz{0}({1}) failed: {2}z, )r;r__name__ra)r=r>earg_list)default_returnerrorsrAloggerr)r*rBs  z.catch_errors..decorator..inner)rCrD)rArB)rrr)rAr*rXs zcatch_errors..decoratorr))rrrrXr))rrrr* catch_errorssr)Fr r )r,)r5)r5)NNN)N)N)r)+ __future__rr_rCrrMrerhrrJrrrcompiler|Z CACHE_ENTRIESr-r.r/r6r+r4r7r8rGr\rprvr{rrrrrrrrrrrrrrr)r)r)r*sJ        $      PKk1]nAޥ *kcarectl/__pycache__/errors.cpython-36.pycnu[3 ;j@sddlmZGdddeZGdddeZGdddeZGdd d eZGd d d eZGd d d eZGdddeZ GdddeZ ddZ dS)) HTTPErrorc@seZdZdddZdS)SafeExceptionWrapperNcCs||_||_||_dS)N)inneretypedetails)selfrrrr,/usr/libexec/kcare/python/kcarectl/errors.py__init__ szSafeExceptionWrapper.__init__)NN)__name__ __module__ __qualname__r rrrr rsrcs$eZdZdZdZfddZZS) KcareErrora4Base kernelcare exception which will be considered as expected error and the full traceback will not be shown. Subclasses may set a class-level ``status`` to provide a short, fixed label for error reporting. Individual raise sites can override it per-instance via the ``status`` kwarg. cs2|jdd}|dk rt||_tt|j|dS)Nstatus)popstrrsuperrr )rargskwargsr) __class__rr r s  zKcareError.__init__)r r r __doc__rr __classcell__rr)rr rsrc@s eZdZdS)NotFoundN)r r r rrrr r!src@seZdZdZdS)NoLibcareLicenseExceptionzno libcare licenseN)r r r rrrrr r%src@seZdZdZdS)CapabilitiesMismatchzcapabilities mismatchN)r r r rrrrr r)srcs(eZdZdZfddZddZZS)AlreadyTrialedExceptionzalready trialedcs0tt|j|||d|jd|_||_dS)NT)rrr indexcreatedip)rr!r rr)rrr r 0sz AlreadyTrialedException.__init__cCsdj|j|jS)Nz6The IP {0} was already used for a trial license on {1})formatr!r )rrrr __str__5szAlreadyTrialedException.__str__)r r r rr r#rrr)rr r-s rcs eZdZdZfddZZS)UnableToGetLicenseExceptionzunable to get licensec s tt|jdt|f|dS)Nz6Unknown Issue when getting trial license. Error code: )rr$r r)rcoder)rrr r <s z$UnableToGetLicenseException.__init__)r r r rr rrr)rr r$9sr$c@seZdZdZdS)BadSignatureExceptionz bad signatureN)r r r rrrrr r&Bsr&csfdd}|S)Ncs t|S)N) isinstance)estate)exc_listrr rGszcheck_exc..innerr)r*rr)r*r check_excFs r+N) py23r Exceptionrrrrrrr$r&r+rrrr s   PKk1]N` ` -kcarectl/__pycache__/log_utils.cpython-36.pycnu[3 ;j~ @sddlmZddlZddlZddlZddlZddlZddlmZm Z ej dZ ddZ dd d Z dd d Zdd dZdddZdddZddZddZddZd ddZdS)!)print_functionN)config constantskcarecCst|tjtj|dS)N) _printlvlr PRINT_DEBUGkcarelogdebug)messager //usr/libexec/kcare/python/kcarectl/log_utils.pylogdebugs rTcCs|rt|tjtj|dS)N)rr PRINT_INFOr info)r print_msgr r r loginfos rcCs$|rt|tjtjdtj|dS)N)file)rr PRINT_WARNsysstderrr warning)r rr r r logwarnsrcCs$|rt|tjtjdtj|dS)N)r)rr PRINT_ERRORrrr error)r rr r r logerror&srcCs&|rtjtjkrtjtj|dS)N)rrr PRINT_LEVEL traceback print_excr exception)r rr r r logexc,sr cCs|tjkrt||ddS)N)r)rrprint)r levelrr r r r2s rcCs:tjd}tjjdtjjjd}|jtj|j||S)Nz kcare %(levelname)s: %(message)sz/dev/log)addressZfacility)logging FormatterhandlersZ SysLogHandlerZLOG_USERsetLevelINFO setFormatter)Zsyslog_formattersyslog_handlerr r r get_syslog_handler7s    r+cCsntjd}tjdkrJtjjtjddd}|jt |tj |j ||Stj }|j||j ||SdS)Nz&%(asctime)s %(levelname)s: %(message)sri)ZmaxBytesZ backupCounti) r$r%osgetuidr&ZRotatingFileHandlerrLOG_FILEr'minr(r) StreamHandler)r"Zkcare_formatter kcare_handlerr r r get_kcare_handler?s     r3cCsgtjdd<yt|}tj|Wn,tk rP}ztj|WYdd}~XnXtjjdryt }tj|Wn,tk r}ztj|WYdd}~XnXdS)Nz/dev/log) r r&r3 addHandler Exceptionrr-pathexistsr+)r"r2exr*r r r initialize_loggingPs r9cCs"|pd}tdj|t||dS)Nzz8Unable to fetch {0}. Please try again later (error: {1}))rformatstr)r8urlstdoutr r r print_cln_http_errorasr>)T)T)T)T)N)NT) __future__rr$Zlogging.handlersr-rrrr getLoggerr rrrrr rr+r3r9r>r r r r s"       PKk1]ff0kcarectl/__pycache__/capabilities.cpython-36.pycnu[3 ;j@s$ddZddZddZddZdS) cCsdS)Nrrr2/usr/libexec/kcare/python/kcarectl/capabilities.pyget_kc_capabilites_bits srcCsdS)Nrrrrrrget_lc_capabilites_bitssrcCs| S)Nr)required_capabilitiesrrrhas_kc_capabilitiessrcCs| S)Nr)rrrrhas_lc_capabilities srN)rrrrrrrrs PKk1]b%SS+kcarectl/__pycache__/selinux.cpython-36.pycnu[3 ;j@sRddlZddlmZmZmZmZddZddZdd Zd d Z ej d d Z dS)N)errors log_utils process_utilsutilscCs"tjj|\}}tjj|d|S)Nztmp.)ospathsplitjoin)fnameheadtailr-/usr/libexec/kcare/python/kcarectl/selinux.pyselinux_safe_tmpname srcCsNtrJtjdd d|g}tj|ddd\}}}|rJtjdj|||dd dS) NZ restorecon /usr/sbin/sbinz-RT) catch_stdout catch_stderrz8SELinux context restoration for {0} failed with {1}: {2}F) print_msg)rr)is_selinux_enabledrfind_cmd run_commandrlogerrorformat)dnamecmdcode_stderrrrrrestore_selinux_contexts r cCsVtjddgdd\}}}|r2tjdj||ddx|jdD]}||kr>dSq>Wd S) Nz/usr/sbin/semodulez-lT)rz/SELinux modules list gathering error: '{0}' {1}zselinux modules error)status F)rrr KcareErrorrr )Z semodule_namerouterrlinerrris_selinux_module_presentsr'csfdd}|S)Ncs$trtd rtjd||S)Nlibcarez:SELinux is enabled but libcare policy module is not loaded)rr'rr#)argskwargs)clblrrwrapper%s z*skip_if_no_selinux_module..wrapperr)r+r,r)r+rskip_if_no_selinux_module$s r-cCs,tjjdr tjdg\}}}ndS|dkS)Nz/usr/sbin/selinuxenabledFr)rrisfilerr)rrrrrr-s r) rrrrrrr r'r-cachedrrrrrs    PKk1]aa*kcarectl/__pycache__/config.cpython-36.pycnu[3 ;j @s ddlmZdZdZdZdZdZdZdZdZ dZ ddgZ dZ dZ dZd Zd Zd Zd Zejd ZdZdZd Zd Zd Zd ddddgZdZdZdZdZdZdZ dZ!dZ"dZ#dZ$dZ%ej&Z'd Z(d Z)dZ*d&Z+d Z,dZ-dZ.d Z/ej0Z1dZ2dZ3dZ4dZ5dZ6dZ7d'Z8d Z9d)Z:d+Z;d ZdZ?d Z@d!ZAd"ZBdS),) constantsNTzkpatch.blacklistz kpatch.fixupszkeep-registrationzmanage-libcareFz/dumpsdlibcZlibsslZnscdZlibmZ libnss_dnsi<z kpatch.binz.donez kpatch.infodefaultz /proc/versionz/proc/kcare/effective_versionizhttps://patches.kernelcare.comz#https://ipv6.patches.kernelcare.comz$https://cln.cloudlinux.com/api/kcarez)https://ipv6.cln.cloudlinux.com/api/kcareri@8i,il9i,ii@ii@)CrrAFTER_UPDATE_COMMANDAUTO_STICKY_PATCHSET AUTO_UPDATEAUTO_UPDATE_DELAYBEFORE_UPDATE_COMMANDBLACKLIST_FILECHECK_CLN_LICENSE_STATUSCHECK_SSL_CERTS FIXUPS_FILEFLAGS FORCE_GIDZFORCE_JSON_SIG_V3Z HTTP_TIMEOUTZHTTP_UPLOAD_TIMEOUTIGNORE_UNKNOWN_KERNEL KPATCH_DEBUGENABLE_CRASHREPORTER PATCH_CACHE KDUMPS_DIR KMSG_OUTPUT KCORE_OUTPUTKCORE_OUTPUT_SIZEIGNORE_FEATURE_FLAGSLIBCARE_DISABLEDZ LIBCARE_LIBSZ!LIBCARE_PIDLOGS_MAX_TOTAL_SIZE_MBZLIBCARE_SOCKET_TIMEOUTZLIB_AUTO_UPDATE PATCH_BIN PATCH_DONE PATCH_INFO PATCH_LEVEL PATCH_METHOD PATCH_TYPEPREFIXPREV_PATCH_TYPEZ PRINT_INFO PRINT_LEVELZ REPORT_FQDNSEND_PERF_METRICSSILENCE_ERRORSZSTATUS_CHANGE_GAP STICKY_PATCHSTICKY_PATCHSET UPDATE_DELAYUPDATE_FROM_LOCAL POLICY_REMOTE UPDATE_POLICYUPDATE_SYSCTL_CONFIGUSERSPACE_PATCHESZUSE_CONTENT_FILE_V3 USE_SIGNATUREZKERNEL_VERSION_FILEZKCARE_UNAME_FILESUCCESS_TIMEOUTKERNEL_ANOMALY_REPORT_ENABLE$KERNEL_ANOMALY_REPORT_MAX_SIZE_BYTESZDOCTOR_REPORT_MAX_SIZE_BYTESZFORCE_DOCTOR_FALLBACKZ FORCE_IPV4Z FORCE_IPV6 PATCH_SERVERZPATCH_SERVER_IPV6ZREGISTRATION_URLZREGISTRATION_URL_IPV6r:r:,/usr/libexec/kcare/python/kcarectl/config.pys|  PKk1]| .kcarectl/__pycache__/http_utils.cpython-36.pycnu[3 ;jE@sddlZddlZddlZddlZddlmZddlmZmZmZm Z m Z ddl m Z m Z mZmZmZmZddZdd d Zd d Zd dZdddZddZddZeZe jeddddZdS)N)SSLError)config constantserrors log_utilsutils) HTTPErrorRequestURLErrorhttplib std_urlopenurlparsec Ost|dr|j}n |}t|}|jdi}|jtjtjdx |jD]\}}|j ||qJWt j dj ||ydd|krt j|d<t j rttddrtj}d|_tj|_||d<t|f||St|f||Stk r&}z0|jd krtj|j|j|j|j|jWYdd}~Xn~tk r}z`|j r|t|j d d r||j d j!t!j"kr|tj|d t#|ddd j |||_$||_WYdd}~XnXdS) N get_full_urlheaders)z KC-VersionzKC-Patch-Versionz#Requesting url: `{0}`. Headers: {1}timeoutHAS_SNIFcontextirerrnozRequest for `{0}` failed: {1})%hasattrrr popupdaterVERSIONKC_PATCH_VERSIONitems add_headerrlogdebugformatr HTTP_TIMEOUTCHECK_SSL_CERTSgetattrsslcreate_default_contextcheck_hostname CERT_NONE verify_moder r coderNotFoundurlmsghdrsfpr argsrENOENTstrreason) r(r,kwargsZ request_urlrheadervaluectxexr50/usr/libexec/kcare/python/kcarectl/http_utils.py urlopen_bases>      .r7Tcsfdd}|S)Ncsbt|tro|jdkSt|ttjttjfr2dSt |dr^t |j dkr^|j dt j kr^dSdS)NiTr,r) isinstancer r&r r HTTPExceptionrsocketrrlenr,rZ ECONNRESET)estate) retry_on_500r5r6check_functionCs  (z3check_urlopen_retry_factory..check_functionr5)r?r@r5)r?r6check_urlopen_retry_factoryBs rAcCst|dr|j}|jdS)Nrzfile:)rr startswith)r(r5r5r6 is_local_urlOs rCcOsV|jdd}|jdtj}t|r2t|f||Stjt|d|dt|f||S)Nr?T retry_count)r?)count)rr RETRY_COUNTrCr7rretryrA)r(r,r0r?rDr5r5r6urlopenUs  rHcCsHt||d}tj r*|r*|jddj|tj rD|rD|jtj||S)N)method Authorizationz Basic {0})r rUPDATE_FROM_LOCALrrrAUTH_TOKEN_HEADER)r( auth_string auth_tokenrIrequestr5r5r6 http_request]s    rPcCs<|dkrtjdptjdS|dkr8tjdp6tjdSdS)NhttpZ http_proxyZ HTTP_PROXYhttpsZ https_proxyZ HTTPS_PROXY)osgetenv)schemer5r5r6get_proxy_from_envhsrVcCsttdpttdS)NrQrR)boolrVr5r5r5r6 proxy_is_usedosrX)Z check_retrycCstjj|}|stdj|ttj|}|j}|j }|jp@d}|dkrRtd|dkrl|j dkrhdnd}|j dkr~t j }n|j dkrt j }ntd |||tjd } i} |rd j|| d <d | d<t|| d<tj| d<z| jd|x | jD]\} } | j| | qW| jt|d} | j| WdQRX| j}|jdkry |j}Wntk rnd}YnXdj|j}|dk r|dj|7}tj|t||j|ddWd| j XdS)aUpload a file to the given URL using HTTP PUT with chunked streaming. Note: The standard library urllib doesn't support PUT with data We need to use httplib directly for this This function uses streaming upload to support large files up to 1GB without loading the entire file into memory. :param file_path: Path to the file to upload :param upload_url: Full URL to upload the file to. Query params are ignored. :param auth_string: Optional authentication string for Basic Auth :return: None if upload succeeded :raises HTTPError: If upload fails with HTTP status >= 400 :raises ValueError: If URL is invalid z"Refusing to upload empty file: {0}/NzInvalid URL: missing hostnamerRiPrQzInvalid URL: unsupported scheme)rz Basic {0}rJzapplication/octet-streamz Content-TypezContent-Lengthz KC-VersionPUTrbizFailed to upload file: HTTP {0}z - {0})!rSpathgetsize ValueErrorrrrnstrhostnameportrUr HTTPConnectionHTTPSConnectionrHTTP_UPLOAD_TIMEOUTr.rr putrequestr putheader endheadersopensend getresponsestatusread Exceptionrlogerrorr close)Z file_path upload_urlrMZ file_sizeparsedhostrbZurl_pathZconn_clsconnrr1r2fresponseZ error_body error_msgr5r5r6 upload_filevsT              rx)T)NN)N)rrSr;r!rrrrrrpy23r r r r r rr7rArCrHrPrVrXcheck_urlopen_retryrGrxr5r5r5r6s   0   PKk1].  0kcarectl/__pycache__/update_utils.cpython-36.pycnu[3 ;j@sddlZddlZddlZddlZddlmZmZmZmZddl m Z dZ ddd Z dd d Z d d ZddZddZddZddZddZdS)N)config constants log_utilsutils)json_loads_nstr< .kcarestatuscCs$tjjtj|}tj|tjdS)N)ospathjoinr PATCH_CACHEr atomic_write timestamp_str)filenamestatus_filepathr2/usr/libexec/kcare/python/kcarectl/update_utils.pytouch_status_gap_filesrcCsztjjtj|}tjj|rvt|dJ}y.t|j}t|t j t t j krTdSWnt k rjYnXWdQRXdS)NrFT)r r r rrisfileopenintreadrSTATUS_CHANGE_GAPSTATUS_CHANGE_GAP_DELAYtime Exception)rrsfile timestamprrrstatus_gap_passeds   r!cCs|dkrtdj|dS)Nkernellibcarez$Unknown update status component: {0})r"r#) ValueErrorformat) componentrrr_check_component%sr'c CsNtjtj}|dkriSy t|}|Sttfk rHtjj diSXdS)Nz"Failed to parse update status file) r read_filerUPDATE_STATUS_PATHrr$ TypeErrorrkcarelogwarning)contentresultrrr_load_update_status+s  r/c Csft|y4t}|ttjd||<tjtjtj |Wn$t k r`t j j dddYnXdS)N)errorr zFailed to save update statusT)exc_info)r'r/rrrrrr)jsondumpsrrr+r,)r&r0datarrrsave_update_status9sr5cCs>t|}tt|dd}|r:||kr:|jr6dj|S|S|S)NstatuszHTTP Error: {0})strgetattrisdigitr%)errmessager6rrr _error_statusGs  r=cstfdd}|S)Ncstjfdd}|S)NcsTy||}Wn4tk rB}ztt|dWYdd}~XnXtdd|S)N)r0r7)rr5r=)argskwargsr.r;)r&fnrrinner_s z5track_update_status..decorator..inner) functoolswraps)r@rA)r&)r@r decorator^s z&track_update_status..decorator)r')r&rDr)r&rtrack_update_statusZs rEc Cs^t|y,t}|j|ijdd}t|dtjStk rXtjj ddddSXdS)Nr0r7zFailed to read update statusT)r1) r'r/getr8rUPDATE_ERROR_MAX_LENGTHrrr+r,)r&r4r0rrrread_update_errorosrHi,)r )r )rBr2r rr7rrrrpy23rrrr!r'r/r5r=rErHrrrrs   PKk1];'"3kcarectl/__pycache__/config_handlers.cpython-36.pycnu[3 ;j&5@sddlZddlZddlZddlmZmZmZmZmZddl m Z dZ dddd d d d d gZ e ZddZddZejdZddZdddedddeeeedeeeeeeeeeddeeeeeeeeddejddddejdejddddeeeeejddejeeeddeed4Zdd Zd!d"ZGd#d$d$eZd%d&Zd'd(Zd)d*Zd+d,Z ej!ej"d-d.d/Z#ej!ej"d-d0d1Z$dS)2N)config constants http_utils log_utilsutils) ConfigParserz/etc/sysconfig/kcare/kcare.confUSE_CONTENT_FILE_V3FORCE_JSON_SIG_V3ENABLE_CRASHREPORTER KCORE_OUTPUT KMSG_OUTPUTSEND_PERF_METRICSKERNEL_ANOMALY_REPORT_ENABLEFORCE_DOCTOR_FALLBACKcCs |jdkS)N1TRUEYESY)rrrr)upper)valuer5/usr/libexec/kcare/python/kcarectl/config_handlers.pybool_converter#srcCsdd|jdDS)NcSs g|]}|jr|jjqSr)striplower).0itemrrr (szcomma_list..,)split)rrrr comma_list'sr!z^[a-z][a-z0-9_.+\-]*$cCsRgg}}x(t|D]}tj|r&|n|j|qW|rNtjdjdj||S)Nz3LIBCARE_LIBS: ignoring invalid library name(s): {0}z, )r!_LIBCARE_LIB_NAME_REmatchappendrlogwarnformatjoin)rZvalidinvalidtokenrrrlibcare_libs_list0s  r*cCs|jS)N)r)vrrr@sr,cCs|jS)N)r)r+rrrr,DscCs |jdS)N/)rstrip)r+rrrr,SscCs|pdS)Nr)r+rrrr,\scCs |jdS)Nr-)r.)r+rrrr,^scCs |jdS)Nr-)r.)r+rrrr,_scCs |jdS)Nr-)r.)r+rrrr,cscCs |jdS)Nr-)r.)r+rrrr,ds)4AFTER_UPDATE_COMMANDAUTO_STICKY_PATCHSET AUTO_UPDATEAUTO_UPDATE_DELAYBEFORE_UPDATE_COMMANDCHECK_SSL_CERTSDOCTOR_REPORT_MAX_SIZE_BYTESr r FORCE_GID FORCE_IPV4 FORCE_IPV6r HTTP_TIMEOUTHTTP_UPLOAD_TIMEOUTIGNORE_FEATURE_FLAGSIGNORE_UNKNOWN_KERNELr KCORE_OUTPUT_SIZE KDUMPS_DIRr$KERNEL_ANOMALY_REPORT_MAX_SIZE_BYTESr LIBCARE_DISABLED LIBCARE_LIBS!LIBCARE_PIDLOGS_MAX_TOTAL_SIZE_MBLIBCARE_SOCKET_TIMEOUTLIB_AUTO_UPDATE PATCH_LEVEL PATCH_METHOD PATCH_SERVERPATCH_SERVER_IPV6 PATCH_TYPEPREFIXPREV_PATCH_TYPEREGISTRATION_URLREGISTRATION_URL_IPV6 PRINT_LEVEL REPORT_FQDNSILENCE_ERRORSSTATUS_CHANGE_GAP STICKY_PATCHSTICKY_PATCHSET UPDATE_DELAY UPDATE_POLICYUPDATE_SYSCTL_CONFIGUSERSPACE_PATCHESr KERNEL_VERSION_FILEKCARE_UNAME_FILESUCCESS_TIMEOUTrc Kstt}|j}|jx|jD]\}}d}|d}|d}x^tt|D]N}||j|sl||j|rL|dkr|||=n|dt|d||<d}PqLW|s"|j |dt|dq"Wt j tdj |dS)NF= z =  T) openCONFIG readlinescloseitemsrangelen startswithstrr$r atomic_writer') kwargsZcflinesZproprupdatedZprop_eqZprop_spirrr update_configws"rmc Csi}tjd}xD|D]<}|j|}|r<|j\}}|sHd}n td||||<qWt|tt}|r~tddjt|x`|j D]T\}}t|} |dks| dkrqy | |Wqt k rtd||fYqXqWt f|dS)Nz^([^=]+)=([^=]*)$z8Invalid parameter format: %s. Format should be KEY=VALUEzUnknown parameter: %sz, zBad value for %s: %s) recompiler#groups SystemExitsetPOSSIBLE_CONFIG_OPTIONSr'sortedrc Exceptionrm) paramsZparams_for_updatepatternparamr#keyrZunknown_paramsvar_nameconvertrrrupdate_config_from_argss,       r|c@s$eZdZddZddZddZdS) FakeSecHeadcCs||_d|_dS)Nz [asection] )fpsechead)selfr~rrr__init__szFakeSecHead.__init__c Cs&|jrz|jSd|_Xn |jjSdS)N)rr~readline)rrrrrs  zFakeSecHead.readlineccs.|jr|jVd|_x|jD] }|VqWdS)N)rr~)rlinerrr__iter__s  zFakeSecHead.__iter__N)__name__ __module__ __qualname__rrrrrrrr}s r}c sitddddy,ttt}tjr4j|n j|Wntk rTiSXd fdd }x4dD],\}}t j |slj d |}|rl|t j |<qlWx tjD]\}}|||d qWS)Nr^) HTTP_PROXY HTTPS_PROXY)defaultsc sJyjd|}Wntk r(|}YnX|dk rF|r>||}||<dS)Nasection)getru)namedefaultr{r)cpresultrrread_vars z%get_config_settings..read_varhttprhttpsrr)r{)NNrrrr)rr)rr}r_r`rPY2readfp read_filerurget_proxy_from_envrosenvironrsrc)rrschemevariableproxyrzr{r)rrrget_config_settingss$     rcCs(tjt}tjj|tj|dS)N)_CONFIG_OPTIONSclearrr__dict__update)Zsettingsrrrset_settings_from_config_files rc Csi}xv|jD]j\}}|j}|jds*q|jddjdd}ytt|||<Wqtk rvtjj d||YqXqW|S)ak Checking headers for feature flags which start with 'KC-Flag-' and reformat it to dictionary with keys in upper case and without 'KC-Flag-' prefix and dashes replaced with underscores. For unification all header keys are checked in upper case. For example: 'KC-Flag-Some-Value' -> 'SOME_VALUE' :return: dict {'SOME_VALUE': bool, ...} zKC-FLAG-r^-_z(Invalid feature flag header value %s: %s) rcrrfreplaceboolint ValueErrorrkcarelogerror)headersflagsZhdr_nameZ hdr_valueZ upper_name param_namerrr convert_headers_to_feature_flagss  rcCst|tjstdS)N)save_feature_flags_cacherr;set_feature_flags_from_cache)rrrrset_feature_flags_from_headerssr)loggercCs"t|}tjtjtj|ddS)N)content)rrrhrFEATURE_FLAGS_CACHEjsondumps)r feature_flagsrrrr src CsztjjtjsdSttj}tj|}WdQRXxB|jD]6\}}|t krNq<|t krXq<|t j |<t jjd||qs  % PKk1]W2ǔ0kcarectl/__pycache__/delivery_kit.cpython-36.pycnu[3 ;j+@sddlZddlZddlZddlZddlZddlZddlZddlmZddl m Z m Z m Z m Z mZmZddlmZddZGdddeZGd d d eZdS) N)NamedTemporaryFile)authconfig http_utils ipv6_support log_utilsutils) run_commandcCs<t|}x(dD] }|dkr&dj||S|d}qWdj|S) zBRender a byte count as a short human-readable string for the logs.BKiBMiBGiBg@z {0:.1f} {1}z {0:.1f} TiB)r r r r )floatformat)Z num_bytessizeZunitr2/usr/libexec/kcare/python/kcarectl/delivery_kit.py format_sizes    rc@seZdZdZdZdZddZeddZeddZ d d Z d(d dZ ddZ ddZ ddZddZddZddZddZddZdd Zejejd!d"d#Zd$d%Zd&d'Zd S)) DataPackagezGeneric archive package for the patch server uploads pipeline. Based on DataPackage from eportal (delivery_kit.py). Subclasses supply the manifest `data_type`, the `upload_uri` to PUT the archive to and the `max_size` payload limit. cCsd|_g|_d|_dS)Nr)_tar_errors_buffer_total_payload_size)selfrrr__init__-szDataPackage.__init__cCstdS)N)NotImplementedError)rrrrmax_size3szDataPackage.max_sizecCs|j}t|jS)N)_ensure_tar_createdstrname)rtarrrr archive_path8szDataPackage.archive_pathcCsd}d}yttj|ddd\}}}Wn*tk rP}zt|}WYdd}~XnX|rh|jdj|||dk r|j|tj |ddddS)NT) catch_stdout catch_stderrz!failed to dump stdout of {0}: {1}zutf-8)encoding) data_bytes) r shlexsplit Exceptionr log_errorradd_filerbstr)rarcnamecmdstdoutstderr_errr add_stdout>szDataPackage.add_stdoutNFc Csh|dkr|dkrtd|j}d}|dk rZtjj|sL|jdj|dStjj|}nt|}|j |s|jdj|dS| r|j | r|j dj|t |t |j t |jdSyp|r|j||dn"tj|}||_|j|tj||s*|j|7_tjdj|t |t |jdd Wn6tk rb}z|jd j||WYdd}~XnXdS) Nz"No src_path or data_bytes providedrzfile not found: {0}z no available space to store: {0}zPskipping {0}: {1} would exceed the {2} report size limit (already collected {3}))r,z%collected {0}: {1} (report total {2})F) print_msgzfailed to store {0}: {1}) ValueErrorrospathexistsr)rgetsizelen_check_required_space_check_total_payload_limit log_warningrrraddtarfileTarInforaddfileioBytesIOrloginfor() rr,src_pathr%skip_limit_checkr entry_sizeinfor1rrrr*NsJ     zDataPackage.add_filecCsbytjtj|dddd}Wn2tk rN}z|jdj||dSd}~XnX|j||ddS)N)indentzutf-8)r$zfailed to dump {0}: {1})r%)rr+jsondumps TypeErrorr)rr*)rr,datar%r1rrradd_jsons zDataPackage.add_jsoncCstj|j}|j|j|kS)N)r5statvfsr!f_frsizef_bfree)rrFrOrrrr:s z!DataPackage._check_required_spacecCs|j|j|kS)N)rr)rrFrrrr;sz&DataPackage._check_total_payload_limitcCsd|jttjdS)N)Zschema_versiontypeZ time_created) data_typeinttime)rrrr make_manifestszDataPackage.make_manifestcCsNtjtj|jdddd}|j}tjd}t||_ |j |t j |dS)NrH)rIzutf-8)r$z manifest.json) rr+rJrKrWrr>r?r9rr@rArB)rr%r rGrrr _add_manifests   zDataPackage._add_manifestcCs&|j}tj|dd|jj|dS)NF)r3)striprlogerrorrappend)rZ error_msgrrrr)szDataPackage.log_errorcCs&|j}tj|dd|jj|dS)NF)r3)rYrlogwarnrr[)rZ warning_msgrrrr<szDataPackage.log_warningcCsxd D]}tdj|dddd}|jy6tjdj|jdd tj|j|d d |_|j |St k r}zb|jdk ry|jjWnt k rYnXd|_t j j |jrt j|jt|tjsЂWYdd}~XqXqWtjd dS)Nw:xzw:bz2w:gzz.tar.{0}F)suffixdeletezCreating DataPackage: {0})r3T)rmodeZ dereferencez%No supported compression method found)r]r^r_)rrcloserrCrr>openrrXr(r5r6r7unlink isinstanceZCompressionError)rZcompression_modeZtmpfileerrrrr __enter__s(    zDataPackage.__enter__cCsP|jr,dj|jd}|jdtj|dd|jrL|jj|rL|jdSdS)N z errors.logT)r%rEF)rjoinr*rr+rrdremove_archive)rexc_typeZexc_valexc_tberrorsrrr__exit__s zDataPackage.__exit__)loggercCs$|jr tjj|jr tj|jdS)N)rr5r6r7r!rf)rrrrrlszDataPackage.remove_archivecCs|jstd|jS)Nz/DataPackage should be used as a context manager)r RuntimeError)rrrrrszDataPackage._ensure_tar_createdcCst|jjtjj|j}d|kr4||jddnd}ttj |}t j |j |}t j|j|tjd|S)aSend the package archive to the patch server. Upload errors propagate to the caller (see the eportal precedent): wrap with utils.catch_errors where a silent failure is acceptable. :return: Upload name (package identifier) .Nr) upload_urlZ auth_string)rrdr5r6basenamer!findruuidZuuid4rget_patch_server upload_urirZ upload_filerget_http_auth_string)rruext upload_namertrrrsends  zDataPackage.send)NNF)__name__ __module__ __qualname____doc__rTryrpropertyrr!r2r*rNr:r;rWrXr)r<rirpr catch_errorsrr\rlrr}rrrrr"s(   ;    rc@s eZdZdZdZeddZdS)KernelAnomalyPackagezkernel-anomalyz/upload/kernel-anomaly/cCstjS)N)rZ$KERNEL_ANOMALY_REPORT_MAX_SIZE_BYTES)rrrrrszKernelAnomalyPackage.max_sizeN)r~rrrTryrrrrrrrsr)rArJr5r&r>rVrwtempfilerkcarectlrrrrrrZkcarectl.process_utilsr robjectrrrrrrs    yPKk1]^;ѧ((2kcarectl/__pycache__/platform_utils.cpython-36.pycnu[3 ;j(@sddlZddlZddlZddlZddlZddlZddlZddlmZm Z m Z m Z m Z m Z dZdZddZe jdd Zd d ZdQd dZdZdddZdRddZddZddZddZe jddZe jddZe jd d!Zd"d#Zd$d%Zd&d'Z d(d)Z!d*d+Z"d,d-Z#d.d/Z$d0d1Z%d2efd3efd4e fd5e!fd6e"fd7e#fd8e$ffZ&d9d:Z'd;d<Z(d=d>Z)e j*e j+d?d@dAZ,e j*e j+d?dBdCZ-e je j*e j+d?dDdEZ.e j*e j+ddFdGdHZ/e j*e j+ddFdIdJZ0e j*e j+d?dKdLZ1e j*e j+dSdFdMdNZ2dOdPZ3dS)TN)config constants log_utils process_utilsselinuxutilsz/usr/libexec/kcare/virt-whatz/proccCs2tjdddkrtjSddl}|jddSdS)NrF)full_distribution_name)r r )sys version_infoplatformlinux_distributiondistro)rr4/usr/libexec/kcare/python/kcarectl/platform_utils.py get_distrosrcCs tjdS)Nr )runamerrrrget_system_unamesrcCsdtjdtjdfS)Nz%s.%srr)r rrrrrget_python_version$srFc Csttjd}tjr^tjddddttj gdd\}}}|sN|j d}nd |}||d <|rlt j |St |}d }x |D]}|d |||f7}q~W|jS) N)python_version agent_versionZpsz-Zz --no-headersz--pidT) catch_stdoutrz error: %sselinux_contextz%s: %s )rrVERSIONrZis_selinux_enabledr run_commandstrosgetpidsplitjsondumpssortedrstrip) is_jsoninforcstdoutstderrrZ info_keysZinfo_strZinfo_keyrrrapp_info(s &  r,z/sys/firmware/efi/efivarsz$8be4df61-93ca-11d2-aa0d-00e098032b8cz$605dab50-e046-4300-abb6-3dd810dd8b23)globalshimc CsFtjjtd||f}tjj|s&dSt|d }|j|SQRXdS)Nz%s-%srb)r pathjoin EFIVARS_PATHexistsopenread)namevendorZ max_bytesZvar_pathvarrrr_read_uefi_varIs   r:c Cs@y&tdtd}|r$|dddkSWntk r:YnXdS)N SecureBootr-rF)r: EFI_VENDORS Exception)Zsecure_boot_varrrris_secure_bootRsr@cCsZyt||}|dkrdSWn.tk rH}zt|j}WYdd}~XnXtjtj|S)N)r:r?rencodernstrbase64urlsafe_b64encode)r7r8Z value_byteserrr_get_uefi_var_encoded]s rFcCstjtjjtd}|r0t|dkr0|dd}|tjjtjjt d}|dsV|Syt dddD|d <t d d tj t D}d |i|d <t ddddg}x<|D]4}|dks|jdr||krt|td |d |<qWWn2tk r}ztjt|WYdd}~XnX|S)Ncmdlinei)rGhas_efirHcss |]}|t|tdfVqdS)r-N)rFr>).0r9rrr rsz#secure_boot_info..r; SetupModer-cSs4g|],}|jtdr|dttd dqS)r.rr)endswithr>len)rIr9rrr tsz$secure_boot_info..varsr.Z MokListRTZ MokListXRTZMokListTrustedRTZ SbatLevelRT HSIStatus MokIgnoreDBZRT)r;rK)rPrQ)r try_to_readr r1r2PROC_DIRrMr4dirnamer3dictr%listdirsetrLrFr>r?rlogwarnr)rGr(Z shim_varsZshim_exclude_varsr9errrrrsecure_boot_infohs$    rZcCsrtjrfy&tjtjddddtjdd}Wqntjk rb}ztj|t j }WYdd}~XqnXnt j }|S)Nrr ) r REPORT_FQDNsocket getaddrinfo gethostname AI_CANONNAMEgaierrorrlogerrorrnode)hostnamegerrr get_hostnames& recCsTtjjtd}tjj|rPt|d}|j}ttt |j d}|j |SdS)Nuptimerrz-1) r r1r2rSisfiler5readlinerintfloatr"close)Z uptime_fileflineresultrrr get_uptimes  rpcCs tjjtrtjtgjSdS)Nz no-virt-what)r r1rhVIRTWHATr check_outputstriprrrrget_virts rtcCs tjjdS)Nz/usr/local/cpanel/cpanel)r r1rhrrrr is_cpanelsrucCs tjjdS)Nz/usr/local/psa/admin/)r r1isdirrrrris_plesksrwcCs tjjdS)Nz/usr/local/interworx/)r r1rvrrrr is_interworxsrxcCs tjjdS)Nz/usr/local/ispmgr/)r r1rvrrrr is_ispmanagersrycCs tjjdS)Nz/usr/local/directadmin/plugins/)r r1rvrrrris_directadminsrzcCs tjjdS)Nz/usr/local/hostingcontroller/)r r1rvrrrris_hosting_controllersr{cCs tjjdS)Nz/hsphere/shared)r r1rvrrrr is_hspheresr|cCstdddDS)z:Softaculous markers checked by the kcdoctor.sh detect_cp()css|]}tjj|VqdS)N)r r1r4)rIr1rrrrJsz"has_softaculous../usr/local/softaculous*/usr/local/cpanel/whostmgr/cgi/softaculous*/usr/local/directadmin/plugins/softaculous)r}r~r)anyrrrrhas_softaculouss rZPleskZcPanelZ InterWorxZ ISPmanagerZ DirectAdminzHosting ControllerzH-SpherecCs2tjjtjjtddo0tjjtjjtdd S)NZvzZveinfoversion)r r1r4r2rSrrrrinside_vz_containersrcCsdttjjtddjkS)Nz/lxc/1Zcgroup)r5r r1r2rSr6rrrrinside_lxc_containersrcCs tjjdS)Nz /.dockerenv)r r1rhrrrrinside_docker_containersr)loggercCsFtjtjjtd}|sdS|jdd\}}}}t|t|t|fS)Nloadavg r )rrRr r1r2rSr"rk)rm1Zm5Zm15_rrrget_load_averages rcsDtjtjjtd}|sdSd tfddd d|jDDS) z!Returns dict of memory info in kBmeminfoNMemTotalMemFree SwapTotalSwapFreec3s&|]\}}|kr|t|fVqdS)N)rj)rIkv) filter_paramsrrrJszget_mem_info..css"|]}tjd|ddVqdS)z[\s:]+Nr )rer")rIrnrrrrJs)rrrr)rrRr r1r2rSrU splitlines)rr)rr get_mem_infos rc Cstjtjjtd}|sdSdd|jdD}t|ttdd|D|dj dt |dj d d|dj d t |dj d dt |dj d d|dj d |dj ddjd S)NcpuinfocSs&g|]}|rtdd|jDqS)css|]}tjd|VqdS)z\s*:\s*N)rr")rIrnrrrrJ sz*get_cpu_info...)rUr)rIZ cpu_linesrrrrN sz get_cpu_info..z css"|]}|jd|jdfVqdS)z physical idzcore idN)get)rIZcpurrrrJszget_cpu_info..r vendor_idmodelz model namez cpu familystepping microcodeflagsr) Z logical_coresZphysical_coresrrZ model_nameZ cpu_familyrrr) rrRr r1r2rSr"rMrWrrj)rZcpusrrr get_cpu_infos   r)rdefault_returncCstddtjtDS)NcSsg|]}|jr|qSr)isdigit)rIdrrrrN sz%get_process_count..)rMr rVrSrrrrget_process_countsrcCs(tjtjjtd}t|pdjdS)Nzsys/fs/file-nr0r)rrRr r1r2rSrjr")Zfd_inforrrget_opened_files_count#srcCs$xtjdD]\}}}t|SWdS)Nz/sys/kernel/debug/kvm)r walkrM)Z_rootdirs_filesrrrget_vm_count_kvm*s rcCs(dd}|d|d|d|dfS)z8Return tuple of total numbers of TCP and UDP connectionscSs4tjtjjtd|}|sdStt|jddS)Nnetrr) rrRr r1r2rSmaxrMr)protorecordsrrrconn_records_count7sz9get_network_connections_count..conn_records_countZtcpZtcp6ZudpZudp6r)rrrrget_network_connections_count2src Cs,t\}}tttttt||dS)N)Z load_averageZmem_infoZcpu_infoZvm_countZ processesZ open_filesZtcp_connectionsZudp_connections)rrrrrrr)Zconn_tcpZconn_udprrrget_performance_metricsAs r)F)r/)rr)4rCr#r rrr\r rrrrrrrrqrSrcachedrrr,r3r>r:r@rFrZrerprtrurwrxryrzr{r|rZCONTROL_PANEL_PROBESrrr catch_errorsrXrrrrrrrrrrrrsd          PKk1]""(kcarectl/__pycache__/auth.cpython-36.pycnu[3 ;j/@sddlZddlZddlZddlZddlmZmZmZmZm Z m Z m Z m Z m Z ddlmZmZmZd"ddZdd Zd d Zd d Zd#ddZe jddZddZddZddZddZddZddZd$ddZd d!Z dS)%N) config constantserrors http_utils ipv6_support log_utilsplatform_utilsserveridutils) HTTPErrorURLError urlencodeFcCsd}ytj}|dkr(|s$tjddStjdj|}tj|}t j |j }t j |}|ddkrtj tj|stjdn |stj|tjd|dWn2tk r}z|stj||WYdd}~XnXdS)Nz1Error unregistering server: cannot find server idz&/unregister_server.plain?server_id={0}successtruezServer was unregisteredzError unregistering server: message)r get_serveridrlogerrorrget_registration_urlformatrurlopenr nstrread data_as_dictZ rm_serverid clear_cacheloginfor print_cln_http_error)Zsilenturl server_idresponsecontentreser#*/usr/libexec/kcare/python/kcarectl/auth.py unregisters,      r%cCstjdtj}|dkrdStjtj}ddl}|dkrH|jd|jjt dd}t dd}tj |j |j j tj |j |jj tj |j |j j xLtjd t|\}}}|dkr|rtj|t|tj|jdqWdS) NzHRegister auto-retry has been enabled, the system can be registered laterrz /dev/nullrza+<ii )r print_wrapperosforksetsidsysexitstdoutflushopendup2filenostdinstderrtimesleep _try_registerr set_server_id_set_auth_tokenrr)rpidr-sisocoder auth_tokenr#r#r$_register_retry)s.        r@cCs&|dk r"tjd| r"td||S)Nz ^[\w.-]+$zInvalid value received: %s)rematch ValueError)valuer#r#r$_validate_urlsafe_encodingGs rEcCsyNtj|}|jjtjd}tjtj|j }t |dt |jdt |fSt t fk r~}ztj||dSd}~Xn$tk rtjjd|dSXdS)Nr>rz)Exception while trying to register URL %s)NNN)NNN)rrheadersgetrZAUTH_TOKEN_HEADERr rrrintrEr r rr Exceptionkcarelog exception)rrr?r!r"r#r#r$r8Ms   r8c Cs>y tdWn tk r,tjjdYnXtj}td|fd|fg}djt j |}t |\}}}|dkrt j |t|t jtjddS|dkrtjd nv|d krtjd nb|d krtjd nN|dkrtjdn:|dkrtjdn&|dkrtjdntjdj||r4t|dS|prr?r#r#r$register[s@         rUcCs tjtjS)N)r try_to_readrAUTH_TOKEN_DUMP_PATHr#r#r#r$_get_auth_tokensrXcCs|sdStjtj|dS)N)r atomic_writerrW)r?r#r#r$r:sr:cOsv|jdd}|jddrt}ntj}tj|r@tj|f||Stj|tt|d}t j |ddtj|f||S)Nmethod check_licenseT)rZ)count) pop_check_auth_retryrcheck_urlopen_retryZ is_local_url urlopen_base http_requestget_http_auth_stringrXr rS)rargskwargsrZcheckrequestr#r#r$ urlopen_auths   rhcCs.tj}|r*tjtjtjdj|dSdS)Nz{0}:{1}Z kernelcare)r rr rbase64 b64encodebstrr)rr#r#r$rcsrccCs(t|tr|jdkrt|Stj||S)N)rlrm) isinstancer r>_handle_forbiddenrr`)r"stater#r#r$r_sr_cCsd|kr dStjrtj}tjd}|r8|dj|7}y&tjt j |ddj }tj |}Wn0t k r}ztj||dddSd}~XnX| s|jd  rtjjd j|dS|d dkrd|d<tjd dStdS)aIn case of 403 error we should check what's happen. Case #1. We are trying to register unlicensed machine and should try to register trial. Case #2. We have a valid license but access restrictions on server are not consistent yet and we had to try later. licenseTz /check.plainz?server_id={0}F)Z retry_on_500)r/Nr>zUnexpected CLN response: {0}01z$Unable to access server. Retrying...)rrrs)rCHECK_CLN_LICENSE_STATUSr rrrrr rrrrrr rrrGrJerrorr_register_trial)rprrr infoexr#r#r$ros*   rocCstj}|rtjdj|}ytj|}tj|j }tj |}| sT|j d rhtj dj|dSt |d}|dkrtj ddStdd}|dkrtj d|SWqtk r}ztj||dSd}~XqXntSdS) Nz/check.plain?server_id={0}r>zUnexpected CLN response: {0}rrzKey-based valid license found) key_checkedz No valid key-based license found)r rrrrrrr rrrrGr)rH_get_license_info_by_ipr rr)rrrr r!r>Z license_typer"r#r#r$ license_infos,       r{c Cstjd}y6tj|}tj|j}tj|}|djdkr&t |d}|dkrptj dj |ddS|dkr|d}tj |d j d }tj d j ||d S|d kr|dkr|d}tj |d j d }tj d j |||dko|dkrBd|krtj dj |dn tj dn|jdd}tj dj |Wnhtk rt} ztj| |WYdd} ~ Xn:tk r} ztj dj | |jWYdd} ~ XnXdS)Nz /check.plainrrr>rzValid license found for IP {0}iprZ expire_datez%Y-%m-%dz?You have a trial license for the IP {0} that will expire on {1}r(z0Your trial license for the IP {0} expired on {1}rNzThe IP {0} hasn't been licensedz This server hasn't been licensedrz"Error retrieving license info: {0}z1Unexpected CLN response, cannot find {0} key: {1})rrrrr rrrlowerrHr)rZparse_response_datestrftimerGr rrKeyErrorstrip) ryrrr r!r>r|Z expires_strrr"rMr#r#r$rzs<       (rzcCsFtjjtjd}tjj|r dSytjtj d}t j t j |j }y|djdkrt j|dddtj|ddkrtj|d |d tjd j|d dS|dd krt j|dddtjd n tjdWn.tk r }ztj|WYdd}~XnXWn0tk r@}ztj|jWYdd}~XnXdS)Nztrial-requestedz /trial.plainrrr}T) ensure_dirZexpiredr|createdz3Requesting trial license for IP {0}. Please wait...ZnazInvalid LicenserrR)r*pathjoinr PATCH_CACHEexistsrrrrr rrrr~rYrrZAlreadyTrialedExceptionrrr KcareErrorZUnableToGetLicenseExceptionrr r>)Z trial_markrr!Zker"r#r#r$rvs,     rv)F)F)r)!rir*rAr6r}rrrrrrr r r py23r r rr%r@rEr8rUcachedrXr:rhrcr_ror{rzrvr#r#r#r$s&,  . ) #PKk1]ʠmm)kcarectl/__pycache__/fetch.cpython-36.pycnu[3 ;j@sddlZddlZddlZddlZddlmZmZmZmZm Z m Z m Z ej ej gZdZdZdZddd Zd d Zd d Ze jejejddddddZGdddeZe jddZddZdS)N)authconfig constantserrors http_utilsselinuxutilsz /usr/bin/gpgz/var/lib/kcare/gpgzrelease.content.jsonFc Cstj}|rtj}tjr&tddd}nt}xT|D]L}y|||}PWq0tjk rz}z||dkrj|WYdd}~Xq0Xq0W||}t j |||S)Nrr ) rurlopenr urlopen_authrFORCE_JSON_SIG_V3SIG_VERIFY_ORDERrNotFoundr save_to_file) urldstdo_authZ urlopen_localZsig_extsZsig_ext signatureZnfZsig_dstr+/usr/libexec/kcare/python/kcarectl/fetch.pyfetch_signatures     rcCs$tjjts tjdjtdddS)Nz$No {0} present. Please install gnupgzgnupg not found)status)ospathisfileGPG_BINr KcareErrorformatrrrr check_gpg_bin)s rcCst|jtjrptjjtd}ytj |||Wqtj k rl}zt j dj |t|WYdd}~XqXnxt|d}|j}WdQRXtjjtd}ytj|||Wn8tk r}zt j dj |t|WYdd}~XnXdS)a8 Check a file signature using the gpg tool. If signature is wrong BadSignatureException will be raised. :param file_path: path to file which signature will be checked :param signature: a file with the signature :return: True in case of valid signature :raises: BadSignatureException zroot-keys.jsonzBad Signature: {0}: {1}Nrbz kcare_pub.key)rendswithrSIG_JSONrrjoin GPG_KEY_DIR kcsig_verifyZverifyErrorrBadSignatureExceptionrstropenreadZrun_gpg_verify Exception) file_pathrZ root_keysefZsigdataZkeyringrrrcheck_gpg_signature.s  * r/)countdelaycCs^tj|}tj|}tj|||r2|j||n|rNt||dd}t||t j |||S)NT)r) rr rselinux_safe_tmpnamer rcheckrr/rrename)rrZcheck_signature hash_checkerresponsetmprrrr fetch_urlMs     r9c@seZdZddZddZdS) HashCheckercCs6||_tj|jdd|_tjtj|d|_dS)N/files) content_filer get_patch_server_urlrstrip url_prefixjsonloads read_filehashes)selfbaseurlr=rrr__init__^szHashChecker.__init__cCsv|t|jd}||jkr4tjdj||jddtjt j |j }|j|d}||krrtj dj|||dS)Nz3Invalid checksum: {0} not found in content file {1}zinvalid checksum)rsha256z USE_SIGNATURErrr:)levelrrrrget_hash_checkerts  rWcsfdd}|S)z=Enrich request with a cache key, and save it if response had.cshtj}|dk r.d|kr i|d<||dtj<||}|jjtj}|dk rd||krdtjtj||S)Nheaders)r get_cache_keyrCACHE_KEY_HEADERrXget atomic_writeCACHE_KEY_DUMP_PATH)argskwargs cache_keyrespZ new_cache_key)clblrrwrappers z$wrap_with_cache_key..wrapperr)rbrcr)rbrwrap_with_cache_keys rd)F)FN)rJrArr%rrrrrrr SIGr"rrr$rSrrr/retry check_excr'r9objectr:cachedrWrdrrrrs $   PKk1]+,kcarectl/__pycache__/__init__.cpython-36.pycnu[3 ;j*: @sddlmZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlmZddlmZddlmZddlmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+ddlm,Z,m-Z-m.Z.dd l/m0Z0m1Z1m2Z2m3Z3m4Z4d Z5d Z6dZ7dZ8dZ9dZ:dZ;dZZ?ej=dZ@ejAjBdre jAjCddejDdeEde$jFjGejHddZIddZJdd ZKd!d"ZLd#d$ZMdd%d&ZNd'd(ZOd)d*ZPd+d,ZQd-d.ZRd/d0ZSd1d2ZTGd3d4d4eUZVGd5d6d6e,ZWGd7d8d8e,ZXGd9d:d:e,ZYd;d<ZZed=d>Z[dd?d@Z\dAdBZ]dCdDZ^iZ_dEdFZ`e`e2ja_bece dGdsy8ddldZeddlfZgeejhjiegjjeejhjidHkrekdIWnekk rYn8XdJdKZle2jmZnGdLdMdMeoZpGdNdOdOe2jmZqeqe2_mdPdQZrejsfdRdSZtdTdUZudVdWZvGdXdYdYeoZwdZd[Zxd\d]Zydd_d`ZzdadbZ{dcddZ|ddedfZ}dgdhZ~didjZdkdlZdmdnZdodpZdqdrZdsdtZdudvZdwdxZdydzZd{d|Zd}d~ZddZddZddZddZdddZddZddZddZddZdddZddZddZddZddZe&jdddZddZddZGdddZddZddZddZddZejejsfddZddZe&je*jdejfddZddZddZddZdddZddZddZdS))print_functionN)ArgumentParser)contextmanager)datetime)anomalyauth capabilitiesconfigconfig_handlers constantsdoctorerrorsfetch http_utils ipv6_supportkcarelibcare log_utilsplatform_utils process_utilsselinux server_infoserverid update_utilsutils) KcareErrorNotFoundSafeExceptionWrapper) HTTPErrorURLErrorhttplibjson_loads_nstr urlencodecZv312h24h48htestz./etc/sysconfig/kcare/freezer.modules.blacklistz/usr/libexec/kcare/kcdoctor.sh latest.v3 latest.v2z /etc/sysconfig/kcare/sysctl.conf z$==BLACKLIST== (.*)==END BLACKLIST== z'(kpatch.*|ksplice.*|kpatch_livepatch.*)z/usr/libexec/kcare/pythonignore)categorycCsDt}tjjtr@ttd}x|D]}|j|jq"W|j|S)Nr) setospathisfileFREEZER_BLACKLISTopenaddrstripclose)resultfliner;./usr/libexec/kcare/python/kcarectl/__init__.pyget_freezer_blacklistSs   r=cCsB|jd}|r(dj|d||dg}ndj|d|dg}|S)N.rrr?)splitjoin)ptypefilenameZ name_partsr;r;r< _apply_ptype]s  rDcCsJt|tjt_t|tjt_t|tjt_t|tjt_t|tjt_dS)N)rDr PATCH_BIN PATCH_INFOBLACKLIST_FILE FIXUPS_FILE PATCH_DONE)rBr;r;r< apply_ptypefs rJcCstj\}}}d}t|trbt|t rbyd|jtj|j|jf}Wqt t fk r^YqXnPt|t t t frt|t rd|}n*t|t r|jpt|j}|jpd|j}tj}tjtj|d|dt|dt||djtj|dt|ddd S) Nz[Errno %i] %s: '%s'z%srr__name__dattempts)Z agent_versionZpython_versiondistroZdistro_versionerrordetails tracebackrN)sysexc_info isinstanceOSErrorr errnor0strerrorrCAttributeError TypeErrorKeyErrorIOErrorretypetypeinnerrQr get_distror VERSIONget_python_versiongetattrstrrArRZ format_tb)r]valuetbZdetails_sanitizedrOr;r;r< format_exception_without_detailsns*  rgc Csvtjr dStjt}tjtjtj |}tj dd|}t j |t j}yt j|Wntk rpYnXdS)Nz/api/kcarectl-tracez?trace=)r UPDATE_FROM_LOCALjsondumpsrgrnstrbase64Zurlsafe_b64encodeZbstrget_patch_server_urlrZ http_requestrZget_http_auth_stringZ urlopen_base Exception)ZtraceZ encoded_traceurlZrequestr;r;r<send_excs rpcCstj}|dkr tj|ddStjtj}|dkrBtjdtjdttjd&}tj |j dtj |j dWdQRX|rt j |y |Wn*t k rtjjdtjdYnXtjddS)z Run func in a fork in an own process group (will stay alive after kcarectl process death). :param func: function to execute :return: rNarzWait exception)r0forkwaitpidsetsid_exitr7r4r ZLOG_FILEdup2filenotimesleeprnrkcarelog exception)funcrzpidfdr;r;r< nohup_forks(      rcCstjjtjd}tjj|rtt|dH}y,t|j}|t j t j krRt ||Wnt k rhYnXWdQRXtj|tjdS)aCheck the fact that there was a failed patching attempt. If anchor file not exists we should create an anchor with timestamp and schedule its deletion at $timeout. If anchor exists and its timestamp more than $timeout from now we should raise an error. z.kcareprev.lockr.N)r0r1rAr PATCH_CACHEr2r4intreadr SUCCESS_TIMEOUTryPreviousPatchFailedException ValueErrorr atomic_write timestamp_str)Zanchor_filepathZafile timestampr;r;r< touch_anchors   rcCsxytjtjjtjdWntk r.YnXtd|tj j yt ddWn t k rrt jjdYnXdS)z See touch_anchor() for detailed explanation of anchor mechanics. See KPT-730 for details about action registration. :param state_data: dict with current level, kernel_id etc. z.kcareprev.lockdone)reasonzCannot send update info!N)r0remover1rAr rrVregister_actionrget_loaded_modulesclearget_latest_patch_levelrnrr{r|) state_datar;r;r< commit_updates  rcCs(tjtjjtjdtj||dddS)NpatchesrK)Z exclude_path) rclean_directoryr0r1rAr rrget_cache_path)khashZplevelr;r;r< clear_cachesrcCs>tjpd}dj||g}tjd|f}|r2||f7}tjj|S)Nnone-modules)r PREFIXrAr rr0r1)rfnameprefixZ module_dirr8r;r;r<get_current_level_paths    rcCstjt|dt|dddS)NlatestT)Z ensure_dir)rrrrd)r patch_levelr;r;r<save_cache_latestsrc CsVt|d}tjj|rRy"tt|djj}tj ||St t fk rPYnXdS)Nrr.) rr0r1r2rr4rstriprLegacyKernelPatchLevelrrZ)rZpath_with_latestplr;r;r<get_cache_latests   rc@s eZdZdS)CertificateErrorN)rL __module__ __qualname__r;r;r;r<r srcs eZdZdZfddZZS)UnknownKernelExceptionzunknown kernelc s6djtjdtjtj}tt|j |f|dS)NzLNew kernel detected ({0} {1} {2}). There are no updates for this kernel yet.r) formatrr`platformreleaserget_kernel_hashsuperr__init__)selfkwargsmsg) __class__r;r<rszUnknownKernelException.__init__)rLrrstatusr __classcell__r;r;)rr<rsrcs(eZdZdZfddZddZZS)ApplyPatchErrorzpatch apply errorcsFtt|j||||_||_||_||_tjd|_ t j |_ dS)Nr) rrrcode freezer_stylelevel patch_filerr`rOrr)rrrrrargsr)rr;r<rszApplyPatchError.__init__c Cs0dj|j|j|j|j|jdjdd|jDS)Nz0Unable to apply patch ({0} {1} {2} {3} {4}, {5})z, cSsg|] }t|qSr;)rd).0ir;r;r< -sz+ApplyPatchError.__str__..)rrrrrOrrAr)rr;r;r<__str__&szApplyPatchError.__str__)rLrrrrrrr;r;)rr<rs rcs(eZdZdZfddZddZZS)rzprevious patch failedcs"tt|j||||_||_dS)N)rrrranchor)rrrrr)rr;r<r5sz%PreviousPatchFailedException.__init__cCsd}|j|j|jS)NzIt seems, the latest patch, applying at {0}, crashed, and further attempts will be suspended. To force patch applying, remove `{1}` file)rrr)rmessager;r;r<r:sz$PreviousPatchFailedException.__str__)rLrrrrrrr;r;)rr<r2s rcCstjdj|}yztj|}tjtj|j}t |d}|dkrRtj dn8|dkrftj dn$|dkrztj dntj d j||St k r}zt j ||WYdd}~XnXd S) Nz"/nagios/register_key.plain?key={0}rrzKey successfully registeredrzWrong key format or sizerrz!No KernelCare license for that IPzUnknown error {0}r?)rget_registration_urlrrurlopenr data_as_dictrkrr print_wrapperrrprint_cln_http_error)keyroresponseresrer;r;r<!set_monitoring_key_for_ip_licenseCs      rc cs>tjrtjtjddz dVWdtjr8tjtjddXdS)NT)shell)r ZBEFORE_UPDATE_COMMANDr run_commandZAFTER_UPDATE_COMMANDr;r;r;r< execute_hooksWs  rcCst}|j}|j}tj}|dkrht|tjtj t j |t t j|d}tjdtjtj|njtjdtjt|tjdt|tjtjtjtj tjt j tj|tjt jdS)a1 The output will consist of: Ignore output up to the line with "--START--" Line 1: show if update is needed: 0 - updated to latest, 1 - update available, 2 - unknown kernel 3 - kernel doesn't need patches 4 - no license, cannot determine Line 2: licensing message (can be skipped, can be more then one line) Line 3: LICENSE: CODE: 1: license present, 2: trial license present, 0: no license Line 4: Update mode (True - auto-update, False, no auto update) Line 5: Effective kernel version Line 6: Real kernel version Line 7: Patchset Installed # --> If None, no patchset installed Line 8: Uptime (in seconds) If *format* is 'json' return the results in JSON format. Any other output means error retrieving info :return: ri)Z updateCodeZ autoUpdateZeffectiveKernelZ realKernelZloadedPatchLevelZuptimelicensez --START--z LICENSE: N)_patch_level_infor applied_lvlr license_infordr AUTO_UPDATEr kcare_unamerrrrZ get_uptimerrrirj)fmtpliZ update_codeZ loaded_plZlicense_info_resultZresultsr;r;r< plugin_infocs,     rc Cs^tj}ytdd}Wntk r4tjr0dSdSX|dkrBdS||krNdStjrZdSdS)Ninfo)rrrrr)rloaded_patch_levelrrr IGNORE_UNKNOWN_KERNELrZstatus_gap_passed) current_levelZlatest_patch_levelr;r;r<get_update_statussrcCs2tjdd\}}|dkr*|jdr*dSdSdS)NrrZ CloudLinuxz7.extrarK)rr` startswith)rOversionr;r;r<edf_fallback_ptypesrcCsl|j|jf}tj||}tj||j|_|jjtj tj d|tkrZ|jj ddt|<|j rh|j dS)zFunction remembers IP address of host connected to and uses it for later connections. Replaces stdlib version of httplib.HTTPConnection.connect rNrr)hostZportCONNECTION_STICKY_MAPgetsocketZcreate_connectionZtimeoutsockZ setsockoptZ IPPROTO_TCPZ TCP_NODELAYZ getpeername _tunnel_hostZ_tunnel)rZaddrZ resolved_addrr;r;r<sticky_connects  rZHAS_SNIz0.13z%No pyOpenSSL module with SNI ability.cGsdS)NTr;)rr;r;r<dummy_verify_callbacksrc@s,eZdZddZddZddZddZd S) SSLSockcCs||_d|_dS)Nr) _ssl_conn_makefile_refs)rrr;r;r<rszSSLSock.__init__cGs&|jd7_tj|jf|ddiS)Nrr7T)rrZ _fileobjectr)rrr;r;r<makefileszSSLSock.makefilecCs"|j r|jr|jjd|_dS)N)rrr7)rr;r;r<r7s z SSLSock.closecGs |jj|S)N)rsendall)rrr;r;r<rszSSLSock.sendallN)rLrrrrr7rr;r;r;r<rsrc@seZdZddZdS)PyOpenSSLHTTPSConnectioncCstjj|tjjtjj}|jtjjtjj Bt j rJ|j tjj tn|j tjjt|jtjj||j}|j|jp|j}|j|j|jt j rt|j|t||_dS)N)r!HTTPConnectionconnectOpenSSLZSSLZContextZ SSLv23_METHODZ set_optionsZ OP_NO_SSLv2Z OP_NO_SSLv3r CHECK_SSL_CERTSZ set_verifyZ VERIFY_PEERrZ VERIFY_NONEZset_default_verify_pathsZ ConnectionrZset_connect_staterrZset_tlsext_host_nameencodeZ do_handshakematch_hostnameZget_peer_certificater)rZctxZconnZ server_hostr;r;r<rs  z PyOpenSSLHTTPSConnection.connectN)rLrrrr;r;r;r<rsrcCstjr&tj||}tjtj|ddS|dk}tjo6|}xrd|fd|fdgD]Z\}}t j |||d} t j | |d} |rdj | } tj|t ||d | }d } |s|rt || kr|rd nd } tjd j | qNyxtjtj|dd} tjrJtj| rJtj| }tj|}|r.tjdj |ddntjddd|rJ|j| Stk r}z>|sl|r|jdks|jdkrtjdj |wNWYdd}~XqNXqNWdS)NF) check_license latest.v1 latest.v2T)secure_boot_info perf_metrics) b64_encodingzinfo={0}?iXzsecure boot infoz perf metricsz/Check-in URL param is too large, discarding {0}z:Automatic kernel anomaly report uploaded successfully: {0}) print_msgz$Failed to send kernel anomaly reportizCCheck-in request failed with error: {0}, retrying with reduced info)rr)FF)rr)r rhrZget_kernel_prefixed_urlrZwrap_with_cache_keyr urlopen_authZSEND_PERF_METRICSrZencode_checkin_payloadrstickyfylenrlogwarnZKERNEL_ANOMALY_REPORT_ENABLErZdetect_anomalyprepare_kernel_anomaly_reportsend_data_packageloginforemove_archiverr)rrrmoderorZ perf_enabledrrZsinfoZ request_paramZmax_url_lengthZ discard_infor8 data_package upload_nameexr;r;r<_fetch_patch_level_requestsB       $r c Cs8tj}tjdk r$tj|ttjSxtD]}yt||||}tj |j t t j |jj}tjdj||dd|r|jdrt|}|jdg}tj|stjdtj||d|d|d Stj|t|Stk rYq,tk r(}z|jd krtd WYdd}~Xq,Xq,WtdS)Nz;fetch patch level, reason: {0}, kernel latest response: {1}F)r{r zeLatest KernelCare patchset is incompatible with the current kernecare package version, please upgraderbaseurlrzKC licence is required)rr) rrr PATCH_LEVELrr PATCH_LATESTr r Zset_feature_flags_from_headersheadersupdate_all_kmod_paramsrrkrrrrrrr"rr Zhas_kc_capabilitiesrCapabilitiesMismatchZKernelPatchLevelrrrrr) rr rrrrZ latest_infoZrequired_capabilitiesr r;r;r<fetch_patch_level;s2     rcCs<|jt|tj}tjjdj|ytj |ddddSt k r^tjjdj|dSt k r}ztjj dj|t |WYdd}~XnX|jt|tjtj}tjjdj|ytj |ddWnbt k rtjjdj|dStk r6}ztjjd j|t |WYdd}~XnXdS) NzProbing patch URL: {0}FHEAD)rmethodTz{0} is not available: 404zFHEAD request for {0} raised an error, fallback to the GET request: {1})rz{0} is not available: {1})file_urlrDr rErr{rrrrrrndebugrdr ZSIGr )rrBZbin_urlr ror;r;r< probe_patch\s(**rcCsF|tjkr|jtj}n |j|}|j|}tj||tjtj |dS)N)Z hash_checker) r KMOD_BINZkmod_urlr cache_pathrZ fetch_urlr USE_SIGNATUREZget_hash_checker)rnameroZdstr;r;r<fetch_and_verify_kernel_fileus    r!c@s>eZdZdddZddZddZdd Zd d Zd d ZdS) PatchFetcherNcCs ||_dS)N)r)rrr;r;r<rszPatchFetcher.__init__cCs t|j|S)N)r!r)rr r;r;r<_fetchszPatchFetcher._fetchcCsr|jjtj}|jjtj}|jjtj}|jjtj}tdd||||fDopt j j |dkopt j j |dkS)Ncss|]}tjj|VqdS)N)r0r1r2)rr1r;r;r< sz0PatchFetcher.is_patch_fetched..r) rrr rIrErFr rallr0r1getsize)rZpatch_done_pathZpatch_bin_pathZpatch_info_pathZ kmod_bin_pathr;r;r<is_patch_fetchedszPatchFetcher.is_patch_fetchedcCs4|jdkrtd|js|jS|jr6tjd|jStjdt|jtjrytj |jj t j dd}Wnt k r~Yn(X|jjdd}|r|jjtj||_y|jt j Wn0t k rtdj|jt jpdd d YnX|jt j|jtj|jtj|jjt jd d d tjtj |jS)Nz+Cannot fetch patch as no patch level is setzUpdates already downloadedzDownloading updatesr)rz KC-Base-UrlzfThe `{0}` patch level is not found for `{1}` patch type. Please select valid patch type or patch leveldefaultzpatch level not found)rwb)r )!rrr'rrrUrrrrrr rErrrupgraderrkr#rr PATCH_TYPErFr rextract_blacklistrrrIrrestore_selinux_contextr)rresprr;r;r< fetch_patchs:      zPatchFetcher.fetch_patchcCsJt|jjtjdj}|rFtj|}|rFtj |jjtj |j ddS)Nr.r) r4rrr rFr BLACKLIST_REsearchrrrGgroup)rZbufZmor;r;r<r-s  zPatchFetcher.extract_blacklistcCs|dkr dSyt|tj}Wntk r0dSX|jjdd}|rT|jtj|}|j tj}t |d}t dd|j D}WdQRXx|D]}t||qWt jtjdS)z Download fixup files for defined patch level :param level: download fixups for this patch level (usually it's a level of loaded patch) :return: None Nz KC-Base-Urlr.cSsg|] }|jqSr;)r)rfixupr;r;r<rsz-PatchFetcher.fetch_fixups..)r!r rHrrrr+rrkrr4r/ readlinesrr.r r)rrr/rZ fixups_fnamer9fixupsr4r;r;r< fetch_fixupss    zPatchFetcher.fetch_fixups)N) rLrrrr#r'r0r-r7r;r;r;r<r"~s   )r"cCs8t}tj|j|jtjkr*tjdn tjddS)Nrr) rrrrrPLIPATCH_NEED_UPDATErSexit)rr;r;r< kcare_checks    r;c Cs\t}t|}y tj}Wntk r2i}YnXtj}d}|dk r\tj|dj d}tj }|j dg}t t j|dd}t |}dd|D} t t j| d d} td d |D} || } tj} | st jd n t jd t jdj|t jdj||dkr t jdj|| dkr:t jdj| | dkrNt jdt jddS)NZUnknowntsz%Y-%m-%drz kpatch-cve)Z cve_fieldcSs"g|]}|jdgD]}|qqS)r)r)rrecpatchr;r;r<rsz%show_generic_info..Zcvecss|]}t|jdgVqdS)rN)rr)rr=r;r;r<r$sz$show_generic_info..z$KernelCare live patching is disabledz"KernelCare live patching is activez - Last updated on {0}z - Effective kernel version {0}rz* - {0} kernel vulnerabilities live patchedz- - {0} userspace vulnerabilities live patchedz% - This system has no applied patchesz(Type kcarectl --patch-info to learn more)r_kcare_patch_info_jsonrZlibcare_patch_info_basicrrZ get_staterZ fromtimestampZstrftimerrrrZextract_unique_cvessumrrr)r kcare_info libcare_infostateZ latest_updateZeffective_versionZkernel_patchesZkernel_vulnerabilitiesZkernel_patches_countZuserspace_patchesZuserspace_vulnerabilitiesZuserspace_patches_countZtotal_patches_countrr;r;r<show_generic_infos>         rDFc Csytdtjd}|st|jtj}tjt j |j }|rgi}}x>|j dD]0}tj |}|rxd|krx|j|qR|j|qRW||d<tj|}tj|WnJtk r}ztj||jdSd}~Xntk rtjdYnXd S) z Retrieve and output to STDOUT latest patch info, so it is easy to get list of CVEs in use. More info at https://cloudlinux.atlassian.net/browse/KCARE-952 :return: None r)rpolicyz z kpatch-namerrNzNo patches availabler)rr POLICY_REMOTErrr rFrrkrrrr@rappendupdaterirjrrrrro) is_jsonrro patch_inforr8chunkdatarr;r;r<kcare_latest_patch_infos,      rMcCsd|ji}|jdk rt|}g}x>|jdD]0}tj|}|rRd|krR|j|q,|j|q,W||d<tj }|r||dnd|d<|S)Nrz z kpatch-namerrunknown) rr_kcare_patch_infor@rrrGrHrZread_dumped_kernel_patch_level)rr8rJrrKrLZsaved_patch_levelr;r;r<r?4s     r?cCsTtj}tj||jtj}tjj|s2t dddt |dj }|rPt j d|}|S)NzvCan't find information due to the absent patch information file. Please, run /usr/bin/kcarectl --update and try again.zpatch info not found)rr.rK)rrrrr rFr0r1r2rr4rr1sub)rrrrr;r;r<rOHs  rOcCsZt}|s>|jdkr tj|j|jdkr.dStjt|ntjtjt |dddS)NrT)Z sort_keys) rrrrrrrOrirjr?)rIrr;r;r<rJWs   rJcCs:tjd|g}tj|}tj}d}tj||tj||kS)Nz file-infozkpatch-build-time)r KPATCH_CTLr check_outputr _patch_infoZget_patch_value)new_patch_filerZnew_patch_infoZcurrent_patch_infoZbuild_time_labelr;r;r< is_same_patchcs   rUcCsL|dkr dS|r||krdS||kr(dStjtj|tj}t|sHdSdS)NrFT)rrrr rErU) applied_level new_levelrTr;r;r<kcare_need_updateks rXcCsptjrltjjtotjttjs6tj j dj tdSt j dddtgdd\}}}|dkrltj j dj |dS) Nz-File {0} does not exist or has no read accessz /sbin/sysctlz-qz-pT) catch_stdoutrz%Unable to load kcare sysctl.conf: {0})r ZUPDATE_SYSCTL_CONFIGr0r1r2 SYSCTL_CONFIGaccessR_OKrr{warningrrr)r_r;r;r< update_sysctl}sr_c stjjtsttdjtjttjs>tj j dj tdSttdj}|j }|j dx,|D]$tfdd|Dsb|jqbWx|D]}|j|dqW|jWdQRXdS) z*Update SYSCTL_CONFIG accordingly the editsrqzFile {0} has no read accessNzr+rc3s|]}j|VqdS)N)r)rr.)r:r;r<r$sz#edit_sysctl_conf.. )r0r1r2rZr4r7r[r\rr{r]rr5seekanywritetruncate)rrGZsysctllinesrqr;)r:r<edit_sysctl_confs     rfcCs.x(|D] }tj|rtdj|ddqWdS)NzDDetected '{0}' kernel module loaded. Please unload that module firstzconflicting kernel module)r)CONFLICTING_MODULES_REmatchrr)rmoduler;r;r<detect_conflicting_moduless   rjcCsdjtjS)Nz/lib/modules/{0}/extra/kcare.ko)rrZget_system_unamer;r;r;r<get_kcare_kmod_linksrkc CsXtdd}tjtj|tj}tjj|s.dSt |d}|j dddkSQRXdS)Nr)rrbs~Module signature appended~ i) rrrrr rr0r1r2r4r)rZ kmod_fileZvfdr;r;r<kmod_is_signeds    rncs4tjddkrdSddg}tfdd|DS)Nz /proc/keysZ(12ff0613c0f80cfba3b2f8eba71ebc27c5a76170Z(69a6d9eed3f620d5c2e13a1d211c46510a5ad9f5c3s|]}|kVqdS)Nr;)rr) system_keysr;r<r$sz'kcare_certs_enrolled..)rZ try_to_readrb)Z kcare_keysr;)ror<kcare_certs_enrolleds  rpcKsdd|g}x&|jD]\}}|jdj||qWtj|dd\}}}|dkr`tdj||dddS) Nz /sbin/insmodz{0}={1}T)rYrzLUnable to load kmod ({0} {1}). Try to run with `--check-compatibility` flag.zkmod load error)r)itemsrGrrrr)Zkmodrcmdrrerr^r;r;r< load_kmods rscCsTtjr,tdkrtdtdkr,tdtjsDtjsDtjrPtddddS)NFz4Secure boot is enabled. Not supported by KernelCare.z|}YnXtj rbt j j tj  rbt j tj t}t|tfdd|jD}t|f|tdS)Nc3s"|]\}}|kr||fVqdS)Nr;)rkv)available_kmod_paramsr;r<r$!sz"load_kcare_kmod..)rkrrr rshutilcopyrnr rr0r1rrrr}dictrqrs update_depmod)rrr{Z kcare_fileZ kmod_paramsr;)rr<load_kcare_kmods   rcCsXdg}|dk r|jd|gtj|ddd\}}}|rTtjdjdj|||dddS) Nz /sbin/depmodz-aT)rYruz%Running of `{0}` failed with {1}: {2} F)r)extendrrrrwrrA)unamerrrr^stderrr;r;r<r's rcCs8tjd|gdd\}}}|dkr4tdj||dddS)Nz /sbin/rmmodT)rYrzUnable to unload {0} kmod {1}zkmod unload error)r)rrrr)modnamerr^r;r;r< unload_kmod3srcCsTg}xJdg|D]<}tj||dj|}tjj|rt||jdj|qW|S)NZvmlinuxz fixup_{0}.koz fixup_{0})rrrr0r1rrsrG)rrrZloadedmodZmodpathr;r;r< apply_fixups9s rc CsDx>|D]6}y t|Wqtk r:tjjd|YqXqWdS)Nz$Exception while unloading module %s.)rrnrr{r|)r6rr;r;r< remove_fixupsCs   rcCs|r |}n6tjrtj}n(tj|r2d|tjdfSd|tjdfSdddddd}|j}||krj||}ntdj||tjdd d ||tjdfS) NZfreeze_conflictTr(FZ freeze_noneZ freeze_all)ZNONEZNOFREEZEZFULLZFREEZEZSMARTz3Unable to detect freezer style ({0}, {1}, {2}, {3})zfreezer style detection error)r)r Z PATCH_METHODr= intersectionupperrr)freezerrrZpatch_method_mapr;r;r<get_freezer_styleKs&  rrKcs|||dtdtj}tj}t|t||}tj||tj}t ||dj |tj t j tj|} d|k} | otj||} |dk } | ot|otj| } j|| d| rtddS| rtdt|||}tdt|td t|| r"td tdd } | sz5Patch level {0} applied. Effective kernel version {1}waitcstS)N)rr;)rr;r<szkcare_load..)rz)"rrrrrjrrr rErrr,rrZ parse_unameZis_kmod_version_changedrUZkcare_update_effective_versionrHrkpatch_ctl_unpatchrrrrkpatch_ctl_patchr_rrrrZtouch_status_gap_filerr)rrr r use_anchorrrrr descriptionZ kmod_loadedrZ patch_loadedZ same_patchr6r;)rr< kcare_loadmsR              rc Cstjg}tj||tj}tjj|r2|j d|g|j dd|g|j d|dg|j |t j |dd\}}}|dkrt ||||dS)Nz-br>z-dz-mrT)rY)r rQrrr rGr0r1rrrGrrr) rrrrrrZblacklist_filerr^r;r;r<rs  rcCs^tjtjdd|dgddd\}}}|dkrZtjdj||ddtd j|t|d d dS) Nrz-mrT)rYruz4Error unpatching, kpatch_ctl stdout: {0} stderr: {1}F)rzError unpatching [{0}] {1}z unpatch error)r) rrr rQrrwrrrd)rrr|rr;r;r<rs  rcCs8||d<ttj|d<tjtjjtjdt |dS)Nactionr<z kcare.state) rryrrr0r1rAr rrd)rrr;r;r<rsrcCspd}tjj|sdSxVtj|D]H}tjj||dd}tjj|sDq tj|}||kr tj|t|q WdS)Nz/usr/lib/modules/z weak-updateszkcare.ko) r0r1isdirlistdirrAislinkreadlinkunlinkr) kmod_linkZ modules_pathentryZ sym_link_pathZ target_pathr;r;r<update_weak_moduless    rc CsJtj}t}y|j|Wn8tk rT}z|sDtdj|ddWYdd}~XnXtj}t||}t d|kr|dk }|rt tj ||}t j tjdd|dgddd \} } } t|| dkrtjd j| | d d td j| t|ddtjtjtdtdtdt} tjj| r4tj| t| WdQRXdS)NzUnable to retrieve fixups: '{0}'. The unloading of patches has been interrupted. To proceed without fixups, use the --force flag.zfixups retrieval error)rrrz-mrT)rYruz4Error unpatching, kpatch_ctl stdout: {0} stderr: {1}F)rzError unpatching [{0}] {1}z unpatch errorr)countdelay) rrr"r7rnrrrrrrrrrr rQrrrwrdrZretryrZ check_excUNLOAD_RETRY_DELAYrrkr0r1r2rr) rforcerpferrrrZ need_unpatchr6rr|rrr;r;r< kcare_unloads:    rcCs8t}|rt|S|jdkr"|jS|jdk r4tjSdS)Nr)r_kcare_info_jsonrrrrrS)rIrr;r;r<rAs  rAcCsRd|ji}|jdk r>|jtjtj|jtj|jd|j |d<t j |S)Nrzkpatch-descriptionz kpatch-state) rrrHrrrrSZparse_patch_descriptionrrCrirj)rr8r;r;r<rs    rc@s$eZdZdZdZdZdZddZdS)r8rrrrrcCs"||_||_||_||_||_dS)N)rr remote_lvlrrC)rrrrrrCr;r;r<r%s z PLI.__init__N)rLrrrr9PATCH_UNAVALIABLEPATCH_NOT_NEEDEDrr;r;r;r<r8s r8c Cstj}ytdd}|rJt||r6tjdd}}}qxtjdd}}}n.|dkrftjdd}}}ntjd d}}}t|||||}Wnltk rtj }t j rd j t j t jdtj}nd j t jdtjtj}t||ddd }YnX|S) Nr)rz*Update available, run 'kcarectl --update'.ZappliedzThe latest patch is applied.rz(This kernel doesn't require any patches.ZunsetzDNo patches applied, but some are available, run 'kcarectl --update'.zuInvalid sticky patch tag {0} for kernel ({1} {2}). Please check /etc/sysconfig/kcare/kcare.conf STICKY_PATCH settingszLNew kernel detected ({0} {1} {2}). There are no updates for this kernel yet.Z unavailable)rrrrXr8r9rrrrr STICKY_PATCHrrr`rrr)Zcurrent_patch_levelZnew_patch_levelrrrCrr;r;r<r-s8   rc Csd}yXtj}td|fd|fg}tjdj|}tj|}tj tj |j }t |dSt k r}ztj||d Sd}~XnZtk r}ztj||d Sd}~Xn0tk r}ztjdj|d Sd}~XnXdS) z Request to tag server from ePortal. See KCARE-947 for more info :param tag: String used to tag the server :return: 0 on success, -1 on wrong server id, other values otherwise N server_idtagz/tag_server.plain?{0}rrzInternal Error {0})r get_serveridr#rrrrrrrrkrrrrrr rnrw) rrorZqueryrrrZueZeer;r;r< tag_server_s"    rcCstjd}tjdj|t}tj}y:tj ||j }tj t j ||j tj|j ||j }Wn2tk r}ztjdj|WYdd}~XnXtjd|tjgdd\}}}|rtdj||dd WdQRXdS) Nz doctor.shz#Requesting doctor script from `{0}`z3Kcare doctor error: {0}. Fallback to the local one.ZbashT)ruzScript failed with '{0}' {1}zdoctor script failed)r)rrmrZlogdebugrKCDOCTORtempfileZNamedTemporaryFilerZfetch_signaturer Z save_to_filerrZcheck_gpg_signaturernrwrrrZget_patch_serverr)Z doctor_urlZdoctor_filenameZ doctor_dstZ signaturerrr^rr;r;r<kcdoctorzs   "rc CsBtjdjt}ytj|Wntk r2dSXtjddS)Nz{0}-new-versionFzwA new version of the KernelCare package is available. To continue to get kernel updates, please install the new versionT) rrmrEFFECTIVE_LATESTrrr rr)ror;r;r<check_new_kc_versionsrc Cstj}t|}|tjkp*|tjko*|dk}yt||}Wntjk r}z.|dkrXt j t |t j dtj }WYdd}~Xn<t k r}z |rnt jjdj|WYdd}~XnX|tjkr|} n@|} |dkr|tj krtj|d} n|tjkr |} ntd| S)a Get patch level to apply. :param reason: what was the source of request (update, info etc.) :param policy: REMOTE -- get latest patch_level from patchserver, LOCAL -- use cached latest, LOCAL_FIRST -- if cached level is None get latest from patchserver, use cache otherwise :param mode: constants.UPDATE_MODE_MANUAL, constants.UPDATE_MODE_AUTO or constants.UPDATE_MODE_SMART :return: patch_level string Nz#Using previously downloaded patcheszUnable to send data: {0}rz9Unknown policy, choose one of: REMOTE, LOCAL, LOCAL_FIRST)rrrr rFZPOLICY_LOCAL_FIRSTrrrrrrdZ POLICY_LOCALrnr{r]rrr) rrEr rZ cached_levelZconsider_remote_exZ remote_levelrr rr;r;r<rs2  $    rcCs|dkr dS|dkrdn|t_ttddtjrtjtjdtjdkrntjrntjpXt }t dd d j |ft j d j |ntdj |dddS)Nedfr(rKZprobe)r)r,rvrfs.enforce_symlinksifownerfs.symlinkown_gidzfs.enforce_symlinksifowner=1zfs.symlinkown_gid={0}z'{0}' patch type selectedz/'{0}' patch type is unavailable for your kernelzpatch type unavailable)r)rvr)rr)r r,rrr update_configrZ is_cpanelZ FORCE_GID CPANEL_GIDrfrrrr)rBZgidr;r;r<update_patch_types rZkernelc $Cshttj|tjkrtytd||d}WnRtk r~}z6|tjtj fkrltj rlt |}t j j|dSWYdd}~XnXtj}|tjkrtj rdSt|}|jt||dst jddSy(tjtjdddtjtjdd dWn"tk rt j jd YnXtj}t(|j|t|||||tj kd WdQRXtj|t ||dS) ax :param mode: constants.UPDATE_MODE_MANUAL, constants.UPDATE_MODE_AUTO or constants.UPDATE_MODE_SMART :param policy: REMOTE -- download latest and patches from patchserver, LOCAL -- use cached files, LOCAL_FIRST -- download latest and patches if cached level is None, use cache in other cases :param freezer: freezer mode rH)rrEr N)rVrWz%No updates are needed for this kernelrz kcore*.dump)Zkeep_nZpatternz kmsg*.logz#Error during crash reporter cleanup)r)!rxr r,r rFrrrUPDATE_MODE_AUTOUPDATE_MODE_SMARTrrdrr{r]rrrr"r0rXrrrrrnr|rrr7rZdump_kernel_patch_levelr) rr rErrrrrrr;r;r< do_updates<      " rcCstttjttjptjttjp$tjf}|dkr@tdddtjrLtjS|t j krptjp`tj}tjpltj}n tj}tj}|r|S|rd|SdS)NrzInvalid configuration: conflicting settings STICKY_PATCH, [AUTO_]UPDATE_DELAY or [AUTO_]STICKY_PATCHSET. There should be only one of themzconflicting sticky settings)rzrelease-) r@boolr rZ UPDATE_DELAYZAUTO_UPDATE_DELAYZSTICKY_PATCHSETZAUTO_STICKY_PATCHSETrr UPDATE_MODE_MANUAL)r rrZpatchsetr;r;r< get_stickys&  rcCs |d|S)Nr>r;)rrr;r;r< _stickyfy<srcCs t|}|s|S|dkr"t||Stj}|sDtjjdtjdyt j t j dj |}Wn:tk r}ztj||jtjdWYdd}~XnXtjtj|j}t|d}|dkrt|d |S|d kr|S|d krtjjd tjdtjjd |dtjddS)z Used to add sticky prefix to satisfy KCARE-953 :param file: name of the file to stickify :return: stickified file. KEYzHPatch set to STICKY_PATCH=KEY, but server is not registered with the keyrz!/sticky_patch.plain?server_id={0}rNrrrrrrzEServer ID is not recognized. Please check if the server is registeredzError: rrrrr?r)rrrrrr{rrSr:rrrrrrrrorrrkrr)filer srrrrrr;r;r<r@s2       rc Csg}|s dS|jd}|d}|dd}|jd}||krLtdt||s`|j|jkS|dkrt|jdn>|jd s|jd r|jtj|n|jtj|j d d x|D]}|jtj|qWtj d d j |dtj } | j |S)zhMatching according to RFC 6125, section 6.4.3 http://tools.ietf.org/html/rfc6125#section-6.4.3 Fr>rrN*z,too many wildcards in certificate DNS name: z[^.]+zxn--z\*z[^.]*z\Az\.z\Z)r@rrreprlowerrGrreescapereplacecompilerAZ IGNORECASErh) ZdnhostnameZ max_wildcardsZpatspiecesZleftmostZ remainderZ wildcardsZfragZpatr;r;r<_dnsname_matchls(     rc Cs g}xBt|jD]2}|j|}|jdkrddt|jdD}qW|sTtdg}x0|D](\}}|dkr^t||r|dS|j|q^W|s|j j }t||rdS|j|t |dkrt dj |d jtt|n,t |dkrt d j ||d nt d dS) NZsubjectAltNamecSsg|]}|jjddqS)ryr)rr@)ritr;r;r<rsz"match_hostname..,ztempty or no certificate, match_hostname needs a SSL socket or SSL context with either CERT_OPTIONAL or CERT_REQUIREDZDNSrz(hostname {0} doesn't match either of {1}z, zhostname {0} doesn't match {1}rz=no appropriate commonName or subjectAltName fields were found)rangeZget_extension_countZ get_extensionZget_short_namerdr@rrrGZ get_subjectZ commonNamerrrrAmapr) ZcertrZsanrrZdnsnamesrreZcnr;r;r<rs0       rc Cs tddd}|jdddd|jdd d dd|jd d dd|jd dddd|jdddd|jdddd|jdddd|jdddd|jdddd|jdddd|jdd dd|jd!d"dd|jd#d$dd|jd%d&dd|jd'd(d)d|jd*d+dd|jd,d-dd|jd.d/dd|jd0d1dd|jd2d3dd|jd4d5d6d|jd7d8d9d|jd:d;dd|jdd?dd|jd@dAdd|jdBdCdd|jdDdEddFdG|jdHdIdd|jdJdKdd|jdLdMdd|jdNdOdd|jdPdQdd|jdRdSdd|jdTdUdd|jdVdWdd|jdXdYdd|jdZd[d\tdd]d^|jd_d`dd|jdadbdd|j}|jdcddd\d|jdedfdd|jdgdhdd|jdidjd\dd]dk|jdldmdndd]do|jdpdqdr|jdsdtdd|jdudvdwdxdytjs|jdzd{d|d}d]d~|jddd|d}dd~|jdddd|jddddd|jddddd|jdddd|jddddd|jddddd|jddddd|jdddddd|jdddd|jdddd|jddd6dd\dd]d|j}tjtjsFtj dg7_ |j dk rzt t d|j j djtj rvdSdS|js|jrtjrtjt_ntjt_n|jrtjt_|jstjdkrtdtjddStj}|jrtj }n|jrtj!}t"j#|tj$stj%|j&r,t'j(|j)rn|j)dkr\t*|j)t_+tj,tj+dndt_+tj,dd|j-dk rtj,|j-d|j-t_.|j/rd]t_0|j1rd]t_2|j3rdt_4|j5rt5|j6rt7j8dt9n8|j:rtj;dkrtj|j?r&|j?t_@|jAr@t7j8dt9dt_@tj@jBdt_@tj@r~tj@tCkr~t"jDjEdjFtj@djGtC|jHrdt_Id|jHt_J|j=rtK|j=tj;dkrtLt_;t7j8djFtj;pdt9|jMrt'jNtOjM|jPddS|jQr$tQjQdddd}t'jNtPjR|dStStj;|jTrJtTjUtV|jWddS|jXrtYjZtQjQdddd}djF|j[}|j\rt'jN|nRtYj]|}|rt"j^djF|nt"j_ddd|j`rt'jN|n|r|ja|jbr|jPrtbddntbdS|jcrtj,dddS|jdr0tj,dddS|jerHtjf|jedS|jgrZth|jgS|jirjtjji|jkrtj;dkrtj,ddtjjk|jk|jlS|jmrtjjmdkrdSdS|jndk rto|jnS|jprt'jNtjqtr|d|ddk rtsjt|judStj s|jv rd|jvini}|jw r2tsjxS|jy rVtsjzf|dk rVt"j^dă|j{ rvtsjzfdtj|i|n|j} rtsj~t"j^dƃ|j rtsjt"j^dǃ|j rt'jNtsj|j rt'jNtsj|j rtsj rt'jNtsj|j|jdk rj|jdk r,tj p(ttsjj} nddɄ|jj dD} tsjzfdt| i|dk rjt"j^dă|j rtsjzftj|dd˜||j rt'jNt|jPdd} |j rt7j8dt9d} |j r|j} |j rt| tjtjd΍|j> rt| tjdύt"j^dЃ|j rt'jNtj|j r>t| |jdэt"j^d҃|j rld]t_tjtjddӃt| tj|dύ|j rt|jPd|j rtS|j rt|jPd|j rtttjdk rtdS)NZkcarectlz)Manage KernelCare patches for your kernel)Zprogrz--debugrKZ store_true)helprz-iz--infoz]Display information about KernelCare. Use with --json parameter to get result in JSON format.z --app-infozcDisplay information about KernelCare agent. Use with --json parameter to get result in JSON format.z-uz--updatez) into an isolated cache, leaving the default storage untouched. Use together with --lib-update or --userspace-update.)rrrr(rzlibcare-enabledrrrzPlease run as root)r)r)rzTFlag --edf-enabled has been deprecated and will be not available in future releases.rr(zMFlag --test has been deprecated and will be not available in future releases.r(/z(Prefix `{0}` is not in expected one {1}.rzfile:z+edf patches are deprecated. Fallback to {0})rIr)rrr)Zforce_fallbackz)Kernel anomaly report file generated: {0}z0Kernel anomaly report uploaded successfully: {0}z$Failed to send kernel anomaly report)rri)rZYES)rZNOrvr)r,rzUserspace patches are applied.r zUserspace patches are unloaded.zLibcare plugin reloaded.cSsg|]}|jjqSr;)rr)rZptchr;r;r<r5szmain..limit)r rzQFlag --nofreeze has been deprecated and will be not available in future releases.r)r rE)r zKernel is safe)rz=KernelCare protection disabled. Your kernel might not be safe<)rZ add_argumentrZadd_mutually_exclusive_groupr ZLIBCARE_DISABLEDZ parse_argsr Zset_settings_from_config_fileZFLAGSZ has_flagsr/filterr@issubsetquietZ auto_updateZSILENCE_ERRORSr ZPRINT_CRITICALZ PRINT_LEVELZ PRINT_ERRORrZ PRINT_DEBUGrr0getuidprintrSrloggingZINFOZWARNINGDEBUGrZinitialize_loggingZIGNORE_FEATURE_FLAGSZset_feature_flags_from_cacherrZclear_all_cacheZset_patch_levelrdrrZset_sticky_patchrZ nosignaturerZ no_check_certrr~rrtZ edf_enabledwarningswarnDeprecationWarningZ edf_disabledr,ZPREV_PATCH_TYPEZset_patch_typerHrrr(rEXPECTED_PREFIXr{r]rrAZlocalrhZ PATCH_SERVERrrZapp_inforrrirrjrJr Zsend_doctor_reportrZfallbackZkernel_anomaly_reportrrZ archive_pathrrrrZ keep_localrrZenable_auto_updateZdisable_auto_updateZ set_configZupdate_config_from_argsZset_monitoring_keyrZ unregisterrregisterZregister_autoretryrrrrrarcrZset_libcare_statusrZlib_tagZuserspace_statusZget_userspace_update_statusZ lib_updateZdo_userspace_updateZlib_auto_updaterZ lib_unloadZlibcare_unloadZ lib_repluginZlibcare_repluginZlib_inforBZlib_patch_infoZlibcare_patch_infoZ lib_versionZlibcare_server_startedZlibcare_versionZuserspace_updaterlistZget_userspace_mapkeyssortedZuserspace_auto_updaterrAZnofreezerZ smart_updaterrZ UPDATE_POLICYrrrrrrZCHECK_CLN_LICENSE_STATUSryrzrandomZuniformrJrrZlatest_patch_inforMZcheckr;rargvrD) ZparserZexclusive_grouprrrr Zlocal_path_messager Z lib_tag_kwrrr;r;r<mainsr                                               r)r%r&r'r()r)r*)N)N)F)F)N)rKF)rKF)r)Z __future__rrlrirr0rrrrrZsslrSrryrRrZargparser contextlibrrrKrrr r r r r rrrrrrrrrrrrrrrrrZpy23rr r!r"r#rrrr3rrrZrrZDOTALLr1rgr1rinsertfilterwarningsrr{ZsetLevelrr=rDrJrgrprrrrrrrrrrrrrrrrrrrrrrcZdistutils.versionZ distutilsZ OpenSSL.SSLrrZ StrictVersionZ __version__ ImportErrorrZHTTPSConnectionZPureHTTPSConnectionobjectrrr rrrr!r"r;rDrMr?rOrJrUrXr_rfrjrkrnrprsrtrxr}rrrrrrrrrrrrrrZlog_all_parent_processesrrArr8rrrrrFrrZtrack_update_statusrrrrrrrr;r;r;r<s    \    &    4  -! b +             " ?   -  2 .= , 3)PKk1]ץӒ&&kcarectl/config_handlers.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import json import os import re from . import config, constants, http_utils, log_utils, utils from .py23 import ConfigParser if False: # pragma: no cover from typing import Dict, List, Optional, Set # noqa: F401 CONFIG = '/etc/sysconfig/kcare/kcare.conf' FEATURE_FLAGS_WHITELIST = [ # signatures-related things 'USE_CONTENT_FILE_V3', 'FORCE_JSON_SIG_V3', # kernel module - related things 'ENABLE_CRASHREPORTER', 'KCORE_OUTPUT', 'KMSG_OUTPUT', # checkin-related things 'SEND_PERF_METRICS', # anomaly reports 'KERNEL_ANOMALY_REPORT_ENABLE', # doctor reports 'FORCE_DOCTOR_FALLBACK', ] _CONFIG_OPTIONS = set() # type: Set[str] # options were read from config file def bool_converter(value): # type: (str) -> bool return value.upper() in ('1', 'TRUE', 'YES', 'Y') def comma_list(value): # type: (str) -> List[str] return [item.strip().lower() for item in value.split(',') if item.strip()] # A sane library-name shape: starts with a letter, then letters/digits and the # punctuation that occurs in real soname stems (libnss_dns, libstdc++, libc-2.x). _LIBCARE_LIB_NAME_RE = re.compile(r'^[a-z][a-z0-9_.+\-]*$') def libcare_libs_list(value): # type: (str) -> List[str] # Reuse comma_list for splitting/normalising, then drop tokens that cannot # be a library name (typos/garbage would otherwise reach libcare-server as # part of the match regex and silently never match anything). Warns once at # config-load time so a misconfigured LIBCARE_LIBS is visible to the user. valid, invalid = [], [] # type: (List[str], List[str]) for token in comma_list(value): (valid if _LIBCARE_LIB_NAME_RE.match(token) else invalid).append(token) if invalid: log_utils.logwarn('LIBCARE_LIBS: ignoring invalid library name(s): {0}'.format(', '.join(invalid))) return valid POSSIBLE_CONFIG_OPTIONS = { # name: convert function (could be None) 'AFTER_UPDATE_COMMAND': lambda v: v.strip(), 'AUTO_STICKY_PATCHSET': None, 'AUTO_UPDATE': bool_converter, 'AUTO_UPDATE_DELAY': None, 'BEFORE_UPDATE_COMMAND': lambda v: v.strip(), 'CHECK_SSL_CERTS': bool_converter, 'DOCTOR_REPORT_MAX_SIZE_BYTES': int, 'ENABLE_CRASHREPORTER': bool_converter, 'FORCE_DOCTOR_FALLBACK': bool_converter, 'FORCE_GID': None, 'FORCE_IPV4': bool_converter, 'FORCE_IPV6': bool_converter, 'FORCE_JSON_SIG_V3': bool_converter, 'HTTP_TIMEOUT': int, 'HTTP_UPLOAD_TIMEOUT': int, 'IGNORE_FEATURE_FLAGS': bool_converter, 'IGNORE_UNKNOWN_KERNEL': bool_converter, 'KCORE_OUTPUT': bool_converter, 'KCORE_OUTPUT_SIZE': int, 'KDUMPS_DIR': lambda v: v.rstrip('/'), 'KERNEL_ANOMALY_REPORT_ENABLE': bool_converter, 'KERNEL_ANOMALY_REPORT_MAX_SIZE_BYTES': int, 'KMSG_OUTPUT': bool_converter, 'LIBCARE_DISABLED': bool_converter, 'LIBCARE_LIBS': libcare_libs_list, 'LIBCARE_PIDLOGS_MAX_TOTAL_SIZE_MB': int, 'LIBCARE_SOCKET_TIMEOUT': int, 'LIB_AUTO_UPDATE': bool_converter, 'PATCH_LEVEL': lambda v: v or None, 'PATCH_METHOD': str.upper, 'PATCH_SERVER': lambda v: v.rstrip('/'), 'PATCH_SERVER_IPV6': lambda v: v.rstrip('/'), 'PATCH_TYPE': str.lower, 'PREFIX': None, 'PREV_PATCH_TYPE': str.lower, 'REGISTRATION_URL': lambda v: v.rstrip('/'), 'REGISTRATION_URL_IPV6': lambda v: v.rstrip('/'), 'PRINT_LEVEL': int, 'REPORT_FQDN': bool_converter, 'SILENCE_ERRORS': bool_converter, 'STATUS_CHANGE_GAP': int, 'STICKY_PATCH': str.upper, 'STICKY_PATCHSET': None, 'UPDATE_DELAY': None, 'UPDATE_POLICY': str.upper, 'UPDATE_SYSCTL_CONFIG': bool_converter, 'USERSPACE_PATCHES': comma_list, 'USE_CONTENT_FILE_V3': bool_converter, 'KERNEL_VERSION_FILE': None, 'KCARE_UNAME_FILE': None, 'SUCCESS_TIMEOUT': int, 'SEND_PERF_METRICS': bool_converter, } # pragma: no py2 cover def update_config(**kwargs): cf = open(CONFIG) lines = cf.readlines() cf.close() for prop, value in kwargs.items(): updated = False prop_eq = prop + '=' prop_sp = prop + ' ' for i in range(len(lines)): if lines[i].startswith(prop_eq) or lines[i].startswith(prop_sp): if value is None: del lines[i] else: lines[i] = prop + ' = ' + str(value) + '\n' updated = True break if not updated: lines.append(prop + ' = ' + str(value) + '\n') utils.atomic_write(CONFIG, ''.join(lines)) def update_config_from_args(params): # type: (List[str]) -> None params_for_update = {} pattern = re.compile(r'^([^=]+)=([^=]*)$') for param in params: match = pattern.match(param) if match: key, value = match.groups() if not value: value = None else: raise SystemExit('Invalid parameter format: %s. Format should be KEY=VALUE' % param) params_for_update[key] = value unknown_params = set(params_for_update) - set(POSSIBLE_CONFIG_OPTIONS) if unknown_params: raise SystemExit('Unknown parameter: %s' % ', '.join(sorted(unknown_params))) for var_name, value in params_for_update.items(): convert = POSSIBLE_CONFIG_OPTIONS[var_name] if value is None or convert is None: continue try: convert(value) except Exception: raise SystemExit('Bad value for %s: %s' % (var_name, value)) update_config(**params_for_update) class FakeSecHead(object): def __init__(self, fp): self.fp = fp self.sechead = '[asection]\n' # type: Optional[str] def readline(self): # pragma: no py3 cover if self.sechead: try: return self.sechead finally: self.sechead = None else: return self.fp.readline() def __iter__(self): # pragma: no py2 cover if self.sechead: yield self.sechead self.sechead = None for line in self.fp: yield line def get_config_settings(): result = {} cp = ConfigParser(defaults={'HTTP_PROXY': '', 'HTTPS_PROXY': ''}) try: config = FakeSecHead(open(CONFIG)) if constants.PY2: # pragma: no py3 cover cp.readfp(config) else: # pragma: no py2 cover cp.read_file(config) except Exception: return {} def read_var(name, default=None, convert=None): try: value = cp.get('asection', name) except Exception: value = default if value is not None: if convert: value = convert(value) result[name] = value for scheme, variable in [('http', 'HTTP_PROXY'), ('https', 'HTTPS_PROXY')]: # environment settings take precedence over kcare.config ones if not http_utils.get_proxy_from_env(scheme): proxy = cp.get('asection', variable) if proxy: os.environ[variable] = proxy for var_name, convert in POSSIBLE_CONFIG_OPTIONS.items(): read_var(var_name, convert=convert) return result def set_settings_from_config_file(): _CONFIG_OPTIONS.clear() settings = get_config_settings() config.__dict__.update(settings) # memorize keys defined in the config file _CONFIG_OPTIONS.update(settings) def convert_headers_to_feature_flags(headers): # type: (Dict[str, str]) -> Dict[str, bool] """ Checking headers for feature flags which start with 'KC-Flag-' and reformat it to dictionary with keys in upper case and without 'KC-Flag-' prefix and dashes replaced with underscores. For unification all header keys are checked in upper case. For example: 'KC-Flag-Some-Value' -> 'SOME_VALUE' :return: dict {'SOME_VALUE': bool, ...} """ flags = {} for hdr_name, hdr_value in headers.items(): upper_name = hdr_name.upper() if not upper_name.startswith('KC-FLAG-'): continue param_name = upper_name.replace('KC-FLAG-', '').replace('-', '_') try: flags[param_name] = bool(int(hdr_value)) except ValueError: log_utils.kcarelog.error('Invalid feature flag header value %s: %s', upper_name, hdr_value) return flags def set_feature_flags_from_headers(headers): # type: (Dict[str, str]) -> None save_feature_flags_cache(headers) if not config.IGNORE_FEATURE_FLAGS: set_feature_flags_from_cache() @utils.catch_errors(logger=log_utils.logwarn) def save_feature_flags_cache(headers): # type: (Dict[str, str]) -> None feature_flags = convert_headers_to_feature_flags(headers) utils.atomic_write(constants.FEATURE_FLAGS_CACHE, content=json.dumps(feature_flags)) @utils.catch_errors(logger=log_utils.logwarn) def set_feature_flags_from_cache(): # type: () -> None """ Set global variables using feature flag from cached values received with patchserver headers. Checks that option is allowed by whitelist and update global variable using globals() :return: None """ if not os.path.exists(constants.FEATURE_FLAGS_CACHE): return with open(constants.FEATURE_FLAGS_CACHE) as f: feature_flags = json.load(f) for key, value in feature_flags.items(): if key not in FEATURE_FLAGS_WHITELIST: continue if key in _CONFIG_OPTIONS: # param was already set from config file, it has higher priority continue config.__dict__[key] = value log_utils.kcarelog.info('feature flags config override: %s=%s', key, value) PKk1]U/bbkcarectl/libcare.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import json import os import re import shutil import socket from . import ( auth, capabilities, config, config_handlers, constants, errors, fetch, log_utils, platform_utils, process_utils, selinux, server_info, update_utils, utils, ) from .py23 import HTTPError, json_loads_nstr, urlquote if False: # pragma: no cover from typing import Dict, List, Optional, Set, Tuple # noqa: F401 LIBCARE_CLIENT = '/usr/libexec/kcare/libcare-client' LIBCARE_SOCKET = ( "/run/libcare/libcare.sock", "/var/run/libcare.sock", ) LIBCARE_PATCHES = '/var/cache/kcare/libcare_patches' LIBCARE_CVE_LIST = '/var/cache/kcare/libcare_cvelist' LIBCARE_LOGROTATE_CONFIG = '/etc/sysconfig/kcare/libcare.logrotate' LIBNAME_MAP = {'mysqld': 'db', 'mariadbd': 'db', 'postgres': 'db'} # Exclude libs on distros with cross-library patches (libnss_dns + libresolv) already deployed: # - EL7 (all distros): glibc-rh1296031.patch (CVE-2015-7547) # - Ubuntu 16.04: revert-CVE-2015-5180.diff # See LIBCARE-2943 for details. # Entries: (distro_substring | None for any, version_prefix, blacklisted_libs). # version_prefix is matched as a dotted component prefix: '7.' matches '7', # '7.9' and '7.9.2009' but not '70'. CentOS 7's VERSION_ID is bare '7'. # Order matters: more specific rules first; first match wins. # NOTE: distro is matched by substring (`bl_distro in distro`) -- pick a substring # that is unique enough to avoid accidentally matching unrelated distros. LIBCARE_LIBS_BLACKLIST = [ ('ubuntu', '16.', set(['libnss_dns'])), (None, '7.', set(['libnss_dns'])), ] # type: List[Tuple[Optional[str], str, Set[str]]] @utils.cached def _get_effective_libcare_libs(): # type: () -> List[str] libs = list(config.LIBCARE_LIBS) blacklisted = set() # type: Set[str] try: distro_info = platform_utils.get_distro() distro = distro_info[0].lower() version = distro_info[1] except Exception: # Distro unknown: exclude the union of all blacklisted libs so we # never ship a lib that would conflict on *some* affected distro. for _, _, bl_libs in LIBCARE_LIBS_BLACKLIST: blacklisted |= bl_libs else: # Append a trailing dot so a bare major version like '7' matches # a prefix like '7.' without also matching '70'. version_dotted = version + '.' for bl_distro, bl_version, bl_libs in LIBCARE_LIBS_BLACKLIST: if (bl_distro is None or bl_distro in distro) and version_dotted.startswith(bl_version): blacklisted = bl_libs break return [lib for lib in libs if lib not in blacklisted] def get_userspace_map(): # type: () -> Dict[str, List[str]] return { 'db': ['mysqld', 'mariadbd', 'postgres'], 'libs': _get_effective_libcare_libs(), } def get_userspace_cache_path(libname, *parts): return os.path.join(constants.PATCH_CACHE, 'userspace', libname, *parts) def clear_libcare_cache(clbl): def wrapper(*args, **kwargs): try: return clbl(*args, **kwargs) finally: try: libcare_client('clearcache') except Exception as err: # We don't want to show the error to the user but want to see it in logs log_utils.logerror("Libcare cache clearing failed: '{0}'".format(err), print_msg=False) return wrapper class UserspacePatchLevel(int): def __new__(cls, libname, buildid, level, baseurl=None): return super(cls, cls).__new__(cls, level) def __init__(self, libname, buildid, level, baseurl=None): self.level = level self.libname = libname self.buildid = buildid self.baseurl = baseurl def cache_path(self, *parts): return get_userspace_cache_path(self.libname, self.buildid, str(self), *parts) def refresh_applied_patches_list(clbl): def save_current_state(info): """KPT-1543 Save info about applied patches""" versions, cves = '', '' try: if info is None: info = _libcare_info() packages = {} all_patches = [] for rec in _get_patches_info(info): packages[rec.get('package')] = rec.get('latest-version', '') all_patches.extend(rec.get('patches', [])) cves_set = utils.extract_unique_cves(all_patches, cve_field='cve') versions = '\n'.join([' '.join(rec) for rec in packages.items()]) cves = '\n'.join(sorted(cves_set)) # sort for consistent output finally: utils.atomic_write(LIBCARE_PATCHES, versions, ensure_dir=True) utils.atomic_write(LIBCARE_CVE_LIST, cves, ensure_dir=True) def wrapper(*args, **kwargs): info = None try: info = clbl(*args, **kwargs) return info finally: save_current_state(info) return wrapper def fetch_userspace_patch(libname, build_id, patch_level=None, tag=None): prefix = config.PREFIX or 'main' libname = urlquote(libname) build_id = urlquote(build_id.strip()) url = utils.get_patch_server_url(LIBNAME_MAP.get(libname, 'u'), prefix, libname, build_id, 'latest.v1') url += '?info=' + server_info.encoded_server_lib_info('update', patch_level) cache_dst = LIBNAME_MAP.get(libname, 'libs') if tag: cache_dst = os.path.join('tags', tag, cache_dst) extra_kwargs = {} if tag: extra_kwargs['headers'] = {'Sticky': tag} try: response = fetch.wrap_with_cache_key(auth.urlopen_auth)(url, check_license=False, **extra_kwargs) except errors.NotFound: if tag: # In transient tag mode the user explicitly asked for a snapshot; # libraries without a patchset on that date are simply not patched # - skip silently instead of failing the whole update. log_utils.loginfo( 'No libcare patchset available for {0} at tag {1}, skipping.'.format(libname, tag), print_msg=False, ) return None # There is no latest info, so we need to clear cache for corresponding # build_id to prevent updates by "-ctl" utility. shutil.rmtree(get_userspace_cache_path(cache_dst, build_id), ignore_errors=True) raise except HTTPError as ex: if ex.code == 400 and tag: raise errors.KcareError( 'Invalid sticky patch tag {0}: server rejected the value.'.format(tag), status='invalid lib sticky patch', ) raise config_handlers.set_feature_flags_from_headers(response.headers) meta = json_loads_nstr(utils.nstr(response.read())) required_capabilities = meta.get('capabilities', []) if not capabilities.has_lc_capabilities(required_capabilities): raise errors.CapabilitiesMismatch( 'Latest LibCare patchset for {0} is incompatible ' 'with the current kernecare package version, please upgrade.'.format(libname) ) level = UserspacePatchLevel(cache_dst, build_id, meta['level'], meta.get('baseurl')) plevel = str(meta['level']) patch_path = get_userspace_cache_path(cache_dst, build_id, plevel, 'patch.tar.gz') if not os.path.exists(patch_path) or os.path.getsize(patch_path) == 0: url = utils.get_patch_server_url(meta['patch_url']) try: fetch.fetch_url(url, patch_path, check_signature=config.USE_SIGNATURE, hash_checker=fetch.get_hash_checker(level)) except HTTPError as ex: # No license - no access if ex.code in (403, 401): raise errors.NoLibcareLicenseException('KC+ licence is required') raise dst = get_userspace_cache_path(cache_dst, build_id, plevel) cmd = ['tar', 'xf', patch_path, '-C', dst, '--no-same-owner'] code, stdout, stderr = process_utils.run_command(cmd, catch_stdout=True, catch_stderr=True) if code: raise errors.KcareError( "Patches unpacking error: '{0}' '{1}' {2}".format(stderr, stdout, code), status='patches unpacking error' ) link_name = get_userspace_cache_path(cache_dst, build_id, 'latest') if not os.path.islink(link_name) and os.path.isdir(link_name): shutil.rmtree(link_name) os.symlink(plevel, link_name + '.tmp') os.rename(link_name + '.tmp', link_name) return level def set_libcare_status(enabled): config.LIBCARE_DISABLED = not enabled if not enabled: libcare_server_stop() config_handlers.update_config(LIBCARE_DISABLED=('FALSE' if enabled else 'YES')) if enabled: libcare_server_start() log_utils.kcarelog.info('libcare service is ' + ('enabled' if enabled else 'disabled')) def libcare_server_stop(): # Stop the socket first to break cascading restart loops on # systemd 219 (CentOS 7) where a pending connection in the # socket backlog re-activates a failed service. if constants.SKIP_SYSTEMCTL_CHECK or os.path.exists(constants.SYSTEMCTL): process_utils.run_command([constants.SYSTEMCTL, 'stop', 'libcare.socket']) process_utils.run_command([constants.SYSTEMCTL, 'stop', 'libcare.service']) process_utils.run_command([constants.SYSTEMCTL, 'reset-failed', 'libcare']) process_utils.run_command([constants.SYSTEMCTL, 'reset-failed', 'libcare.socket']) else: # pragma: no cover unit try: cmd = [process_utils.find_cmd('service', ('/usr/sbin/', '/sbin/')), 'libcare', 'stop'] except Exception: return process_utils.run_command(cmd) def libcare_server_start(): # KPT-2884: skip restart when libcare.service is already active -- systemd # refuses to activate a socket whose service is already running if constants.SKIP_SYSTEMCTL_CHECK or os.path.exists(constants.SYSTEMCTL): code, _, _ = process_utils.run_command( [constants.SYSTEMCTL, 'is-active', '--quiet', 'libcare.service'], catch_stdout=True, catch_stderr=True, ) if code == 0: return # Break out of a possible cascading restart loop on systemd 219 # (CentOS 7) by stopping socket first, then service, then clearing # failed state. process_utils.run_command([constants.SYSTEMCTL, 'stop', 'libcare.socket']) process_utils.run_command([constants.SYSTEMCTL, 'stop', 'libcare.service']) process_utils.run_command([constants.SYSTEMCTL, 'reset-failed', 'libcare']) process_utils.run_command([constants.SYSTEMCTL, 'reset-failed', 'libcare.socket']) process_utils.run_command([constants.SYSTEMCTL, 'start', 'libcare.socket']) else: if libcare_server_started(): return try: cmd = [process_utils.find_cmd('service', ('/usr/sbin/', '/sbin/')), 'libcare', 'start'] except Exception: # pragma: no cover unit return process_utils.run_command(cmd) def _libcare_info(patched=True, limit=None): # Escape each name: library/process names contain regex metacharacters # (e.g. '.'/'+' in libstdc++ and libc-2.17.so, or '()' in # 'libcrypto.so.1.0.1e (deleted)') that must match literally, not as a regex. regexp = '|'.join("({0})".format(re.escape(proc)) for proc in sorted(limit or [])) cmd = ['info', '-j'] if not patched: cmd += ['-l', '-r', regexp] try: lines = libcare_client(*cmd) except Exception as err: raise errors.KcareError("Gathering userspace libraries info error: '{0}'".format(err), status='userspace libs info error') result = [] for line in lines.split('\n'): if line: try: result.append(json.loads(line)) except ValueError: # We have to do that because socket's output isn't separated to stderr and stdout # so there are chances that will be non-json lines pass # FIXME: remove that libe when library names will be separated to lower # level from process name and pid result = [{'comm': line.pop('comm'), 'pid': line.pop('pid'), 'libs': line} for line in result] for line in result: line['libs'] = dict((k, v) for k, v in line['libs'].items() if ('patchlvl' in v or not patched)) return result def _get_patches_info(info): patches = set() for rec in info: for _, data in rec['libs'].items(): patches.add((data['buildid'], data['patchlvl'])) result = [] umap = get_userspace_map() for cache_dst in umap: for build_id, patchlvl in patches: patch_info_filename = get_userspace_cache_path(cache_dst, build_id, str(patchlvl), 'info.json') if os.path.isfile(patch_info_filename): with open(patch_info_filename, 'r') as fd: result.append(json.load(fd)) return result @clear_libcare_cache def libcare_patch_info_basic(): return _get_patches_info(_libcare_info()) @clear_libcare_cache def libcare_patch_info(): result = libcare_patch_info_basic() if not result: log_utils.logerror("No patched processes.") return json.dumps({'result': result}) @clear_libcare_cache def libcare_info(): result = _libcare_info() if not result: log_utils.logerror("No patched processes.") return json.dumps({'result': result}) def _libcare_version(): result = {} for rec in libcare_patch_info_basic(): result[rec.get('package')] = rec.get('latest-version', '') return result def libcare_version(libname): for package, version in _libcare_version().items(): if libname.startswith(package): return version return '' def libcare_client_format(params): return b''.join(utils.bstr(p) + b'\0' for p in params) + b'\0' def get_available_libcare_socket(): for libcare_socket in LIBCARE_SOCKET: if os.path.exists(libcare_socket): return libcare_socket raise errors.KcareError("Libcare socket is not found.") def libcare_client(*params): if config.LIBCARE_DISABLED: raise errors.KcareError('Libcare is disabled.') sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0) sock.settimeout(10) # connect timeout res = b'' try: sock.connect(get_available_libcare_socket()) sock.settimeout(config.LIBCARE_SOCKET_TIMEOUT) cmd = libcare_client_format(params) log_utils.logdebug("Libcare socket send: {cmd}".format(cmd=params)) sock.sendall(cmd) while True: data = sock.recv(4096) if not data: break res += data result = res.decode('utf-8', 'replace') log_utils.logdebug("Libcare socket recieved: {result}".format(result=result)) return result finally: sock.close() def libcare_patch_apply(limit, tag=None): if tag: # Atomic apply from an isolated, tag-specific storage. Leaves the # default storage untouched, so a transient `--lib-tag` update does # not interfere with the normal `--lib-update` flow. for dst in limit: storage_path = get_userspace_cache_path('tags', tag, dst) # check_userspace_updates only creates the tag-specific storage # directory for groups that had running processes with available # patchsets. If a group (e.g. 'db' on a host without a DB) had # nothing fetched, the directory does not exist - skip the apply # for it explicitly so we don't rely on libcare-server's # behavior of returning 0 on "cannot open storage". if not os.path.isdir(storage_path): continue try: libcare_client('update', '--storage', storage_path) except Exception as err: raise errors.KcareError( "Userspace patch applying error (storage={0}): '{1}'".format(storage_path, err), status='userspace patch apply error', ) return for dst in limit: try: libcare_client('storage', get_userspace_cache_path(dst)) except Exception as err: raise errors.KcareError("Userspace storage switching error: '{0}'".format(err), status='userspace storage switch error') try: libcare_client('update') except Exception as err: raise errors.KcareError("Userspace patch applying error: '{0}'".format(err), status='userspace patch apply error') @clear_libcare_cache @refresh_applied_patches_list @process_utils.log_all_parent_processes def libcare_unload(): try: libcare_client('unload') except Exception as err: raise errors.KcareError("Userspace patch unloading error: '{0}'".format(err), status='userspace patch unload error') def libcare_replugin(): # pragma: no cover unit """Reload libcare-server plugin without restarting the server.""" try: libcare_client('replugin') except Exception as err: raise errors.KcareError("Userspace replugin error: '{0}'".format(err)) # log_all_parent_processes must be outermost to run first @process_utils.log_all_parent_processes @update_utils.track_update_status('libcare') @selinux.skip_if_no_selinux_module @clear_libcare_cache @refresh_applied_patches_list def do_userspace_update(mode=constants.UPDATE_MODE_MANUAL, limit=None, tag=None): """Patch userspace processes to the latest version.""" rotate_libcare_logs() # Auto-update means cron-initiated run and if no # LIB_AUTO_UPDATE flag in the config - nothing will happen. if mode == constants.UPDATE_MODE_AUTO and not config.LIB_AUTO_UPDATE: return None umap = get_userspace_map() if limit is None: limit = list(umap.keys()) process_filter = [] for userspace_patch in limit: process_filter.extend(umap.get(userspace_patch, [])) if not process_filter: # Unknown limits were defined. Do nothing log_utils.loginfo('No such userspace patches: {0}'.format(limit)) return None failed, something_found, _, before = check_userspace_updates(limit=process_filter, tag=tag) if failed: raise errors.KcareError('There were errors while patches downloading (unpacking).') if not something_found: log_utils.loginfo('No patches were found.') return None selinux.restore_selinux_context(os.path.join(constants.PATCH_CACHE, 'userspace')) rotate_libcare_logs() try: # Batch apply for all collected patches libcare_patch_apply(limit, tag=tag) # TODO: clear userspace cache. We need the same logic as for kernel, lets do # it later to reduce this patch size. except errors.KcareError as ex: log_utils.logerror(str(ex)) raise errors.KcareError('There were errors while patches applying.') data_after = _libcare_info() after = _get_userspace_procs(data_after) if not any(list(item['libs'] for item in data_after)): # No patches were applied return None # Info on how many patches were actually patched via before and after diff log_utils.logdebug("Patched before: {before}".format(before=before)) log_utils.logdebug("Patched after: {after}".format(after=after)) uniq_procs_after = set(v for items in after.values() for v in items) uniq_procs_before = set(v for items in before.values() for v in items) diff = uniq_procs_after - uniq_procs_before overall = sum(len(v) for v in after.values()) log_utils.loginfo( "The patches have been successfully applied to {count} newly " "discovered processes. The overall amount of applied patches " "is {overall}.".format(count=len(diff), overall=overall) ) for k, v in after.items(): log_utils.loginfo("Object `{0}` is patched for {1} processes.".format(k, len(v))) return data_after @clear_libcare_cache def get_userspace_update_status(): try: failed, _, libs_not_patched, _ = check_userspace_updates() except errors.KcareError: return 3 finally: rotate_libcare_logs() if failed: return 3 if libs_not_patched: return 1 return 2 if update_utils.status_gap_passed(filename='.libcarestatus') else 0 def _get_userspace_procs(info): result = {} # type: Dict[str, List[Tuple[int, str]]] for item in info: for libname, rec in item['libs'].items(): if rec.get('patchlvl'): if libname not in result: result[libname] = [] result[libname].append((item['pid'], item['comm'])) return result def _get_userspace_libs(info): result = set() for item in info: for libname, rec in item['libs'].items(): result.add((libname, rec['buildid'], rec.get('patchlvl', 0))) return result def check_userspace_updates(limit=None, tag=None): if not limit: umap = get_userspace_map() limit = [] [limit.extend(libs) for libs in umap.values()] data_before = _libcare_info(patched=False, limit=limit) before = _get_userspace_procs(data_before) failed = something_found = False libs_not_patched = True for rec in _get_userspace_libs(data_before): # Download and unpack patches libname, build_id, patchlvl = rec try: result = fetch_userspace_patch(libname, build_id, patchlvl, tag=tag) # In tag mode a None result means the patchset was missing for # this library on the requested date - that's a legitimate skip, # not a "found update". if tag and result is None: continue something_found = True if patchlvl != 0: libs_not_patched = False except errors.CapabilitiesMismatch as e: failed = True log_utils.logwarn(str(e)) except (errors.NotFound, errors.NoLibcareLicenseException): pass except errors.AlreadyTrialedException: raise except errors.KcareError as ex: # An invalid sticky tag is rejected by the server for every # build_id (the 400 is a property of the tag value, not of # the library). Continuing the loop would just hammer the # server with N identical 400s and bury the specific error # under a generic "There were errors while patches downloading" # at the end. Fail fast with the original message instead, # mirroring AlreadyTrialedException handling above. if getattr(ex, 'status', None) == 'invalid lib sticky patch': raise failed = True log_utils.logerror(str(ex)) update_utils.touch_status_gap_file(filename='.libcarestatus') return failed, something_found, libs_not_patched, before def rotate_libcare_logs(): rc = 0 stderr = '' logrotate_path = process_utils.find_cmd('logrotate', raise_exc=False) if logrotate_path: try: rc, _, stderr = process_utils.run_command([logrotate_path, LIBCARE_LOGROTATE_CONFIG], catch_stderr=True) except Exception as e: rc = 1 stderr = str(e) if rc: log_utils.logerror('failed to run logrotate for libcare logs, stderr: {0}'.format(stderr), print_msg=False) else: log_utils.logwarn("logrotate utility wasn't found", print_msg=False) libcare_log_directory = '/var/log/libcare/' if not os.path.isdir(libcare_log_directory): return max_total_size = config.LIBCARE_PIDLOGS_MAX_TOTAL_SIZE_MB * (1024**2) try: log_files = os.listdir(libcare_log_directory) pidlog_re = re.compile(r'^\d+\.log.*') # both .log and .log.x.gz pidlog_files = [os.path.join(libcare_log_directory, fn) for fn in log_files if pidlog_re.match(fn)] pidlog_files_with_ct = [(os.path.getctime(fp), fp) for fp in pidlog_files] pidlog_files_with_ct.sort(reverse=True) # newest files first # delete old files if we have overflow total_size = 0 for _, filepath in pidlog_files_with_ct: total_size += os.path.getsize(filepath) if total_size >= max_total_size: os.remove(filepath) log_utils.kcarelog.info('Removed %s because of logs size limit', filepath) except Exception: # pragma: no cover log_utils.logexc('Failed to cleanup libcare server logfiles', print_msg=False) def libcare_server_started(): """Assume that whenever the service is not running, we did not patch anything.""" try: cmd = [process_utils.find_cmd('service', ('/usr/sbin/', '/sbin/')), 'libcare', 'status'] except Exception: # pragma: no cover unit return False code, _, _ = process_utils.run_command(cmd, catch_stdout=True, catch_stderr=True) return code == 0 PKk1]^uk//kcarectl/auth.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import base64 import os import re import time from . import config, constants, errors, http_utils, ipv6_support, log_utils, platform_utils, serverid, utils from .py23 import HTTPError, URLError, urlencode def unregister(silent=False): url = None try: server_id = serverid.get_serverid() if server_id is None: if not silent: log_utils.logerror('Error unregistering server: cannot find server id') return url = ipv6_support.get_registration_url() + '/unregister_server.plain?server_id={0}'.format(server_id) response = http_utils.urlopen(url) content = utils.nstr(response.read()) res = utils.data_as_dict(content) if res['success'] == 'true': serverid.rm_serverid() # License state transitioned (licensed -> none); the cached ipv6 decision # may have been "ipv4 because server id was found" and no longer applies. ipv6_support.clear_cache() if not silent: log_utils.loginfo('Server was unregistered') elif not silent: log_utils.logerror(content) log_utils.logerror('Error unregistering server: ' + res['message']) except HTTPError as e: if not silent: log_utils.print_cln_http_error(e, url) def _register_retry(url): # pragma: no cover unit utils.print_wrapper('Register auto-retry has been enabled, the system can be registered later') pid = os.fork() if pid > 0: return os.setsid() pid = os.fork() import sys if pid > 0: sys.exit(0) sys.stdout.flush() si = open('/dev/null', 'r') so = open('/dev/null', 'a+') os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(so.fileno(), sys.stderr.fileno()) while True: time.sleep(60 * 60 * 2) code, server_id, auth_token = _try_register(url) if code == 0 and server_id: serverid.set_server_id(server_id) _set_auth_token(auth_token) # Daemonized retry: this success runs in a forked child hours after # register() returned, so it can't piggy-back on the synchronous # clear_cache() in register() -- it has to invalidate the cache itself. ipv6_support.clear_cache() sys.exit(0) def _validate_urlsafe_encoding(value): if value is not None and not re.match(r'^[\w.-]+$', value): raise ValueError('Invalid value received: %s' % value) return value def _try_register(url): try: response = http_utils.urlopen(url) auth_token = response.headers.get(constants.AUTH_TOKEN_HEADER, None) res = utils.data_as_dict(utils.nstr(response.read())) return int(res['code']), _validate_urlsafe_encoding(res.get('server_id')), _validate_urlsafe_encoding(auth_token) except (HTTPError, URLError) as e: log_utils.print_cln_http_error(e, url) return None, None, None except Exception: log_utils.kcarelog.exception('Exception while trying to register URL %s' % url) return None, None, None def register(key, retry=False): try: unregister(True) except Exception: log_utils.kcarelog.exception('Exception while trying to unregister URL before register.') hostname = platform_utils.get_hostname() query = urlencode([('hostname', hostname), ('key', key)]) url = '{0}/register_server.plain?{1}'.format(ipv6_support.get_registration_url(), query) code, server_id, auth_token = _try_register(url) if code == 0: serverid.set_server_id(server_id) _set_auth_token(auth_token) # License state transitioned (none -> licensed) and a serverid now exists, # so the next is_ipv6_preferred() will hit a different branch than the # cached "no license yet" decision -- invalidate after the transition, # not before (re-evaluating pre-register would just repeat the probes # and return the same answer since no license exists yet). ipv6_support.clear_cache() log_utils.loginfo('Server Registered') return 0 elif code == 1: log_utils.logerror('Account Locked') elif code == 2: log_utils.logerror('Invalid Key') elif code == 3: log_utils.logerror( 'You have reached maximum registered servers for this key. ' 'Please go to your CLN account, remove unused servers and try again.' ) elif code == 4: log_utils.logerror('IP is not allowed. Please change allowed IP ranges for the key in KernelCare Key tab in CLN') elif code == 5: log_utils.logerror('This IP was already used for trial, you cannot use it for trial again') elif code == 6: log_utils.logerror('This IP was banned. Please contact support for more information at https://www.kernelcare.com/support/') else: log_utils.logerror('Unknown Error {0}'.format(code)) if retry: # pragma: no cover _register_retry(url) return 0 return code or -1 @utils.cached def _get_auth_token(): return utils.try_to_read(constants.AUTH_TOKEN_DUMP_PATH) def _set_auth_token(auth_token): if not auth_token: return utils.atomic_write(constants.AUTH_TOKEN_DUMP_PATH, auth_token) def urlopen_auth(url, *args, **kwargs): method = kwargs.pop('method', None) if kwargs.pop('check_license', True): check = _check_auth_retry else: check = http_utils.check_urlopen_retry if http_utils.is_local_url(url): return http_utils.urlopen_base(url, *args, **kwargs) request = http_utils.http_request(url, get_http_auth_string(), _get_auth_token(), method=method) return utils.retry(check, count=8)(http_utils.urlopen_base)(request, *args, **kwargs) def get_http_auth_string(): server_id = serverid.get_serverid() if server_id: return utils.nstr(base64.b64encode(utils.bstr('{0}:{1}'.format(server_id, 'kernelcare')))) return None def _check_auth_retry(e, state): if isinstance(e, HTTPError) and e.code in (403, 401): return _handle_forbidden(state) return http_utils.check_urlopen_retry(e, state) def _handle_forbidden(state): """In case of 403 error we should check what's happen. Case #1. We are trying to register unlicensed machine and should try to register trial. Case #2. We have a valid license but access restrictions on server are not consistent yet and we had to try later. """ if 'license' in state: # license has already been checked and is valid, no need to ask CLN again return True if config.CHECK_CLN_LICENSE_STATUS: server_id = serverid.get_serverid() url = ipv6_support.get_registration_url() + '/check.plain' if server_id: url += '?server_id={0}'.format(server_id) try: # do not retry in case of 500 from CLN! # otherwise, CLN will die in pain because of too many requests content = utils.nstr(http_utils.urlopen(url, retry_on_500=False).read()) info = utils.data_as_dict(content) except URLError as ex: log_utils.print_cln_http_error(ex, url, stdout=False) return if not info or not info.get('code'): log_utils.kcarelog.error('Unexpected CLN response: {0}'.format(content)) return if info['code'] in ['0', '1']: # license is fine: 0 - valid license, 1 - valid trial license; # looks like htpasswd not updated yet; # mark state as licensed to avoid repeated requests to CLN state['license'] = True log_utils.logerror('Unable to access server. Retrying...') return True else: _register_trial() def license_info(): server_id = serverid.get_serverid() if server_id: url = ipv6_support.get_registration_url() + '/check.plain?server_id={0}'.format(server_id) try: response = http_utils.urlopen(url) content = utils.nstr(response.read()) res = utils.data_as_dict(content) if not res or not res.get('code'): utils.print_wrapper('Unexpected CLN response: {0}'.format(content)) return 1 code = int(res['code']) if code == 0: utils.print_wrapper('Key-based valid license found') return 1 else: license_type = _get_license_info_by_ip(key_checked=1) if license_type == 0: utils.print_wrapper('No valid key-based license found') return license_type except URLError as e: log_utils.print_cln_http_error(e, url) return 0 else: return _get_license_info_by_ip() def _get_license_info_by_ip(key_checked=0): url = ipv6_support.get_registration_url() + '/check.plain' try: response = http_utils.urlopen(url) content = utils.nstr(response.read()) res = utils.data_as_dict(content) if res['success'].lower() == 'true': code = int(res['code']) if code == 0: utils.print_wrapper('Valid license found for IP {0}'.format(res['ip'])) return 1 # valid license if code == 1: ip = res['ip'] expires_str = utils.parse_response_date(res['expire_date']).strftime('%Y-%m-%d') utils.print_wrapper('You have a trial license for the IP {0} that will expire on {1}'.format(ip, expires_str)) return 2 # trial license if code == 2 and key_checked == 0: ip = res['ip'] expires_str = utils.parse_response_date(res['expire_date']).strftime('%Y-%m-%d') utils.print_wrapper('Your trial license for the IP {0} expired on {1}'.format(ip, expires_str)) if code == 3 and key_checked == 0: if 'ip' in res: utils.print_wrapper("The IP {0} hasn't been licensed".format(res['ip'])) else: utils.print_wrapper("This server hasn't been licensed") else: message = res.get('message', '') utils.print_wrapper('Error retrieving license info: {0}'.format(message)) except URLError as e: log_utils.print_cln_http_error(e, url) except KeyError as key: utils.print_wrapper('Unexpected CLN response, cannot find {0} key:\n{1}'.format(key, content.strip())) return 0 # no valid license def _register_trial(): trial_mark = os.path.join(constants.PATCH_CACHE, 'trial-requested') if os.path.exists(trial_mark): return try: response = http_utils.urlopen(ipv6_support.get_registration_url() + '/trial.plain') res = utils.data_as_dict(utils.nstr(response.read())) try: if res['success'].lower() == 'true': utils.atomic_write(trial_mark, '', ensure_dir=True) # Trial just granted: license state flipped (none -> trial), so # the cached ipv4 decision may no longer reflect the right branch # in is_ipv6_preferred(). ipv6_support.clear_cache() if res['expired'] == 'true': raise errors.AlreadyTrialedException(res['ip'], res['created']) log_utils.loginfo('Requesting trial license for IP {0}. Please wait...'.format(res['ip'])) return None elif res['success'] == 'na': utils.atomic_write(trial_mark, '', ensure_dir=True) raise errors.KcareError('Invalid License') else: # TODO: make sane exception messages raise errors.UnableToGetLicenseException(-1) # Invalid response? except KeyError as ke: raise errors.UnableToGetLicenseException(ke) except HTTPError as e: raise errors.UnableToGetLicenseException(e.code) PKk1]t*kcarectl/errors.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT from .py23 import HTTPError class SafeExceptionWrapper(Exception): def __init__(self, inner, etype=None, details=None): self.inner = inner self.etype = etype self.details = details class KcareError(Exception): """Base kernelcare exception which will be considered as expected error and the full traceback will not be shown. Subclasses may set a class-level ``status`` to provide a short, fixed label for error reporting. Individual raise sites can override it per-instance via the ``status`` kwarg. """ status = '' # type: str def __init__(self, *args, **kwargs): # type: (*object, **object) -> None status = kwargs.pop('status', None) if status is not None: self.status = str(status) super(KcareError, self).__init__(*args) class NotFound(HTTPError): pass class NoLibcareLicenseException(KcareError): status = 'no libcare license' class CapabilitiesMismatch(KcareError): status = 'capabilities mismatch' class AlreadyTrialedException(KcareError): status = 'already trialed' def __init__(self, ip, created, *args, **kwargs): super(AlreadyTrialedException, self).__init__(*args, **kwargs) self.created = created[0 : created.index('T')] self.ip = ip def __str__(self): return 'The IP {0} was already used for a trial license on {1}'.format(self.ip, self.created) class UnableToGetLicenseException(KcareError): status = 'unable to get license' def __init__(self, code, **kwargs): super(UnableToGetLicenseException, self).__init__( 'Unknown Issue when getting trial license. Error code: ' + str(code), **kwargs ) class BadSignatureException(KcareError): status = 'bad signature' def check_exc(*exc_list): def inner(e, state): return isinstance(e, exc_list) return inner PKk1]M((kcarectl/platform_utils.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import base64 import json import os import platform import re import socket import sys from . import config, constants, log_utils, process_utils, selinux, utils if False: # pragma: no cover from typing import Any, Dict, Optional, Tuple # noqa: F401 VIRTWHAT = '/usr/libexec/kcare/virt-what' PROC_DIR = '/proc' def get_distro(): if sys.version_info[:2] < (3, 6): # pragma: no py3 cover return platform.linux_distribution() else: # pragma: no distro cover import distro return distro.linux_distribution(full_distribution_name=False) @utils.cached def get_system_uname(): return platform.uname()[2] def get_python_version(): # type: () -> str return '%s.%s' % (sys.version_info[0], sys.version_info[1]) def app_info(is_json=False): # type: (bool) -> str info = { 'python_version': get_python_version(), 'agent_version': constants.VERSION, } if selinux.is_selinux_enabled(): rc, stdout, stderr = process_utils.run_command(['ps', '-Z', '--no-headers', '--pid', str(os.getpid())], catch_stdout=True) if not rc: selinux_context = stdout.split()[0] else: selinux_context = 'error: %s' % stderr info['selinux_context'] = selinux_context if is_json: return json.dumps(info) info_keys = sorted(info) info_str = '' for info_key in info_keys: info_str += '%s: %s\n' % (info_key, info[info_key]) return info_str.rstrip() EFIVARS_PATH = '/sys/firmware/efi/efivars' EFI_VENDORS = { 'global': '8be4df61-93ca-11d2-aa0d-00e098032b8c', 'shim': '605dab50-e046-4300-abb6-3dd810dd8b23', } def _read_uefi_var(name, vendor, max_bytes=256): # type: (str, str, Optional[int]) -> Optional[bytes] var_path = os.path.join(EFIVARS_PATH, '%s-%s' % (name, vendor)) if not os.path.exists(var_path): return None with open(var_path, 'rb') as var: return var.read(max_bytes) def is_secure_boot(): # mocked: tests/unit/test_load_kmod.py # type: () -> bool try: secure_boot_var = _read_uefi_var('SecureBoot', EFI_VENDORS['global']) if secure_boot_var: return secure_boot_var[-1:] == b'\x01' # Get last byte except Exception: # pragma: no cover pass return False def _get_uefi_var_encoded(name, vendor): # type: (str, str) -> Optional[str] try: value_bytes = _read_uefi_var(name, vendor) if value_bytes is None: return None except Exception as e: value_bytes = str(e).encode() return utils.nstr(base64.urlsafe_b64encode(value_bytes)) def secure_boot_info(): # type: () -> dict[str, Any] cmdline = utils.try_to_read(os.path.join(PROC_DIR, 'cmdline')) if cmdline and len(cmdline) > 1024: # pragma: no cover cmdline = cmdline[:1024] info = {'cmdline': cmdline, 'has_efi': os.path.exists(os.path.dirname(EFIVARS_PATH))} # type: dict[str, Any] if not info['has_efi']: return info try: info['global'] = dict((var, _get_uefi_var_encoded(var, EFI_VENDORS['global'])) for var in ('SecureBoot', 'SetupMode')) shim_vars = sorted( [var[0 : -len(EFI_VENDORS['shim']) - 1] for var in os.listdir(EFIVARS_PATH) if var.endswith(EFI_VENDORS['shim'])] ) info['shim'] = {'vars': shim_vars} shim_exclude_vars = set(['MokListRT', 'MokListXRT', 'MokListTrustedRT', 'SbatLevelRT']) for var in shim_vars: if var in ('HSIStatus', 'MokIgnoreDB') or (var.endswith('RT') and var not in shim_exclude_vars): info['shim'][var] = _get_uefi_var_encoded(var, EFI_VENDORS['shim']) except Exception as err: log_utils.logwarn(str(err)) return info @utils.cached def get_hostname(): # type: () -> str # KCARE-1165 If fqdn gathering is forced if config.REPORT_FQDN: try: # getaddrinfo() -> [(family, socktypeget_hostname, proto, canonname, sockaddr), ...] hostname = socket.getaddrinfo(socket.gethostname(), 0, 0, 0, 0, socket.AI_CANONNAME)[0][3] except socket.gaierror as ge: log_utils.logerror(ge) hostname = platform.node() else: hostname = platform.node() return hostname @utils.cached def get_uptime(): # type: () -> str uptime_file = os.path.join(PROC_DIR, 'uptime') if os.path.isfile(uptime_file): f = open(uptime_file, 'r') line = f.readline() result = str(int(float(line.split()[0]))) f.close() return result return '-1' @utils.cached def get_virt(): if os.path.isfile(VIRTWHAT): return process_utils.check_output([VIRTWHAT]).strip() return 'no-virt-what' # pragma: no cover def is_cpanel(): # type: () -> bool return os.path.isfile('/usr/local/cpanel/cpanel') def is_plesk(): # type: () -> bool return os.path.isdir('/usr/local/psa/admin/') def is_interworx(): # type: () -> bool return os.path.isdir('/usr/local/interworx/') def is_ispmanager(): # type: () -> bool return os.path.isdir('/usr/local/ispmgr/') def is_directadmin(): # type: () -> bool return os.path.isdir('/usr/local/directadmin/plugins/') def is_hosting_controller(): # type: () -> bool return os.path.isdir('/usr/local/hostingcontroller/') def is_hsphere(): # type: () -> bool return os.path.isdir('/hsphere/shared') def has_softaculous(): # type: () -> bool """Softaculous markers checked by the kcdoctor.sh detect_cp()""" return any( os.path.exists(path) for path in ( '/usr/local/softaculous', '/usr/local/cpanel/whostmgr/cgi/softaculous', '/usr/local/directadmin/plugins/softaculous', ) ) # control panels reported by the doctor report, ported from the # kcdoctor.sh detect_cp() probes (presence only, no version detection) CONTROL_PANEL_PROBES = ( ('Plesk', is_plesk), ('cPanel', is_cpanel), ('InterWorx', is_interworx), ('ISPmanager', is_ispmanager), ('DirectAdmin', is_directadmin), ('Hosting Controller', is_hosting_controller), ('H-Sphere', is_hsphere), ) def inside_vz_container(): # mocked: tests/unit/test_load_kmod.py return os.path.exists(os.path.join(PROC_DIR, 'vz', 'veinfo')) and not os.path.exists(os.path.join(PROC_DIR, 'vz', 'version')) def inside_lxc_container(): # mocked: tests/unit/test_load_kmod.py return '/lxc/' in open(os.path.join(PROC_DIR, '1', 'cgroup')).read() def inside_docker_container(): # mocked: tests/unit/test_load_kmod.py return os.path.isfile('/.dockerenv') @utils.catch_errors(logger=log_utils.logwarn) def get_load_average(): # type: () -> Optional[Tuple[float, float, float]] loadavg = utils.try_to_read(os.path.join(PROC_DIR, 'loadavg')) if not loadavg: return None m1, m5, m15, _ = loadavg.split(' ', 3) return (float(m1), float(m5), float(m15)) @utils.catch_errors(logger=log_utils.logwarn) def get_mem_info(): # type: () -> Optional[Dict[str, int]] """Returns dict of memory info in kB""" meminfo = utils.try_to_read(os.path.join(PROC_DIR, 'meminfo')) if not meminfo: return None filter_params = ('MemTotal', 'MemFree', 'SwapTotal', 'SwapFree') # optional units are ignored (assumed to be always kB for mem size) return dict((k, int(v)) for k, v in (re.split(r'[\s:]+', line)[:2] for line in meminfo.splitlines()) if k in filter_params) @utils.cached @utils.catch_errors(logger=log_utils.logwarn) def get_cpu_info(): # type: () -> Optional[Dict[str, Any]] cpuinfo = utils.try_to_read(os.path.join(PROC_DIR, 'cpuinfo')) if not cpuinfo: return None cpus = [ dict(re.split(r'\s*:\s*', line) for line in cpu_lines.splitlines()) for cpu_lines in cpuinfo.split('\n\n') # cpu records are separated by an empty line if cpu_lines ] return { 'logical_cores': len(cpus), 'physical_cores': len(set((cpu.get('physical id'), cpu.get('core id')) for cpu in cpus)), 'vendor_id': cpus[0].get('vendor_id'), 'model': int(cpus[0].get('model', 0)), 'model_name': cpus[0].get('model name'), 'cpu_family': int(cpus[0].get('cpu family', 0)), 'stepping': int(cpus[0].get('stepping', 0)), 'microcode': cpus[0].get('microcode'), 'flags': cpus[0].get('flags', '').split(), } @utils.catch_errors(logger=log_utils.logwarn, default_return=0) def get_process_count(): # type: () -> int return len([d for d in os.listdir(PROC_DIR) if d.isdigit()]) @utils.catch_errors(logger=log_utils.logwarn, default_return=0) def get_opened_files_count(): # type: () -> int fd_info = utils.try_to_read(os.path.join(PROC_DIR, 'sys/fs/file-nr')) return int((fd_info or '0').split()[0]) @utils.catch_errors(logger=log_utils.logwarn) def get_vm_count_kvm(): # type: () -> Optional[int] for _root, dirs, _files in os.walk('/sys/kernel/debug/kvm'): return len(dirs) return None @utils.catch_errors(logger=log_utils.logwarn, default_return=(0, 0)) def get_network_connections_count(): # type: () -> Tuple[int, int] """Return tuple of total numbers of TCP and UDP connections""" def conn_records_count(proto): # type: (str) -> int records = utils.try_to_read(os.path.join(PROC_DIR, 'net', proto)) if not records: return 0 return max(len(records.splitlines()) - 1, 0) return conn_records_count('tcp') + conn_records_count('tcp6'), conn_records_count('udp') + conn_records_count('udp6') def get_performance_metrics(): # type: () -> Dict[str, Any] conn_tcp, conn_udp = get_network_connections_count() return { 'load_average': get_load_average(), 'mem_info': get_mem_info(), 'cpu_info': get_cpu_info(), 'vm_count': get_vm_count_kvm(), 'processes': get_process_count(), 'open_files': get_opened_files_count(), 'tcp_connections': conn_tcp, 'udp_connections': conn_udp, } PKk1]«++kcarectl/delivery_kit.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import io import json import os import shlex import tarfile import time import uuid from tempfile import NamedTemporaryFile from kcarectl import auth, config, http_utils, ipv6_support, log_utils, utils from kcarectl.process_utils import run_command if False: # pragma: no cover from typing import Any, Dict, List, Optional # noqa: F401 from typing_extensions import Self # noqa: F401 def format_size(num_bytes): # type: (int) -> str """Render a byte count as a short human-readable string for the logs.""" size = float(num_bytes) for unit in ('B', 'KiB', 'MiB', 'GiB'): if size < 1024.0: return '{0:.1f} {1}'.format(size, unit) size /= 1024.0 return '{0:.1f} TiB'.format(size) class DataPackage(object): """Generic archive package for the patch server uploads pipeline. Based on DataPackage from eportal (delivery_kit.py). Subclasses supply the manifest `data_type`, the `upload_uri` to PUT the archive to and the `max_size` payload limit. """ data_type = '' # type: str upload_uri = '' # type: str def __init__(self): # type: () -> None self._tar = None # type: Optional[tarfile.TarFile] self._errors_buffer = [] # type: List[str] self._total_payload_size = 0 @property def max_size(self): # type: () -> int raise NotImplementedError # pragma: no cover @property def archive_path(self): # type: () -> str tar = self._ensure_tar_created() return str(tar.name) def add_stdout(self, arcname, cmd): # type: (str, str) -> None stdout = None stderr = None try: _, stdout, stderr = run_command(shlex.split(cmd), catch_stdout=True, catch_stderr=True) except Exception as e: stderr = str(e) if stderr: self.log_error('failed to dump stdout of {0}:\n{1}'.format(cmd, stderr)) if stdout is not None: self.add_file(arcname, data_bytes=utils.bstr(stdout, encoding='utf-8')) def add_file(self, arcname, src_path=None, data_bytes=None, skip_limit_check=False): # type: (str, Optional[str], Optional[bytes], bool) -> None if src_path is None and data_bytes is None: raise ValueError('No src_path or data_bytes provided') tar = self._ensure_tar_created() entry_size = 0 if src_path is not None: if not os.path.exists(src_path): self.log_error('file not found: {0}'.format(src_path)) return entry_size = os.path.getsize(src_path) else: entry_size = len(data_bytes) # type: ignore[arg-type] if not self._check_required_space(entry_size): self.log_error('no available space to store: {0}'.format(arcname)) return if not skip_limit_check and not self._check_total_payload_limit(entry_size): # a single artifact that would push the report past the size # budget is dropped, not the whole report: warn (so the omission # is visible in kcarectl.log and recorded in errors.log) and skip self.log_warning( 'skipping {0}: {1} would exceed the {2} report size limit (already collected {3})'.format( arcname, format_size(entry_size), format_size(self.max_size), format_size(self._total_payload_size), ) ) return try: if src_path: tar.add(src_path, arcname=arcname) else: info = tarfile.TarInfo(arcname) info.size = entry_size tar.addfile(info, io.BytesIO(data_bytes)) # type: ignore[arg-type] if not skip_limit_check: # entries exempt from the limit (manifest.json, errors.log) # are not counted toward the payload size either self._total_payload_size += entry_size # per-artifact size accounting so an oversized report can be # traced to the item(s) that bloated it (kcarectl.log only) log_utils.loginfo( 'collected {0}: {1} (report total {2})'.format( arcname, format_size(entry_size), format_size(self._total_payload_size), ), print_msg=False, ) except Exception as e: self.log_error('failed to store {0}: {1}'.format(arcname, e)) def add_json(self, arcname, data): # type: (str, Dict[str, Any]) -> None try: data_bytes = utils.bstr(json.dumps(data, indent=4), encoding='utf-8') except TypeError as e: self.log_error('failed to dump {0}:\n{1}'.format(arcname, e)) return self.add_file(arcname, data_bytes=data_bytes) def _check_required_space(self, entry_size): # type: (int) -> bool # here we simplify the check and ignore that the compressed file size will be less statvfs = os.statvfs(self.archive_path) return statvfs.f_frsize * statvfs.f_bfree > entry_size def _check_total_payload_limit(self, entry_size): # type: (int) -> bool # here we simplify the check and ignore that the compressed file size will be less return self.max_size > self._total_payload_size + entry_size def make_manifest(self): # type: () -> Dict[str, Any] return { "schema_version": 1, "type": self.data_type, "time_created": int(time.time()), } def _add_manifest(self): # type: () -> None # manifest.json must always be present (the patch server dispatches # uploads by its `type`), so it bypasses the lenient add_file: write # failures propagate to __enter__ and abort the package creation # instead of being downgraded to errors.log; the entry is exempt # from the payload limit and not counted toward it data_bytes = utils.bstr(json.dumps(self.make_manifest(), indent=4), encoding='utf-8') tar = self._ensure_tar_created() info = tarfile.TarInfo('manifest.json') info.size = len(data_bytes) tar.addfile(info, io.BytesIO(data_bytes)) def log_error(self, error_msg): # type: (str) -> None error_msg = error_msg.strip() log_utils.logerror(error_msg, print_msg=False) self._errors_buffer.append(error_msg) def log_warning(self, warning_msg): # type: (str) -> None # warn to kcarectl.log (print_msg=False: no console noise, like # log_error) and keep the note in the archived errors.log so the # uploaded report records what was dropped warning_msg = warning_msg.strip() log_utils.logwarn(warning_msg, print_msg=False) self._errors_buffer.append(warning_msg) def __enter__(self): # type: () -> Self for compression_mode in ('w:xz', 'w:bz2', 'w:gz'): # pragma: no branch tmpfile = NamedTemporaryFile(suffix='.tar.{0}'.format(compression_mode[2:]), delete=False) tmpfile.close() try: log_utils.loginfo('Creating DataPackage: {0}'.format(tmpfile.name), print_msg=False) # dereference=True mirrors the kcdoctor.sh `dump` (`cat "$1"`): # a symlinked source added via add_file(src_path=...) -- e.g. # /etc/yum.conf -> dnf/dnf.conf on EL8+, /boot/grub2/grub.cfg # on EFI -- is archived by content, not as a dangling link. self._tar = tarfile.open(name=tmpfile.name, mode=compression_mode, dereference=True) self._add_manifest() return self except Exception as err: if self._tar is not None: # the manifest write may fail after a successful open; # don't leak the open handle try: self._tar.close() except Exception: # pragma: no cover pass self._tar = None if os.path.exists(tmpfile.name): # pragma: no branch os.unlink(tmpfile.name) if not isinstance(err, tarfile.CompressionError): raise raise tarfile.CompressionError('No supported compression method found') # pragma: no cover def __exit__(self, exc_type, exc_val, exc_tb): # type: (Optional[type[BaseException]], Optional[BaseException], Any) -> bool if self._errors_buffer: # pragma: no branch errors = '\n'.join(self._errors_buffer) + '\n' self.add_file('errors.log', data_bytes=utils.bstr(errors), skip_limit_check=True) if self._tar: # pragma: no branch self._tar.close() if exc_val: self.remove_archive() return False return True @utils.catch_errors(logger=log_utils.logwarn) def remove_archive(self): # type: () -> None if self._tar and os.path.exists(self.archive_path): # pragma: no branch os.unlink(self.archive_path) def _ensure_tar_created(self): # type: () -> tarfile.TarFile if not self._tar: raise RuntimeError('DataPackage should be used as a context manager') return self._tar def send(self): # type: () -> str """Send the package archive to the patch server. Upload errors propagate to the caller (see the eportal precedent): wrap with utils.catch_errors where a silent failure is acceptable. :return: Upload name (package identifier) """ # flush buffered tar data even when called inside the `with` # block (close() is a no-op on an already closed tar) self._ensure_tar_created().close() # Generate a unique package name # Use find('.') to get extension from first dot to preserve .tar.xz/.tar.bz2/.tar.gz basename = os.path.basename(self.archive_path) ext = basename[basename.find('.') :] if '.' in basename else '' upload_name = str(uuid.uuid4()) + ext upload_url = ipv6_support.get_patch_server() + self.upload_uri + upload_name http_utils.upload_file( self.archive_path, upload_url=upload_url, auth_string=auth.get_http_auth_string(), ) return upload_name class KernelAnomalyPackage(DataPackage): data_type = 'kernel-anomaly' upload_uri = '/upload/kernel-anomaly/' @property def max_size(self): # type: () -> int return config.KERNEL_ANOMALY_REPORT_MAX_SIZE_BYTES PKk1]⢁EEkcarectl/http_utils.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import errno import os import socket import ssl from ssl import SSLError if False: # pragma: no cover from typing import Optional, Union # noqa: F401 from . import config, constants, errors, log_utils, utils from .py23 import HTTPError, Request, URLError, httplib, std_urlopen, urlparse def urlopen_base(url, *args, **kwargs): # mocked: tests/unit if hasattr(url, 'get_full_url'): request_url = url.get_full_url() else: request_url = url url = Request(url) headers = kwargs.pop('headers', {}) headers.update( { 'KC-Version': constants.VERSION, 'KC-Patch-Version': constants.KC_PATCH_VERSION, } ) for header, value in headers.items(): url.add_header(header, value) log_utils.logdebug("Requesting url: `{0}`. Headers: {1}".format(request_url, headers)) try: if 'timeout' not in kwargs: kwargs['timeout'] = config.HTTP_TIMEOUT # bandit warns about use of file: in urlopen which can happen here but is secure if not config.CHECK_SSL_CERTS and getattr(ssl, 'HAS_SNI', None): # pragma: no cover unit ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE kwargs['context'] = ctx return std_urlopen(url, *args, **kwargs) # nosec B310 return std_urlopen(url, *args, **kwargs) # nosec B310 except HTTPError as ex: if ex.code == 404: raise errors.NotFound(ex.url, ex.code, ex.msg, ex.hdrs, ex.fp) # HTTPError is a URLError descendant and contains URL, raise it as is raise except URLError as ex: # Local patches OSError(No such file) should be interpreted as Not found(404) # It was done as a chain because when it implemented with "duck-typing" it will mess # with error context if ex.args and hasattr(ex.args[0], 'errno') and ex.args[0].errno == errno.ENOENT: raise errors.NotFound(url, 404, str(ex), None, None) # type: ignore[arg-type] # there is no information about URL in the base URLError class, add it and raise ex.reason = 'Request for `{0}` failed: {1}'.format(request_url, ex) ex.url = request_url # type: ignore[attr-defined] raise def check_urlopen_retry_factory(retry_on_500=True): def check_function(e, state): if isinstance(e, HTTPError): return retry_on_500 and e.code >= 500 elif isinstance(e, (URLError, httplib.HTTPException, SSLError, socket.timeout)): return True elif hasattr(e, 'args') and len(e.args) == 2 and e.args[0] == errno.ECONNRESET: # pragma: no cover unit # SysCallError "Connection reset by peer" from PyOpenSSL return True return check_function def is_local_url(url): if hasattr(url, 'get_full_url'): url = url.get_full_url() return url.startswith('file:') def urlopen(url, *args, **kwargs): retry_on_500 = kwargs.pop('retry_on_500', True) retry_count = kwargs.pop('retry_count', constants.RETRY_COUNT) if is_local_url(url): return urlopen_base(url, *args, **kwargs) return utils.retry(check_urlopen_retry_factory(retry_on_500=retry_on_500), count=retry_count)(urlopen_base)(url, *args, **kwargs) def http_request(url, auth_string, auth_token=None, method=None): request = Request(url, method=method) if not config.UPDATE_FROM_LOCAL and auth_string: request.add_header('Authorization', 'Basic {0}'.format(auth_string)) if not config.UPDATE_FROM_LOCAL and auth_token: request.add_header(constants.AUTH_TOKEN_HEADER, auth_token) return request def get_proxy_from_env(scheme): if scheme == 'http': return os.getenv('http_proxy') or os.getenv('HTTP_PROXY') elif scheme == 'https': return os.getenv('https_proxy') or os.getenv('HTTPS_PROXY') def proxy_is_used(): return bool(get_proxy_from_env('http')) or bool(get_proxy_from_env('https')) check_urlopen_retry = check_urlopen_retry_factory() @utils.retry(check_retry=check_urlopen_retry) def upload_file(file_path, upload_url, auth_string=None): # type: (str, str, Optional[str]) -> None """Upload a file to the given URL using HTTP PUT with chunked streaming. Note: The standard library urllib doesn't support PUT with data We need to use httplib directly for this This function uses streaming upload to support large files up to 1GB without loading the entire file into memory. :param file_path: Path to the file to upload :param upload_url: Full URL to upload the file to. Query params are ignored. :param auth_string: Optional authentication string for Basic Auth :return: None if upload succeeded :raises HTTPError: If upload fails with HTTP status >= 400 :raises ValueError: If URL is invalid """ file_size = os.path.getsize(file_path) if not file_size: raise ValueError('Refusing to upload empty file: {0}'.format(file_path)) parsed = urlparse(utils.nstr(upload_url)) host = parsed.hostname port = parsed.port url_path = parsed.path or '/' if host is None: raise ValueError('Invalid URL: missing hostname') if port is None: # pragma: no cover port = 443 if parsed.scheme == 'https' else 80 if parsed.scheme == 'http': conn_cls = httplib.HTTPConnection # type: Union[type[httplib.HTTPConnection], type[httplib.HTTPSConnection]] elif parsed.scheme == 'https': # pragma: no cover conn_cls = httplib.HTTPSConnection else: raise ValueError('Invalid URL: unsupported scheme') conn = conn_cls(host, port, timeout=config.HTTP_UPLOAD_TIMEOUT) headers = {} if auth_string: headers['Authorization'] = 'Basic {0}'.format(auth_string) headers['Content-Type'] = 'application/octet-stream' headers['Content-Length'] = str(file_size) headers['KC-Version'] = constants.VERSION try: # Use the lower-level API to support streaming conn.putrequest('PUT', url_path) # Send headers for header, value in headers.items(): conn.putheader(header, value) conn.endheaders() # Stream file data in chunks with open(file_path, 'rb') as f: conn.send(f) response = conn.getresponse() if response.status >= 400: # Read response body for error details try: error_body = response.read() except Exception: # pragma: no cover error_body = None error_msg = 'Failed to upload file: HTTP {0}'.format(response.status) if error_body is not None: # pragma: no branch error_msg += ' - {0}'.format(error_body) # type: ignore[str-bytes-safe] log_utils.logerror(error_msg) # HTTPError compatible with retry mechanism raise HTTPError(upload_url, response.status, error_msg, None, None) # type: ignore[arg-type] finally: conn.close() PKk1]/7~ ~ kcarectl/log_utils.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT from __future__ import print_function import logging import logging.handlers import os import sys import traceback from . import config, constants kcarelog = logging.getLogger('kcare') # mocked: tests/unit def logdebug(message): # type: (str) -> None _printlvl(message, constants.PRINT_DEBUG) kcarelog.debug(message) def loginfo(message, print_msg=True): # type: (str, bool) -> None if print_msg: _printlvl(message, constants.PRINT_INFO) kcarelog.info(message) def logwarn(message, print_msg=True): # type: (str, bool) -> None if print_msg: _printlvl(message, constants.PRINT_WARN, file=sys.stderr) # pragma: no cover kcarelog.warning(message) def logerror(message, print_msg=True): if print_msg: _printlvl(message, constants.PRINT_ERROR, file=sys.stderr) kcarelog.error(message) def logexc(message, print_msg=True): if print_msg and constants.PRINT_ERROR >= config.PRINT_LEVEL: traceback.print_exc() kcarelog.exception(message) def _printlvl(message, level, file=None): if level >= config.PRINT_LEVEL: print(message, file=file) # noqa: T201 def get_syslog_handler(): syslog_formatter = logging.Formatter('kcare %(levelname)s: %(message)s') syslog_handler = logging.handlers.SysLogHandler(address='/dev/log', facility=logging.handlers.SysLogHandler.LOG_USER) syslog_handler.setLevel(logging.INFO) syslog_handler.setFormatter(syslog_formatter) return syslog_handler def get_kcare_handler(level): kcare_formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s') if os.getuid() == 0: kcare_handler = logging.handlers.RotatingFileHandler( constants.LOG_FILE, maxBytes=1024**2, backupCount=2 ) # type: logging.Handler # We need at least INFO level logs at all times kcare_handler.setLevel(min(level, logging.INFO)) kcare_handler.setFormatter(kcare_formatter) return kcare_handler else: kcare_handler = logging.StreamHandler() kcare_handler.setLevel(level) kcare_handler.setFormatter(kcare_formatter) return kcare_handler def initialize_logging(level): kcarelog.handlers[:] = [] try: kcare_handler = get_kcare_handler(level) kcarelog.addHandler(kcare_handler) except Exception as ex: kcarelog.exception(ex) if os.path.exists('/dev/log'): try: syslog_handler = get_syslog_handler() kcarelog.addHandler(syslog_handler) except Exception as ex: kcarelog.exception(ex) def print_cln_http_error(ex, url=None, stdout=True): url = url or '' logerror('Unable to fetch {0}. Please try again later (error: {1})'.format(url, str(ex)), stdout) PKk1]kcarectl/selinux.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import os from . import errors, log_utils, process_utils, utils def selinux_safe_tmpname(fname): head, tail = os.path.split(fname) return os.path.join(head, 'tmp.' + tail) def restore_selinux_context(dname): if is_selinux_enabled(): # Try to restore selinux context cmd = [process_utils.find_cmd('restorecon', ('/usr/sbin', '/sbin')), '-R', dname] code, _, stderr = process_utils.run_command(cmd, catch_stdout=True, catch_stderr=True) if code: log_utils.logerror( "SELinux context restoration for {0} failed with {1}: {2}".format(dname, code, stderr), print_msg=False ) def is_selinux_module_present(semodule_name): code, out, err = process_utils.run_command(['/usr/sbin/semodule', '-l'], catch_stdout=True) if code: raise errors.KcareError("SELinux modules list gathering error: '{0}' {1}".format(err, code), status='selinux modules error') for line in out.split('\n'): if semodule_name in line: return True return False def skip_if_no_selinux_module(clbl): def wrapper(*args, **kwargs): if is_selinux_enabled() and not is_selinux_module_present('libcare'): raise errors.KcareError('SELinux is enabled but libcare policy module is not loaded') return clbl(*args, **kwargs) return wrapper @utils.cached def is_selinux_enabled(): if os.path.isfile('/usr/sbin/selinuxenabled'): code, _, _ = process_utils.run_command(['/usr/sbin/selinuxenabled']) else: return False return code == 0 PKk1]*[#[#kcarectl/utils.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT from __future__ import print_function import fnmatch import functools import os import random import re import shutil import tempfile import time from datetime import datetime from . import constants if False: # pragma: no cover from typing import Any, Callable, Dict, List, Optional, Set, Tuple, TypeVar, Union # noqa: F401 T = TypeVar('T', bound=Callable[..., Any]) VERSION_RE = re.compile(r'^(\d+[.]\d+[-]\d+)') CACHE_ENTRIES = 3 ntype = type('') btype = type(b'') utype = type(u'') def atomic_write(fname, content, ensure_dir=False, mode='w', create_mode=0o644): # type: (str, Union[str, bytes], bool, str, int) -> None dname = os.path.dirname(fname) if ensure_dir and not os.path.exists(dname): os.makedirs(dname) try: st_mode = os.stat(fname).st_mode except Exception: st_mode = create_mode with tempfile.NamedTemporaryFile(mode=mode, dir=dname, prefix=os.path.basename(fname) + '.', delete=False) as f: os.fchmod(f.fileno(), st_mode) f.write(content) f.flush() os.fsync(f.fileno()) tmp_fname = f.name # ensure folder is also updated # https://www.quora.com/When-should-you-fsync-the-containing-directory-in-addition-to-the-file-itself # https://www.reddit.com/r/kernel/comments/1du6ot8/comment/lbgu46i/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button folder_fd = os.open(dname, os.O_RDONLY) try: os.fsync(folder_fd) finally: os.close(folder_fd) os.rename(tmp_fname, fname) def nstr(data, encoding='utf-8'): # pragma: no py2 cover # type: (Union[str, bytes, None], str) -> str if type(data) is ntype: return data elif type(data) is btype: return data.decode(encoding) else: return data.encode(encoding) # type: ignore # pragma: no py3 cover def bstr(data, encoding='latin1'): # pragma: no py2 cover # type: (Union[str, bytes], str) -> bytes if type(data) is utype: data = data.encode(encoding) return data # type: ignore def ustr(data, encoding='latin1'): # pragma: no py2 cover # type: (Union[str, bytes], str) -> str if type(data) is btype: data = data.decode(encoding) return data # type: ignore def cached(fn): # type: (T) -> Any cache = {} # type: dict[tuple[Any, ...], Any] @functools.wraps(fn) def inner(*args, **kwargs): # type: (Any, Any) -> Any cache_key = (args, tuple(sorted(kwargs.items()))) try: return cache[cache_key] except KeyError: pass result = cache[cache_key] = fn(*args, **kwargs) return result inner.cache = cache # type: ignore[attr-defined] inner.clear = cache.clear # type: ignore[attr-defined] inner.orig = fn # type: ignore[attr-defined] return inner def retry(check_retry, count=None, delay=None, backoff=None): # type: (Callable[[Exception, dict[str, Any]], bool], Optional[int], Optional[float], Optional[float]) -> Callable[..., Any] if delay is None: delay = constants.RETRY_DELAY if count is None: count = constants.RETRY_COUNT if backoff is None: backoff = constants.RETRY_BACKOFF state = {} # type: dict[str, Any] def decorator(fn): # type: (Callable[..., Any]) -> Callable[..., Any] def inner(*args, **kwargs): # type: (Any, Any) -> Any ldelay = delay for _ in range(count): try: return fn(*args, **kwargs) except Exception as ex: if not check_retry(ex, state): raise time.sleep(ldelay) # bandit warns about using random.uniform for security which is not the case here ldelay = min(ldelay * random.uniform(1, backoff), constants.RETRY_MAX_DELAY) # nosec B311 # last try try: return fn(*args, **kwargs) except Exception as final_ex: setattr(final_ex, 'attempts', count) raise return inner return decorator def clean_directory(directory, exclude_path=None, keep_n=CACHE_ENTRIES, pattern=None): # type: (str, Optional[str], int, Optional[str]) -> None if not os.path.exists(directory): return data = [] items = os.listdir(directory) if pattern is not None: items = fnmatch.filter(items, pattern) for item in items: full_path = os.path.join(directory, item) if full_path != exclude_path: data.append((os.stat(full_path).st_mtime, full_path)) data.sort(reverse=True) for _, entry in data[keep_n:]: if os.path.isfile(entry) or os.path.islink(entry): os.remove(entry) else: shutil.rmtree(entry) def clear_all_cache(): # type: () -> None clean_directory(os.path.join(constants.PATCH_CACHE, 'modules'), keep_n=0) clean_directory(os.path.join(constants.PATCH_CACHE, 'patches'), keep_n=0) if os.path.exists(constants.CACHE_KEY_DUMP_PATH): os.unlink(constants.CACHE_KEY_DUMP_PATH) def save_to_file(response, dst): # type: (Any, str) -> None parent_dir = os.path.dirname(dst) if not os.path.exists(parent_dir): os.makedirs(parent_dir) with open(dst, 'wb') as f: shutil.copyfileobj(response, f) f.flush() os.fsync(f.fileno()) def strip_version_timestamp(version): # type: (str) -> str match = VERSION_RE.match(version) return match and match.group(1) or version def parse_response_date(str_raw): # type: (str) -> datetime # Try to split it by T str_date, sep, _ = str_raw.partition('T') # No success - split by space if not sep: str_date, _, _ = str_raw.partition(' ') return datetime.strptime(str_date, '%Y-%m-%d') def get_patch_server_url(*parts): # type: (*str) -> str from . import ipv6_support # TODO fix circular import return '/'.join(it.strip('/') for it in filter(None, (ipv6_support.get_patch_server(),) + parts)) def try_to_read(filename): # type: (str) -> Optional[str] if not os.path.exists(filename): return None with open(filename) as f: return f.read().strip() @cached def get_cache_key(): # type: () -> Optional[str] return try_to_read(constants.CACHE_KEY_DUMP_PATH) def _read_file(fname, mode, default): # type: (str, str, Optional[Union[str, bytes]]) -> Union[str, bytes] if not os.path.exists(fname): return default # type: ignore with open(fname, mode) as f: return f.read() # type: ignore def read_file(fname, default=None): # type: (str, Optional[str]) -> str result = _read_file(fname, 'r', default) # type: str # type: ignore[assignment] return result def read_file_bin(fname, default=None): # type: (str, Optional[bytes]) -> bytes result = _read_file(fname, 'rb', default) # type: bytes # type: ignore[assignment] return result def data_as_dict(data): # type: (str) -> dict[str, str] result = {} data_lines = data.splitlines() # type: list[str] for line in data_lines: if line: key, delimiter, value = line.partition(':') if delimiter: result[key] = value.strip() return result def extract_unique_cves(patches, cve_field='cve'): # type: (List[Dict[str, Any]], str) -> Set[str] """ Extract unique CVEs from a list of patches. Args: patches: List of patch dictionaries cve_field: Field name to extract CVE from (default 'cve' for userspace, 'kpatch-cve' for kernel) Returns: Set of unique CVE strings """ unique_cves = set() for patch in patches: cve = patch.get(cve_field) if cve: # only add non-empty CVEs unique_cves.add(cve) return unique_cves def timestamp_str(): # type: () -> str return str(int(time.time())) def print_wrapper(*values): # type: (object) -> None """a workaround to fix T201""" print(*values) # noqa: T201 def catch_errors(logger=None, errors=(Exception,), default_return=None): # type: (Optional[Callable[[str], None]], Tuple[Any, ...], Any) -> Callable[..., Any] def decorator(fn): # type: (T) -> Callable[..., Any] @functools.wraps(fn) def inner(*args, **kwargs): # type: (Any, Any) -> Any try: return fn(*args, **kwargs) except errors as e: if logger: # pragma: no branch arg_list = [str(a) for a in args] + ['{0}={1}'.format(k, v) for k, v in kwargs.items()] logger('{0}({1}) failed: {2}'.format(fn.__name__, ', '.join(arg_list), e)) return default_return return inner return decorator PKk1]lkcarectl/server_info.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import base64 import json import os import platform import time import zlib from . import capabilities, constants, http_utils, kcare, platform_utils, serverid, update_utils, utils if False: # pragma: no cover from typing import Any, Dict # noqa: F401 def server_info(reason, now=None, secure_boot_info=False, perf_metrics=False): data = dict() # type: Dict[str, Any] data['ts'] = int(now or time.time()) data['reason'] = reason data['machine'] = platform.machine() data['processor'] = platform.processor() data['release'] = platform.release() data['system'] = platform.system() data['version'] = platform.version() distro = platform_utils.get_distro() data['distro'] = distro[0] data['distro_version'] = distro[1] data['euname'] = kcare.kcare_uname() data['kcare_version'] = utils.strip_version_timestamp(constants.VERSION) data['last_stop'] = kcare.get_last_stop() data['node'] = platform_utils.get_hostname() data['uptime'] = platform_utils.get_uptime() data['virt'] = platform_utils.get_virt() data['proxy'] = http_utils.proxy_is_used() description = kcare.parse_patch_description(kcare.loaded_patch_description()) data['ltimestamp'] = description['last-update'] data['patch_level'] = description['patch-level'] data['patch_type'] = description['patch-type'] data['kmod'] = kcare.get_current_kmod_version() or '' data['crashreporter_ts'] = kcare.crashreporter_latest_event_timestamp() data['kdump_status'] = kcare.kdump_status() data['capabilities'] = capabilities.get_kc_capabilites_bits() try: data['kdump_ts'] = kcare.kdumps_latest_event_timestamp() except Exception: # Not critical data pass server_id = serverid.get_serverid() if server_id: data['server_id'] = server_id state = kcare.get_state() if state is not None: data['state'] = state data['update_error'] = update_utils.read_update_error('kernel') if secure_boot_info: data['secure_boot'] = platform_utils.secure_boot_info() if perf_metrics: data['perf_metrics'] = platform_utils.get_performance_metrics() return data def server_lib_info(reason, patch_level, now=None): data = dict() # type: Dict[str, Any] data['ts'] = int(now or time.time()) data['reason'] = reason data['patch_level'] = patch_level distro = platform_utils.get_distro() data['distro'] = distro[0] data['distro_version'] = distro[1] data['machine'] = platform.machine() data['kcare_version'] = utils.strip_version_timestamp(constants.VERSION) data['node'] = platform_utils.get_hostname() data['uptime'] = platform_utils.get_uptime() data['virt'] = platform_utils.get_virt() data['capabilities'] = capabilities.get_lc_capabilites_bits() stop_ts = 0.0 if os.path.exists('/var/lib/libcare/stop'): stop_ts = os.path.getctime('/var/lib/libcare/stop') data['stop_ts'] = stop_ts data['update_error'] = update_utils.read_update_error('libcare') return data def encoded_server_lib_info(reason, patch_level, now=None): info = server_lib_info(reason=reason, patch_level=patch_level, now=now) return encode_checkin_payload(info, b64_encoding=True) def encode_checkin_payload(data, b64_encoding): # type: (Dict[str, Any], bool) -> str if b64_encoding: data_str = json.dumps(data, ensure_ascii=False, separators=(',', ':')) return utils.nstr(base64.urlsafe_b64encode(zlib.compress(utils.bstr(data_str, 'utf-8')))) else: # legacy serialization return utils.nstr(base64.b16encode(utils.bstr(str(data)))) PKk1]u+))kcarectl/kcare.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import ast import errno import glob import hashlib import json import os import platform import subprocess from . import config, constants, log_utils, process_utils, utils from .errors import SafeExceptionWrapper from .py23 import json_loads_nstr if False: # pragma: no cover from typing import List, Optional, Tuple # noqa: F401 UNAME_LABEL = 'uname: ' def is_uname_char(c): # type: (str) -> bool return str.isalnum(c) or c in '.-_+' def parse_uname(patch_level): khash = get_kernel_hash() with open(get_cache_path(khash, patch_level, config.PATCH_INFO), 'r') as f: for line in f.readlines(): if line.startswith(UNAME_LABEL): return ''.join(filter(is_uname_char, line[len(UNAME_LABEL) :].strip())) return '' def kcare_update_effective_version(new_version): if os.path.exists(config.KCARE_UNAME_FILE): try: f = open(config.KCARE_UNAME_FILE, 'w') f.write(new_version) f.close() return True except Exception: pass return False def get_kernel_hash(): # type: () -> str f = open(config.KERNEL_VERSION_FILE, 'rb') try: # sha1 is not used for security, turn off bandit warning # bandit issues a warning that B324 has no test when `nosec B324` is # set here. Using broad `nosec` here to bypass the warning. return hashlib.sha1(f.read()).hexdigest() # nosec B324 finally: f.close() def get_last_stop(): # type: () -> str """Returns timestamp from PATCH_CACHE/stoped.at if its exsits""" stopped_at_filename = os.path.join(constants.PATCH_CACHE, 'stopped.at') if os.path.exists(stopped_at_filename): with open(stopped_at_filename, 'r') as fh: value = fh.read().rstrip() try: int(value) except ValueError: return str(int(os.path.getctime(stopped_at_filename))) except Exception: # pragma: no cover, it should not happen return 'error' return value return '-1' def get_cache_path(khash, plevel, fname): prefix = config.PREFIX or 'none' ptype = config.PATCH_TYPE or 'default' patch_dir = '-'.join([prefix, khash, str(plevel), ptype]) result = (constants.PATCH_CACHE, 'patches', patch_dir) # type: Tuple[str, ...] if fname: result += (fname,) return os.path.join(*result) def get_kernel_prefixed_url(*parts): return utils.get_patch_server_url(config.PREFIX, *parts) class BaseKernelPatchLevel(int): def cache_path(self, *parts): return get_cache_path(self.khash, str(self), *parts) # type: ignore[attr-defined] def as_dict(self): return { 'level': self.level, 'khash': self.khash, 'baseurl': self.baseurl, 'release': self.release, } class KernelPatchLevel(BaseKernelPatchLevel): def __new__(cls, khash, level, baseurl, release=None): return super(cls, cls).__new__(cls, level) def __init__(self, khash, level, baseurl, release=None): self.level = level self.khash = khash self.baseurl = baseurl self.release = release def kmod_url(self, *parts): return utils.get_patch_server_url(self.baseurl, self.khash, *parts) def file_url(self, *parts): return utils.get_patch_server_url(self.baseurl, self.khash, str(self), *parts) class LegacyKernelPatchLevel(BaseKernelPatchLevel): def __new__(cls, khash, level): try: return super(cls, cls).__new__(cls, level) except ValueError as exc: # common error with this class raise SafeExceptionWrapper(exc) def __init__(self, khash, level): self.level = level self.khash = khash self.baseurl = None self.release = None def kmod_url(self, *parts): if 'patches.kernelcare.com' in config.PATCH_SERVER: return get_kernel_prefixed_url(self.khash, str(self), *parts) # ePortal workaround, it doesn't support leveled links to kmod return get_kernel_prefixed_url(self.khash, *parts) def file_url(self, *parts): return get_kernel_prefixed_url(self.khash, str(self), *parts) def upgrade(self, baseurl): return KernelPatchLevel(self.khash, int(self), baseurl) def dump_kernel_patch_level(kernel_patch_level): # type: (BaseKernelPatchLevel) -> None try: with open(os.path.join(constants.PATCH_CACHE, 'kernel_patch_level.json'), 'w') as f: json.dump(kernel_patch_level.as_dict(), f) except Exception: log_utils.logexc('failed to dump kernel patch level', print_msg=False) def read_dumped_kernel_patch_level(): try: with open(os.path.join(constants.PATCH_CACHE, 'kernel_patch_level.json')) as f: return json_loads_nstr(f.read()) except Exception: log_utils.logexc('failed to read dumped kernel patch level', print_msg=False) def sort_files_by_ctime(files_list): # type: (List[str]) -> List[Tuple[str, float]] return sorted( [(it, os.path.getctime(it)) for it in files_list], key=lambda pair: pair[1], reverse=True, ) def get_kdump_root(): # type: () -> str kdump_path = "/var/crash" if not os.path.isfile("/etc/kdump.conf"): return kdump_path with open("/etc/kdump.conf") as kdump_conf: for line in kdump_conf: line = line.strip() if line.startswith('path '): _, kdump_path = line.split(None, 1) return kdump_path def list_kdump_vcore_files(): # type: () -> List[str] kdump_root = get_kdump_root() if not os.path.isdir(kdump_root): return [] return glob.glob(os.path.join(kdump_root, '*/vmcore')) def list_kdump_txt_files(): # type: () -> List[str] kdump_root = get_kdump_root() if not os.path.isdir(kdump_root): return [] return glob.glob(os.path.join(kdump_root, '*/*.txt')) def list_crashreporter_log_files(): # type: () -> List[str] if not os.path.isdir(config.KDUMPS_DIR): return [] return glob.glob(os.path.join(config.KDUMPS_DIR, '*.log')) def list_crashreporter_artifacts(): # type: () -> List[str] if not os.path.isdir(config.KDUMPS_DIR): return [] return [os.path.join(config.KDUMPS_DIR, it) for it in os.listdir(config.KDUMPS_DIR)] @utils.cached def kdumps_latest_event_timestamp(): # type: () -> Optional[float] kdumps = list_kdump_vcore_files() if not kdumps: return None return sort_files_by_ctime(kdumps)[0][1] @utils.cached def kdump_status(): if constants.SKIP_SYSTEMCTL_CHECK or os.path.isfile(constants.SYSTEMCTL): _, stdout, _ = process_utils.run_command([constants.SYSTEMCTL, 'is-active', 'kdump'], catch_stdout=True, catch_stderr=True) return stdout.strip() return 'systemd-absent' @utils.cached def crashreporter_latest_event_timestamp(): # type: () -> Optional[float] artifacts = list_crashreporter_artifacts() if not artifacts: return None return sort_files_by_ctime(artifacts)[0][1] def get_current_kmod_version(): kmod_version_file = '/sys/module/kcare/version' if not os.path.exists(kmod_version_file): return with open(kmod_version_file, 'r') as f: version = f.read().strip() return version def is_kmod_version_changed(khash, plevel): old_version = get_current_kmod_version() if not old_version: return True new_version = process_utils.check_output( ['/sbin/modinfo', '-F', 'version', get_cache_path(khash, plevel, constants.KMOD_BIN)] ).strip() return old_version != new_version def kcare_uname_su(): patch_level = loaded_patch_level() if not patch_level: return platform.release() return parse_uname(patch_level) def kcare_uname(): if os.path.exists(config.KCARE_UNAME_FILE): return open(config.KCARE_UNAME_FILE, 'r').read().strip() else: # TODO: talk to @kolshanov about runtime results from KPATCH_CTL info # (euname from kpatch-description -- not from kpatch.info file) return kcare_uname_su() def loaded_patch_level(): # mocked: tests/unit pl = parse_patch_description(loaded_patch_description())['patch-level'] if pl: try: int(pl) except ValueError as e: raise SafeExceptionWrapper(e, 'Unexpected patch state', _patch_info()) return LegacyKernelPatchLevel(get_kernel_hash(), pl) def _patch_info(): try: return process_utils.check_output([constants.KPATCH_CTL, 'info'], check=True) except subprocess.CalledProcessError as e: if e.returncode == errno.EBUSY: raise return '' @utils.cached def get_loaded_modules(): try: return [line.split()[0] for line in open('/proc/modules')] except (OSError, IOError) as ex: log_utils.logerror('Error getting loaded modules list: ' + str(ex), print_msg=False) return [] def loaded_patch_description(): if 'kcare' not in get_loaded_modules(): return None # example: 28-:1532349972;4.4.0-128.154 # (patch level: number)-(patch type: free/extra/empty):(timestamp);(effective kernel version from kpatch.info) return get_patch_value(_patch_info(), 'kpatch-description') def get_patch_value(info, label): return utils.data_as_dict(info).get(label) def parse_patch_description(desc): result = {'patch-level': None, 'patch-type': 'default', 'last-update': '', 'kernel-version': ''} if not desc: return result level_type_timestamp, _, kernel = desc.partition(';') level_type, _, timestamp = level_type_timestamp.partition(':') patch_level, _, patch_type = level_type.partition('-') # need to return patch_level=None not to break old code # TODO: refactor all loaded_patch_level() usages to work with empty string instead of None result['patch-level'] = patch_level or None result['patch-type'] = patch_type or 'default' result['last-update'] = timestamp result['kernel-version'] = kernel return result def get_state(): state_file = os.path.join(constants.PATCH_CACHE, 'kcare.state') if os.path.exists(state_file): with open(state_file, 'r') as f: try: state = f.read() return ast.literal_eval(state) except (SyntaxError, OSError, ValueError, TypeError, UnicodeDecodeError): pass PKk1]_kcarectl/anomaly.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import os import time from kcarectl import delivery_kit, kcare, log_utils, utils if False: # pragma: no cover from typing import Any, Dict, List # noqa: F401 @utils.catch_errors(logger=log_utils.logwarn) def send_data_package(data_package): # type: (delivery_kit.DataPackage) -> str """Send the DataPackage archive to the patch server. Upload errors are logged and swallowed (catch_errors), preserving the historical kernel-anomaly behavior. :param data_package: DataPackage instance to send :return: Upload name (package identifier) """ return data_package.send() def copy_recent_files(files, data_package, archive_prefix): # type: (List[str], delivery_kit.DataPackage, str) -> None """adds recent files for the last hour to the given data package starting from the newest one""" now = time.time() for path, ctime in kcare.sort_files_by_ctime(files): if now - ctime > 3600: break arcname = '{0}/{1}'.format(archive_prefix, path.replace('/', '_')) data_package.add_file(arcname, src_path=path) @utils.catch_errors(logger=log_utils.logwarn) def prepare_kernel_anomaly_report(server_info): # pragma: no cover # type: (Dict[str, Any]) -> delivery_kit.KernelAnomalyPackage data_package = delivery_kit.KernelAnomalyPackage() with data_package: if os.path.exists('/var/log/messages'): data_package.add_stdout('messages', 'tail -n10000 /var/log/messages') if os.path.exists('/var/log/syslog'): data_package.add_stdout('syslog', 'tail -n10000 /var/log/syslog') data_package.add_stdout('kcarectl.log', 'tail -n10000 /var/log/kcarectl.log') data_package.add_stdout('dmesg', 'dmesg') data_package.add_stdout('ls_var_cache_kcare', 'ls -lR /var/cache/kcare/') if os.path.exists('/usr/bin/rpm') or os.path.exists('/bin/rpm'): packages_cmd = r'rpm -q -a --queryformat="%{N}|%{V}-%{R}|%{arch}|%{INSTALLTIME:date}\n"' elif os.path.exists('/usr/bin/dpkg'): packages_cmd = r'/usr/bin/dpkg-query -W -f "${binary:Package}|${Version}|${Architecture}\n"' data_package.add_file('dpkg.log', src_path='/var/log/dpkg.log') else: packages_cmd = 'echo "unknown package manager"' data_package.add_stdout('packages.list', packages_cmd) # tar fails to add files from /proc directly so we first read them to memory with open('/proc/version') as f: data_package.add_file('proc_version', data_bytes=utils.bstr(f.read())) with open('/proc/modules') as f: data_package.add_file('proc_modules', data_bytes=utils.bstr(f.read())) data_package.add_file('kcare.conf', src_path='/etc/sysconfig/kcare/kcare.conf') data_package.add_json('server_info.json', server_info) # kdump data_package.add_file('kdump.conf', src_path='/etc/kdump.conf') data_package.add_stdout('ls_kdump', 'ls -lR {0}'.format(kcare.get_kdump_root())) try: copy_recent_files(kcare.list_kdump_txt_files(), data_package, 'kdump') except Exception as e: data_package.log_error('failed to copy kdumps:\n{0}'.format(e)) try: copy_recent_files(kcare.list_crashreporter_log_files(), data_package, 'crashreporter') except Exception as e: data_package.log_error('failed to copy crashreporter artifacts:\n{0}'.format(e)) return data_package @utils.catch_errors(logger=log_utils.logwarn, default_return=False) def detect_anomaly(server_info): # type: (Dict[str, Any]) -> bool """taken from eportal - anomalies::detect_agent_reboot""" reason = server_info['reason'] # type: str uptime = int(server_info['uptime']) patch_level = int(server_info.get('patch_level') or '-1') last_stop = int(server_info['last_stop']) ts = server_info['ts'] # type: int try: state_ts = int(server_info['state']['ts']) except (KeyError, TypeError, ValueError): state_ts = 0 fields = [reason, uptime, patch_level, state_ts, last_stop, ts] if not all(fields): return False first_update_after_reboot_marker = False crash_soon_after_update_marker = False no_proper_shutdown_marker = False if uptime < 300 and patch_level == -1: first_update_after_reboot_marker = True if (ts - uptime) > state_ts > (ts - uptime - 1800) and reason == 'update': crash_soon_after_update_marker = True if last_stop < state_ts: # pragma: no branch no_proper_shutdown_marker = True markers = [ first_update_after_reboot_marker, crash_soon_after_update_marker, no_proper_shutdown_marker, ] if all(markers): log_utils.loginfo('Agent anomaly detected: {0}'.format(server_info)) return True return False if __name__ == '__main__': # pragma: no cover prepare_kernel_anomaly_report({}) PKk1]݌*:*:kcarectl/__init__.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT from __future__ import print_function import base64 import json import logging import os import platform import random import re import shutil import socket import ssl import sys import tempfile import time import traceback import warnings from argparse import ArgumentParser from contextlib import contextmanager from datetime import datetime from . import ( anomaly, auth, capabilities, config, config_handlers, constants, doctor, errors, fetch, http_utils, ipv6_support, kcare, libcare, log_utils, platform_utils, process_utils, selinux, server_info, serverid, update_utils, utils, ) from .errors import KcareError, NotFound, SafeExceptionWrapper from .py23 import HTTPError, URLError, httplib, json_loads_nstr, urlencode CPANEL_GID = 99 EFFECTIVE_LATEST = 'v3' EXPECTED_PREFIX = ('12h', '24h', '48h', 'test') FREEZER_BLACKLIST = '/etc/sysconfig/kcare/freezer.modules.blacklist' KCDOCTOR = '/usr/libexec/kcare/kcdoctor.sh' PATCH_LATEST = ( 'latest.v3', 'latest.v2', ) SYSCTL_CONFIG = '/etc/sysconfig/kcare/sysctl.conf' UNLOAD_RETRY_DELAY = 10 BLACKLIST_RE = re.compile('==BLACKLIST==\n(.*)==END BLACKLIST==\n', re.DOTALL) CONFLICTING_MODULES_RE = re.compile('(kpatch.*|ksplice.*|kpatch_livepatch.*)') if os.path.isdir('/usr/libexec/kcare/python'): # pragma: no cover sys.path.insert(0, '/usr/libexec/kcare/python') warnings.filterwarnings('ignore', category=DeprecationWarning) if False: # pragma: no cover from typing import Any, Dict, Optional, Set, Tuple, Union # noqa: F401 log_utils.kcarelog.setLevel(logging.DEBUG) def get_freezer_blacklist(): result = set() if os.path.isfile(FREEZER_BLACKLIST): f = open(FREEZER_BLACKLIST, 'r') for line in f: result.add(line.rstrip()) f.close() return result def _apply_ptype(ptype, filename): name_parts = filename.split('.') if ptype: filename = '.'.join([name_parts[0], ptype, name_parts[-1]]) else: filename = '.'.join([name_parts[0], name_parts[-1]]) return filename def apply_ptype(ptype): config.PATCH_BIN = _apply_ptype(ptype, config.PATCH_BIN) config.PATCH_INFO = _apply_ptype(ptype, config.PATCH_INFO) config.BLACKLIST_FILE = _apply_ptype(ptype, config.BLACKLIST_FILE) config.FIXUPS_FILE = _apply_ptype(ptype, config.FIXUPS_FILE) config.PATCH_DONE = _apply_ptype(ptype, config.PATCH_DONE) def format_exception_without_details(): etype, value, tb = sys.exc_info() details_sanitized = '' if isinstance(value, OSError) and not isinstance(value, URLError): try: # reconstruct for safety, it may be any IO-related subclass details_sanitized = "[Errno %i] %s: '%s'" % (value.errno, os.strerror(value.errno), value.filename) except (AttributeError, TypeError): pass elif isinstance(value, (KeyError, TypeError, IOError)) and not isinstance(value, URLError): details_sanitized = '%s' % value elif isinstance(value, SafeExceptionWrapper): etype = value.etype or type(value.inner) details_sanitized = value.details or ('%s' % value.inner) distro = platform_utils.get_distro() return { 'agent_version': constants.VERSION, 'python_version': platform_utils.get_python_version(), 'distro': distro[0], 'distro_version': distro[1], 'error': getattr(etype, '__name__', str(etype)), 'details': details_sanitized, 'traceback': ''.join(traceback.format_tb(tb, 100)), 'attempts': getattr(value, 'attempts', 0), } def send_exc(): if config.UPDATE_FROM_LOCAL: # pragma: no cover return trace = json.dumps(format_exception_without_details()) encoded_trace = utils.nstr(base64.urlsafe_b64encode(utils.bstr(trace))) # type: str url = utils.get_patch_server_url('/api/kcarectl-trace') + '?trace=' + encoded_trace request = http_utils.http_request(url, auth.get_http_auth_string()) try: http_utils.urlopen_base(request) except Exception: # import traceback # traceback.print_exc() # we really don't interested in exception pass def nohup_fork(func, sleep=None): # pragma: no cover """ Run func in a fork in an own process group (will stay alive after kcarectl process death). :param func: function to execute :return: """ # TODO move to process_utils.py pid = os.fork() if pid != 0: os.waitpid(pid, 0) return os.setsid() pid = os.fork() if pid != 0: os._exit(0) # close standard files to release TTY os.close(0) # redirect stdout/stdin into log file with open(constants.LOG_FILE, 'a') as fd: os.dup2(fd.fileno(), 1) os.dup2(fd.fileno(), 2) if sleep: time.sleep(sleep) try: func() except Exception: log_utils.kcarelog.exception('Wait exception') os._exit(1) os._exit(0) def touch_anchor(): """Check the fact that there was a failed patching attempt. If anchor file not exists we should create an anchor with timestamp and schedule its deletion at $timeout. If anchor exists and its timestamp more than $timeout from now we should raise an error. """ anchor_filepath = os.path.join(constants.PATCH_CACHE, '.kcareprev.lock') if os.path.isfile(anchor_filepath): with open(anchor_filepath, 'r') as afile: try: timestamp = int(afile.read()) # anchor was created quite recently # that means that something went wrong if timestamp + config.SUCCESS_TIMEOUT > time.time(): raise PreviousPatchFailedException(timestamp, anchor_filepath) except ValueError: pass utils.atomic_write(anchor_filepath, utils.timestamp_str()) # write a new timestamp def commit_update(state_data): """ See touch_anchor() for detailed explanation of anchor mechanics. See KPT-730 for details about action registration. :param state_data: dict with current level, kernel_id etc. """ try: os.remove(os.path.join(constants.PATCH_CACHE, '.kcareprev.lock')) except OSError: pass register_action('done', state_data) # reset module cache, to allow server_info get fresh data kcare.get_loaded_modules.clear() try: get_latest_patch_level(reason='done') except Exception: log_utils.kcarelog.exception('Cannot send update info!') def clear_cache(khash, plevel): utils.clean_directory(os.path.join(constants.PATCH_CACHE, 'patches'), exclude_path=kcare.get_cache_path(khash, plevel, '')) def get_current_level_path(khash, fname): prefix = config.PREFIX or 'none' module_dir = '-'.join([prefix, khash]) result = (constants.PATCH_CACHE, 'modules', module_dir) # type: Tuple[str, ...] if fname: result += (fname,) return os.path.join(*result) def save_cache_latest(khash, patch_level): utils.atomic_write(get_current_level_path(khash, 'latest'), str(patch_level), ensure_dir=True) def get_cache_latest(khash): # type: (str) -> Optional[kcare.LegacyKernelPatchLevel] path_with_latest = get_current_level_path(khash, 'latest') if os.path.isfile(path_with_latest): try: pl = int(open(path_with_latest, 'r').read().strip()) return kcare.LegacyKernelPatchLevel(khash, pl) except (ValueError, TypeError): pass return None class CertificateError(ValueError): pass class UnknownKernelException(KcareError): status = 'unknown kernel' def __init__(self, **kwargs): msg = 'New kernel detected ({0} {1} {2}).\nThere are no updates for this kernel yet.'.format( platform_utils.get_distro()[0], platform.release(), kcare.get_kernel_hash() ) super(UnknownKernelException, self).__init__(msg, **kwargs) class ApplyPatchError(KcareError): status = 'patch apply error' def __init__(self, code, freezer_style, level, patch_file, *args, **kwargs): super(ApplyPatchError, self).__init__(*args, **kwargs) self.code = code self.freezer_style = freezer_style self.level = level self.patch_file = patch_file self.distro = platform_utils.get_distro()[0] self.release = platform.release() def __str__(self): return 'Unable to apply patch ({0} {1} {2} {3} {4}, {5})'.format( self.patch_file, self.level, self.code, self.distro, self.release, ', '.join([str(i) for i in self.freezer_style]), ) # KCARE-509 class PreviousPatchFailedException(KcareError): status = 'previous patch failed' def __init__(self, timestamp, anchor, *args, **kwargs): super(PreviousPatchFailedException, self).__init__(*args, **kwargs) self.timestamp = timestamp self.anchor = anchor def __str__(self): message = ( 'It seems, the latest patch, applying at {0}, crashed, ' 'and further attempts will be suspended. ' 'To force patch applying, remove `{1}` file' ) return message.format(self.timestamp, self.anchor) def set_monitoring_key_for_ip_license(key): url = ipv6_support.get_registration_url() + '/nagios/register_key.plain?key={0}'.format(key) try: response = http_utils.urlopen(url) res = utils.data_as_dict(utils.nstr(response.read())) code = int(res['code']) if code == 0: utils.print_wrapper('Key successfully registered') elif code == 1: utils.print_wrapper('Wrong key format or size') elif code == 2: utils.print_wrapper('No KernelCare license for that IP') else: utils.print_wrapper('Unknown error {0}'.format(code)) return code except HTTPError as e: log_utils.print_cln_http_error(e, url) return -1 @contextmanager def execute_hooks(): if config.BEFORE_UPDATE_COMMAND: process_utils.run_command(config.BEFORE_UPDATE_COMMAND, shell=True) try: yield finally: if config.AFTER_UPDATE_COMMAND: process_utils.run_command(config.AFTER_UPDATE_COMMAND, shell=True) def plugin_info(fmt=None): """ The output will consist of: Ignore output up to the line with "--START--" Line 1: show if update is needed: 0 - updated to latest, 1 - update available, 2 - unknown kernel 3 - kernel doesn't need patches 4 - no license, cannot determine Line 2: licensing message (can be skipped, can be more then one line) Line 3: LICENSE: CODE: 1: license present, 2: trial license present, 0: no license Line 4: Update mode (True - auto-update, False, no auto update) Line 5: Effective kernel version Line 6: Real kernel version Line 7: Patchset Installed # --> If None, no patchset installed Line 8: Uptime (in seconds) If *format* is 'json' return the results in JSON format. Any other output means error retrieving info :return: """ pli = _patch_level_info() update_code = pli.code loaded_pl = pli.applied_lvl license_info_result = auth.license_info() if fmt == 'json': results = { 'updateCode': str(update_code), 'autoUpdate': config.AUTO_UPDATE, 'effectiveKernel': kcare.kcare_uname(), 'realKernel': platform.release(), 'loadedPatchLevel': loaded_pl, 'uptime': int(platform_utils.get_uptime()), 'license': license_info_result, } utils.print_wrapper('--START--') utils.print_wrapper(json.dumps(results)) else: utils.print_wrapper('--START--') utils.print_wrapper(str(update_code)) utils.print_wrapper('LICENSE: ' + str(license_info_result)) utils.print_wrapper(config.AUTO_UPDATE) utils.print_wrapper(kcare.kcare_uname()) utils.print_wrapper(platform.release()) utils.print_wrapper(loaded_pl) utils.print_wrapper(platform_utils.get_uptime()) def get_update_status(): current_level = kcare.loaded_patch_level() try: latest_patch_level = get_latest_patch_level(reason='info') except UnknownKernelException: return 0 if config.IGNORE_UNKNOWN_KERNEL else 3 if current_level is None: return 1 if current_level >= latest_patch_level: return 0 return 2 if update_utils.status_gap_passed() else 0 def edf_fallback_ptype(): distro, version = platform_utils.get_distro()[:2] # From talk with @kolshanov if distro == 'CloudLinux' and version.startswith('7.'): return 'extra' else: return '' # addr -> resolved_peer_addr map CONNECTION_STICKY_MAP = {} # type: Dict[Tuple[str, int], Tuple[Optional[str], int]] def sticky_connect(self): """Function remembers IP address of host connected to and uses it for later connections. Replaces stdlib version of httplib.HTTPConnection.connect """ addr = self.host, self.port resolved_addr = CONNECTION_STICKY_MAP.get(addr, addr) # type: Tuple[Optional[str], int] self.sock = socket.create_connection(resolved_addr, self.timeout) self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) if addr not in CONNECTION_STICKY_MAP: CONNECTION_STICKY_MAP[addr] = self.sock.getpeername()[:2] if self._tunnel_host: self._tunnel() httplib.HTTPConnection.connect = sticky_connect # type: ignore[method-assign] # python >= 2.7.9 stdlib (with ssl.HAS_SNI) is able to process https request on its own, # for earlier versions manual checks should be done if not getattr(ssl, 'HAS_SNI', None): # pragma: no cover unit # TODO move to http_utils or py23 try: import distutils.version import OpenSSL.SSL if distutils.version.StrictVersion(OpenSSL.__version__) < distutils.version.StrictVersion('0.13'): # type: ignore[attr-defined] raise ImportError('No pyOpenSSL module with SNI ability.') except ImportError: pass else: def dummy_verify_callback(*args): # OpenSSL.SSL.Context.set_verify() requires callback # where additional checks could be done; # here is a dummy callback and a hostname check is made externally # to provide original exception from match_hostname() return True PureHTTPSConnection = httplib.HTTPSConnection class SSLSock(object): def __init__(self, sock): self._ssl_conn = sock self._makefile_refs = 0 def makefile(self, *args): self._makefile_refs += 1 return socket._fileobject(self._ssl_conn, *args, close=True) # type: ignore[attr-defined] def close(self): if not self._makefile_refs and self._ssl_conn: self._ssl_conn.close() self._ssl_conn = None def sendall(self, *args): return self._ssl_conn.sendall(*args) class PyOpenSSLHTTPSConnection(httplib.HTTPSConnection): def connect(self): httplib.HTTPConnection.connect(self) # workaround to force pyopenssl to use TLSv1.2 ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2 | OpenSSL.SSL.OP_NO_SSLv3) if config.CHECK_SSL_CERTS: ctx.set_verify(OpenSSL.SSL.VERIFY_PEER, dummy_verify_callback) else: ctx.set_verify(OpenSSL.SSL.VERIFY_NONE, dummy_verify_callback) ctx.set_default_verify_paths() conn = OpenSSL.SSL.Connection(ctx, self.sock) conn.set_connect_state() # self._tunnel_host is an original hostname in case of proxy use server_host = self._tunnel_host or self.host # type: ignore[attr-defined] conn.set_tlsext_host_name(server_host.encode()) conn.do_handshake() if config.CHECK_SSL_CERTS: match_hostname(conn.get_peer_certificate(), server_host) self.sock = SSLSock(conn) httplib.HTTPSConnection = PyOpenSSLHTTPSConnection # type: ignore[misc] def _fetch_patch_level_request(khash, latest, reason, mode): if config.UPDATE_FROM_LOCAL: url = kcare.get_kernel_prefixed_url(khash, latest) return fetch.wrap_with_cache_key(auth.urlopen_auth)(url, check_license=False) b64_encoding = latest not in ['latest.v1', 'latest.v2'] perf_enabled = config.SEND_PERF_METRICS and b64_encoding for secure_boot_info, perf_metrics in [(True, perf_enabled), (False, perf_enabled), (False, False)]: # pragma: no branch sinfo = server_info.server_info(reason, secure_boot_info=secure_boot_info, perf_metrics=perf_metrics) request_param = server_info.encode_checkin_payload(sinfo, b64_encoding=b64_encoding) if b64_encoding: request_param = 'info={0}'.format(request_param) url = kcare.get_kernel_prefixed_url(khash, stickyfy(latest, mode)) + '?' + request_param max_url_length = 7000 # the entire request should fit in 8K if (secure_boot_info or perf_metrics) and len(url) > max_url_length: discard_info = 'secure boot info' if secure_boot_info else 'perf metrics' log_utils.logwarn('Check-in URL param is too large, discarding {0}'.format(discard_info)) continue try: result = fetch.wrap_with_cache_key(auth.urlopen_auth)(url, check_license=False) if config.KERNEL_ANOMALY_REPORT_ENABLE and anomaly.detect_anomaly(sinfo): # possible errors in prepare_kernel_anomaly_report and send_data_package are silently ignored data_package = anomaly.prepare_kernel_anomaly_report(sinfo) upload_name = anomaly.send_data_package(data_package) if upload_name: # will be None in case of errors in send_data_package log_utils.loginfo( 'Automatic kernel anomaly report uploaded successfully: {0}'.format(upload_name), print_msg=False ) else: log_utils.logwarn('Failed to send kernel anomaly report', print_msg=False) if data_package: data_package.remove_archive() return result except HTTPError as ex: if (secure_boot_info or perf_metrics) and (ex.code in (413, 414) or ex.code >= 500): log_utils.logwarn('Check-in request failed with error: {0}, retrying with reduced info'.format(ex)) continue raise def fetch_patch_level(reason, mode=constants.UPDATE_MODE_MANUAL): khash = kcare.get_kernel_hash() if config.PATCH_LEVEL is not None: return kcare.LegacyKernelPatchLevel(khash, int(config.PATCH_LEVEL)) for latest in PATCH_LATEST: try: response = _fetch_patch_level_request(khash, latest, reason, mode) config_handlers.set_feature_flags_from_headers(response.headers) update_all_kmod_params() pl = utils.nstr(response.read()).strip() log_utils.loginfo('fetch patch level, reason: {0}, kernel latest response: {1}'.format(reason, pl), print_msg=False) if pl and pl.startswith('{'): latest_info = json_loads_nstr(pl) required_capabilities = latest_info.get('capabilities', []) if not capabilities.has_kc_capabilities(required_capabilities): raise errors.CapabilitiesMismatch( 'Latest KernelCare patchset is incompatible with the current kernecare package version, please upgrade' ) return kcare.KernelPatchLevel(khash, latest_info['level'], latest_info['baseurl'], latest_info['release']) return kcare.LegacyKernelPatchLevel(khash, int(pl)) except NotFound: # old ePortal version < 2.20 returns 404 for latest.v3 requests pass except HTTPError as ex: # No license - no access if ex.code in (403, 401): raise KcareError('KC licence is required') raise raise UnknownKernelException() def probe_patch(level, ptype): bin_url = level.file_url(_apply_ptype(ptype, config.PATCH_BIN)) log_utils.kcarelog.info('Probing patch URL: {0}'.format(bin_url)) try: auth.urlopen_auth(bin_url, check_license=False, method='HEAD') return True except NotFound: log_utils.kcarelog.info('{0} is not available: 404'.format(bin_url)) return False except Exception as ex: # Fallback to GET in case of any error. log_utils.kcarelog.debug('HEAD request for {0} raised an error, fallback to the GET request: {1}'.format(bin_url, str(ex))) url = level.file_url(_apply_ptype(ptype, config.PATCH_BIN) + constants.SIG) log_utils.kcarelog.info('Probing patch URL: {0}'.format(url)) try: auth.urlopen_auth(url, check_license=False) except NotFound: log_utils.kcarelog.info('{0} is not available: 404'.format(url)) return False except URLError as ex: log_utils.kcarelog.info('{0} is not available: {1}'.format(url, str(ex))) return True def fetch_and_verify_kernel_file(level, name): if name == constants.KMOD_BIN: url = level.kmod_url(constants.KMOD_BIN) else: url = level.file_url(name) dst = level.cache_path(name) return fetch.fetch_url(url, dst, config.USE_SIGNATURE, hash_checker=fetch.get_hash_checker(level)) class PatchFetcher(object): # TODO move to fetch.py def __init__(self, patch_level=None): self.patch_level = patch_level # LegacyKernelPatchLevel or KernelPatchLevel def _fetch(self, name): return fetch_and_verify_kernel_file(self.patch_level, name) def is_patch_fetched(self): patch_done_path = self.patch_level.cache_path(config.PATCH_DONE) patch_bin_path = self.patch_level.cache_path(config.PATCH_BIN) patch_info_path = self.patch_level.cache_path(config.PATCH_INFO) kmod_bin_path = self.patch_level.cache_path(constants.KMOD_BIN) return ( all(os.path.isfile(path) for path in (patch_done_path, patch_bin_path, patch_info_path, kmod_bin_path)) and os.path.getsize(patch_bin_path) > 0 and os.path.getsize(kmod_bin_path) > 0 ) def fetch_patch(self): if self.patch_level is None: raise ValueError("Cannot fetch patch as no patch level is set") if not self.patch_level: # level is 0, do nothing return self.patch_level if self.is_patch_fetched(): log_utils.loginfo('Updates already downloaded') return self.patch_level log_utils.loginfo('Downloading updates') # try to upgrade patch level if isinstance(self.patch_level, kcare.LegacyKernelPatchLevel): try: resp = auth.urlopen_auth(self.patch_level.file_url(config.PATCH_BIN), method='HEAD') except NotFound: pass else: baseurl = resp.headers.get('KC-Base-Url', None) if baseurl: self.patch_level = self.patch_level.upgrade(utils.nstr(baseurl)) try: self._fetch(config.PATCH_BIN) except NotFound: raise KcareError( 'The `{0}` patch level is not found for `{1}` patch type. ' 'Please select valid patch type or patch level'.format(self.patch_level, config.PATCH_TYPE or 'default'), status='patch level not found', ) self._fetch(config.PATCH_INFO) self._fetch(constants.KMOD_BIN) self.extract_blacklist() utils.atomic_write(self.patch_level.cache_path(config.PATCH_DONE), b'', mode='wb') selinux.restore_selinux_context(constants.PATCH_CACHE) return self.patch_level def extract_blacklist(self): buf = open(self.patch_level.cache_path(config.PATCH_INFO), 'r').read() if buf: mo = BLACKLIST_RE.search(buf) if mo: utils.atomic_write(self.patch_level.cache_path(config.BLACKLIST_FILE), mo.group(1)) def fetch_fixups(self, level): """ Download fixup files for defined patch level :param level: download fixups for this patch level (usually it's a level of loaded patch) :return: None """ if level is None: return try: # never use cache for fixup files, must be downloaded from scratch resp = fetch_and_verify_kernel_file(level, config.FIXUPS_FILE) except NotFound: return # Upgrade level to a new format with baseurl to fetch fixup files baseurl = resp.headers.get('KC-Base-Url', None) if baseurl: level = level.upgrade(utils.nstr(baseurl)) fixups_fname = level.cache_path(config.FIXUPS_FILE) with open(fixups_fname, 'r') as f: fixups = set([fixup.strip() for fixup in f.readlines()]) for fixup in fixups: fetch_and_verify_kernel_file(level, fixup) selinux.restore_selinux_context(constants.PATCH_CACHE) def kcare_check(): pli = _patch_level_info() utils.print_wrapper(pli.msg) if pli.code == PLI.PATCH_NEED_UPDATE: sys.exit(0) else: sys.exit(1) def show_generic_info(): pli = _patch_level_info() kcare_info = _kcare_patch_info_json(pli) try: libcare_info = libcare.libcare_patch_info_basic() except KcareError: libcare_info = {} state = kcare.get_state() latest_update = "Unknown" if state is not None: latest_update = datetime.fromtimestamp(state['ts']).strftime('%Y-%m-%d') effective_version = kcare.kcare_uname() # count unique CVEs for accurate vulnerability counts kernel_patches = kcare_info.get('patches', []) kernel_vulnerabilities = len(utils.extract_unique_cves(kernel_patches, cve_field='kpatch-cve')) kernel_patches_count = len(kernel_patches) userspace_patches = [patch for rec in libcare_info for patch in rec.get('patches', [])] userspace_vulnerabilities = len(utils.extract_unique_cves(userspace_patches, cve_field='cve')) userspace_patches_count = sum(len(rec.get('patches', [])) for rec in libcare_info) total_patches_count = kernel_patches_count + userspace_patches_count patch_level = kcare.loaded_patch_level() if not patch_level: utils.print_wrapper("KernelCare live patching is disabled") else: utils.print_wrapper("KernelCare live patching is active") utils.print_wrapper(" - Last updated on {0}".format(latest_update)) utils.print_wrapper(" - Effective kernel version {0}".format(effective_version)) if kernel_vulnerabilities > 0: utils.print_wrapper(" - {0} kernel vulnerabilities live patched".format(kernel_vulnerabilities)) if userspace_vulnerabilities > 0: utils.print_wrapper(" - {0} userspace vulnerabilities live patched".format(userspace_vulnerabilities)) if total_patches_count == 0: utils.print_wrapper(" - This system has no applied patches") utils.print_wrapper("Type kcarectl --patch-info to learn more") def kcare_latest_patch_info(is_json=False): """ Retrieve and output to STDOUT latest patch info, so it is easy to get list of CVEs in use. More info at https://cloudlinux.atlassian.net/browse/KCARE-952 :return: None """ try: latest = get_latest_patch_level(reason='info', policy=constants.POLICY_REMOTE) if not latest: raise UnknownKernelException url = latest.file_url(config.PATCH_INFO) patch_info = utils.nstr(auth.urlopen_auth(url).read()) if is_json: patches, result = [], {} for chunk in patch_info.split('\n\n'): data = utils.data_as_dict(chunk) if data and 'kpatch-name' in data: patches.append(data) else: result.update(data) result['patches'] = patches # type: ignore[assignment] patch_info = json.dumps(result) utils.print_wrapper(patch_info) except HTTPError as e: log_utils.print_cln_http_error(e, e.url) return 1 except UnknownKernelException: utils.print_wrapper('No patches available') return 0 def _kcare_patch_info_json(pli): result = {'message': pli.msg} if pli.applied_lvl is not None: patch_info = _kcare_patch_info(pli) patches = [] for chunk in patch_info.split('\n\n'): data = utils.data_as_dict(chunk) if data and 'kpatch-name' in data: patches.append(data) else: result.update(data) result['patches'] = patches saved_patch_level = kcare.read_dumped_kernel_patch_level() result['release'] = saved_patch_level['release'] if saved_patch_level else 'unknown' return result def _kcare_patch_info(pli): khash = kcare.get_kernel_hash() cache_path = kcare.get_cache_path(khash, pli.applied_lvl, config.PATCH_INFO) if not os.path.isfile(cache_path): raise KcareError( "Can't find information due to the absent patch information file." " Please, run /usr/bin/kcarectl --update and try again.", status='patch info not found', ) info = open(cache_path, 'r').read() if info: info = BLACKLIST_RE.sub('', info) return info def patch_info(is_json=False): pli = _patch_level_info() if not is_json: if pli.code != 0: utils.print_wrapper(pli.msg) if pli.applied_lvl is None: return utils.print_wrapper(_kcare_patch_info(pli)) else: utils.print_wrapper(json.dumps(_kcare_patch_info_json(pli), sort_keys=True)) def is_same_patch(new_patch_file): # mocked: tests/unit args = [constants.KPATCH_CTL, 'file-info', new_patch_file] new_patch_info = process_utils.check_output(args) current_patch_info = kcare._patch_info() build_time_label = 'kpatch-build-time' return kcare.get_patch_value(new_patch_info, build_time_label) == kcare.get_patch_value(current_patch_info, build_time_label) def kcare_need_update(applied_level, new_level): if new_level == 0: return False # ignore down-patching if applied_level and new_level < applied_level: return False if applied_level != new_level: return True new_patch_file = kcare.get_cache_path(kcare.get_kernel_hash(), new_level, config.PATCH_BIN) if not is_same_patch(new_patch_file): return True return False def update_sysctl(): # TODO move to platform_utils.py if config.UPDATE_SYSCTL_CONFIG: if not (os.path.isfile(SYSCTL_CONFIG) and os.access(SYSCTL_CONFIG, os.R_OK)): log_utils.kcarelog.warning('File {0} does not exist or has no read access'.format(SYSCTL_CONFIG)) return code, _, _ = process_utils.run_command(['/sbin/sysctl', '-q', '-p', SYSCTL_CONFIG], catch_stdout=True) if code != 0: log_utils.kcarelog.warning('Unable to load kcare sysctl.conf: {0}'.format(code)) def edit_sysctl_conf(remove, append): """Update SYSCTL_CONFIG accordingly the edits""" # TODO move to platform_utils.py # Create if it does not exist if not os.path.isfile(SYSCTL_CONFIG): open(SYSCTL_CONFIG, 'a').close() # Check kcare sysctl path and read access if not os.access(SYSCTL_CONFIG, os.R_OK): log_utils.kcarelog.warning('File {0} has no read access'.format(SYSCTL_CONFIG)) return with open(SYSCTL_CONFIG, 'r+') as sysctl: lines = sysctl.readlines() sysctl.seek(0) for line in lines: # Do not rewrite lines that should be deleted if not any(line.startswith(r) for r in remove): sysctl.write(line) # Write additional lines for a in append: sysctl.write(a + '\n') sysctl.truncate() def detect_conflicting_modules(modules): for module in modules: if CONFLICTING_MODULES_RE.match(module): raise KcareError( "Detected '{0}' kernel module loaded. Please unload that module first".format(module), status='conflicting kernel module', ) def get_kcare_kmod_link(): return '/lib/modules/{0}/extra/kcare.ko'.format(platform_utils.get_system_uname()) def kmod_is_signed(): level = get_latest_patch_level(reason='info') kmod_file = kcare.get_cache_path(kcare.get_kernel_hash(), level, constants.KMOD_BIN) if not os.path.isfile(kmod_file): return None with open(kmod_file, 'rb') as vfd: return vfd.read()[-28:] == b'~Module signature appended~\n' def kcare_certs_enrolled(): # pragma: no cover system_keys = utils.try_to_read('/proc/keys') if system_keys is None: return None kcare_keys = [ '12ff0613c0f80cfba3b2f8eba71ebc27c5a76170', # CloudLinux key '69a6d9eed3f620d5c2e13a1d211c46510a5ad9f5', # AlmaLinux kpatch signing key ] return any(key in system_keys for key in kcare_keys) def load_kmod(kmod, **kwargs): cmd = ['/sbin/insmod', kmod] for key, value in kwargs.items(): cmd.append('{0}={1}'.format(key, value)) code, _, _ = process_utils.run_command(cmd, catch_stdout=True) if code != 0: raise KcareError( 'Unable to load kmod ({0} {1}). Try to run with `--check-compatibility` flag.'.format(kmod, code), status='kmod load error', ) def check_compatibility(): if platform_utils.is_secure_boot(): if kmod_is_signed() is False: raise KcareError('Secure boot is enabled. Not supported by KernelCare.') if kcare_certs_enrolled() is False: raise KcareError('Secure boot is enabled. No KernelCare certificates enrolled.') if platform_utils.inside_vz_container() or platform_utils.inside_lxc_container() or platform_utils.inside_docker_container(): raise KcareError( 'You are running inside a container. Kernelcare should be executed on host side instead.', status='running in container', ) def check_patch_type_compatibility(ptype): # type: (str) -> None # TODO KPT-4474 patch type autodetection cmd = process_utils.find_cmd('modinfo') has_kmodlve = process_utils.run_command([cmd, 'kmodlve'], catch_stdout=True, catch_stderr=True)[0] == 0 if has_kmodlve and ptype in ('free', 'extra'): # KPT-4269 kcarectl: free/extra patches confict with kmodlve log_utils.logerror('{0} patch type conflicts with kmodlve kernel module'.format(ptype)) sys.exit(1) def get_kmod_available_params(kcare_link): stdout = process_utils.check_output(["/sbin/modinfo", "-F", "parm", kcare_link]) available_params = [] for line in stdout.split('\n'): if line.strip(): param_name, _, _ = line.partition(':') available_params.append(param_name) return available_params def make_kmod_new_params(): return { 'kpatch_debug': 1 if config.KPATCH_DEBUG else 0, 'kmsg_output': 1 if config.KMSG_OUTPUT else 0, 'kcore_output': config.KCORE_OUTPUT_SIZE if config.KCORE_OUTPUT else 0, 'kdumps_dir': config.KDUMPS_DIR if isinstance(config.KDUMPS_DIR, str) else "", 'enable_crashreporter': 1 if config.ENABLE_CRASHREPORTER else 0, } def update_all_kmod_params(): if config.KDUMPS_DIR and not os.path.exists(config.KDUMPS_DIR): os.makedirs(config.KDUMPS_DIR) for param, val in make_kmod_new_params().items(): update_kmod_param(param, val) def update_kmod_param(kmod_param_name, param_value): params_root = '/sys/module/kcare/parameters' param_path = os.path.join(params_root, kmod_param_name) if not os.path.exists(param_path): return try: with open(param_path, 'w') as f: f.write(str(param_value)) except Exception: # pragma: no cover log_utils.kcarelog.error('failed to set %s kmod param to %s', kmod_param_name, param_value) def load_kcare_kmod(khash, level): # To make `kdump` service work. We need to copy # `kcare.ko` into `/lib/modules/$(uname -r)/extra/kcare.ko` # and call `/sbin/depmod` kcare_link = get_kcare_kmod_link() kcare_file = kcare.get_cache_path(khash, level, constants.KMOD_BIN) try: shutil.copy(kcare_file, kcare_link) except Exception: kcare_link = kcare_file if config.KDUMPS_DIR and not os.path.exists(config.KDUMPS_DIR): os.makedirs(config.KDUMPS_DIR) kmod_params = make_kmod_new_params() available_kmod_params = get_kmod_available_params(kcare_link) kmod_params = dict((k, v) for k, v in kmod_params.items() if k in available_kmod_params) load_kmod(kcare_link, **kmod_params) update_depmod() def update_depmod(uname=None): cmd = [ '/sbin/depmod', ] if uname is not None: cmd.extend(['-a', uname]) code, _, stderr = process_utils.run_command(cmd, catch_stdout=True, catch_stderr=True) if code: # We don't want to show the error to the user but want to see it in logs log_utils.logerror('Running of `{0}` failed with {1}: {2}'.format(' '.join(cmd), code, stderr), print_msg=False) def unload_kmod(modname): code, _, _ = process_utils.run_command(['/sbin/rmmod', modname], catch_stdout=True) if code != 0: raise KcareError('Unable to unload {0} kmod {1}'.format(modname, code), status='kmod unload error') def apply_fixups(khash, current_level, modules): loaded = [] for mod in ['vmlinux'] + modules: modpath = kcare.get_cache_path(khash, current_level, 'fixup_{0}.ko'.format(mod)) if os.path.exists(modpath): load_kmod(modpath) loaded.append('fixup_{0}'.format(mod)) return loaded def remove_fixups(fixups): for mod in fixups: try: unload_kmod(mod) except Exception: log_utils.kcarelog.exception('Exception while unloading module %s.' % mod) def get_freezer_style(freezer, modules): if freezer: method = freezer elif config.PATCH_METHOD: method = config.PATCH_METHOD elif get_freezer_blacklist().intersection(modules): # blacklist module found, use smart freezer # xxx: this branch could be safely removed when smart would work by default return 'freeze_conflict', freezer, config.PATCH_METHOD, True else: # user doesn't provide patch method and no conflicting modules loaded return 'default', freezer, config.PATCH_METHOD, False # non default patch method, translate it into form accepted by kpatch_ctl patch_method_map = { 'NONE': 'freeze_none', 'NOFREEZE': 'freeze_none', 'FULL': 'freeze_all', 'FREEZE': 'freeze_all', 'SMART': 'freeze_conflict', } method = method.upper() if method in patch_method_map: method = patch_method_map[method] else: raise KcareError( 'Unable to detect freezer style ({0}, {1}, {2}, {3})'.format(method, freezer, config.PATCH_METHOD, False), status='freezer style detection error', ) return method, freezer, config.PATCH_METHOD, False def kcare_load(khash, level, mode, freezer='', use_anchor=False): state_data = {'khash': khash, 'future': level, 'mode': mode} register_action('start', state_data) current_level = kcare.loaded_patch_level() modules = kcare.get_loaded_modules() detect_conflicting_modules(modules) # get freezer in the beginning to prevent any further job in case of exception freezer_style = get_freezer_style(freezer, modules) patch_file = kcare.get_cache_path(khash, level, config.PATCH_BIN) save_cache_latest(khash, level) description = '{0}-{1}:{2};{3}'.format( level, config.PATCH_TYPE, utils.timestamp_str(), kcare.parse_uname(level) # future server_info['ltimestamp'] ) kmod_loaded = 'kcare' in modules kmod_changed = kmod_loaded and kcare.is_kmod_version_changed(khash, level) patch_loaded = current_level is not None same_patch = patch_loaded and is_same_patch(patch_file) and kcare.kcare_update_effective_version(description) state_data.update({'current': current_level, 'kmod_changed': kmod_changed}) if same_patch: register_action('done', state_data) return if patch_loaded: register_action('fxp', state_data) fixups = apply_fixups(khash, current_level, modules) register_action('unpatch', state_data) kpatch_ctl_unpatch(freezer_style) register_action('unfxp', state_data) remove_fixups(fixups) if kmod_changed: register_action('unload', state_data) unload_kmod('kcare') kmod_loaded = False if not kmod_loaded: register_action('load', state_data) load_kcare_kmod(khash, level) if use_anchor: # KCARE-509 touch_anchor() register_action('patch', state_data) kpatch_ctl_patch(patch_file, khash, level, description, freezer_style) update_sysctl() log_utils.loginfo('Patch level {0} applied. Effective kernel version {1}'.format(level, kcare.kcare_uname())) # Update last status check timestamp update_utils.touch_status_gap_file() # do final actions when update is considered as successful register_action('wait', state_data) nohup_fork(lambda: commit_update(state_data), sleep=config.SUCCESS_TIMEOUT) def kpatch_ctl_patch(patch_file, khash, level, description, freezer_style): args = [constants.KPATCH_CTL] blacklist_file = kcare.get_cache_path(khash, level, config.BLACKLIST_FILE) if os.path.exists(blacklist_file): args.extend(['-b', blacklist_file]) args.extend(['patch', '-d', description]) args.extend(['-m', freezer_style[0]]) args.append(patch_file) code, _, _ = process_utils.run_command(args, catch_stdout=True) if code != 0: raise ApplyPatchError(code, freezer_style, level, patch_file) def kpatch_ctl_unpatch(freezer_style): # TODO KPT-4001 refactoring, extract kpatch_ctl run to a class with patch/unpatch/etc methods with logging and error handling code, stdout, stderr = process_utils.run_command( [constants.KPATCH_CTL, 'unpatch', '-m', freezer_style[0]], catch_stdout=True, catch_stderr=True ) if code != 0: log_utils.logerror('Error unpatching, kpatch_ctl stdout:\n{0}\nstderr:\n{1}'.format(stdout, stderr), print_msg=False) raise KcareError('Error unpatching [{0}] {1}'.format(code, str(freezer_style)), status='unpatch error') def register_action(action, state_data): state_data['action'] = action state_data['ts'] = int(time.time()) utils.atomic_write(os.path.join(constants.PATCH_CACHE, 'kcare.state'), str(state_data)) def update_weak_modules(kmod_link): modules_path = '/usr/lib/modules/' if not os.path.isdir(modules_path): return for entry in os.listdir(modules_path): sym_link_path = os.path.join(modules_path, entry, 'weak-updates', 'kcare.ko') if not os.path.islink(sym_link_path): continue target_path = os.readlink(sym_link_path) if target_path == kmod_link: os.unlink(sym_link_path) update_depmod(entry) @process_utils.log_all_parent_processes def kcare_unload(freezer='', force=False): current_level = kcare.loaded_patch_level() pf = PatchFetcher() try: pf.fetch_fixups(current_level) except Exception as err: if not force: raise KcareError( "Unable to retrieve fixups: '{0}'. The unloading of patches has been " "interrupted. To proceed without fixups, use the --force flag.".format(err), status='fixups retrieval error', ) modules = kcare.get_loaded_modules() freezer_style = get_freezer_style(freezer, modules) with execute_hooks(): if 'kcare' in modules: need_unpatch = current_level is not None if need_unpatch: fixups = apply_fixups(kcare.get_kernel_hash(), current_level, modules) code, stdout, stderr = process_utils.run_command( [constants.KPATCH_CTL, 'unpatch', '-m', freezer_style[0]], catch_stdout=True, catch_stderr=True ) remove_fixups(fixups) if code != 0: log_utils.logerror( 'Error unpatching, kpatch_ctl stdout:\n{0}\nstderr:\n{1}'.format(stdout, stderr), print_msg=False ) raise KcareError('Error unpatching [{0}] {1}'.format(code, str(freezer_style)), status='unpatch error') # Unload kcare module and retry once after 10 seconds if failed # Kernel module could be loaded even if patch is not applyed utils.retry(errors.check_exc(KcareError), count=1, delay=UNLOAD_RETRY_DELAY)(unload_kmod)('kcare') kmod_link = get_kcare_kmod_link() if os.path.isfile(kmod_link): os.unlink(kmod_link) # KPT-3469 fix the case with kernel upgrade where third party modules are linked under # /usr/lib/modules/{uname_r}/weak-updates/kcare.ko so that kdump work good update_weak_modules(kmod_link) def kcare_info(is_json): pli = _patch_level_info() if is_json: return _kcare_info_json(pli) else: if pli.code != 0: return pli.msg if pli.applied_lvl is not None: return kcare._patch_info() def _kcare_info_json(pli): result = {'message': pli.msg} if pli.applied_lvl is not None: result.update(utils.data_as_dict(kcare._patch_info())) result.update(kcare.parse_patch_description(result.get('kpatch-description'))) result['kpatch-state'] = pli.state return json.dumps(result) class PLI: PATCH_LATEST = 0 PATCH_NEED_UPDATE = 1 PATCH_UNAVALIABLE = 2 PATCH_NOT_NEEDED = 3 def __init__(self, code, msg, remote_lvl, applied_lvl, state): self.code = code self.msg = msg self.remote_lvl = remote_lvl self.applied_lvl = applied_lvl self.state = state def _patch_level_info(): current_patch_level = kcare.loaded_patch_level() try: # this line raises UnknownKernel from the bottom of this try new_patch_level = get_latest_patch_level(reason='info') if current_patch_level: if kcare_need_update(current_patch_level, new_patch_level): code, msg, state = ( PLI.PATCH_NEED_UPDATE, "Update available, run 'kcarectl --update'.", 'applied', ) else: code, msg, state = ( PLI.PATCH_LATEST, 'The latest patch is applied.', 'applied', ) else: # no patch applied if new_patch_level == 0: code, msg, state = ( PLI.PATCH_NOT_NEEDED, "This kernel doesn't require any patches.", 'unset', ) else: code, msg, state = ( PLI.PATCH_NEED_UPDATE, "No patches applied, but some are available, run 'kcarectl --update'.", 'unset', ) info = PLI(code, msg, new_patch_level, current_patch_level, state) except UnknownKernelException: code = PLI.PATCH_UNAVALIABLE if config.STICKY_PATCH: msg = ( 'Invalid sticky patch tag {0} for kernel ({1} {2}). ' 'Please check /etc/sysconfig/kcare/kcare.conf ' 'STICKY_PATCH settings'.format(config.STICKY_PATCH, platform_utils.get_distro()[0], platform.release()) ) else: msg = 'New kernel detected ({0} {1} {2}).\nThere are no updates for this kernel yet.'.format( platform_utils.get_distro()[0], platform.release(), kcare.get_kernel_hash() ) info = PLI(code, msg, None, None, 'unavailable') return info def tag_server(tag): """ Request to tag server from ePortal. See KCARE-947 for more info :param tag: String used to tag the server :return: 0 on success, -1 on wrong server id, other values otherwise """ url = None try: # TODO: is it ok to send request in case when no server_id found? (machine is not registered in ePortal) server_id = serverid.get_serverid() query = urlencode([('server_id', server_id), ('tag', tag)]) url = ipv6_support.get_registration_url() + '/tag_server.plain?{0}'.format(query) response = http_utils.urlopen(url) res = utils.data_as_dict(utils.nstr(response.read())) return int(res['code']) except HTTPError as e: log_utils.print_cln_http_error(e, url) return -3 except URLError as ue: log_utils.print_cln_http_error(ue, url) return -4 except Exception as ee: log_utils.logerror('Internal Error {0}'.format(ee)) return -5 def kcdoctor(): doctor_url = utils.get_patch_server_url("doctor.sh") log_utils.logdebug("Requesting doctor script from `{0}`".format(doctor_url)) doctor_filename = KCDOCTOR with tempfile.NamedTemporaryFile() as doctor_dst: try: signature = fetch.fetch_signature(doctor_url, doctor_dst.name) utils.save_to_file(http_utils.urlopen(doctor_url), doctor_dst.name) fetch.check_gpg_signature(doctor_dst.name, signature) doctor_filename = doctor_dst.name except Exception as err: log_utils.logerror('Kcare doctor error: {0}. Fallback to the local one.'.format(err)) code, _, stderr = process_utils.run_command(['bash', doctor_filename, ipv6_support.get_patch_server()], catch_stderr=True) if code: raise KcareError("Script failed with '{0}' {1}".format(stderr, code), status='doctor script failed') def check_new_kc_version(): url = utils.get_patch_server_url('{0}-new-version'.format(EFFECTIVE_LATEST)) try: http_utils.urlopen(url) except URLError: return False log_utils.loginfo( 'A new version of the KernelCare package is available. To continue to get kernel updates, please install the new version' ) return True # mocked: tests/unit/test_patch_level_info.py def get_latest_patch_level(reason, policy=constants.POLICY_REMOTE, mode=constants.UPDATE_MODE_MANUAL): """ Get patch level to apply. :param reason: what was the source of request (update, info etc.) :param policy: REMOTE -- get latest patch_level from patchserver, LOCAL -- use cached latest, LOCAL_FIRST -- if cached level is None get latest from patchserver, use cache otherwise :param mode: constants.UPDATE_MODE_MANUAL, constants.UPDATE_MODE_AUTO or constants.UPDATE_MODE_SMART :return: patch_level string """ khash = kcare.get_kernel_hash() cached_level = get_cache_latest(khash) consider_remote_ex = policy == constants.POLICY_REMOTE or (policy == constants.POLICY_LOCAL_FIRST and cached_level is None) try: remote_level = fetch_patch_level(reason, mode) except errors.CapabilitiesMismatch as e: if cached_level is None: # error will be logged in __main__.py raise log_utils.logwarn(str(e)) log_utils.logwarn('Using previously downloaded patches') # force using already downloaded patches policy = constants.POLICY_LOCAL except Exception as ex: if consider_remote_ex: raise else: log_utils.kcarelog.warning('Unable to send data: {0}'.format(ex)) if policy == constants.POLICY_REMOTE: level = remote_level else: level = cached_level if cached_level is None: if policy == constants.POLICY_LOCAL: level = kcare.LegacyKernelPatchLevel(khash, 0) elif policy == constants.POLICY_LOCAL_FIRST: level = remote_level else: raise KcareError('Unknown policy, choose one of: REMOTE, LOCAL, LOCAL_FIRST') return level def update_patch_type(ptype): if ptype == 'edf': # The only way user can get here if call kcarectl --set-patch-type # we don't support this anyway and can silently ignore return config.PATCH_TYPE = '' if ptype == 'default' else ptype if probe_patch(fetch_patch_level(reason='probe'), config.PATCH_TYPE): config_handlers.update_config(PATCH_TYPE=config.PATCH_TYPE) if config.PATCH_TYPE in ('free', 'extra') and platform_utils.is_cpanel(): gid = config.FORCE_GID or CPANEL_GID edit_sysctl_conf( ('fs.enforce_symlinksifowner', 'fs.symlinkown_gid'), ('fs.enforce_symlinksifowner=1', 'fs.symlinkown_gid={0}'.format(gid)), ) log_utils.loginfo("'{0}' patch type selected".format(ptype)) else: raise KcareError("'{0}' patch type is unavailable for your kernel".format(ptype), status='patch type unavailable') # log_all_parent_processes must be outermost to run first @process_utils.log_all_parent_processes @update_utils.track_update_status('kernel') def do_update(freezer, mode, policy=constants.POLICY_REMOTE): """ :param mode: constants.UPDATE_MODE_MANUAL, constants.UPDATE_MODE_AUTO or constants.UPDATE_MODE_SMART :param policy: REMOTE -- download latest and patches from patchserver, LOCAL -- use cached files, LOCAL_FIRST -- download latest and patches if cached level is None, use cache in other cases :param freezer: freezer mode """ check_patch_type_compatibility(config.PATCH_TYPE) if policy == constants.POLICY_REMOTE: check_new_kc_version() try: level = get_latest_patch_level(reason='update', policy=policy, mode=mode) except UnknownKernelException as e: if mode in (constants.UPDATE_MODE_AUTO, constants.UPDATE_MODE_SMART) and config.IGNORE_UNKNOWN_KERNEL: msg = str(e) log_utils.kcarelog.warning(msg) return raise current_level = kcare.loaded_patch_level() # Cron triggers `kcarectl -q --auto-update` regardless of AUTO_UPDATE. # When AUTO_UPDATE=NO, return before touching the on-disk cache so the # currently-applied patch's cache directory is not rotated out by # subsequent fetches (CACHE_ENTRIES rotation would otherwise evict it # and break --patch-info). if mode == constants.UPDATE_MODE_AUTO and not config.AUTO_UPDATE: return pf = PatchFetcher(level) pf.fetch_patch() if not kcare_need_update(applied_level=current_level, new_level=level): log_utils.loginfo('No updates are needed for this kernel') return # Rotate crash report dumps try: utils.clean_directory(config.KDUMPS_DIR, keep_n=3, pattern="kcore*.dump") utils.clean_directory(config.KDUMPS_DIR, keep_n=3, pattern="kmsg*.log") except Exception: log_utils.kcarelog.exception('Error during crash reporter cleanup') khash = kcare.get_kernel_hash() with execute_hooks(): pf.fetch_fixups(current_level) kcare_load(khash, level, mode, freezer, use_anchor=mode == constants.UPDATE_MODE_SMART) kcare.dump_kernel_patch_level(level) clear_cache(khash, level) """ This is needed to support sticky keys as per https://cloudlinux.atlassian.net/browse/KCARE-953 """ def get_sticky(mode): count = sum( ( bool(config.STICKY_PATCH), bool(config.UPDATE_DELAY or config.AUTO_UPDATE_DELAY), bool(config.STICKY_PATCHSET or config.AUTO_STICKY_PATCHSET), ) ) if count > 1: raise KcareError( 'Invalid configuration: conflicting settings STICKY_PATCH,' ' [AUTO_]UPDATE_DELAY or [AUTO_]STICKY_PATCHSET. There should be only one of them', status='conflicting sticky settings', ) if config.STICKY_PATCH: return config.STICKY_PATCH if mode != constants.UPDATE_MODE_MANUAL: delay = config.AUTO_UPDATE_DELAY or config.UPDATE_DELAY patchset = config.AUTO_STICKY_PATCHSET or config.STICKY_PATCHSET else: delay = config.UPDATE_DELAY patchset = config.STICKY_PATCHSET if delay: return delay if patchset: return 'release-' + patchset def _stickyfy(prefix, fname): return prefix + '.' + fname def stickyfy(file, mode): """ Used to add sticky prefix to satisfy KCARE-953 :param file: name of the file to stickify :return: stickified file. """ s = get_sticky(mode) if not s: return file if s != 'KEY': return _stickyfy(s, file) server_id = serverid.get_serverid() if not server_id: log_utils.kcarelog.info('Patch set to STICKY_PATCH=KEY, but server is not registered with the key') sys.exit(-4) try: response = http_utils.urlopen(ipv6_support.get_registration_url() + '/sticky_patch.plain?server_id={0}'.format(server_id)) except HTTPError as e: log_utils.print_cln_http_error(e, e.url) sys.exit(-5) res = utils.data_as_dict(utils.nstr(response.read())) code = int(res['code']) if code == 0: return _stickyfy(res['prefix'], file) elif code == 1: return file elif code == 2: log_utils.kcarelog.info('Server ID is not recognized. Please check if the server is registered') sys.exit(-1) log_utils.kcarelog.info('Error: ' + res['message']) sys.exit(-3) ################################# # from python 2.7.17 ssl stdlib # ################################# def _dnsname_match(dn, hostname, max_wildcards=1): # pragma: no cover """Matching according to RFC 6125, section 6.4.3 http://tools.ietf.org/html/rfc6125#section-6.4.3 """ pats = [] if not dn: return False pieces = dn.split(r'.') leftmost = pieces[0] remainder = pieces[1:] wildcards = leftmost.count('*') if wildcards > max_wildcards: # Issue #17980: avoid denials of service by refusing more # than one wildcard per fragment. A survery of established # policy among SSL implementations showed it to be a # reasonable choice. raise CertificateError('too many wildcards in certificate DNS name: ' + repr(dn)) # speed up common case w/o wildcards if not wildcards: return dn.lower() == hostname.lower() # RFC 6125, section 6.4.3, subitem 1. # The client SHOULD NOT attempt to match a presented identifier in which # the wildcard character comprises a label other than the left-most label. if leftmost == '*': # When '*' is a fragment by itself, it matches a non-empty dotless # fragment. pats.append('[^.]+') elif leftmost.startswith('xn--') or hostname.startswith('xn--'): # RFC 6125, section 6.4.3, subitem 3. # The client SHOULD NOT attempt to match a presented identifier # where the wildcard character is embedded within an A-label or # U-label of an internationalized domain name. pats.append(re.escape(leftmost)) else: # Otherwise, '*' matches any dotless string, e.g. www* pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) # add the remaining fragments, ignore any wildcards for frag in remainder: pats.append(re.escape(frag)) pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) return pat.match(hostname) # match_hostname tweaked to get dns names from pyopenssl x509 cert object def match_hostname(cert, hostname): # pragma: no cover san = [] for i in range(cert.get_extension_count()): e = cert.get_extension(i) if e.get_short_name() == 'subjectAltName': san = [it.strip().split(':', 1) for it in str(e).split(',')] if not cert: raise ValueError( 'empty or no certificate, match_hostname needs a ' 'SSL socket or SSL context with either ' 'CERT_OPTIONAL or CERT_REQUIRED' ) dnsnames = [] for key, value in san: if key == 'DNS': if _dnsname_match(value, hostname): return dnsnames.append(value) if not dnsnames: # The subject is only checked when there is no dNSName entry # in subjectAltName cn = cert.get_subject().commonName if _dnsname_match(cn, hostname): return dnsnames.append(value) if len(dnsnames) > 1: raise CertificateError("hostname {0} doesn't match either of {1}".format(hostname, ', '.join(map(repr, dnsnames)))) elif len(dnsnames) == 1: raise CertificateError("hostname {0} doesn't match {1}".format(hostname, dnsnames[0])) else: raise CertificateError('no appropriate commonName or subjectAltName fields were found') ##################### # end of ssl stdlib # ##################### def main(): parser = ArgumentParser(prog="kcarectl", description='Manage KernelCare patches for your kernel') parser.add_argument('--debug', help='', action='store_true') parser.add_argument( '-i', '--info', help='Display information about KernelCare. Use with --json parameter to get result in JSON format.', action='store_true', ) parser.add_argument( '--app-info', help='Display information about KernelCare agent. Use with --json parameter to get result in JSON format.', action='store_true', ) parser.add_argument('-u', '--update', help='Download latest patches and apply them to the current kernel', action='store_true') parser.add_argument('--unload', help='Unload patches', action='store_true') parser.add_argument('--smart-update', help='Patch kernel based on UPDATE POLICY settings', action='store_true') parser.add_argument('--auto-update', help='Check if update is available, if so -- update', action='store_true') parser.add_argument( '--local', help='Update from a server local directory; accepts a path where patches are located', metavar='PATH' ) parser.add_argument('--patch-info', help='Return the list of applied patches', action='store_true') parser.add_argument('--freezer', help='Freezer type: full (default), smart, none', metavar='freezer') parser.add_argument('--nofreeze', help="[deprecated] Don't freeze tasks before patching", action='store_true') parser.add_argument('--uname', help='Return safe kernel version', action='store_true') parser.add_argument('--license-info', help='Return current license info', action='store_true') parser.add_argument('--status', help='Return status of updates', action='store_true') parser.add_argument('--register', help='Register using KernelCare Key', metavar='KEY') parser.add_argument( '--register-autoretry', help='Retry registering indefinitely if failed on the first attempt', action='store_true' ) parser.add_argument('--unregister', help='Unregister from KernelCare (for key-based servers only)', action='store_true') parser.add_argument('--check', help='Check if new update available', action='store_true') parser.add_argument( '--latest-patch-info', help='Return patch info for the latest available patch. Use with --json parameter to get result in JSON format.', action='store_true', ) parser.add_argument('--test', help='[deprecated] Use --prefix=test instead', action='store_true') parser.add_argument('--tag', help='Tag server with custom metadata, for ePortal users only', metavar='TAG') parser.add_argument( '--prefix', help='Patch source prefix used to test different builds by downloading builds from different locations based on prefix', metavar='PREFIX', ) parser.add_argument('--nosignature', help='Do not check signature', action='store_true') parser.add_argument( '--set-monitoring-key', help='Set monitoring key for IP based licenses. 16 to 32 characters, alphanumeric only', metavar='KEY' ) parser.add_argument('--doctor', help='Submits a vitals report to CloudLinux for analysis and bug-fixes', action='store_true') parser.add_argument( '--fallback', help='With --doctor, force the legacy kcdoctor.sh flow instead of the v2 upload path', action='store_true', ) parser.add_argument( '--kernel-anomaly-report', help='Submits a kernel anomaly report to CloudLinux for analysis and bug-fixes', action='store_true', ) parser.add_argument('--no-send', help='Skip sending artifacts', action='store_true', dest='save_only') parser.add_argument('--keep-local', help="Don't delete generated kernel anomaly report after sending", action='store_true') parser.add_argument('--enable-auto-update', help='Enable auto updates', action='store_true') parser.add_argument('--disable-auto-update', help='Disable auto updates', action='store_true') parser.add_argument( '--plugin-info', help='Provides the information shown in control panel plugins for KernelCare. ' 'Use with --json parameter to get result in JSON format.', action='store_true', ) parser.add_argument( '--server-info', help='Provides information about the host in JSON format.', action='store_true', ) parser.add_argument( '--json', help="Return '--plugin-info', '--latest-patch-info', '--patch-info', '--app-info' and '--info' results in JSON format", action='store_true', ) parser.add_argument('--version', help='Return the current version of KernelCare', action='store_true') parser.add_argument('--kpatch-debug', help='Enable the debug mode', action='store_true') parser.add_argument('--no-check-cert', help='Disable the patch server SSL certificates checking', action='store_true') parser.add_argument( '--set-patch-level', help='Set patch level to be applied. To select latest patch level set -1', action='store', type=int, default=None, required=False, ) parser.add_argument('--check-compatibility', help='Check compatibility.', action='store_true') parser.add_argument('--clear-cache', help='Clear all cached files', action='store_true') exclusive_group = parser.add_mutually_exclusive_group() exclusive_group.add_argument( '--set-patch-type', help="Set patch type feed. To select default feed use 'default' option", action='store' ) exclusive_group.add_argument('--edf-enabled', help='Enable exploit detection framework', action='store_true') exclusive_group.add_argument('--edf-disabled', help='Disable exploit detection framework', action='store_true') parser.add_argument( '--set-sticky-patch', help='Set patch to stick to date in DDMMYY format, or retrieve it from KEY if set to KEY. Leave empty to unstick', action='store', default=None, required=False, ) parser.add_argument( '-q', '--quiet', help='Suppress messages, provide only errors and warnings to stderr', action='store_true', required=False ) parser.add_argument('--has-flags', help='Check agent features') parser.add_argument('--force', help='Force action and ignore several restristions.', action="store_true") parser.add_argument('--set-config', help='Change configuration option', action='append', metavar='KEY=VALUE') if not config.LIBCARE_DISABLED: parser.add_argument( '--disable-libcare', help='Disable libcare services', dest='enable_libcare', action='store_const', const=False ) parser.add_argument( '--enable-libcare', help='Enable libcare services', dest='enable_libcare', action='store_const', const=True ) parser.add_argument( '--lib-update', help='Download latest patches and apply them to the current userspace libraries', action='store_true' ) parser.add_argument('--lib-unload', '--userspace-unload', help='Unload userspace patches', action='store_true') parser.add_argument('--lib-replugin', '--userspace-replugin', help='Reload libcare-server plugin', action='store_true') parser.add_argument('--lib-auto-update', help='Check if update is available, if so -- update', action='store_true') parser.add_argument('--lib-info', '--userspace-info', help='Display information about KernelCare+.', action='store_true') parser.add_argument( '--lib-patch-info', '--userspace-patch-info', help='Return the list of applied userspace patches', action='store_true' ) parser.add_argument('--lib-version', '--userspace-version', help='Return safe package version', metavar='PACKAGENAME') parser.add_argument( '--userspace-update', metavar='USERSPACE_PATCHES', nargs='?', const="", help='Download latest patches and apply them to the corresponding userspace processes', ) parser.add_argument( '--userspace-auto-update', help='Download latest patches and apply them to the corresponding userspace processes', action='store_true', ) parser.add_argument('--userspace-status', help='Return status of userspace updates', action='store_true') parser.add_argument( '--lib-tag', '--userspace-tag', metavar='TAG', help='Apply userspace patches for a specific tag (DDMMYY, ' 'YYYY-MM-DD, Nd, Nh, release-) into an isolated ' 'cache, leaving the default storage untouched. Use together with ' '--lib-update or --userspace-update.', action='store', default=None, required=False, ) args = parser.parse_args() config_handlers.set_settings_from_config_file() if not config.LIBCARE_DISABLED: config.FLAGS += ['libcare-enabled'] if args.has_flags is not None: if set(filter(None, args.has_flags.split(','))).issubset(config.FLAGS): return 0 else: return 1 # do not remove args.auto_update! # once added to machine, kcare-cron is never changed by package update; # old clients has no -q option in their cron, # so auto_update default silent mode must be saved forever if args.quiet or args.auto_update: if config.SILENCE_ERRORS: config.PRINT_LEVEL = constants.PRINT_CRITICAL else: config.PRINT_LEVEL = constants.PRINT_ERROR elif args.debug: config.PRINT_LEVEL = constants.PRINT_DEBUG if not args.uname: if os.getuid() != 0: print('Please run as root', file=sys.stderr) # noqa: T201 return 1 level = logging.INFO if args.quiet: level = logging.WARNING elif args.debug: level = logging.DEBUG # should be after root role check to create a log file with correct rights log_utils.initialize_logging(level) if not config.IGNORE_FEATURE_FLAGS: # run this after initialize_logging to log settings overrides config_handlers.set_feature_flags_from_cache() if args.clear_cache: utils.clear_all_cache() if args.set_patch_level: if args.set_patch_level >= 0: config.PATCH_LEVEL = str(args.set_patch_level) # type: ignore config_handlers.update_config(PATCH_LEVEL=config.PATCH_LEVEL) else: config.PATCH_LEVEL = None config_handlers.update_config(PATCH_LEVEL='') if args.set_sticky_patch is not None: config_handlers.update_config(STICKY_PATCH=args.set_sticky_patch) config.STICKY_PATCH = args.set_sticky_patch if args.nosignature: config.USE_SIGNATURE = False if args.no_check_cert: config.CHECK_SSL_CERTS = False if args.kpatch_debug: config.KPATCH_DEBUG = True if args.check_compatibility: check_compatibility() # EDF do nothing if args.edf_enabled: warnings.warn('Flag --edf-enabled has been deprecated and will be not available in future releases.', DeprecationWarning) elif args.edf_disabled: if config.PATCH_TYPE == 'edf': args.set_patch_type = ('' if config.PREV_PATCH_TYPE == 'edf' else config.PREV_PATCH_TYPE) or 'default' args.update = True if args.prefix: config.PREFIX = args.prefix if args.test: warnings.warn('Flag --test has been deprecated and will be not available in future releases.', DeprecationWarning) config.PREFIX = 'test' config.PREFIX = config.PREFIX.strip('/') if config.PREFIX and config.PREFIX not in EXPECTED_PREFIX: log_utils.kcarelog.warning('Prefix `{0}` is not in expected one {1}.'.format(config.PREFIX, ' '.join(EXPECTED_PREFIX))) if args.local: config.UPDATE_FROM_LOCAL = True config.PATCH_SERVER = 'file:' + args.local if args.set_patch_type: update_patch_type(args.set_patch_type) if config.PATCH_TYPE == 'edf': config.PATCH_TYPE = edf_fallback_ptype() warnings.warn('edf patches are deprecated. Fallback to {0}'.format(config.PATCH_TYPE or 'default'), DeprecationWarning) if args.app_info: utils.print_wrapper(platform_utils.app_info(is_json=args.json)) return if args.server_info: info = server_info.server_info(reason='debug', secure_boot_info=True, perf_metrics=True) utils.print_wrapper(json.dumps(info)) return apply_ptype(config.PATCH_TYPE) if args.doctor: doctor.send_doctor_report(kcdoctor, force_fallback=args.fallback) return if args.kernel_anomaly_report: data_package = anomaly.prepare_kernel_anomaly_report( server_info.server_info(reason='debug', secure_boot_info=True, perf_metrics=True) ) local_path_message = 'Kernel anomaly report file generated: {0}'.format(data_package.archive_path) if args.save_only: utils.print_wrapper(local_path_message) else: upload_name = anomaly.send_data_package(data_package) if upload_name: log_utils.loginfo('Kernel anomaly report uploaded successfully: {0}'.format(upload_name)) else: # pragma: no cover log_utils.logwarn('Failed to send kernel anomaly report', print_msg=True) if args.keep_local: utils.print_wrapper(local_path_message) elif data_package: # pragma: no branch data_package.remove_archive() if args.plugin_info: if args.json: plugin_info(fmt='json') else: plugin_info() return if args.enable_auto_update: config_handlers.update_config(AUTO_UPDATE='YES') return if args.disable_auto_update: config_handlers.update_config(AUTO_UPDATE='NO') return if args.set_config: config_handlers.update_config_from_args(args.set_config) return if args.set_monitoring_key: return set_monitoring_key_for_ip_license(args.set_monitoring_key) if args.unregister: auth.unregister() if args.register: if config.PATCH_TYPE == 'free': config_handlers.update_config(PATCH_TYPE='extra') return auth.register(args.register, args.register_autoretry) if args.license_info: # license_info returns zero if no valid license found and non-zero otherwise if auth.license_info() != 0: return 0 else: return 1 if args.tag is not None: return tag_server(args.tag) if args.version: utils.print_wrapper(constants.VERSION) if getattr(args, 'enable_libcare', None) is not None: libcare.set_libcare_status(args.enable_libcare) return 0 if not config.LIBCARE_DISABLED: lib_tag_kw = {'tag': args.lib_tag} if args.lib_tag else {} if args.userspace_status: return libcare.get_userspace_update_status() if args.lib_update: if libcare.do_userspace_update(**lib_tag_kw) is not None: log_utils.loginfo('Userspace patches are applied.') if args.lib_auto_update: libcare.do_userspace_update(mode=constants.UPDATE_MODE_AUTO, **lib_tag_kw) elif args.lib_unload: libcare.libcare_unload() log_utils.loginfo('Userspace patches are unloaded.') if args.lib_replugin: # pragma: no cover unit libcare.libcare_replugin() log_utils.loginfo('Libcare plugin reloaded.') if args.lib_info: utils.print_wrapper(libcare.libcare_info()) if args.lib_patch_info: utils.print_wrapper(libcare.libcare_patch_info()) if args.lib_version and libcare.libcare_server_started(): utils.print_wrapper(libcare.libcare_version(args.lib_version)) if args.userspace_update is not None: if args.userspace_update == '': # Get from config or defaults limit = config.USERSPACE_PATCHES or list(libcare.get_userspace_map().keys()) else: limit = [ptch.strip().lower() for ptch in args.userspace_update.split(',')] if libcare.do_userspace_update(limit=sorted(limit), **lib_tag_kw) is not None: log_utils.loginfo('Userspace patches are applied.') if args.userspace_auto_update: libcare.do_userspace_update(mode=constants.UPDATE_MODE_AUTO, limit=None, **lib_tag_kw) if args.info: utils.print_wrapper(kcare_info(is_json=args.json)) freezer = '' if args.nofreeze: warnings.warn('Flag --nofreeze has been deprecated and will be not available in future releases.', DeprecationWarning) freezer = 'none' if args.freezer: freezer = args.freezer if args.smart_update: do_update(freezer, mode=constants.UPDATE_MODE_SMART, policy=config.UPDATE_POLICY) if args.update: do_update(freezer, mode=constants.UPDATE_MODE_MANUAL) log_utils.loginfo('Kernel is safe') if args.uname: utils.print_wrapper(kcare.kcare_uname()) if args.unload: kcare_unload(freezer, force=args.force) log_utils.loginfo('KernelCare protection disabled. Your kernel might not be safe') if args.auto_update: config.CHECK_CLN_LICENSE_STATUS = False # wait to prevent spikes at the beginning of each minute KPT-1874 # bandit warns about using random.uniform for security which is not the case here time.sleep(random.uniform(0, 60)) # nosec B311 do_update(freezer, mode=constants.UPDATE_MODE_AUTO) if args.patch_info: patch_info(is_json=args.json) if args.status: return get_update_status() if args.latest_patch_info: kcare_latest_patch_info(is_json=args.json) if args.check: kcare_check() # No arg were provided if len(sys.argv) == 1: show_generic_info() PKk1]獅kcarectl/ipv6_support.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import json import numbers import os import time from . import config, constants, http_utils, log_utils, serverid, utils from .py23 import json_loads_nstr if False: # pragma: no cover from typing import Optional # noqa: F401 # from CLN sources: # code: 0 -> valid license (for key based, or ip based) # code: 1 -> trial license, unexpired # code: 2 -> no valid license, but there is expired trial license # code: 3 -> no valid or trial license CLN_VALID_LICENSE = 0 CLN_TRIAL_ACTIVE_LICENSE = 1 CLN_NO_LICENSE = 3 CACHE_FILE = os.path.join(constants.PATCH_CACHE, 'ipv6_preference.json') CACHE_TTL_SECONDS = 24 * 60 * 60 class IPProtoSelector(object): def is_ipv6_preferred(self): # type: () -> bool """ Choose ipv6 if it is more suitable. Checks order: - check config values (it is faster) - eportal setup and FORCE_IPVx - then check each proto availability using HEAD requests - then check if we have server_id, it means we don't expect an ip license - and finally we need to check if there is an ip license """ # each case is in a separate block for better coverage check if config.FORCE_IPV4: log_utils.logdebug('decided to use ipv4 because of config values') return False elif not config.PATCH_SERVER.endswith('kernelcare.com'): # eportal setup, we don't need to change urls log_utils.logdebug('decided to use ipv4 because of config values') return False elif config.FORCE_IPV6: log_utils.logdebug('decided to use ipv6 because of config values') return True # further checks are more expensive, use cached value if it is set cached = _read_cache() if cached is not None: log_utils.logdebug('decided to use {0} from on-disk cache'.format('ipv6' if cached else 'ipv4')) return cached result = None if not self._is_url_reachable(config.PATCH_SERVER_IPV6): log_utils.logdebug('decided to use ipv4 because ipv6 is not available') result = False elif not self._is_url_reachable(config.PATCH_SERVER): log_utils.logdebug('decided to use ipv6 because ipv4 is not available') result = True elif serverid.get_serverid(): log_utils.logdebug('decided to use ipv4 because server id was found') result = False if result is not None: _write_cache(result) return result ipv4_license = self._get_cln_license(ipv6=False) ipv6_license = self._get_cln_license(ipv6=True) if ipv4_license == CLN_VALID_LICENSE: log_utils.logdebug('decided to use ipv4 because ipv4 license was found') result = False elif ipv6_license == CLN_VALID_LICENSE: log_utils.logdebug('decided to use ipv6 because ipv6 license was found') result = True elif ipv4_license == CLN_TRIAL_ACTIVE_LICENSE: log_utils.logdebug('decided to use ipv4 because ipv4 trial license was found') result = False elif ipv6_license == CLN_TRIAL_ACTIVE_LICENSE: log_utils.logdebug('decided to use ipv6 because ipv6 trial license was found') result = True else: # we don't have any license yet result = False _write_cache(result) return result @staticmethod def _is_url_reachable(url): # type: (str) -> bool request = http_utils.http_request(url, method='HEAD', auth_string=None) # type: ignore[no-untyped-call] try: http_utils.urlopen(request, timeout=10, retry_on_500=False, retry_count=2) # type: ignore[no-untyped-call] return True except Exception as e: log_utils.logdebug('error during HEAD request to {0}: {1}'.format(url, str(e))) return False @staticmethod def _get_cln_license(ipv6): # type: (bool) -> int base_url = config.REGISTRATION_URL_IPV6 if ipv6 else config.REGISTRATION_URL # a comment from auth.py: # do not retry in case of 500 from CLN! # otherwise, CLN will die in pain because of too many requests url = base_url + '/check.plain' content = utils.nstr(http_utils.urlopen(url, retry_on_500=False).read()) # type: ignore[no-untyped-call] info = utils.data_as_dict(content) if not info or not info.get('code'): log_utils.kcarelog.error('Unexpected CLN response: {0}'.format(content)) return CLN_NO_LICENSE try: return int(info['code']) except ValueError: return CLN_NO_LICENSE ip_proto_selector = IPProtoSelector() def _read_cache(): # type: () -> Optional[bool] content = utils.try_to_read(CACHE_FILE) if not content: return None try: data = json_loads_nstr(content) except (ValueError, TypeError): log_utils.logwarn('ipv6 preference cache: malformed json {0!r}'.format(content), print_msg=False) return None if not isinstance(data, dict): log_utils.logwarn('ipv6 preference cache: unexpected payload {0!r}'.format(data), print_msg=False) return None prefer_ipv6 = data.get('prefer_ipv6') if not isinstance(prefer_ipv6, bool): log_utils.logwarn('ipv6 preference cache: unexpected prefer_ipv6 {0!r}'.format(prefer_ipv6), print_msg=False) return None cached_ts = data.get('ts') # numbers.Integral covers int and Python 2 long (the latter matters # once a 32-bit Python 2 host crosses the 2038 sys.maxint boundary); # exclude bool explicitly since it would silently round-trip as 0/1 if not isinstance(cached_ts, numbers.Integral) or isinstance(cached_ts, bool): log_utils.logwarn('ipv6 preference cache: malformed ts {0!r}'.format(cached_ts), print_msg=False) return None # negative age means the system clock jumped backwards (NTP correction etc.) # since we wrote the cache; treat it as a miss rather than as a fresh entry. age = time.time() - int(cached_ts) if age < 0 or age > CACHE_TTL_SECONDS: log_utils.logdebug('ipv6 preference cache: stale entry (age={0:.0f}s, ttl={1}s)'.format(age, CACHE_TTL_SECONDS)) return None return prefer_ipv6 def _write_cache(result): # type: (bool) -> None data = { 'prefer_ipv6': result, 'ts': int(time.time()), } try: utils.atomic_write(CACHE_FILE, json.dumps(data), ensure_dir=True) except (OSError, IOError) as e: log_utils.logwarn('failed to write ipv6 preference cache: {0}'.format(e), print_msg=False) def clear_cache(): # type: () -> None """Drop the on-disk ipv6 preference cache.""" try: os.unlink(CACHE_FILE) except OSError: pass def get_patch_server(): # type: () -> str return config.PATCH_SERVER_IPV6 if ip_proto_selector.is_ipv6_preferred() else config.PATCH_SERVER def get_registration_url(): # type: () -> str return config.REGISTRATION_URL_IPV6 if ip_proto_selector.is_ipv6_preferred() else config.REGISTRATION_URL PKk1]xג44kcarectl/process_utils.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import functools import os import subprocess import textwrap from . import log_utils, utils if False: # pragma: no cover from typing import Any, List, Optional, Tuple, Union # noqa: F401 @utils.cached def find_cmd(name, paths=None, raise_exc=True): # type: (str, Optional[tuple[str, ...]], bool) -> Optional[str] paths = paths or ('/usr/sbin', '/sbin', '/usr/bin', '/bin') for it in paths: fname = os.path.join(it, name) if os.path.isfile(fname): return fname if raise_exc: raise Exception('{0} could not be found at {1}'.format(name, paths)) else: return None def run_command(command, catch_stdout=False, catch_stderr=False, shell=False, check=False): # mocked: tests/unit/conftest.py stdout = subprocess.PIPE if catch_stdout else None stderr = subprocess.PIPE if catch_stderr else None # We need to eventually keep shell=True as it might break customer's hooks, skip this bandit check. p = subprocess.Popen(command, stdout=stdout, stderr=stderr, shell=shell) # nosec B602 stdout_captured, stderr_captured = p.communicate() # type: Union[bytes, str, None], Union[bytes, str, None] code = p.returncode if stdout_captured is not None: stdout_captured = utils.nstr(stdout_captured) if stderr is not None: stderr_captured = utils.nstr(stderr_captured) log_utils.logdebug( textwrap.dedent( """ Call result for `{cmd}`: exit code {exit_code} === STDOUT === {stdout} === STDERR === {stderr} === END === """ ).format(exit_code=p.returncode, stdout=stdout_captured, stderr=stderr_captured, cmd=' '.join(command)) ) if check and code: exc = subprocess.CalledProcessError(code, command) exc.output = stdout_captured exc.stderr = stderr_captured raise exc return code, stdout_captured, stderr_captured def check_output(args, check=False): # type: (list[str], bool) -> Any _, stdout, _ = run_command(args, catch_stdout=True, check=check) return stdout def _get_parent_pid_and_process_name(pid): # type: (int) -> tuple[Optional[int], Optional[str]] try: # use two subprocesses for ppid and comm to prevent parsing problems (there could be any symbols in comm) cmd_ppid = ['ps', '--no-headers', '-o', 'ppid', '-p', str(pid)] code, stdout, _ = run_command(cmd_ppid, catch_stdout=True) if code: log_utils.loginfo("Could not retrieve process parent PID for PID {pid}".format(pid=pid), print_msg=False) return None, None ppid = stdout.strip() cmd_comm = ['ps', '--no-headers', '-o', 'comm', '-p', str(pid)] code, stdout, _ = run_command(cmd_comm, catch_stdout=True) if code: log_utils.loginfo("Could not retrieve process name for PID {pid}".format(pid=pid), print_msg=False) return None, None name = stdout.strip() return int(ppid), name except Exception as e: log_utils.loginfo( "Could not retrieve process name and parent PID for PID {pid}, error: {err}".format(pid=pid, err=e), print_msg=False ) return None, None def log_all_parent_processes(func): """Decorator that logs parent process chain before calling the wrapped function.""" @functools.wraps(func) def wrapper(*args, **kwargs): _log_all_parent_processes() return func(*args, **kwargs) return wrapper def _log_all_parent_processes(): # type: () -> None process_chain = [] # type: list[tuple[int, Optional[str]]] current_pid = os.getpid() while current_pid != 1 and current_pid != 0: ppid, process_name = _get_parent_pid_and_process_name(current_pid) process_chain.append((current_pid, process_name)) if ppid is None: break current_pid = ppid log_utils.loginfo("Agent parent processes chain:", print_msg=False) for level, (pid, name) in enumerate(reversed(process_chain)): prefix = "-" * level + "->" log_utils.loginfo( '{prefix} "{name}" (pid: {pid})'.format(prefix=prefix, name=name or 'unknown', pid=pid or 'unknown'), print_msg=False ) PKk1])okcarectl/constants.pynu[# Copyright (c) Cloud Linux Software, Inc # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT import os import sys PRINT_DEBUG = 0 PRINT_INFO = 1 PRINT_WARN = 2 PRINT_ERROR = 3 PRINT_CRITICAL = 4 PY2 = sys.version_info[0] == 2 PATCH_CACHE = '/var/cache/kcare' FEATURE_FLAGS_CACHE = os.path.join(PATCH_CACHE, 'feature_flags.json') UPDATE_STATUS_PATH = os.path.join(PATCH_CACHE, 'update_status.json') UPDATE_ERROR_MAX_LENGTH = 100 CACHE_KEY_HEADER = 'Kc-Cache-Key' CACHE_KEY_DUMP_PATH = '/etc/sysconfig/kcare/cache_key' POLICY_REMOTE = 'REMOTE' POLICY_LOCAL = 'LOCAL' POLICY_LOCAL_FIRST = 'LOCAL_FIRST' KC_PATCH_VERSION = '3' LOG_FILE = '/var/log/kcarectl.log' SIG = '.sig' SIG_JSON = '.json-sig' # false positives by bandit based on the `TOKEN` keyword in name AUTH_TOKEN_HEADER = 'Kc-Auth-Token' # nosec hardcoded_password_string AUTH_TOKEN_DUMP_PATH = '/etc/sysconfig/kcare/auth_token' # nosec hardcoded_password_string # urlopen retry options RETRY_DELAY = 3 RETRY_MAX_DELAY = 30 RETRY_BACKOFF = 2 RETRY_COUNT = 4 # helper vars for tests SKIP_SYSTEMCTL_CHECK = False SYSTEMCTL = '/usr/bin/systemctl' UPDATE_MODE_MANUAL = 'manual' # update is launched manually by `kcarectl -u` UPDATE_MODE_AUTO = 'auto' # update is launched by cron UPDATE_MODE_SMART = 'smart' # update is launched by kcare daemon KMOD_BIN = 'kcare.ko' KPATCH_CTL = '/usr/libexec/kcare/kpatch_ctl' VERSION = '3.8-1.el8' PKk1]r\\kcsig_verify.pynu[# COPY of scripts/kcsig/kcsig/verify.py from 4fdf3255d5490df60f7dd import base64 import contextlib import json import os import shutil import subprocess import tempfile if False: from typing import Any, Dict, Iterator, List, Mapping, Optional, Sequence, Tuple, Union # noqa: F401 from .types import AnyKey, ReleaseKey, RootKey, RootKeys, Signature, anystr # noqa: F401 AVAILABLE_KINDS = ['rsa4096'] PAE_FIELDS = {'gpg': ('type', 'kind', 'role', 'serial', 'key')} TMPDIR = '/dev/shm' btype = type(b'') utype = type(u'') ntype = type('') class Error(Exception): pass def to_bytes(data, encoding='latin1'): # type: (Union[str, bytes, int], str) -> bytes dtype = type(data) if dtype is btype: return data # type: ignore elif dtype is utype: return data.encode(encoding) # type: ignore elif dtype is int: return to_bytes(str(data)) raise ValueError('Unsupported pae type ' + str(dtype)) def nstr(data): # type: (anystr) -> str dtype = type(data) if dtype is ntype: return data # type: ignore elif dtype is btype: return data.decode('utf-8') # type: ignore elif dtype is utype: # pragma: no cover, used only in py2 return data.encode('utf-8') # type: ignore raise NotImplementedError # pragma: no cover def atomic_write(fname, content, mode='w'): # type: (str, anystr, str) -> None tmp_fname = fname + '.tmp' with open(tmp_fname, mode) as f: f.write(content) os.rename(tmp_fname, fname) def read_file(fname): # type: (str) -> str with open(fname) as f: return f.read() def read_json(fname): # type: (str) -> Any return json.loads(read_file(fname)) def pae(*parts): # type: (Union[str, bytes, int]) -> bytes result = b'%d' % len(parts) for p in parts: bp = to_bytes(p) result += b'%d%s' % (len(bp), bp) return result def pae_fields(data, fields): # type: (Mapping[str, Any], Sequence[str]) -> bytes return pae(*[data[f] for f in fields]) def pae_type(data): # type: (ReleaseKey) -> bytes return pae_fields(data, PAE_FIELDS[data['type']]) def check_key(key): # type: (AnyKey) -> None if key['type'] not in PAE_FIELDS: raise ValueError('invalid key type: ' + nstr(key['type'])) @contextlib.contextmanager def temp_datafile(data, data_is_file): # type: (anystr, bool) -> Iterator[str] if data_is_file: yield data # type: ignore else: with tempfile.NamedTemporaryFile(dir=TMPDIR, prefix='kcsig-data-') as f: f.write(to_bytes(data)) f.flush() yield f.name @contextlib.contextmanager def temp_directory(prefix, dir): # type: (str, str) -> Iterator[str] temp_dir = tempfile.mkdtemp(prefix=prefix, dir=dir) try: yield temp_dir finally: shutil.rmtree(temp_dir) def run_gpg_verify(keyfile, datafile, sigdata): # type: (str, str, bytes) -> None with temp_directory(dir=TMPDIR, prefix='kcsig-gpgtmp-') as tmp_dir: cmd = ['gpg', '--homedir', tmp_dir, '--keyring', keyfile, '--verify', '-', datafile] p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate(sigdata) if p.returncode != 0: raise Exception('Verify error: ' + nstr(stderr) + '\n' + nstr(stdout)) def verify_key(signature, key, data, data_is_file): # type: (str, AnyKey, anystr, bool) -> None check_key(key) with tempfile.NamedTemporaryFile(dir=TMPDIR, prefix='kcsig-key-') as key_file: key_file.write(base64.b64decode(to_bytes(key['key']))) key_file.flush() with temp_datafile(data, data_is_file) as datafile: sigdata = base64.b64decode(to_bytes(signature)) run_gpg_verify(key_file.name, datafile, sigdata) def verify_count(signatures, keys, data, data_is_file=False): # type: (Mapping[str, str], Mapping[str, RootKey], anystr, bool) -> Tuple[int, Mapping[str, str]] count = 0 errors = {} for keyid, sig in signatures.items(): if keyid not in keys: errors[keyid] = 'no corresponding root key' continue try: verify_key(sig, keys[keyid], data, data_is_file) except Exception as e: errors[keyid] = str(e) else: count += 1 return count, errors def _verify(sigdata, datafile, root_keys, kinds=None): # type: (Signature, str, RootKeys, Optional[List[str]]) -> None threshold = root_keys.get('threshold', 9999) min_serial = root_keys.get('min_serial', 99999999) errors = {} # type: Dict[str, Union[str, Mapping[str, str]]] kinds = kinds or AVAILABLE_KINDS applicable_keys = {} for keyid, key in sigdata['keys'].items(): try: check_key(key) if key['kind'] not in kinds: errors[keyid] = 'invalid kind {0}, accepted list is {1}'.format(key['kind'], kinds) elif key['serial'] < min_serial: errors[keyid] = 'invalid serial {0}, current is {1}'.format(key['serial'], min_serial) else: applicable_keys[keyid] = key except Exception as e: errors[keyid] = str(e) continue verified_keys = {} for keyid, key in applicable_keys.items(): count, root_errors = verify_count(key['signatures'], root_keys['keys'], data=pae_type(key)) if count < threshold: errors[keyid] = root_errors else: verified_keys[keyid] = key count = 0 for keyid, key in verified_keys.items(): try: verify_key(sigdata['signatures'][keyid], key, data=datafile, data_is_file=True) except Exception as e: errors[keyid] = str(e) else: count += 1 if not count: raise Error('Error validating file signature: ' + json.dumps(errors)) def verify(sigfile, datafile, rootfile, kinds=None): # type: (str, str, str, Optional[List[str]]) -> None sigdata = read_json(sigfile) # type: Signature root_keys = read_json(rootfile) # type: RootKeys _verify(sigdata, datafile, root_keys, kinds=kinds) PK3]policygenerators/libssh.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from .configgenerator import ConfigGenerator class LibsshGenerator(ConfigGenerator): CONFIG_NAME = 'libssh' SCOPES = {'ssh', 'libssh'} cipher_map = { 'AES-256-GCM':'aes256-gcm@openssh.com', 'AES-256-CTR':'aes256-ctr', 'AES-192-GCM':'', # not supported 'AES-192-CTR':'aes192-ctr', 'AES-128-GCM':'aes128-gcm@openssh.com', 'AES-128-CTR':'aes128-ctr', 'CHACHA20-POLY1305':'chacha20-poly1305@openssh.com', 'CAMELLIA-256-GCM':'', 'AES-256-CCM':'', 'AES-192-CCM':'', 'AES-128-CCM':'', 'CAMELLIA-128-GCM':'', 'AES-256-CBC':'aes256-cbc', 'AES-192-CBC':'aes192-cbc', 'AES-128-CBC':'aes128-cbc', 'CAMELLIA-256-CBC':'', 'CAMELLIA-128-CBC':'', 'RC4-128':'', 'DES-CBC':'', 'CAMELLIA-128-CTS':'', '3DES-CBC':'3des-cbc' } mac_map_etm = { 'HMAC-MD5':'', 'UMAC-64':'', 'UMAC-128':'', 'HMAC-SHA1':'hmac-sha1-etm@openssh.com', 'HMAC-SHA2-256':'hmac-sha2-256-etm@openssh.com', 'HMAC-SHA2-512':'hmac-sha2-512-etm@openssh.com' } mac_map = { 'HMAC-MD5':'', 'UMAC-64':'', 'UMAC-128':'', 'HMAC-SHA1':'hmac-sha1', 'HMAC-SHA2-256':'hmac-sha2-256', 'HMAC-SHA2-512':'hmac-sha2-512' } kx_map = { 'ECDHE-SECP521R1-SHA2-512':'ecdh-sha2-nistp521', 'ECDHE-SECP384R1-SHA2-384':'ecdh-sha2-nistp384', 'ECDHE-SECP256R1-SHA2-256':'ecdh-sha2-nistp256', 'ECDHE-X25519-SHA2-256':'curve25519-sha256,curve25519-sha256@libssh.org', 'DHE-FFDHE-1024-SHA1':'diffie-hellman-group1-sha1', 'DHE-FFDHE-2048-SHA1':'diffie-hellman-group14-sha1', 'DHE-FFDHE-2048-SHA2-256':'diffie-hellman-group14-sha256', 'DHE-FFDHE-4096-SHA2-512':'diffie-hellman-group16-sha512', 'DHE-FFDHE-8192-SHA2-512':'diffie-hellman-group18-sha512', } gx_map = { 'DHE-SHA1':'diffie-hellman-group-exchange-sha1', 'DHE-SHA2-256':'diffie-hellman-group-exchange-sha256', } sign_map = { 'RSA-SHA1':'ssh-rsa', 'DSA-SHA1':'ssh-dss', 'RSA-SHA2-256':'rsa-sha2-256', 'RSA-SHA2-512':'rsa-sha2-512', 'ECDSA-SHA2-256':'ecdsa-sha2-nistp256', 'ECDSA-SHA2-384':'ecdsa-sha2-nistp384', 'ECDSA-SHA2-512':'ecdsa-sha2-nistp521', 'EDDSA-ED25519':'ssh-ed25519', } sign_map_certs = { 'RSA-SHA1':'ssh-rsa-cert-v01@openssh.com', 'DSA-SHA1':'ssh-dss-cert-v01@openssh.com', 'RSA-SHA2-256':'rsa-sha2-256-cert-v01@openssh.com', 'RSA-SHA2-512':'rsa-sha2-512-cert-v01@openssh.com', 'ECDSA-SHA2-256':'ecdsa-sha2-nistp256-cert-v01@openssh.com', 'ECDSA-SHA2-384':'ecdsa-sha2-nistp384-cert-v01@openssh.com', 'ECDSA-SHA2-512':'ecdsa-sha2-nistp521-cert-v01@openssh.com', 'EDDSA-ED25519':'ssh-ed25519-cert-v01@openssh.com', } @classmethod def generate_config(cls, policy): p = policy.enabled cfg = '' sep = ',' s = '' for i in p['cipher']: try: s = cls.append(s, cls.cipher_map[i], sep) except KeyError: pass if s: cfg += 'Ciphers ' + s + '\n' s = '' if policy.integers['ssh_etm']: for i in p['mac']: try: s = cls.append(s, cls.mac_map_etm[i], sep) except KeyError: pass for i in p['mac']: try: s = cls.append(s, cls.mac_map[i], sep) except KeyError: pass if s: cfg += 'MACs ' + s + '\n' s = '' for kx in p['key_exchange']: for h in p['hash']: if policy.integers['arbitrary_dh_groups'] == 1: try: val = cls.gx_map[kx + '-' + h] s = cls.append(s, val, sep) except KeyError: pass for g in p['group']: try: val = cls.kx_map[kx + '-' + g + '-' + h] s = cls.append(s, val, sep) except KeyError: pass if s: cfg += 'KexAlgorithms ' + s + '\n' s = '' for i in p['sign']: try: s = cls.append(s, cls.sign_map[i], sep) except KeyError: pass if policy.integers['ssh_certs']: try: s = cls.append(s, cls.sign_map_certs[i], sep) except KeyError: pass if s: cfg += 'HostKeyAlgorithms ' + s + '\n' cfg += 'PubkeyAcceptedKeyTypes ' + s + '\n' return cfg @classmethod def test_config(cls, config): # pylint: disable=unused-argument return True PK3]R$$policygenerators/nss.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from subprocess import call, CalledProcessError from tempfile import mkstemp import ctypes import ctypes.util import os from .configgenerator import ConfigGenerator class NSSGenerator(ConfigGenerator): CONFIG_NAME = 'nss' SCOPES = {'tls', 'ssl', 'nss'} mac_map = { 'AEAD':'', 'HMAC-SHA1':'HMAC-SHA1', 'HMAC-MD5':'HMAC-MD5', 'HMAC-SHA2-256':'HMAC-SHA256', 'HMAC-SHA2-384':'HMAC-SHA384', 'HMAC-SHA2-512':'HMAC-SHA512' } hash_map = { 'SHA1':'SHA1', 'MD5':'MD5', 'SHA2-224':'SHA224', 'SHA2-256':'SHA256', 'SHA2-384':'SHA384', 'SHA2-512':'SHA512', 'SHA3-256':'', 'SHA3-384':'', 'SHA3-512':'', 'GOST':'' } curve_map = { 'X25519':'CURVE25519', 'X448':'', 'SECP256R1':'SECP256R1', 'SECP384R1':'SECP384R1', 'SECP521R1':'SECP521R1' } cipher_map = { 'AES-256-CTR':'', 'AES-128-CTR':'', 'RC2-CBC':'rc2', 'RC4-128':'rc4', 'AES-256-GCM':'aes256-gcm', 'AES-128-GCM':'aes128-gcm', 'AES-256-CBC':'aes256-cbc', 'AES-128-CBC':'aes128-cbc', 'CAMELLIA-256-CBC':'camellia256-cbc', 'CAMELLIA-128-CBC':'camellia128-cbc', 'CAMELLIA-256-GCM':'', 'CAMELLIA-128-GCM':'', 'AES-256-CCM':'', 'AES-128-CCM':'', 'CHACHA20-POLY1305':'chacha20-poly1305', '3DES-CBC':'des-ede3-cbc' } key_exchange_map = { 'PSK':'', 'DHE-PSK':'', 'ECDHE-PSK':'', 'RSA':'RSA', 'DHE-RSA':'DHE-RSA', 'DHE-DSS':'DHE-DSS', 'ECDHE':'ECDHE-RSA:ECDHE-ECDSA', 'ECDH':'ECDH-RSA:ECDH-ECDSA', 'DH':'DH-RSA:DH-DSS' } protocol_map = { 'SSL3.0':'ssl3.0', 'TLS1.0':'tls1.0', 'TLS1.1':'tls1.1', 'TLS1.2':'tls1.2', 'TLS1.3':'tls1.3', 'DTLS1.0':'dtls1.0', 'DTLS1.2':'dtls1.2' } # Depends on a dict being ordered, # impl. detail in CPython 3.6, guaranteed starting from Python 3.7. sign_prefix_ordmap = { 'RSA-PSS-':'RSA-PSS', # must come before RSA- 'RSA-':'RSA-PKCS', 'ECDSA-':'ECDSA', 'DSA-':'DSA', } @classmethod def generate_config(cls, policy): p = policy.enabled cfg = 'library=\n' cfg += 'name=Policy\n' cfg += 'NSS=flags=policyOnly,moduleDB\n' cfg += 'config="disallow=ALL allow=' s = '' for i in p['mac']: try: s = cls.append(s, cls.mac_map[i]) except KeyError: pass for i in p['group']: try: s = cls.append(s, cls.curve_map[i]) except KeyError: pass for i in p['cipher']: try: s = cls.append(s, cls.cipher_map[i]) except KeyError: pass for i in p['hash']: try: s = cls.append(s, cls.hash_map[i]) except KeyError: pass for i in p['key_exchange']: try: s = cls.append(s, cls.key_exchange_map[i]) except KeyError: pass dsa = [i for i in p['sign'] if i.find('DSA-') == 0] if dsa: s = cls.append(s, 'DSA') enabled_sigalgs = set() for i in p['sign']: for prefix, sigalg in cls.sign_prefix_ordmap.items(): if i.startswith(prefix): if sigalg not in enabled_sigalgs: enabled_sigalgs.add(sigalg) s = cls.append(s, sigalg) break # limit to first match if policy.min_tls_version: minver = cls.protocol_map[policy.min_tls_version] s = cls.append(s, 'tls-version-min=' + minver) else: # FIXME, preserving behaviour, but this is wrong s = cls.append(s, 'tls-version-min=0') if policy.min_dtls_version: minver = cls.protocol_map[policy.min_dtls_version] s = cls.append(s, 'dtls-version-min=' + minver) else: # FIXME, preserving behaviour, but this is wrong s = cls.append(s, 'dtls-version-min=0') s = cls.append(s, 'DH-MIN=' + str(policy.integers['min_dh_size'])) s = cls.append(s, 'DSA-MIN=' + str(policy.integers['min_dsa_size'])) s = cls.append(s, 'RSA-MIN=' + str(policy.integers['min_rsa_size'])) cfg += s + '"\n\n\n' return cfg @classmethod def test_config(cls, config): try: nss_path = ctypes.util.find_library('nss3') nss_lib = ctypes.CDLL(nss_path) if not nss_lib.NSS_VersionCheck(b'3.66'): # Cannot validate with pre-3.59 NSS # that doesn't know ECDSA/RSA-PSS/RSA-PKCS # identifiers yet. Checking for 3.66 because # that's what we'll have in RHEL-8.5. cls.eprint('Skipping nss-policy-check due to ' 'nss being older than 3.66') return True except AttributeError: cls.eprint('Cannot determine nss version with ctypes') if not os.access('/usr/bin/nss-policy-check', os.X_OK): return True fd, path = mkstemp() ret = 255 try: with os.fdopen(fd, 'w') as f: f.write(config) try: ret = call('/usr/bin/nss-policy-check ' + path + ' >/dev/null', shell=True) except CalledProcessError: cls.eprint("/usr/bin/nss-policy-check: Execution failed") finally: os.unlink(path) if ret: cls.eprint("There is an error in NSS generated policy") cls.eprint("Policy:\n%s" % config) return False return True PK3]H‘#policygenerators/configgenerator.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz import sys class ConfigGenerator: RELOAD_CMD = '' @staticmethod def append(s, val, sep=':'): if s: if val: return s + sep + val return s return val @staticmethod def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) PK3]y!SSpolicygenerators/java.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from .configgenerator import ConfigGenerator class JavaGenerator(ConfigGenerator): CONFIG_NAME = 'java' SCOPES = {'tls', 'ssl', 'java-tls'} hash_not_map = { 'MD2' :'MD2', 'MD5' :'MD5', 'SHA1':'SHA1', 'SHA2-224':'SHA224', 'SHA2-256':'SHA256', 'SHA2-384':'SHA384', 'SHA2-512':'SHA512', 'SHA3-256':'SHA3_256', 'SHA3-384':'SHA3_384', 'SHA3-512':'SHA3_512', 'GOST':'' } cipher_not_map = { 'AES-256-CTR':'', 'AES-128-CTR':'', 'CHACHA20-POLY1305':'', 'CAMELLIA-256-GCM':'', 'CAMELLIA-128-GCM':'', 'CAMELLIA-256-CBC':'', 'CAMELLIA-128-CBC':'', 'AES-256-CBC':'AES_256_CBC', 'AES-128-CBC':'AES_128_CBC', 'AES-256-GCM':'AES_256_GCM', 'AES-128-GCM':'AES_128_GCM', 'AES-256-CCM':'AES_256_CCM', 'AES-128-CCM':'AES_128_CCM', 'RC4-128':'RC4_128', 'RC4-40':'RC4_40', 'RC2-CBC':'RC2', 'DES-CBC':'DES_CBC', 'DES40-CBC':'DES40_CBC', '3DES-CBC' :'3DES_EDE_CBC', 'SEED-CBC' :'', 'IDEA-CBC' :'', 'NULL':'' } cipher_legacy_map = { 'RC4-128':'RC4_128', '3DES-CBC':'3DES_EDE_CBC', } key_exchange_not_map = { 'EXPORT':'RSA_EXPORT, DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_DSS_EXPORT, DH_RSA_EXPORT', 'DH':'DH_RSA, DH_DSS', 'ANON':'DH_anon, ECDH_anon', 'RSA':'TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256', 'DHE-RSA':'DHE_RSA', 'DHE-DSS':'DHE_DSS', 'ECDHE':'ECDHE', 'ECDH':'ECDH', 'PSK':'', 'DHE-PSK':'', 'ECDHE-PSK':'' } sign_not_map = { # we handle signature algorithms via disabled hashes 'DSA-SHA1':'DSA', 'RSA-SHA1':'', 'ECDSA-SHA1':'', 'RSA-MD5':'' } protocol_not_map = { 'SSL2.0':'SSLv2', 'SSL3.0':'SSLv3', 'TLS1.0':'TLSv1', 'TLS1.1':'TLSv1.1', 'TLS1.2':'TLSv1.2', 'DTLS1.0':'', 'DTLS1.2':'' } mac_not_map = { 'AEAD':'', 'HMAC-MD5':'HmacMD5', 'HMAC-SHA1':'HmacSHA1', 'HMAC-SHA2-256':'HmacSHA256', 'HMAC-SHA2-384':'HmacSHA384', 'HMAC-SHA2-512':'HmacSHA512', } @classmethod def generate_config(cls, policy): p = policy.enabled ip = policy.disabled sep = ', ' cfg = 'jdk.tls.ephemeralDHKeySize=' + str(policy.integers['min_dh_size']) + '\n' cfg += 'jdk.certpath.disabledAlgorithms=' s = '' s = cls.append(s, 'MD2', sep) for i in ip['hash']: try: s = cls.append(s, cls.hash_not_map[i], sep) except KeyError: pass for i in ip['sign']: try: s = cls.append(s, cls.sign_not_map[i], sep) except KeyError: pass s = cls.append(s, 'RSA keySize < ' + str(policy.integers['min_rsa_size']), sep) cfg += s cfg += '\njdk.tls.disabledAlgorithms=' s = '' s = cls.append(s, 'DH keySize < ' + str(policy.integers['min_dh_size']), sep) for i in ip['protocol']: try: s = cls.append(s, cls.protocol_not_map[i], sep) except KeyError: pass for i in ip['key_exchange']: try: s = cls.append(s, cls.key_exchange_not_map[i], sep) except KeyError: pass for i in ip['cipher']: try: s = cls.append(s, cls.cipher_not_map[i], sep) except KeyError: pass for i in ip['mac']: try: s = cls.append(s, cls.mac_not_map[i], sep) except KeyError: pass cfg += s cfg += '\njdk.tls.legacyAlgorithms=' s = '' for i in p['cipher']: try: s = cls.append(s, cls.cipher_legacy_map[i], sep) except KeyError: pass cfg += s cfg += '\n' return cfg @classmethod def test_config(cls, config): # pylint: disable=unused-argument return True PK3]Ypolicygenerators/bind.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from subprocess import check_output, CalledProcessError from tempfile import mkstemp import os from .configgenerator import ConfigGenerator class BindGenerator(ConfigGenerator): CONFIG_NAME = 'bind' SCOPES = {'dnssec', 'bind'} RELOAD_CMD = 'systemctl try-reload-or-restart bind.service 2>/dev/null || :\n' sign_not_map = { 'DSA-SHA1': ('DSA', 'NSEC3DSA'), 'RSA-SHA1': ('RSASHA1', 'NSEC3RSASHA1'), 'RSA-SHA2-256': ('RSASHA256',), 'RSA-SHA2-512': ('RSASHA512',), 'ECDSA-SHA2-256': ('ECDSAP256SHA256',), # + custom handling below 'ECDSA-SHA2-384': ('ECDSAP384SHA384',), # + custom handling below 'EDDSA-ED25519': ('ED25519',), 'EDDSA-ED448': ('ED448',), } hash_not_map = { 'SHA1': 'SHA-1', 'SHA2-256': 'SHA-256', 'SHA2-384': 'SHA-384', 'GOST': 'GOST', } @classmethod def generate_config(cls, policy): ip = policy.disabled s = '' s += 'disable-algorithms "." {\n' s += 'RSAMD5;\n' # deprecated, disabled unconditionally s += 'ECCGOST;\n' # deprecated, disabled unconditionally, no such knob for i in ip['sign']: try: for disabled_sign in cls.sign_not_map[i]: s += f'{disabled_sign};\n' except KeyError: pass if 'ECDSA-SHA256' not in ip['sign'] and 'SECP256R1' in ip['group']: s += 'ECDSAP256SHA256;\n' # additionally disabled on lack of P-256 if 'ECDSA-SHA384' not in ip['sign'] and 'SECP384R1' in ip['group']: s += 'ECDSAP384SHA384;\n' # additionally disabled on lack of P-384 s += '};\n' s += 'disable-ds-digests "." {\n' for i in ip['hash']: try: s += f'{cls.hash_not_map[i]};\n' except KeyError: pass s += '};\n' return s @classmethod def test_config(cls, config): fd, path = mkstemp() try: with os.fdopen(fd, 'w') as f: f.write('options {\n') f.write(config) f.write('\n};\n') try: _ = check_output(["/usr/sbin/named-checkconf", path]) except CalledProcessError: cls.eprint("There is an error in bind generated policy") cls.eprint("Policy:\n%s" % config) return False except OSError: # Ignore missing check command pass finally: os.unlink(path) return True PK3]ɨ5policygenerators/__pycache__/libreswan.cpython-36.pycnu[3 ."d@sDddlmZmZddlmZddlZddlmZGdddeZdS))callCalledProcessError)mkstempN)ConfigGeneratorc@seZdZdZdddhZdZddddddd d d d d d ZddddddddZdddddddddddddd Zddddddddddddd Z ddddd Z ddddd!Z e d"d#Z e d$d%Ze d&d'Ze d(d)Zd*S)+LibreswanGeneratorZ libreswanZipsecZikez5systemctl try-restart ipsec.service 2>/dev/null || : Zdh19Zdh20Zdh21Zdh5Zdh14Zdh15Zdh16Zdh18) ZX448ZX25519Z SECP256R1Z SECP384R1Z SECP521R1z FFDHE-6144z FFDHE-1536z FFDHE-2048z FFDHE-3072z FFDHE-4096z FFDHE-8192Zaes256Zaes192Zaes128Z aes_gcm256Z aes_gcm192Z aes_gcm128Zchacha20_poly1305)z AES-256-CBCz AES-192-CBCz AES-128-CBCz AES-256-GCMz AES-192-GCMz AES-128-GCMzCHACHA20-POLY1305Zsha2_512Zsha2_256) zAES-256-CBC-HMAC-SHA2-512zAES-256-CBC-HMAC-SHA2-256zAES-192-CBC-HMAC-SHA2-512zAES-192-CBC-HMAC-SHA2-256zAES-128-CBC-HMAC-SHA2-256zAES-256-GCM-HMAC-SHA2-512zAES-256-GCM-HMAC-SHA2-256zAES-192-GCM-HMAC-SHA2-512zAES-192-GCM-HMAC-SHA2-256zAES-128-GCM-HMAC-SHA2-512zAES-128-GCM-HMAC-SHA2-256zCHACHA20-POLY1305-HMAC-SHA2-512zCHACHA20-POLY1305-HMAC-SHA2-256Zsha1) zAES-256-CBC-HMAC-SHA2-512zAES-192-CBC-HMAC-SHA2-512zAES-256-CBC-HMAC-SHA2-256zAES-192-CBC-HMAC-SHA2-256zAES-128-CBC-HMAC-SHA2-256zAES-256-CBC-HMAC-SHA1zAES-192-CBC-HMAC-SHA1zAES-128-CBC-HMAC-SHA1zAES-256-GCM-AEADzAES-192-GCM-AEADzAES-128-GCM-AEADzCHACHA20-POLY1305-AEADrr)AEADz HMAC-SHA2-512z HMAC-SHA2-256z HMAC-SHA1)r z HMAC-SHA2-512z HMAC-SHA1z HMAC-SHA2-256cCs||jkrdS|j|S)Nc)mac_ike_prio_map)clskeyr@./usr/share/crypto-policies/python/policygenerators/libreswan.pyZ__get_ike_priobs z!LibreswanGenerator.__get_ike_priocCs||jkrdS|j|S)Nr )mac_esp_prio_map)rrrrrZ__get_esp_priohs z!LibreswanGenerator.__get_esp_priocCsd}d}|j}d}|d}d|kr(d}n d|kr4d}|rH|d |d 7}|d 7}t|d |jd }d}x|dD]} y|j| } Wntk rwrYnX| d} d}xH|D]@} y|j| d| } Wntk rwYnX|j|| d}qW|sqr| |7} d}xJ|dD]>}y|j|}Wntk r:wYnX|j||d}qW|j| |d} |j|| |}qrW|r|d|d 7}t|d |jd }d}x|dD]} y|j| } Wntk rwYnX| d} d}xZ|D]R} y|j | d| } Wntk rwYnX| s(| } P|j|| d}qW| |7} | dddkrZq|j|| |}qW|r|d|d 7}|S)Nzconn %default ,rZprotocolZIKEv2z ikev2=insistZIKEv1z ikev2=never  z pfs=yes mac)rcipher-+groupz ike=rz esp=) Zenabledsorted!_LibreswanGenerator__get_ike_prio cipher_mapKeyErrorcipher_prf_mapappend group_map!_LibreswanGenerator__get_esp_priocipher_mac_map)rZpolicyZcfgseppsprotoZ sorted_macsZtmprcmZcomborZmmirrrrgenerate_configns      z"LibreswanGenerator.generate_configcCstjdtjsdSt\}}d}z^tj|d}|j|WdQRXytd|ddd}Wntk rz|jdYnXWdtj |X|r|jd |jd |d SdS) Nz/usr/sbin/ipsecTwz'/usr/sbin/ipsec readwriteconf --config z >/dev/null)shellz!/usr/sbin/ipsec: Execution failedz/There is an error in libreswan generated policyz Policy: %sF) osaccessX_OKrfdopenwriterrZeprintunlink)rconfigfdpathZretfrrr test_configs&    zLibreswanGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESZ RELOAD_CMDr"rr r$r r classmethodrr#r+r9rrrrrst    Pr) subprocessrrZtempfilerr/Zconfiggeneratorrrrrrrs  PK3]9 6policygenerators/__pycache__/java.cpython-36.opt-1.pycnu[3 ."dS@s ddlmZGdddeZdS))ConfigGeneratorc@seZdZdZdddhZddddd d d d d ddd ZdddddddddddddddddddddddZdddZdd d!d"d#d$d%d&dddd' Zd(dddd)Z d*d+d,d-d.ddd/Z dd0d1d2d3d4d5Z e d6d7Z e d8d9Zd:S); JavaGeneratorjavaZtlsZsslzjava-tlsMD2MD5SHA1ZSHA224ZSHA256ZSHA384ZSHA512ZSHA3_256ZSHA3_384ZSHA3_512) rrrzSHA2-224zSHA2-256zSHA2-384zSHA2-512zSHA3-256zSHA3-384zSHA3-512ZGOSTZ AES_256_CBCZ AES_128_CBCZ AES_256_GCMZ AES_128_GCMZ AES_256_CCMZ AES_128_CCMZRC4_128ZRC4_40ZRC2ZDES_CBCZ DES40_CBCZ 3DES_EDE_CBC)z AES-256-CTRz AES-128-CTRzCHACHA20-POLY1305zCAMELLIA-256-GCMzCAMELLIA-128-GCMzCAMELLIA-256-CBCzCAMELLIA-128-CBCz AES-256-CBCz AES-128-CBCz AES-256-GCMz AES-128-GCMz AES-256-CCMz AES-128-CCMzRC4-128zRC4-40zRC2-CBCzDES-CBCz DES40-CBCz3DES-CBCzSEED-CBCzIDEA-CBCZNULL)zRC4-128z3DES-CBCzHRSA_EXPORT, DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_DSS_EXPORT, DH_RSA_EXPORTzDH_RSA, DH_DSSzDH_anon, ECDH_anonzTLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256ZDHE_RSAZDHE_DSSECDHEECDH) ZEXPORTZDHZANONZRSAzDHE-RSAzDHE-DSSr r ZPSKzDHE-PSKz ECDHE-PSKZDSA)zDSA-SHA1zRSA-SHA1z ECDSA-SHA1zRSA-MD5ZSSLv2ZSSLv3ZTLSv1zTLSv1.1zTLSv1.2)zSSL2.0zSSL3.0zTLS1.0zTLS1.1zTLS1.2zDTLS1.0zDTLS1.2ZHmacMD5ZHmacSHA1Z HmacSHA256Z HmacSHA384Z HmacSHA512)ZAEADzHMAC-MD5z HMAC-SHA1z HMAC-SHA2-256z HMAC-SHA2-384z HMAC-SHA2-512c Cs|j}|j}d}dt|jdd}|d7}d}|j|d|}x>|dD]2}y|j||j||}WqJtk rzYqJXqJWx>|d D]2}y|j||j||}Wqtk rYqXqW|j|d t|jd |}||7}|d 7}d}|j|d t|jd|}xB|dD]6}y|j||j||}Wntk rHYnXqWxB|dD]6}y|j||j ||}Wntk rYnXqZWxB|dD]6}y|j||j ||}Wntk rYnXqWxB|dD]6}y|j||j ||}Wntk rYnXqW||7}|d7}d}xB|dD]6}y|j||j ||}Wntk rlYnXq:W||7}|d7}|S)Nz, zjdk.tls.ephemeralDHKeySize=Z min_dh_size z jdk.certpath.disabledAlgorithms=rrhashZsignzRSA keySize < Z min_rsa_sizez jdk.tls.disabledAlgorithms=z DH keySize < ZprotocolZ key_exchangeZcipherZmacz jdk.tls.legacyAlgorithms=) ZenabledZdisabledstrZintegersappend hash_not_mapKeyError sign_not_mapprotocol_not_mapkey_exchange_not_mapcipher_not_map mac_not_mapcipher_legacy_map)clsZpolicypZipsepZcfgsir;./usr/share/crypto-policies/python/policygenerators/java.pygenerate_configbsj       zJavaGenerator.generate_configcCsdS)NTr)rconfigrrr test_configszJavaGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESrrrrrrr classmethodrr rrrrr s  GrN)Zconfiggeneratorrrrrrrs PK3]9 0policygenerators/__pycache__/java.cpython-36.pycnu[3 ."dS@s ddlmZGdddeZdS))ConfigGeneratorc@seZdZdZdddhZddddd d d d d ddd ZdddddddddddddddddddddddZdddZdd d!d"d#d$d%d&dddd' Zd(dddd)Z d*d+d,d-d.ddd/Z dd0d1d2d3d4d5Z e d6d7Z e d8d9Zd:S); JavaGeneratorjavaZtlsZsslzjava-tlsMD2MD5SHA1ZSHA224ZSHA256ZSHA384ZSHA512ZSHA3_256ZSHA3_384ZSHA3_512) rrrzSHA2-224zSHA2-256zSHA2-384zSHA2-512zSHA3-256zSHA3-384zSHA3-512ZGOSTZ AES_256_CBCZ AES_128_CBCZ AES_256_GCMZ AES_128_GCMZ AES_256_CCMZ AES_128_CCMZRC4_128ZRC4_40ZRC2ZDES_CBCZ DES40_CBCZ 3DES_EDE_CBC)z AES-256-CTRz AES-128-CTRzCHACHA20-POLY1305zCAMELLIA-256-GCMzCAMELLIA-128-GCMzCAMELLIA-256-CBCzCAMELLIA-128-CBCz AES-256-CBCz AES-128-CBCz AES-256-GCMz AES-128-GCMz AES-256-CCMz AES-128-CCMzRC4-128zRC4-40zRC2-CBCzDES-CBCz DES40-CBCz3DES-CBCzSEED-CBCzIDEA-CBCZNULL)zRC4-128z3DES-CBCzHRSA_EXPORT, DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_DSS_EXPORT, DH_RSA_EXPORTzDH_RSA, DH_DSSzDH_anon, ECDH_anonzTLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256ZDHE_RSAZDHE_DSSECDHEECDH) ZEXPORTZDHZANONZRSAzDHE-RSAzDHE-DSSr r ZPSKzDHE-PSKz ECDHE-PSKZDSA)zDSA-SHA1zRSA-SHA1z ECDSA-SHA1zRSA-MD5ZSSLv2ZSSLv3ZTLSv1zTLSv1.1zTLSv1.2)zSSL2.0zSSL3.0zTLS1.0zTLS1.1zTLS1.2zDTLS1.0zDTLS1.2ZHmacMD5ZHmacSHA1Z HmacSHA256Z HmacSHA384Z HmacSHA512)ZAEADzHMAC-MD5z HMAC-SHA1z HMAC-SHA2-256z HMAC-SHA2-384z HMAC-SHA2-512c Cs|j}|j}d}dt|jdd}|d7}d}|j|d|}x>|dD]2}y|j||j||}WqJtk rzYqJXqJWx>|d D]2}y|j||j||}Wqtk rYqXqW|j|d t|jd |}||7}|d 7}d}|j|d t|jd|}xB|dD]6}y|j||j||}Wntk rHYnXqWxB|dD]6}y|j||j ||}Wntk rYnXqZWxB|dD]6}y|j||j ||}Wntk rYnXqWxB|dD]6}y|j||j ||}Wntk rYnXqW||7}|d7}d}xB|dD]6}y|j||j ||}Wntk rlYnXq:W||7}|d7}|S)Nz, zjdk.tls.ephemeralDHKeySize=Z min_dh_size z jdk.certpath.disabledAlgorithms=rrhashZsignzRSA keySize < Z min_rsa_sizez jdk.tls.disabledAlgorithms=z DH keySize < ZprotocolZ key_exchangeZcipherZmacz jdk.tls.legacyAlgorithms=) ZenabledZdisabledstrZintegersappend hash_not_mapKeyError sign_not_mapprotocol_not_mapkey_exchange_not_mapcipher_not_map mac_not_mapcipher_legacy_map)clsZpolicypZipsepZcfgsir;./usr/share/crypto-policies/python/policygenerators/java.pygenerate_configbsj       zJavaGenerator.generate_configcCsdS)NTr)rconfigrrr test_configszJavaGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESrrrrrrr classmethodrr rrrrr s  GrN)Zconfiggeneratorrrrrrrs PK3]/$~~2policygenerators/__pycache__/gnutls.cpython-36.pycnu[3 ."d@sDddlmZmZddlmZddlZddlmZGdddeZdS))callCalledProcessError)mkstempN)ConfigGeneratorc@seZdZdZdddhZdddddd d Zd d d dddddddd Zddddddddddd d!d"d#d$d%d&d'd(d)d*d+Zd,d-d.Zddd/d0d1d2d3d4d5d6d7d8d9d:d;d<Z d=d>d?Z d@dAdBdCddddDZ dEdFdGdHdIdJdKdLZ e dMdNZe dOdPZdQS)RGnuTLSGeneratorZgnutlsZtlsZsslz-AEADz-SHA1z-MD5z-SHA256z-SHA384z-SHA512)ZAEADz HMAC-SHA1zHMAC-MD5z HMAC-SHA2-256z HMAC-SHA2-384z HMAC-SHA2-512z -GROUP-X448z -GROUP-X25519z-GROUP-SECP256R1z-GROUP-SECP384R1z-GROUP-SECP521R1z-GROUP-FFDHE2048z-GROUP-FFDHE3072z-GROUP-FFDHE4096z-GROUP-FFDHE8192) ZX448ZX25519Z SECP256R1Z SECP384R1Z SECP521R1z FFDHE-6144z FFDHE-2048z FFDHE-3072z FFDHE-4096z FFDHE-8192z -SIGN-RSA-MD5z-SIGN-RSA-SHA1z-SIGN-DSA-SHA1z-SIGN-ECDSA-SHA1z-SIGN-RSA-SHA224z-SIGN-DSA-SHA224z-SIGN-ECDSA-SHA224z-SIGN-RSA-SHA256z-SIGN-DSA-SHA256z-SIGN-ECDSA-SHA256z-SIGN-RSA-SHA384z-SIGN-DSA-SHA384z-SIGN-ECDSA-SHA384z-SIGN-RSA-SHA512z-SIGN-DSA-SHA512z-SIGN-ECDSA-SHA512z.-SIGN-RSA-PSS-SHA256:-SIGN-RSA-PSS-RSAE-SHA256z.-SIGN-RSA-PSS-SHA384:-SIGN-RSA-PSS-RSAE-SHA384z.-SIGN-RSA-PSS-SHA512:-SIGN-RSA-PSS-RSAE-SHA512z-SIGN-EDDSA-ED448z-SIGN-EDDSA-ED25519)zRSA-MD5zRSA-SHA1zDSA-SHA1z ECDSA-SHA1z RSA-SHA2-224z DSA-SHA2-224zECDSA-SHA2-224z RSA-SHA2-256z DSA-SHA2-256zECDSA-SHA2-256z RSA-SHA2-384z DSA-SHA2-384zECDSA-SHA2-384z RSA-SHA2-512z DSA-SHA2-512zECDSA-SHA2-512zRSA-PSS-SHA2-256zRSA-PSS-SHA2-384zRSA-PSS-SHA2-512z EDDSA-ED448z EDDSA-ED25519z+SIGN-DSA-SHA1z+SIGN-RSA-SHA1)zDSA-SHA1zRSA-SHA1z -AES-256-GCMz -AES-128-GCMz -AES-256-CCMz -AES-128-CCMz -AES-256-CBCz -AES-128-CBCz-CAMELLIA-256-GCMz-CAMELLIA-128-GCMz-CAMELLIA-256-CBCz-CAMELLIA-128-CBCz-CHACHA20-POLY1305z -3DES-CBCz -ARCFOUR-128)z AES-256-CTRz AES-128-CTRz AES-256-GCMz AES-128-GCMz AES-256-CCMz AES-128-CCMz AES-256-CBCz AES-128-CBCzCAMELLIA-256-GCMzCAMELLIA-128-GCMzCAMELLIA-256-CBCzCAMELLIA-128-CBCzCHACHA20-POLY1305z3DES-CBCzRC4-128z +3DES-CBCz +ARCFOUR-128)z3DES-CBCzRC4-128z+RSAz+ECDHE-RSA:+ECDHE-ECDSAz+DHE-RSAz+DHE-DSS)ZRSAZECDHEzDHE-RSAzDHE-DSSZPSKzDHE-PSKz ECDHE-PSKz -VERS-SSL3.0z -VERS-TLS1.0z -VERS-TLS1.1z -VERS-TLS1.2z -VERS-TLS1.3z -VERS-DTLS1.0z -VERS-DTLS1.2)zSSL3.0zTLS1.0zTLS1.1zTLS1.2zTLS1.3zDTLS1.0zDTLS1.2c Cszd}|j}|j}|drb|j|d}x<|dD]0}y|j||j|}Wq.tk r\Yq.Xq.W|dr|j|d}x<|dD]0}y|j||j|}Wqtk rYqXqW|drL|j|d}x>|dD]2}y|j||j|}Wqtk rYqXqWx@|dD]4}y|j||j|}Wntk rDYnXqW|jdrd|j|d }|d r|j|d }x@|d D]4}y|j||j |}Wntk rYnXqWx@|d D]4}y|j||j |}Wntk rYnXqWx@|d D]4}y|j||j |}Wntk r8YnXqW|d r|j|d}x@|d D]4}y|j||j |}Wntk rYnXq`W|j|d}|jd}|jd}|dks|dkr|j|d}n|dks|dkr|j|d}nr|dks|dkr|j|d}nP|dks2|dkr@|j|d}n.|dksT|dkrb|j|d}n |j|d}|d7}|S)Nz SYSTEM=NONEZmacz+MAC-ALLgroupz +GROUP-ALLZsignz +SIGN-ALLZ sha1_in_certsz%VERIFY_ALLOW_SIGN_WITH_SHA1Zcipherz +CIPHER-ALLZ key_exchangeZprotocolz+VERS-ALL:-VERS-DTLS0.9z +COMP-NULL min_rsa_size min_dh_sizeiz%PROFILE_VERY_WEAKiz %PROFILE_LOWiz%PROFILE_MEDIUMi z %PROFILE_HIGHi z%PROFILE_ULTRAz%PROFILE_FUTURE ) ZenabledZdisabledappend mac_not_mapKeyError group_not_map sign_not_maplegacy_sign_mapZintegerscipher_not_mapcipher_force_mapkey_exchange_mapprotocol_not_map)clsZpolicyspZipir r r=./usr/share/crypto-policies/python/policygenerators/gnutls.pygenerate_configqs                      zGnuTLSGenerator.generate_configcCstjdtjsdSt\}}d}z^tj|d}|j|WdQRXytd|ddd}Wntk rz|jdYnXWdtj |X|r|jd |jd |d SdS) Nz/usr/bin/gnutls-cliTwz(/usr/bin/gnutls-cli -l --priority $(cat z3 | sed 's/SYSTEM=//g' | tr --delete ' ') >/dev/null)shellz%/usr/bin/gnutls-cli: Execution failedz,There is an error in gnutls generated policyz Policy: %sF) osaccessX_OKrfdopenwriterrZeprintunlink)rconfigfdpathZretfrrr test_configs&    zGnuTLSGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESrrrrrrrr classmethodrr+rrrrrs  Vr) subprocessrrZtempfilerr!Zconfiggeneratorrrrrrrs  PK3]6!/policygenerators/__pycache__/nss.cpython-36.pycnu[3 ."d$@sTddlmZmZddlmZddlZddlZddlZddlm Z Gddde Z dS))callCalledProcessError)mkstempN)ConfigGeneratorc@seZdZdZdddhZdddddd d Zd d d dddddddd ZddddddZdddddddddddddddd d!Zdddd"d#d$d%d&d'd( Z d)d*d+d,d-d.d/d0Z d1d2d3d4d5Z e d6d7Z e d8d9Zd:S); NSSGeneratorZnssZtlsZsslz HMAC-SHA1zHMAC-MD5z HMAC-SHA256z HMAC-SHA384z HMAC-SHA512)ZAEADz HMAC-SHA1zHMAC-MD5z HMAC-SHA2-256z HMAC-SHA2-384z HMAC-SHA2-512SHA1MD5ZSHA224ZSHA256ZSHA384ZSHA512) r r zSHA2-224zSHA2-256zSHA2-384zSHA2-512zSHA3-256zSHA3-384zSHA3-512ZGOSTZ CURVE25519 SECP256R1 SECP384R1 SECP521R1)ZX25519ZX448r r r Zrc2Zrc4z aes256-gcmz aes128-gcmz aes256-cbcz aes128-cbczcamellia256-cbczcamellia128-cbczchacha20-poly1305z des-ede3-cbc)z AES-256-CTRz AES-128-CTRzRC2-CBCzRC4-128z AES-256-GCMz AES-128-GCMz AES-256-CBCz AES-128-CBCzCAMELLIA-256-CBCzCAMELLIA-128-CBCzCAMELLIA-256-GCMzCAMELLIA-128-GCMz AES-256-CCMz AES-128-CCMzCHACHA20-POLY1305z3DES-CBCRSAzDHE-RSAzDHE-DSSzECDHE-RSA:ECDHE-ECDSAzECDH-RSA:ECDH-ECDSAz DH-RSA:DH-DSS) ZPSKzDHE-PSKz ECDHE-PSKrzDHE-RSAzDHE-DSSZECDHEZECDHZDHzssl3.0ztls1.0ztls1.1ztls1.2ztls1.3zdtls1.0zdtls1.2)zSSL3.0zTLS1.0zTLS1.1zTLS1.2zTLS1.3zDTLS1.0zDTLS1.2zRSA-PSSzRSA-PKCSZECDSADSA)zRSA-PSS-zRSA-zECDSA-zDSA-c Cs|j}d}|d7}|d7}|d7}d}x<|dD]0}y|j||j|}Wq0tk r^Yq0Xq0Wx<|dD]0}y|j||j|}Wqntk rYqnXqnWx<|dD]0}y|j||j|}Wqtk rYqXqWx>|d D]2}y|j||j|}Wqtk rYqXqWx@|d D]4}y|j||j|}Wntk rZYnXq*Wd d |d D}|r|j|d}t}xZ|d D]N}xF|j j D]8\}} |j |r| |kr|j | |j|| }PqWqW|j r|j|j } |j|d| }n |j|d}|jr@|j|j} |j|d| }n |j|d}|j|dt|jd}|j|dt|jd}|j|dt|jd}||d7}|S)Nz library= z name=Policy zNSS=flags=policyOnly,moduleDB zconfig="disallow=ALL allow=rZmacgroupZcipherhashZ key_exchangecSsg|]}|jddkr|qS)zDSA-r)find).0ir:./usr/share/crypto-policies/python/policygenerators/nss.py sz0NSSGenerator.generate_config..Zsignrztls-version-min=ztls-version-min=0zdtls-version-min=zdtls-version-min=0zDH-MIN=Z min_dh_sizezDSA-MIN=Z min_dsa_sizezRSA-MIN=Z min_rsa_sizez" )Zenabledappendmac_mapKeyError curve_map cipher_maphash_mapkey_exchange_mapsetsign_prefix_ordmapitems startswithaddZmin_tls_version protocol_mapZmin_dtls_versionstrZintegers) clsZpolicypZcfgsrZdsaZenabled_sigalgsprefixZsigalgZminverrrrgenerate_configdsn               zNSSGenerator.generate_configc Csy2tjjd}tj|}|jds0|jddSWntk rP|jdYnXtjdtj sddSt \}}d}z^tj |d}|j |WdQRXyt d |d dd }Wntk r|jd YnXWdtj|X|r|jd |jd|dSdS)NZnss3s3.66z:Skipping nss-policy-check due to nss being older than 3.66Tz(Cannot determine nss version with ctypesz/usr/bin/nss-policy-checkwz/usr/bin/nss-policy-check z >/dev/null)shellz+/usr/bin/nss-policy-check: Execution failedz)There is an error in NSS generated policyz Policy: %sF)ctypesutilZ find_libraryZCDLLZNSS_VersionCheckZeprintAttributeErrorosaccessX_OKrfdopenwriterrunlink)r&configZnss_pathZnss_libfdpathZretfrrr test_configs6        zNSSGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESrrrrrr$r classmethodr*r;rrrrrsz  Hr) subprocessrrZtempfilerr.Z ctypes.utilr1Zconfiggeneratorrrrrrrs   PK3]˿;policygenerators/__pycache__/configgenerator.cpython-36.pycnu[3 ."d@sddlZGdddZdS)Nc@s*eZdZdZedddZeddZdS) ConfigGenerator:cCs|r|r|||S|S|S)N)svalseprrF./usr/share/crypto-policies/python/policygenerators/configgenerator.pyappend s  zConfigGenerator.appendcOst|dtji|dS)Nfile)printsysstderr)argskwargsrrr eprintszConfigGenerator.eprintN)r)__name__ __module__ __qualname__Z RELOAD_CMD staticmethodr rrrrr r s r)r rrrrr sPK3]1#G:policygenerators/__pycache__/__init__.cpython-36.opt-1.pycnu[3 ."dE @sddlmZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZdd lmZdd lmZdd lmZd d dddddddddg ZdS)) BindGenerator)GnuTLSGenerator) JavaGenerator) KRB5Generator)LibreswanGenerator)LibsshGenerator) NSSGenerator)OpenSSHClientGenerator)OpenSSHServerGenerator)OpenSSLConfigGenerator)OpenSSLGeneratorrrrrrrrr r r r N)ZbindrZgnutlsrjavarZkrb5rZ libreswanrZlibsshrZnssrZopensshr r Zopensslr r __all__rr?./usr/share/crypto-policies/python/policygenerators/__init__.pys*           PK3]oc772policygenerators/__pycache__/libssh.cpython-36.pycnu[3 ."d@s ddlmZGdddeZdS))ConfigGeneratorc@seZdZdZddhZddddddd dddddd d d dddddd dZdddddddZdddddddZdddddddddd Zd d!d"Z d#d$d%d&d'd(d)d*d+Z d,d-d.d/d0d1d2d3d+Z e d4d5Z e d6d7Zd8S)9LibsshGeneratorZlibsshZsshzaes256-gcm@openssh.comz aes256-ctrz aes192-ctrzaes128-gcm@openssh.comz aes128-ctrzchacha20-poly1305@openssh.comz aes256-cbcz aes192-cbcz aes128-cbcz3des-cbc)z AES-256-GCMz AES-256-CTRz AES-192-GCMz AES-192-CTRz AES-128-GCMz AES-128-CTRzCHACHA20-POLY1305zCAMELLIA-256-GCMz AES-256-CCMz AES-192-CCMz AES-128-CCMzCAMELLIA-128-GCMz AES-256-CBCz AES-192-CBCz AES-128-CBCzCAMELLIA-256-CBCzCAMELLIA-128-CBCzRC4-128zDES-CBCzCAMELLIA-128-CTSz3DES-CBCzhmac-sha1-etm@openssh.comzhmac-sha2-256-etm@openssh.comzhmac-sha2-512-etm@openssh.com)zHMAC-MD5zUMAC-64zUMAC-128z HMAC-SHA1z HMAC-SHA2-256z HMAC-SHA2-512z hmac-sha1z hmac-sha2-256z hmac-sha2-512zecdh-sha2-nistp521zecdh-sha2-nistp384zecdh-sha2-nistp256z.curve25519-sha256,curve25519-sha256@libssh.orgzdiffie-hellman-group1-sha1zdiffie-hellman-group14-sha1zdiffie-hellman-group14-sha256zdiffie-hellman-group16-sha512zdiffie-hellman-group18-sha512) zECDHE-SECP521R1-SHA2-512zECDHE-SECP384R1-SHA2-384zECDHE-SECP256R1-SHA2-256zECDHE-X25519-SHA2-256zDHE-FFDHE-1024-SHA1zDHE-FFDHE-2048-SHA1zDHE-FFDHE-2048-SHA2-256zDHE-FFDHE-4096-SHA2-512zDHE-FFDHE-8192-SHA2-512z"diffie-hellman-group-exchange-sha1z$diffie-hellman-group-exchange-sha256)zDHE-SHA1z DHE-SHA2-256zssh-rsazssh-dssz rsa-sha2-256z rsa-sha2-512zecdsa-sha2-nistp256zecdsa-sha2-nistp384zecdsa-sha2-nistp521z ssh-ed25519)zRSA-SHA1zDSA-SHA1z RSA-SHA2-256z RSA-SHA2-512zECDSA-SHA2-256zECDSA-SHA2-384zECDSA-SHA2-512z EDDSA-ED25519zssh-rsa-cert-v01@openssh.comzssh-dss-cert-v01@openssh.comz!rsa-sha2-256-cert-v01@openssh.comz!rsa-sha2-512-cert-v01@openssh.comz(ecdsa-sha2-nistp256-cert-v01@openssh.comz(ecdsa-sha2-nistp384-cert-v01@openssh.comz(ecdsa-sha2-nistp521-cert-v01@openssh.comz ssh-ed25519-cert-v01@openssh.comc Cs|j}d}d}d}x>|dD]2}y|j||j||}Wqtk rLYqXqW|rf|d|d7}d}|jdrx>|dD]2}y|j||j||}Wq~tk rYq~Xq~Wx>|dD]2}y|j||j||}Wqtk rYqXqW|r |d|d7}d}x|d D]}x|d D]}|jd d krvy$|j|d |} |j|| |}Wntk rtYnXxV|dD]J} y,|j|d | d |} |j|| |}Wntk rYnXqWq&WqW|r|d|d7}d}x~|dD]r}y|j||j ||}Wntk r0YnX|jdry|j||j ||}Wntk rlYnXqW|r|d|d7}|d|d7}|S)Nr,ZcipherzCiphers  Zssh_etmZmaczMACs Z key_exchangehashZarbitrary_dh_groupsr-groupzKexAlgorithms ZsignZ ssh_certszHostKeyAlgorithms zPubkeyAcceptedKeyTypes ) Zenabledappend cipher_mapKeyErrorZintegers mac_map_etmmac_mapgx_mapkx_mapsign_mapsign_map_certs) clsZpolicypZcfgsepsiZkxhvalgr=./usr/share/crypto-policies/python/policygenerators/libssh.pygenerate_config^sr      zLibsshGenerator.generate_configcCsdS)NTr)rconfigrrr test_configszLibsshGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESr r rrrrr classmethodrrrrrrr s ErN)Zconfiggeneratorrrrrrrs PK3][9policygenerators/__pycache__/openssl.cpython-36.opt-1.pycnu[3 ."d@s@ddlmZmZddlmZGdddeZGdddeZdS) ) check_outputCalledProcessError)ConfigGeneratorc@seZdZdZdddhZdddddddd d d ddd d dddZddddddddZddddddddddd Zd d!d"Zd#d$d%d&d'd(Z e d)d*Z e d+d,Z e d-d.Z e d/d0Zd1S)2OpenSSLGeneratoropensslZtlsZsslz-AES256z-AES128z-SHA256z -CHACHA20z-SEEDz!IDEAz!DESz-3DESz!RC4z!RC2z !eNULL:!aNULL)z AES-256-CTRz AES-128-CTRz AES-256-GCMz AES-128-GCMz AES-256-CBCz AES-128-CBCzCHACHA20-POLY1305zSEED-CBCzIDEA-CBCzDES-CBCzRC4-40z DES40-CBCz3DES-CBCzRC4-128zRC2-CBCZNULLZkRSAZkEECDHZkPSKZkDHEPSKZkEDHZ kECDHEPSK)RSAECDHEPSKzDHE-PSKzDHE-RSAzDHE-DSSz ECDHE-PSKz-kRSAz-kEECDHz-aRSAz-aDSSz-kPSKz-kDHEPSKz -kECDHEPSK) ZANONZDHZECDHr r zDHE-RSAzDHE-DSSr zDHE-PSKz ECDHE-PSKz!MD5z-SHA1)zHMAC-MD5z HMAC-SHA1ZTLS_AES_256_GCM_SHA384ZTLS_AES_128_GCM_SHA256ZTLS_CHACHA20_POLY1305_SHA256ZTLS_AES_128_CCM_SHA256ZTLS_AES_128_CCM_8_SHA256)z AES-256-GCMz AES-128-GCMzCHACHA20-POLY1305z AES-128-CCMz AES-128-CCM8c Csd}|j}|j}|jd}|jd}|dks4|dkrB|j|d}nH|dksR|dkr`|j|d}n*|dksp|dkr~|j|d }n |j|d }x<|d D]0}y|j||j|}Wqtk rYqXqWx>|d D]2}y|j||j|}Wqtk rYqXqWx@|d D]4}y|j||j|}Wntk rBYnXqWd |d krrd|d krr|j|d}x@|dD]4}y|j||j|}Wntk rYnXq|W|j|d}|j|d}|j|d}|j|d}|S)Nr min_dh_size min_rsa_sizeiz @SECLEVEL=0iz @SECLEVEL=1i z @SECLEVEL=2z @SECLEVEL=3Z key_exchangecipherz AES-128-CCMz AES-256-CCMz-AESCCMZmacz-SHA384z -CAMELLIAz-ARIAz-AESCCM8) enabledZdisabledZintegersappendkey_exchange_mapKeyErrorkey_exchange_not_mapcipher_not_map mac_not_map)clspolicyspZipr r ir>./usr/share/crypto-policies/python/policygenerators/openssl.pygenerate_ciphersFsN            z!OpenSSLGenerator.generate_ciphersc CsLd}|j}x<|dD]0}y|j||j|}Wqtk rBYqXqW|S)Nrr)rrciphersuite_mapr)rrrrrrrrgenerate_ciphersuites{s z&OpenSSLGenerator.generate_ciphersuitescCs |j|S)N)r)rrrrrgenerate_configsz OpenSSLGenerator.generate_configc Csd}ytdd|g}Wn>tk rB|jd|jd|dStk rTdSXd|ksfd |kr|jd |jd |dSdS) NrZciphersz-There is an error in openssl generated policyz policy: %sFTsNULLsADHz0There is NULL or ADH in openssl generated policyz Policy: %s)rrZeprintOSError)rconfigoutputrrr test_configs  zOpenSSLGenerator.test_configN)__name__ __module__ __qualname__ CONFIG_NAMEZSCOPESrrrrr classmethodrrr r%rrrrr s\  5 rc@sleZdZdZdddddddd d Zd d d ddddddddddddddddddZed d!Zed"d#Zd$S)%OpenSSLConfigGeneratorZ opensslcnfrZSSLv3ZTLSv1zTLSv1.1zTLSv1.2zTLSv1.3ZDTLSv1zDTLSv1.2)NzSSL3.0zTLS1.0zTLS1.1zTLS1.2zTLS1.3zDTLS1.0zDTLS1.2zRSA+SHA1zDSA+SHA1z ECDSA+SHA1z RSA+SHA224z DSA+SHA224z ECDSA+SHA224z RSA+SHA256z DSA+SHA256z ECDSA+SHA256z RSA+SHA384z DSA+SHA384z ECDSA+SHA384z RSA+SHA512z DSA+SHA512z ECDSA+SHA512z&rsa_pss_pss_sha256:rsa_pss_rsae_sha256z&rsa_pss_pss_sha384:rsa_pss_rsae_sha384z&rsa_pss_pss_sha512:rsa_pss_rsae_sha512Zed25519Zed448)zRSA-SHA1zDSA-SHA1z ECDSA-SHA1z RSA-SHA2-224z DSA-SHA2-224zECDSA-SHA2-224z RSA-SHA2-256z DSA-SHA2-256zECDSA-SHA2-256z RSA-SHA2-384z DSA-SHA2-384zECDSA-SHA2-384z RSA-SHA2-512z DSA-SHA2-512zECDSA-SHA2-512zRSA-PSS-SHA2-256zRSA-PSS-SHA2-384zRSA-PSS-SHA2-512z EDDSA-ED25519z EDDSA-ED448cs|j}d}|j|7}|d7}|d7}|j|7}|d7}|jrd|d7}|dj|jd7}|jr|d7}|dj|jd7}|jr|d7}|dj|jd7}|jr|d7}|dj|jd7}fd d |d D}|d d j|7}|S)NzCipherString =  zCiphersuites = zTLS.MinProtocol = zTLS.MaxProtocol =zDTLS.MinProtocol =zDTLS.MaxProtocol =cs g|]}|jkrj|qSr)sign_map).0r)rrr sz:OpenSSLConfigGenerator.generate_config..ZsignzSignatureAlgorithms = :) rrrZmin_tls_version protocol_mapZmax_tls_versionZmin_dtls_versionZmax_dtls_versionjoin)rrrrZsig_algsr)rrr s.  z&OpenSSLConfigGenerator.generate_configcCsdS)NTr)rr#rrrr%sz"OpenSSLConfigGenerator.test_configN) r&r'r(r)r2r.r*r r%rrrrr+s> r+N) subprocessrrZconfiggeneratorrrr+rrrrs PK3]˿Apolicygenerators/__pycache__/configgenerator.cpython-36.opt-1.pycnu[3 ."d@sddlZGdddZdS)Nc@s*eZdZdZedddZeddZdS) ConfigGenerator:cCs|r|r|||S|S|S)N)svalseprrF./usr/share/crypto-policies/python/policygenerators/configgenerator.pyappend s  zConfigGenerator.appendcOst|dtji|dS)Nfile)printsysstderr)argskwargsrrr eprintszConfigGenerator.eprintN)r)__name__ __module__ __qualname__Z RELOAD_CMD staticmethodr rrrrr r s r)r rrrrr sPK3]6!5policygenerators/__pycache__/nss.cpython-36.opt-1.pycnu[3 ."d$@sTddlmZmZddlmZddlZddlZddlZddlm Z Gddde Z dS))callCalledProcessError)mkstempN)ConfigGeneratorc@seZdZdZdddhZdddddd d Zd d d dddddddd ZddddddZdddddddddddddddd d!Zdddd"d#d$d%d&d'd( Z d)d*d+d,d-d.d/d0Z d1d2d3d4d5Z e d6d7Z e d8d9Zd:S); NSSGeneratorZnssZtlsZsslz HMAC-SHA1zHMAC-MD5z HMAC-SHA256z HMAC-SHA384z HMAC-SHA512)ZAEADz HMAC-SHA1zHMAC-MD5z HMAC-SHA2-256z HMAC-SHA2-384z HMAC-SHA2-512SHA1MD5ZSHA224ZSHA256ZSHA384ZSHA512) r r zSHA2-224zSHA2-256zSHA2-384zSHA2-512zSHA3-256zSHA3-384zSHA3-512ZGOSTZ CURVE25519 SECP256R1 SECP384R1 SECP521R1)ZX25519ZX448r r r Zrc2Zrc4z aes256-gcmz aes128-gcmz aes256-cbcz aes128-cbczcamellia256-cbczcamellia128-cbczchacha20-poly1305z des-ede3-cbc)z AES-256-CTRz AES-128-CTRzRC2-CBCzRC4-128z AES-256-GCMz AES-128-GCMz AES-256-CBCz AES-128-CBCzCAMELLIA-256-CBCzCAMELLIA-128-CBCzCAMELLIA-256-GCMzCAMELLIA-128-GCMz AES-256-CCMz AES-128-CCMzCHACHA20-POLY1305z3DES-CBCRSAzDHE-RSAzDHE-DSSzECDHE-RSA:ECDHE-ECDSAzECDH-RSA:ECDH-ECDSAz DH-RSA:DH-DSS) ZPSKzDHE-PSKz ECDHE-PSKrzDHE-RSAzDHE-DSSZECDHEZECDHZDHzssl3.0ztls1.0ztls1.1ztls1.2ztls1.3zdtls1.0zdtls1.2)zSSL3.0zTLS1.0zTLS1.1zTLS1.2zTLS1.3zDTLS1.0zDTLS1.2zRSA-PSSzRSA-PKCSZECDSADSA)zRSA-PSS-zRSA-zECDSA-zDSA-c Cs|j}d}|d7}|d7}|d7}d}x<|dD]0}y|j||j|}Wq0tk r^Yq0Xq0Wx<|dD]0}y|j||j|}Wqntk rYqnXqnWx<|dD]0}y|j||j|}Wqtk rYqXqWx>|d D]2}y|j||j|}Wqtk rYqXqWx@|d D]4}y|j||j|}Wntk rZYnXq*Wd d |d D}|r|j|d}t}xZ|d D]N}xF|j j D]8\}} |j |r| |kr|j | |j|| }PqWqW|j r|j|j } |j|d| }n |j|d}|jr@|j|j} |j|d| }n |j|d}|j|dt|jd}|j|dt|jd}|j|dt|jd}||d7}|S)Nz library= z name=Policy zNSS=flags=policyOnly,moduleDB zconfig="disallow=ALL allow=rZmacgroupZcipherhashZ key_exchangecSsg|]}|jddkr|qS)zDSA-r)find).0ir:./usr/share/crypto-policies/python/policygenerators/nss.py sz0NSSGenerator.generate_config..Zsignrztls-version-min=ztls-version-min=0zdtls-version-min=zdtls-version-min=0zDH-MIN=Z min_dh_sizezDSA-MIN=Z min_dsa_sizezRSA-MIN=Z min_rsa_sizez" )Zenabledappendmac_mapKeyError curve_map cipher_maphash_mapkey_exchange_mapsetsign_prefix_ordmapitems startswithaddZmin_tls_version protocol_mapZmin_dtls_versionstrZintegers) clsZpolicypZcfgsrZdsaZenabled_sigalgsprefixZsigalgZminverrrrgenerate_configdsn               zNSSGenerator.generate_configc Csy2tjjd}tj|}|jds0|jddSWntk rP|jdYnXtjdtj sddSt \}}d}z^tj |d}|j |WdQRXyt d |d dd }Wntk r|jd YnXWdtj|X|r|jd |jd|dSdS)NZnss3s3.66z:Skipping nss-policy-check due to nss being older than 3.66Tz(Cannot determine nss version with ctypesz/usr/bin/nss-policy-checkwz/usr/bin/nss-policy-check z >/dev/null)shellz+/usr/bin/nss-policy-check: Execution failedz)There is an error in NSS generated policyz Policy: %sF)ctypesutilZ find_libraryZCDLLZNSS_VersionCheckZeprintAttributeErrorosaccessX_OKrfdopenwriterrunlink)r&configZnss_pathZnss_libfdpathZretfrrr test_configs6        zNSSGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESrrrrrr$r classmethodr*r;rrrrrsz  Hr) subprocessrrZtempfilerr.Z ctypes.utilr1Zconfiggeneratorrrrrrrs   PK3]70policygenerators/__pycache__/bind.cpython-36.pycnu[3 ."d@sDddlmZmZddlmZddlZddlmZGdddeZdS)) check_outputCalledProcessError)mkstempN)ConfigGeneratorc @sXeZdZdZddhZdZdddddddd dZdddddZeddZ eddZ dS)! BindGeneratorZbindZdnssecz>systemctl try-reload-or-restart bind.service 2>/dev/null || : DSANSEC3DSARSASHA1 NSEC3RSASHA1 RSASHA256 RSASHA512ECDSAP256SHA256ECDSAP384SHA384ED25519ED448)zDSA-SHA1zRSA-SHA1z RSA-SHA2-256z RSA-SHA2-512zECDSA-SHA2-256zECDSA-SHA2-384z EDDSA-ED25519z EDDSA-ED448zSHA-1zSHA-256zSHA-384GOST)ZSHA1zSHA2-256zSHA2-384rc Cs |j}d}|d7}|d7}|d7}xL|dD]@}y&x |j|D]}||d7}q>WWq,tk rjYq,Xq,Wd|dkrd|d kr|d 7}d |dkrd |d kr|d 7}|d7}|d7}x>|dD]2}y||j|d7}Wqtk rYqXqW|d7}|S)Nzdisable-algorithms "." { zRSAMD5; z ECCGOST; Zsignz; z ECDSA-SHA256Z SECP256R1groupzECDSAP256SHA256; z ECDSA-SHA384Z SECP384R1zECDSAP384SHA384; z}; zdisable-ds-digests "." { hash)Zdisabled sign_not_mapKeyError hash_not_map)clsZpolicyZipsiZ disabled_signr;./usr/share/crypto-policies/python/policygenerators/bind.pygenerate_config%s0  zBindGenerator.generate_configcCst\}}ztj|d$}|jd|j||jdWdQRXytd|g}Wn>tk r~|jd|jd|dStk rYnXWdtj|XdS) Nwz options { z }; z/usr/sbin/named-checkconfz*There is an error in bind generated policyz Policy: %sFT) rosfdopenwriterrZeprintOSErrorunlink)rconfigfdpathf_rrr test_configCs       zBindGenerator.test_configN)rr )r r )r )r )r)r)r)r) __name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESZ RELOAD_CMDrr classmethodrr*rrrrr s" r) subprocessrrZtempfilerr Zconfiggeneratorrrrrrrs  PK3]b!3policygenerators/__pycache__/openssh.cpython-36.pycnu[3 ."d @sdddlmZmZddlmZddlZddlmZGdddeZGdd d eZ Gd d d eZ dS) )callCalledProcessError)mkstempN)ConfigGeneratorc@seZdZdZdddddddddddddd d dddddd d Zd ddddddZdddddddZddddddd d!d"d# Zd$d%d&Zd'd(d)d*d+d,d-d.Z d/d0d1d2d3d4d5d6d7Z d8d9d:d;dd?d7Z e d@dAZ dBS)COpenSSHGeneratorzaes256-gcm@openssh.comz aes256-ctrz aes192-ctrzaes128-gcm@openssh.comz aes128-ctrzchacha20-poly1305@openssh.comz aes256-cbcz aes192-cbcz aes128-cbcz3des-cbc)z AES-256-GCMz AES-256-CTRz AES-192-GCMz AES-192-CTRz AES-128-GCMz AES-128-CTRzCHACHA20-POLY1305zCAMELLIA-256-GCMz AES-256-CCMz AES-192-CCMz AES-128-CCMzCAMELLIA-128-GCMz AES-256-CBCz AES-192-CBCz AES-128-CBCzCAMELLIA-256-CBCzCAMELLIA-128-CBCzRC4-128zDES-CBCzCAMELLIA-128-CTSz3DES-CBCzhmac-md5-etm@openssh.comzumac-64-etm@openssh.comzumac-128-etm@openssh.comzhmac-sha1-etm@openssh.comzhmac-sha2-256-etm@openssh.comzhmac-sha2-512-etm@openssh.com)zHMAC-MD5zUMAC-64zUMAC-128z HMAC-SHA1z HMAC-SHA2-256z HMAC-SHA2-512zhmac-md5zumac-64@openssh.comzumac-128@openssh.comz hmac-sha1z hmac-sha2-256z hmac-sha2-512zecdh-sha2-nistp521zecdh-sha2-nistp384zecdh-sha2-nistp256z.curve25519-sha256,curve25519-sha256@libssh.orgzdiffie-hellman-group1-sha1zdiffie-hellman-group14-sha1zdiffie-hellman-group14-sha256zdiffie-hellman-group16-sha512zdiffie-hellman-group18-sha512) zECDHE-SECP521R1-SHA2-512zECDHE-SECP384R1-SHA2-384zECDHE-SECP256R1-SHA2-256zECDHE-X25519-SHA2-256zDHE-FFDHE-1024-SHA1zDHE-FFDHE-2048-SHA1zDHE-FFDHE-2048-SHA2-256zDHE-FFDHE-4096-SHA2-512zDHE-FFDHE-8192-SHA2-512z"diffie-hellman-group-exchange-sha1z$diffie-hellman-group-exchange-sha256)zDHE-SHA1z DHE-SHA2-256z gss-gex-sha1-zgss-group1-sha1-zgss-group14-sha1-zgss-group14-sha256-zgss-nistp256-sha256-zgss-curve25519-sha256-zgss-group16-sha512-)z DHE-GSS-SHA1zDHE-GSS-FFDHE-1024-SHA1zDHE-GSS-FFDHE-2048-SHA1zDHE-GSS-FFDHE-2048-SHA2-256zECDHE-GSS-SECP256R1-SHA2-256zECDHE-GSS-X25519-SHA2-256zDHE-GSS-FFDHE-4096-SHA2-512zssh-rsazssh-dssz rsa-sha2-256z rsa-sha2-512zecdsa-sha2-nistp256zecdsa-sha2-nistp384zecdsa-sha2-nistp521z ssh-ed25519)zRSA-SHA1zDSA-SHA1z RSA-SHA2-256z RSA-SHA2-512zECDSA-SHA2-256zECDSA-SHA2-384zECDSA-SHA2-512z EDDSA-ED25519zssh-rsa-cert-v01@openssh.comzssh-dss-cert-v01@openssh.comz!rsa-sha2-256-cert-v01@openssh.comz!rsa-sha2-512-cert-v01@openssh.comz(ecdsa-sha2-nistp256-cert-v01@openssh.comz(ecdsa-sha2-nistp384-cert-v01@openssh.comz(ecdsa-sha2-nistp521-cert-v01@openssh.comz ssh-ed25519-cert-v01@openssh.comc&Cs|j}d}d}d}x>|dD]2} y|j||j| |}Wqtk rLYqXqW|rh||jjd|7}d}|jdrx>|dD]2} y|j||j| |}Wqtk rYqXqWx>|dD]2} y|j||j| |}Wqtk rYqXqW|r||jjd|7}d}d} xF|dD]8} x.|d D] } |jd ry$|j | d | } |j|| |}Wntk rYnXy"|| d | } |j| | |} Wntk rYnXx|d D]}y*|| d |d | } |j|| |}Wntk r YnXy*|| d |d | } |j| | |} Wntk rLYnXqWq4Wq"W| rz||jjd | 7}n||jjdd7}|r||jjd|7}d}x|dD]v} y|j||j | |}Wntk rYnX|jddkry|j||j | |}Wntk r$YnXqW|r\|rJ||jjd|7}||jjd|7}d}xB|dD]6} y|j||j | |}Wntk rYnXqjW|r||jjd|7}|S)Nr,ZcipherZCiphersZssh_etmZmacZMACsZ key_exchangehashZarbitrary_dh_groups-groupZGSSAPIKexAlgorithmsZGSSAPIKeyExchangenoZ KexAlgorithmsZsignZ ssh_certsrZHostKeyAlgorithmsZPubkeyAcceptedKeyTypesZCASignatureAlgorithms) Zenabledappend cipher_mapKeyError_FORMAT_STRINGformatZintegers mac_map_etmmac_mapgx_mapsign_mapsign_map_certs)clspolicy local_kx_maplocal_gss_kx_mapZ do_host_keypcfgsepsiZgssZkxhvalgr$>./usr/share/crypto-policies/python/policygenerators/openssh.pygenerate_optionsls       z!OpenSSHGenerator.generate_optionsN)__name__ __module__ __qualname__rrrrkx_mapr gss_kx_maprr classmethodr&r$r$r$r%rsrc@s6eZdZdZdddhZdZeddZeddZd S) OpenSSHClientGeneratoropensshsshzopenssh-clientz{0} {1} cCs$t|j}t|j}|j|||dS)NF)dictr*r+r&)rrrrr$r$r%generate_configs  z&OpenSSHClientGenerator.generate_configcCstjdtjsdSt\}}d}z^tj|d}|j|WdQRXytd|ddd}Wntk rz|jdYnXWdtj |X|r|jd |jd |d SdS) Nz /usr/bin/sshTwz/usr/bin/ssh -G -F z bogus654_server >/dev/null)shellz/usr/bin/ssh: Execution failedz-There is an error in OpenSSH generated policyz Policy: %sF) osaccessX_OKrfdopenwriterreprintunlink)rconfigfdpathretfr$r$r% test_configs&    z"OpenSSHClientGenerator.test_configN) r'r(r) CONFIG_NAMESCOPESrr,r1rAr$r$r$r%r-s   r-c@sReZdZdZdddhZdZdZeddZed d Z ed d Z ed dZ dS)OpenSSHServerGeneratorZ opensshserverr/r.zopenssh-serverz4systemctl try-restart sshd.service 2>/dev/null || : z -o{0}={1} cCsDt|j}t|j}|d=|d=|j|||d}|j}d|dS)NzDHE-FFDHE-1024-SHA1zDHE-GSS-FFDHE-1024-SHA1TzCRYPTO_POLICY='')r0r*r+r&rstrip)rrrrrr$r$r%r1s  z&OpenSSHServerGenerator.generate_configc Csft\}}tj|d}ytd|ddd}Wntk rN|jdYnX|rb|jddS|S) Nr2z&/usr/bin/ssh-keygen -t rsa -b 2048 -f z -N "" >/dev/nullT)r4z%/usr/bin/ssh-keygen: Execution failedz4SSH Keygen failed when testing OpenSSH server policyr)rr5r;rrr:)rZ_fdr>r?r$r$r% _test_setup s    z"OpenSSHServerGenerator._test_setupcCs|rtj|dS)N)r5r;)rr>r$r$r% _test_cleanupsz$OpenSSHServerGenerator._test_cleanupcCstjdtjsdS|j}|s"dSt\}}d}zftj|d}|j|WdQRXy td|d|ddd }Wntk r|j d YnXWdtj ||j |X|r|j d |j d |dSdS) Nz/usr/sbin/sshdTFr2r3z/usr/bin/bash -c 'source z( && /usr/sbin/sshd -T $CRYPTO_POLICY -h z -f /dev/null' >/dev/null)r4z /usr/sbin/sshd: Execution failedz4There is an error in OpenSSH server generated policyz Policy: %s) r5r6r7rGrr8r9rrr:r;rH)rr<Zhost_key_filenamer=r>r?r@r$r$r%rA#s0     z"OpenSSHServerGenerator.test_configN) r'r(r)rBrCZ RELOAD_CMDrr,r1rGrHrAr$r$r$r%rDs   rD) subprocessrrZtempfilerr5Zconfiggeneratorrrr-rDr$r$r$r%s  C(PK3]F9006policygenerators/__pycache__/krb5.cpython-36.opt-1.pycnu[3 ."dp@s ddlmZGdddeZdS))ConfigGeneratorc@sJeZdZdZddhZddddZdddd d Zed d Zed dZ dS) KRB5GeneratorZkrb5Zkerberoszcamellia256-cts-cmaczcamellia128-cts-cmac)zCAMELLIA-256-CBCzCAMELLIA-128-CBCzCAMELLIA-128-CTSzaes256-cts-hmac-sha1-96zaes256-cts-hmac-sha384-192zaes128-cts-hmac-sha1-96zaes128-cts-hmac-sha256-128)zAES-256-CBC-HMAC-SHA1zAES-256-CBC-HMAC-SHA2-384zAES-128-CBC-HMAC-SHA1zAES-128-CBC-HMAC-SHA2-256c Cs|j}d}d}|d7}d}xX|dD]L}xF|dD]:}y |j||j|d||}Wq2tk rjYq2Xq2Wq$Wx>|dD]2}y|j||j||}Wq~tk rYq~Xq~Wd|dkrd |dkr|j|d |}||d 7}|jd d kr|d7}|S)N z[libdefaults] zpermitted_enctypes = ZmacZcipher-zRC4-128zHMAC-MD5zarcfour-hmac-md5 Z min_dh_sizeizpkinit_dh_min_bits=4096 )Zenabledappendcipher_mac_mapKeyError cipher_mapZintegers)clsZpolicypsepZcfgsjir;./usr/share/crypto-policies/python/policygenerators/krb5.pygenerate_configs,   zKRB5Generator.generate_configcCsdS)NTr)r configrrr test_config<szKRB5Generator.test_configN) __name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESr r classmethodrrrrrrr s !rN)Zconfiggeneratorrrrrrrs PK3]ɨ;policygenerators/__pycache__/libreswan.cpython-36.opt-1.pycnu[3 ."d@sDddlmZmZddlmZddlZddlmZGdddeZdS))callCalledProcessError)mkstempN)ConfigGeneratorc@seZdZdZdddhZdZddddddd d d d d d ZddddddddZdddddddddddddd Zddddddddddddd Z ddddd Z ddddd!Z e d"d#Z e d$d%Ze d&d'Ze d(d)Zd*S)+LibreswanGeneratorZ libreswanZipsecZikez5systemctl try-restart ipsec.service 2>/dev/null || : Zdh19Zdh20Zdh21Zdh5Zdh14Zdh15Zdh16Zdh18) ZX448ZX25519Z SECP256R1Z SECP384R1Z SECP521R1z FFDHE-6144z FFDHE-1536z FFDHE-2048z FFDHE-3072z FFDHE-4096z FFDHE-8192Zaes256Zaes192Zaes128Z aes_gcm256Z aes_gcm192Z aes_gcm128Zchacha20_poly1305)z AES-256-CBCz AES-192-CBCz AES-128-CBCz AES-256-GCMz AES-192-GCMz AES-128-GCMzCHACHA20-POLY1305Zsha2_512Zsha2_256) zAES-256-CBC-HMAC-SHA2-512zAES-256-CBC-HMAC-SHA2-256zAES-192-CBC-HMAC-SHA2-512zAES-192-CBC-HMAC-SHA2-256zAES-128-CBC-HMAC-SHA2-256zAES-256-GCM-HMAC-SHA2-512zAES-256-GCM-HMAC-SHA2-256zAES-192-GCM-HMAC-SHA2-512zAES-192-GCM-HMAC-SHA2-256zAES-128-GCM-HMAC-SHA2-512zAES-128-GCM-HMAC-SHA2-256zCHACHA20-POLY1305-HMAC-SHA2-512zCHACHA20-POLY1305-HMAC-SHA2-256Zsha1) zAES-256-CBC-HMAC-SHA2-512zAES-192-CBC-HMAC-SHA2-512zAES-256-CBC-HMAC-SHA2-256zAES-192-CBC-HMAC-SHA2-256zAES-128-CBC-HMAC-SHA2-256zAES-256-CBC-HMAC-SHA1zAES-192-CBC-HMAC-SHA1zAES-128-CBC-HMAC-SHA1zAES-256-GCM-AEADzAES-192-GCM-AEADzAES-128-GCM-AEADzCHACHA20-POLY1305-AEADrr)AEADz HMAC-SHA2-512z HMAC-SHA2-256z HMAC-SHA1)r z HMAC-SHA2-512z HMAC-SHA1z HMAC-SHA2-256cCs||jkrdS|j|S)Nc)mac_ike_prio_map)clskeyr@./usr/share/crypto-policies/python/policygenerators/libreswan.pyZ__get_ike_priobs z!LibreswanGenerator.__get_ike_priocCs||jkrdS|j|S)Nr )mac_esp_prio_map)rrrrrZ__get_esp_priohs z!LibreswanGenerator.__get_esp_priocCsd}d}|j}d}|d}d|kr(d}n d|kr4d}|rH|d |d 7}|d 7}t|d |jd }d}x|dD]} y|j| } Wntk rwrYnX| d} d}xH|D]@} y|j| d| } Wntk rwYnX|j|| d}qW|sqr| |7} d}xJ|dD]>}y|j|}Wntk r:wYnX|j||d}qW|j| |d} |j|| |}qrW|r|d|d 7}t|d |jd }d}x|dD]} y|j| } Wntk rwYnX| d} d}xZ|D]R} y|j | d| } Wntk rwYnX| s(| } P|j|| d}qW| |7} | dddkrZq|j|| |}qW|r|d|d 7}|S)Nzconn %default ,rZprotocolZIKEv2z ikev2=insistZIKEv1z ikev2=never  z pfs=yes mac)rcipher-+groupz ike=rz esp=) Zenabledsorted!_LibreswanGenerator__get_ike_prio cipher_mapKeyErrorcipher_prf_mapappend group_map!_LibreswanGenerator__get_esp_priocipher_mac_map)rZpolicyZcfgseppsprotoZ sorted_macsZtmprcmZcomborZmmirrrrgenerate_configns      z"LibreswanGenerator.generate_configcCstjdtjsdSt\}}d}z^tj|d}|j|WdQRXytd|ddd}Wntk rz|jdYnXWdtj |X|r|jd |jd |d SdS) Nz/usr/sbin/ipsecTwz'/usr/sbin/ipsec readwriteconf --config z >/dev/null)shellz!/usr/sbin/ipsec: Execution failedz/There is an error in libreswan generated policyz Policy: %sF) osaccessX_OKrfdopenwriterrZeprintunlink)rconfigfdpathZretfrrr test_configs&    zLibreswanGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESZ RELOAD_CMDr"rr r$r r classmethodrr#r+r9rrrrrst    Pr) subprocessrrZtempfilerr/Zconfiggeneratorrrrrrrs  PK3]F9000policygenerators/__pycache__/krb5.cpython-36.pycnu[3 ."dp@s ddlmZGdddeZdS))ConfigGeneratorc@sJeZdZdZddhZddddZdddd d Zed d Zed dZ dS) KRB5GeneratorZkrb5Zkerberoszcamellia256-cts-cmaczcamellia128-cts-cmac)zCAMELLIA-256-CBCzCAMELLIA-128-CBCzCAMELLIA-128-CTSzaes256-cts-hmac-sha1-96zaes256-cts-hmac-sha384-192zaes128-cts-hmac-sha1-96zaes128-cts-hmac-sha256-128)zAES-256-CBC-HMAC-SHA1zAES-256-CBC-HMAC-SHA2-384zAES-128-CBC-HMAC-SHA1zAES-128-CBC-HMAC-SHA2-256c Cs|j}d}d}|d7}d}xX|dD]L}xF|dD]:}y |j||j|d||}Wq2tk rjYq2Xq2Wq$Wx>|dD]2}y|j||j||}Wq~tk rYq~Xq~Wd|dkrd |dkr|j|d |}||d 7}|jd d kr|d7}|S)N z[libdefaults] zpermitted_enctypes = ZmacZcipher-zRC4-128zHMAC-MD5zarcfour-hmac-md5 Z min_dh_sizeizpkinit_dh_min_bits=4096 )Zenabledappendcipher_mac_mapKeyError cipher_mapZintegers)clsZpolicypsepZcfgsjir;./usr/share/crypto-policies/python/policygenerators/krb5.pygenerate_configs,   zKRB5Generator.generate_configcCsdS)NTr)r configrrr test_config<szKRB5Generator.test_configN) __name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESr r classmethodrrrrrrr s !rN)Zconfiggeneratorrrrrrrs PK3][3policygenerators/__pycache__/openssl.cpython-36.pycnu[3 ."d@s@ddlmZmZddlmZGdddeZGdddeZdS) ) check_outputCalledProcessError)ConfigGeneratorc@seZdZdZdddhZdddddddd d d ddd d dddZddddddddZddddddddddd Zd d!d"Zd#d$d%d&d'd(Z e d)d*Z e d+d,Z e d-d.Z e d/d0Zd1S)2OpenSSLGeneratoropensslZtlsZsslz-AES256z-AES128z-SHA256z -CHACHA20z-SEEDz!IDEAz!DESz-3DESz!RC4z!RC2z !eNULL:!aNULL)z AES-256-CTRz AES-128-CTRz AES-256-GCMz AES-128-GCMz AES-256-CBCz AES-128-CBCzCHACHA20-POLY1305zSEED-CBCzIDEA-CBCzDES-CBCzRC4-40z DES40-CBCz3DES-CBCzRC4-128zRC2-CBCZNULLZkRSAZkEECDHZkPSKZkDHEPSKZkEDHZ kECDHEPSK)RSAECDHEPSKzDHE-PSKzDHE-RSAzDHE-DSSz ECDHE-PSKz-kRSAz-kEECDHz-aRSAz-aDSSz-kPSKz-kDHEPSKz -kECDHEPSK) ZANONZDHZECDHr r zDHE-RSAzDHE-DSSr zDHE-PSKz ECDHE-PSKz!MD5z-SHA1)zHMAC-MD5z HMAC-SHA1ZTLS_AES_256_GCM_SHA384ZTLS_AES_128_GCM_SHA256ZTLS_CHACHA20_POLY1305_SHA256ZTLS_AES_128_CCM_SHA256ZTLS_AES_128_CCM_8_SHA256)z AES-256-GCMz AES-128-GCMzCHACHA20-POLY1305z AES-128-CCMz AES-128-CCM8c Csd}|j}|j}|jd}|jd}|dks4|dkrB|j|d}nH|dksR|dkr`|j|d}n*|dksp|dkr~|j|d }n |j|d }x<|d D]0}y|j||j|}Wqtk rYqXqWx>|d D]2}y|j||j|}Wqtk rYqXqWx@|d D]4}y|j||j|}Wntk rBYnXqWd |d krrd|d krr|j|d}x@|dD]4}y|j||j|}Wntk rYnXq|W|j|d}|j|d}|j|d}|j|d}|S)Nr min_dh_size min_rsa_sizeiz @SECLEVEL=0iz @SECLEVEL=1i z @SECLEVEL=2z @SECLEVEL=3Z key_exchangecipherz AES-128-CCMz AES-256-CCMz-AESCCMZmacz-SHA384z -CAMELLIAz-ARIAz-AESCCM8) enabledZdisabledZintegersappendkey_exchange_mapKeyErrorkey_exchange_not_mapcipher_not_map mac_not_map)clspolicyspZipr r ir>./usr/share/crypto-policies/python/policygenerators/openssl.pygenerate_ciphersFsN            z!OpenSSLGenerator.generate_ciphersc CsLd}|j}x<|dD]0}y|j||j|}Wqtk rBYqXqW|S)Nrr)rrciphersuite_mapr)rrrrrrrrgenerate_ciphersuites{s z&OpenSSLGenerator.generate_ciphersuitescCs |j|S)N)r)rrrrrgenerate_configsz OpenSSLGenerator.generate_configc Csd}ytdd|g}Wn>tk rB|jd|jd|dStk rTdSXd|ksfd |kr|jd |jd |dSdS) NrZciphersz-There is an error in openssl generated policyz policy: %sFTsNULLsADHz0There is NULL or ADH in openssl generated policyz Policy: %s)rrZeprintOSError)rconfigoutputrrr test_configs  zOpenSSLGenerator.test_configN)__name__ __module__ __qualname__ CONFIG_NAMEZSCOPESrrrrr classmethodrrr r%rrrrr s\  5 rc@sleZdZdZdddddddd d Zd d d ddddddddddddddddddZed d!Zed"d#Zd$S)%OpenSSLConfigGeneratorZ opensslcnfrZSSLv3ZTLSv1zTLSv1.1zTLSv1.2zTLSv1.3ZDTLSv1zDTLSv1.2)NzSSL3.0zTLS1.0zTLS1.1zTLS1.2zTLS1.3zDTLS1.0zDTLS1.2zRSA+SHA1zDSA+SHA1z ECDSA+SHA1z RSA+SHA224z DSA+SHA224z ECDSA+SHA224z RSA+SHA256z DSA+SHA256z ECDSA+SHA256z RSA+SHA384z DSA+SHA384z ECDSA+SHA384z RSA+SHA512z DSA+SHA512z ECDSA+SHA512z&rsa_pss_pss_sha256:rsa_pss_rsae_sha256z&rsa_pss_pss_sha384:rsa_pss_rsae_sha384z&rsa_pss_pss_sha512:rsa_pss_rsae_sha512Zed25519Zed448)zRSA-SHA1zDSA-SHA1z ECDSA-SHA1z RSA-SHA2-224z DSA-SHA2-224zECDSA-SHA2-224z RSA-SHA2-256z DSA-SHA2-256zECDSA-SHA2-256z RSA-SHA2-384z DSA-SHA2-384zECDSA-SHA2-384z RSA-SHA2-512z DSA-SHA2-512zECDSA-SHA2-512zRSA-PSS-SHA2-256zRSA-PSS-SHA2-384zRSA-PSS-SHA2-512z EDDSA-ED25519z EDDSA-ED448cs|j}d}|j|7}|d7}|d7}|j|7}|d7}|jrd|d7}|dj|jd7}|jr|d7}|dj|jd7}|jr|d7}|dj|jd7}|jr|d7}|dj|jd7}fd d |d D}|d d j|7}|S)NzCipherString =  zCiphersuites = zTLS.MinProtocol = zTLS.MaxProtocol =zDTLS.MinProtocol =zDTLS.MaxProtocol =cs g|]}|jkrj|qSr)sign_map).0r)rrr sz:OpenSSLConfigGenerator.generate_config..ZsignzSignatureAlgorithms = :) rrrZmin_tls_version protocol_mapZmax_tls_versionZmin_dtls_versionZmax_dtls_versionjoin)rrrrZsig_algsr)rrr s.  z&OpenSSLConfigGenerator.generate_configcCsdS)NTr)rr#rrrr%sz"OpenSSLConfigGenerator.test_configN) r&r'r(r)r2r.r*r r%rrrrr+s> r+N) subprocessrrZconfiggeneratorrrr+rrrrs PK3]oc778policygenerators/__pycache__/libssh.cpython-36.opt-1.pycnu[3 ."d@s ddlmZGdddeZdS))ConfigGeneratorc@seZdZdZddhZddddddd dddddd d d dddddd dZdddddddZdddddddZdddddddddd Zd d!d"Z d#d$d%d&d'd(d)d*d+Z d,d-d.d/d0d1d2d3d+Z e d4d5Z e d6d7Zd8S)9LibsshGeneratorZlibsshZsshzaes256-gcm@openssh.comz aes256-ctrz aes192-ctrzaes128-gcm@openssh.comz aes128-ctrzchacha20-poly1305@openssh.comz aes256-cbcz aes192-cbcz aes128-cbcz3des-cbc)z AES-256-GCMz AES-256-CTRz AES-192-GCMz AES-192-CTRz AES-128-GCMz AES-128-CTRzCHACHA20-POLY1305zCAMELLIA-256-GCMz AES-256-CCMz AES-192-CCMz AES-128-CCMzCAMELLIA-128-GCMz AES-256-CBCz AES-192-CBCz AES-128-CBCzCAMELLIA-256-CBCzCAMELLIA-128-CBCzRC4-128zDES-CBCzCAMELLIA-128-CTSz3DES-CBCzhmac-sha1-etm@openssh.comzhmac-sha2-256-etm@openssh.comzhmac-sha2-512-etm@openssh.com)zHMAC-MD5zUMAC-64zUMAC-128z HMAC-SHA1z HMAC-SHA2-256z HMAC-SHA2-512z hmac-sha1z hmac-sha2-256z hmac-sha2-512zecdh-sha2-nistp521zecdh-sha2-nistp384zecdh-sha2-nistp256z.curve25519-sha256,curve25519-sha256@libssh.orgzdiffie-hellman-group1-sha1zdiffie-hellman-group14-sha1zdiffie-hellman-group14-sha256zdiffie-hellman-group16-sha512zdiffie-hellman-group18-sha512) zECDHE-SECP521R1-SHA2-512zECDHE-SECP384R1-SHA2-384zECDHE-SECP256R1-SHA2-256zECDHE-X25519-SHA2-256zDHE-FFDHE-1024-SHA1zDHE-FFDHE-2048-SHA1zDHE-FFDHE-2048-SHA2-256zDHE-FFDHE-4096-SHA2-512zDHE-FFDHE-8192-SHA2-512z"diffie-hellman-group-exchange-sha1z$diffie-hellman-group-exchange-sha256)zDHE-SHA1z DHE-SHA2-256zssh-rsazssh-dssz rsa-sha2-256z rsa-sha2-512zecdsa-sha2-nistp256zecdsa-sha2-nistp384zecdsa-sha2-nistp521z ssh-ed25519)zRSA-SHA1zDSA-SHA1z RSA-SHA2-256z RSA-SHA2-512zECDSA-SHA2-256zECDSA-SHA2-384zECDSA-SHA2-512z EDDSA-ED25519zssh-rsa-cert-v01@openssh.comzssh-dss-cert-v01@openssh.comz!rsa-sha2-256-cert-v01@openssh.comz!rsa-sha2-512-cert-v01@openssh.comz(ecdsa-sha2-nistp256-cert-v01@openssh.comz(ecdsa-sha2-nistp384-cert-v01@openssh.comz(ecdsa-sha2-nistp521-cert-v01@openssh.comz ssh-ed25519-cert-v01@openssh.comc Cs|j}d}d}d}x>|dD]2}y|j||j||}Wqtk rLYqXqW|rf|d|d7}d}|jdrx>|dD]2}y|j||j||}Wq~tk rYq~Xq~Wx>|dD]2}y|j||j||}Wqtk rYqXqW|r |d|d7}d}x|d D]}x|d D]}|jd d krvy$|j|d |} |j|| |}Wntk rtYnXxV|dD]J} y,|j|d | d |} |j|| |}Wntk rYnXqWq&WqW|r|d|d7}d}x~|dD]r}y|j||j ||}Wntk r0YnX|jdry|j||j ||}Wntk rlYnXqW|r|d|d7}|d|d7}|S)Nr,ZcipherzCiphers  Zssh_etmZmaczMACs Z key_exchangehashZarbitrary_dh_groupsr-groupzKexAlgorithms ZsignZ ssh_certszHostKeyAlgorithms zPubkeyAcceptedKeyTypes ) Zenabledappend cipher_mapKeyErrorZintegers mac_map_etmmac_mapgx_mapkx_mapsign_mapsign_map_certs) clsZpolicypZcfgsepsiZkxhvalgr=./usr/share/crypto-policies/python/policygenerators/libssh.pygenerate_config^sr      zLibsshGenerator.generate_configcCsdS)NTr)rconfigrrr test_configszLibsshGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESr r rrrrr classmethodrrrrrrr s ErN)Zconfiggeneratorrrrrrrs PK3]/$~~8policygenerators/__pycache__/gnutls.cpython-36.opt-1.pycnu[3 ."d@sDddlmZmZddlmZddlZddlmZGdddeZdS))callCalledProcessError)mkstempN)ConfigGeneratorc@seZdZdZdddhZdddddd d Zd d d dddddddd Zddddddddddd d!d"d#d$d%d&d'd(d)d*d+Zd,d-d.Zddd/d0d1d2d3d4d5d6d7d8d9d:d;d<Z d=d>d?Z d@dAdBdCddddDZ dEdFdGdHdIdJdKdLZ e dMdNZe dOdPZdQS)RGnuTLSGeneratorZgnutlsZtlsZsslz-AEADz-SHA1z-MD5z-SHA256z-SHA384z-SHA512)ZAEADz HMAC-SHA1zHMAC-MD5z HMAC-SHA2-256z HMAC-SHA2-384z HMAC-SHA2-512z -GROUP-X448z -GROUP-X25519z-GROUP-SECP256R1z-GROUP-SECP384R1z-GROUP-SECP521R1z-GROUP-FFDHE2048z-GROUP-FFDHE3072z-GROUP-FFDHE4096z-GROUP-FFDHE8192) ZX448ZX25519Z SECP256R1Z SECP384R1Z SECP521R1z FFDHE-6144z FFDHE-2048z FFDHE-3072z FFDHE-4096z FFDHE-8192z -SIGN-RSA-MD5z-SIGN-RSA-SHA1z-SIGN-DSA-SHA1z-SIGN-ECDSA-SHA1z-SIGN-RSA-SHA224z-SIGN-DSA-SHA224z-SIGN-ECDSA-SHA224z-SIGN-RSA-SHA256z-SIGN-DSA-SHA256z-SIGN-ECDSA-SHA256z-SIGN-RSA-SHA384z-SIGN-DSA-SHA384z-SIGN-ECDSA-SHA384z-SIGN-RSA-SHA512z-SIGN-DSA-SHA512z-SIGN-ECDSA-SHA512z.-SIGN-RSA-PSS-SHA256:-SIGN-RSA-PSS-RSAE-SHA256z.-SIGN-RSA-PSS-SHA384:-SIGN-RSA-PSS-RSAE-SHA384z.-SIGN-RSA-PSS-SHA512:-SIGN-RSA-PSS-RSAE-SHA512z-SIGN-EDDSA-ED448z-SIGN-EDDSA-ED25519)zRSA-MD5zRSA-SHA1zDSA-SHA1z ECDSA-SHA1z RSA-SHA2-224z DSA-SHA2-224zECDSA-SHA2-224z RSA-SHA2-256z DSA-SHA2-256zECDSA-SHA2-256z RSA-SHA2-384z DSA-SHA2-384zECDSA-SHA2-384z RSA-SHA2-512z DSA-SHA2-512zECDSA-SHA2-512zRSA-PSS-SHA2-256zRSA-PSS-SHA2-384zRSA-PSS-SHA2-512z EDDSA-ED448z EDDSA-ED25519z+SIGN-DSA-SHA1z+SIGN-RSA-SHA1)zDSA-SHA1zRSA-SHA1z -AES-256-GCMz -AES-128-GCMz -AES-256-CCMz -AES-128-CCMz -AES-256-CBCz -AES-128-CBCz-CAMELLIA-256-GCMz-CAMELLIA-128-GCMz-CAMELLIA-256-CBCz-CAMELLIA-128-CBCz-CHACHA20-POLY1305z -3DES-CBCz -ARCFOUR-128)z AES-256-CTRz AES-128-CTRz AES-256-GCMz AES-128-GCMz AES-256-CCMz AES-128-CCMz AES-256-CBCz AES-128-CBCzCAMELLIA-256-GCMzCAMELLIA-128-GCMzCAMELLIA-256-CBCzCAMELLIA-128-CBCzCHACHA20-POLY1305z3DES-CBCzRC4-128z +3DES-CBCz +ARCFOUR-128)z3DES-CBCzRC4-128z+RSAz+ECDHE-RSA:+ECDHE-ECDSAz+DHE-RSAz+DHE-DSS)ZRSAZECDHEzDHE-RSAzDHE-DSSZPSKzDHE-PSKz ECDHE-PSKz -VERS-SSL3.0z -VERS-TLS1.0z -VERS-TLS1.1z -VERS-TLS1.2z -VERS-TLS1.3z -VERS-DTLS1.0z -VERS-DTLS1.2)zSSL3.0zTLS1.0zTLS1.1zTLS1.2zTLS1.3zDTLS1.0zDTLS1.2c Cszd}|j}|j}|drb|j|d}x<|dD]0}y|j||j|}Wq.tk r\Yq.Xq.W|dr|j|d}x<|dD]0}y|j||j|}Wqtk rYqXqW|drL|j|d}x>|dD]2}y|j||j|}Wqtk rYqXqWx@|dD]4}y|j||j|}Wntk rDYnXqW|jdrd|j|d }|d r|j|d }x@|d D]4}y|j||j |}Wntk rYnXqWx@|d D]4}y|j||j |}Wntk rYnXqWx@|d D]4}y|j||j |}Wntk r8YnXqW|d r|j|d}x@|d D]4}y|j||j |}Wntk rYnXq`W|j|d}|jd}|jd}|dks|dkr|j|d}n|dks|dkr|j|d}nr|dks|dkr|j|d}nP|dks2|dkr@|j|d}n.|dksT|dkrb|j|d}n |j|d}|d7}|S)Nz SYSTEM=NONEZmacz+MAC-ALLgroupz +GROUP-ALLZsignz +SIGN-ALLZ sha1_in_certsz%VERIFY_ALLOW_SIGN_WITH_SHA1Zcipherz +CIPHER-ALLZ key_exchangeZprotocolz+VERS-ALL:-VERS-DTLS0.9z +COMP-NULL min_rsa_size min_dh_sizeiz%PROFILE_VERY_WEAKiz %PROFILE_LOWiz%PROFILE_MEDIUMi z %PROFILE_HIGHi z%PROFILE_ULTRAz%PROFILE_FUTURE ) ZenabledZdisabledappend mac_not_mapKeyError group_not_map sign_not_maplegacy_sign_mapZintegerscipher_not_mapcipher_force_mapkey_exchange_mapprotocol_not_map)clsZpolicyspZipir r r=./usr/share/crypto-policies/python/policygenerators/gnutls.pygenerate_configqs                      zGnuTLSGenerator.generate_configcCstjdtjsdSt\}}d}z^tj|d}|j|WdQRXytd|ddd}Wntk rz|jdYnXWdtj |X|r|jd |jd |d SdS) Nz/usr/bin/gnutls-cliTwz(/usr/bin/gnutls-cli -l --priority $(cat z3 | sed 's/SYSTEM=//g' | tr --delete ' ') >/dev/null)shellz%/usr/bin/gnutls-cli: Execution failedz,There is an error in gnutls generated policyz Policy: %sF) osaccessX_OKrfdopenwriterrZeprintunlink)rconfigfdpathZretfrrr test_configs&    zGnuTLSGenerator.test_configN)__name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESrrrrrrrr classmethodrr+rrrrrs  Vr) subprocessrrZtempfilerr!Zconfiggeneratorrrrrrrs  PK3]76policygenerators/__pycache__/bind.cpython-36.opt-1.pycnu[3 ."d@sDddlmZmZddlmZddlZddlmZGdddeZdS)) check_outputCalledProcessError)mkstempN)ConfigGeneratorc @sXeZdZdZddhZdZdddddddd dZdddddZeddZ eddZ dS)! BindGeneratorZbindZdnssecz>systemctl try-reload-or-restart bind.service 2>/dev/null || : DSANSEC3DSARSASHA1 NSEC3RSASHA1 RSASHA256 RSASHA512ECDSAP256SHA256ECDSAP384SHA384ED25519ED448)zDSA-SHA1zRSA-SHA1z RSA-SHA2-256z RSA-SHA2-512zECDSA-SHA2-256zECDSA-SHA2-384z EDDSA-ED25519z EDDSA-ED448zSHA-1zSHA-256zSHA-384GOST)ZSHA1zSHA2-256zSHA2-384rc Cs |j}d}|d7}|d7}|d7}xL|dD]@}y&x |j|D]}||d7}q>WWq,tk rjYq,Xq,Wd|dkrd|d kr|d 7}d |dkrd |d kr|d 7}|d7}|d7}x>|dD]2}y||j|d7}Wqtk rYqXqW|d7}|S)Nzdisable-algorithms "." { zRSAMD5; z ECCGOST; Zsignz; z ECDSA-SHA256Z SECP256R1groupzECDSAP256SHA256; z ECDSA-SHA384Z SECP384R1zECDSAP384SHA384; z}; zdisable-ds-digests "." { hash)Zdisabled sign_not_mapKeyError hash_not_map)clsZpolicyZipsiZ disabled_signr;./usr/share/crypto-policies/python/policygenerators/bind.pygenerate_config%s0  zBindGenerator.generate_configcCst\}}ztj|d$}|jd|j||jdWdQRXytd|g}Wn>tk r~|jd|jd|dStk rYnXWdtj|XdS) Nwz options { z }; z/usr/sbin/named-checkconfz*There is an error in bind generated policyz Policy: %sFT) rosfdopenwriterrZeprintOSErrorunlink)rconfigfdpathf_rrr test_configCs       zBindGenerator.test_configN)rr )r r )r )r )r)r)r)r) __name__ __module__ __qualname__Z CONFIG_NAMEZSCOPESZ RELOAD_CMDrr classmethodrr*rrrrr s" r) subprocessrrZtempfilerr Zconfiggeneratorrrrrrrs  PK3]1#G4policygenerators/__pycache__/__init__.cpython-36.pycnu[3 ."dE @sddlmZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z ddlmZdd lmZdd lmZdd lmZd d dddddddddg ZdS)) BindGenerator)GnuTLSGenerator) JavaGenerator) KRB5Generator)LibreswanGenerator)LibsshGenerator) NSSGenerator)OpenSSHClientGenerator)OpenSSHServerGenerator)OpenSSLConfigGenerator)OpenSSLGeneratorrrrrrrrr r r r N)ZbindrZgnutlsrjavarZkrb5rZ libreswanrZlibsshrZnssrZopensshr r Zopensslr r __all__rr?./usr/share/crypto-policies/python/policygenerators/__init__.pys*           PK3]b!9policygenerators/__pycache__/openssh.cpython-36.opt-1.pycnu[3 ."d @sdddlmZmZddlmZddlZddlmZGdddeZGdd d eZ Gd d d eZ dS) )callCalledProcessError)mkstempN)ConfigGeneratorc@seZdZdZdddddddddddddd d dddddd d Zd ddddddZdddddddZddddddd d!d"d# Zd$d%d&Zd'd(d)d*d+d,d-d.Z d/d0d1d2d3d4d5d6d7Z d8d9d:d;dd?d7Z e d@dAZ dBS)COpenSSHGeneratorzaes256-gcm@openssh.comz aes256-ctrz aes192-ctrzaes128-gcm@openssh.comz aes128-ctrzchacha20-poly1305@openssh.comz aes256-cbcz aes192-cbcz aes128-cbcz3des-cbc)z AES-256-GCMz AES-256-CTRz AES-192-GCMz AES-192-CTRz AES-128-GCMz AES-128-CTRzCHACHA20-POLY1305zCAMELLIA-256-GCMz AES-256-CCMz AES-192-CCMz AES-128-CCMzCAMELLIA-128-GCMz AES-256-CBCz AES-192-CBCz AES-128-CBCzCAMELLIA-256-CBCzCAMELLIA-128-CBCzRC4-128zDES-CBCzCAMELLIA-128-CTSz3DES-CBCzhmac-md5-etm@openssh.comzumac-64-etm@openssh.comzumac-128-etm@openssh.comzhmac-sha1-etm@openssh.comzhmac-sha2-256-etm@openssh.comzhmac-sha2-512-etm@openssh.com)zHMAC-MD5zUMAC-64zUMAC-128z HMAC-SHA1z HMAC-SHA2-256z HMAC-SHA2-512zhmac-md5zumac-64@openssh.comzumac-128@openssh.comz hmac-sha1z hmac-sha2-256z hmac-sha2-512zecdh-sha2-nistp521zecdh-sha2-nistp384zecdh-sha2-nistp256z.curve25519-sha256,curve25519-sha256@libssh.orgzdiffie-hellman-group1-sha1zdiffie-hellman-group14-sha1zdiffie-hellman-group14-sha256zdiffie-hellman-group16-sha512zdiffie-hellman-group18-sha512) zECDHE-SECP521R1-SHA2-512zECDHE-SECP384R1-SHA2-384zECDHE-SECP256R1-SHA2-256zECDHE-X25519-SHA2-256zDHE-FFDHE-1024-SHA1zDHE-FFDHE-2048-SHA1zDHE-FFDHE-2048-SHA2-256zDHE-FFDHE-4096-SHA2-512zDHE-FFDHE-8192-SHA2-512z"diffie-hellman-group-exchange-sha1z$diffie-hellman-group-exchange-sha256)zDHE-SHA1z DHE-SHA2-256z gss-gex-sha1-zgss-group1-sha1-zgss-group14-sha1-zgss-group14-sha256-zgss-nistp256-sha256-zgss-curve25519-sha256-zgss-group16-sha512-)z DHE-GSS-SHA1zDHE-GSS-FFDHE-1024-SHA1zDHE-GSS-FFDHE-2048-SHA1zDHE-GSS-FFDHE-2048-SHA2-256zECDHE-GSS-SECP256R1-SHA2-256zECDHE-GSS-X25519-SHA2-256zDHE-GSS-FFDHE-4096-SHA2-512zssh-rsazssh-dssz rsa-sha2-256z rsa-sha2-512zecdsa-sha2-nistp256zecdsa-sha2-nistp384zecdsa-sha2-nistp521z ssh-ed25519)zRSA-SHA1zDSA-SHA1z RSA-SHA2-256z RSA-SHA2-512zECDSA-SHA2-256zECDSA-SHA2-384zECDSA-SHA2-512z EDDSA-ED25519zssh-rsa-cert-v01@openssh.comzssh-dss-cert-v01@openssh.comz!rsa-sha2-256-cert-v01@openssh.comz!rsa-sha2-512-cert-v01@openssh.comz(ecdsa-sha2-nistp256-cert-v01@openssh.comz(ecdsa-sha2-nistp384-cert-v01@openssh.comz(ecdsa-sha2-nistp521-cert-v01@openssh.comz ssh-ed25519-cert-v01@openssh.comc&Cs|j}d}d}d}x>|dD]2} y|j||j| |}Wqtk rLYqXqW|rh||jjd|7}d}|jdrx>|dD]2} y|j||j| |}Wqtk rYqXqWx>|dD]2} y|j||j| |}Wqtk rYqXqW|r||jjd|7}d}d} xF|dD]8} x.|d D] } |jd ry$|j | d | } |j|| |}Wntk rYnXy"|| d | } |j| | |} Wntk rYnXx|d D]}y*|| d |d | } |j|| |}Wntk r YnXy*|| d |d | } |j| | |} Wntk rLYnXqWq4Wq"W| rz||jjd | 7}n||jjdd7}|r||jjd|7}d}x|dD]v} y|j||j | |}Wntk rYnX|jddkry|j||j | |}Wntk r$YnXqW|r\|rJ||jjd|7}||jjd|7}d}xB|dD]6} y|j||j | |}Wntk rYnXqjW|r||jjd|7}|S)Nr,ZcipherZCiphersZssh_etmZmacZMACsZ key_exchangehashZarbitrary_dh_groups-groupZGSSAPIKexAlgorithmsZGSSAPIKeyExchangenoZ KexAlgorithmsZsignZ ssh_certsrZHostKeyAlgorithmsZPubkeyAcceptedKeyTypesZCASignatureAlgorithms) Zenabledappend cipher_mapKeyError_FORMAT_STRINGformatZintegers mac_map_etmmac_mapgx_mapsign_mapsign_map_certs)clspolicy local_kx_maplocal_gss_kx_mapZ do_host_keypcfgsepsiZgssZkxhvalgr$>./usr/share/crypto-policies/python/policygenerators/openssh.pygenerate_optionsls       z!OpenSSHGenerator.generate_optionsN)__name__ __module__ __qualname__rrrrkx_mapr gss_kx_maprr classmethodr&r$r$r$r%rsrc@s6eZdZdZdddhZdZeddZeddZd S) OpenSSHClientGeneratoropensshsshzopenssh-clientz{0} {1} cCs$t|j}t|j}|j|||dS)NF)dictr*r+r&)rrrrr$r$r%generate_configs  z&OpenSSHClientGenerator.generate_configcCstjdtjsdSt\}}d}z^tj|d}|j|WdQRXytd|ddd}Wntk rz|jdYnXWdtj |X|r|jd |jd |d SdS) Nz /usr/bin/sshTwz/usr/bin/ssh -G -F z bogus654_server >/dev/null)shellz/usr/bin/ssh: Execution failedz-There is an error in OpenSSH generated policyz Policy: %sF) osaccessX_OKrfdopenwriterreprintunlink)rconfigfdpathretfr$r$r% test_configs&    z"OpenSSHClientGenerator.test_configN) r'r(r) CONFIG_NAMESCOPESrr,r1rAr$r$r$r%r-s   r-c@sReZdZdZdddhZdZdZeddZed d Z ed d Z ed dZ dS)OpenSSHServerGeneratorZ opensshserverr/r.zopenssh-serverz4systemctl try-restart sshd.service 2>/dev/null || : z -o{0}={1} cCsDt|j}t|j}|d=|d=|j|||d}|j}d|dS)NzDHE-FFDHE-1024-SHA1zDHE-GSS-FFDHE-1024-SHA1TzCRYPTO_POLICY='')r0r*r+r&rstrip)rrrrrr$r$r%r1s  z&OpenSSHServerGenerator.generate_configc Csft\}}tj|d}ytd|ddd}Wntk rN|jdYnX|rb|jddS|S) Nr2z&/usr/bin/ssh-keygen -t rsa -b 2048 -f z -N "" >/dev/nullT)r4z%/usr/bin/ssh-keygen: Execution failedz4SSH Keygen failed when testing OpenSSH server policyr)rr5r;rrr:)rZ_fdr>r?r$r$r% _test_setup s    z"OpenSSHServerGenerator._test_setupcCs|rtj|dS)N)r5r;)rr>r$r$r% _test_cleanupsz$OpenSSHServerGenerator._test_cleanupcCstjdtjsdS|j}|s"dSt\}}d}zftj|d}|j|WdQRXy td|d|ddd }Wntk r|j d YnXWdtj ||j |X|r|j d |j d |dSdS) Nz/usr/sbin/sshdTFr2r3z/usr/bin/bash -c 'source z( && /usr/sbin/sshd -T $CRYPTO_POLICY -h z -f /dev/null' >/dev/null)r4z /usr/sbin/sshd: Execution failedz4There is an error in OpenSSH server generated policyz Policy: %s) r5r6r7rGrr8r9rrr:r;rH)rr<Zhost_key_filenamer=r>r?r@r$r$r%rA#s0     z"OpenSSHServerGenerator.test_configN) r'r(r)rBrCZ RELOAD_CMDrr,r1rGrHrAr$r$r$r%rDs   rD) subprocessrrZtempfilerr5Zconfiggeneratorrrr-rDr$r$r$r%s  C(PK3]'pppolicygenerators/krb5.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from .configgenerator import ConfigGenerator class KRB5Generator(ConfigGenerator): CONFIG_NAME = 'krb5' SCOPES = {'kerberos', 'krb5'} cipher_map = { 'CAMELLIA-256-CBC':'camellia256-cts-cmac', 'CAMELLIA-128-CBC':'camellia128-cts-cmac', 'CAMELLIA-128-CTS':'camellia128-cts-cmac' } cipher_mac_map = { 'AES-256-CBC-HMAC-SHA1':'aes256-cts-hmac-sha1-96', 'AES-256-CBC-HMAC-SHA2-384':'aes256-cts-hmac-sha384-192', 'AES-128-CBC-HMAC-SHA1':'aes128-cts-hmac-sha1-96', 'AES-128-CBC-HMAC-SHA2-256':'aes128-cts-hmac-sha256-128', # 'RC4-128-HMAC-MD5':'arcfour-hmac-md5' # forced last, see below } @classmethod def generate_config(cls, policy): p = policy.enabled sep = ' ' cfg = '[libdefaults]\n' cfg += 'permitted_enctypes = ' s = '' for j in p['mac']: for i in p['cipher']: try: s = cls.append(s, cls.cipher_mac_map[i + '-' + j], sep) except KeyError: pass for i in p['cipher']: try: s = cls.append(s, cls.cipher_map[i], sep) except KeyError: pass if 'RC4-128' in p['cipher'] and 'HMAC-MD5' in p['mac']: s = cls.append(s, 'arcfour-hmac-md5', sep) cfg += s + '\n' # By default libkrb5 sets the min_bits to 2048, don't # go lower than that. if policy.integers['min_dh_size'] > 2048: # $string .= "pkinit_dh_min_bits=$min_dh_size\n"; # krb5.conf only accepts 2048 or 4096 cfg += 'pkinit_dh_min_bits=4096\n' return cfg @classmethod def test_config(cls, config): # pylint: disable=unused-argument return True PK3]hiPpolicygenerators/gnutls.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from subprocess import call, CalledProcessError from tempfile import mkstemp import os from .configgenerator import ConfigGenerator class GnuTLSGenerator(ConfigGenerator): CONFIG_NAME = 'gnutls' SCOPES = {'tls', 'ssl', 'gnutls'} mac_not_map = { 'AEAD':'-AEAD', 'HMAC-SHA1':'-SHA1', 'HMAC-MD5':'-MD5', 'HMAC-SHA2-256':'-SHA256', 'HMAC-SHA2-384':'-SHA384', 'HMAC-SHA2-512':'-SHA512' } group_not_map = { 'X448':'-GROUP-X448', 'X25519':'-GROUP-X25519', 'SECP256R1':'-GROUP-SECP256R1', 'SECP384R1':'-GROUP-SECP384R1', 'SECP521R1':'-GROUP-SECP521R1', 'FFDHE-6144':'', 'FFDHE-2048':'-GROUP-FFDHE2048', 'FFDHE-3072':'-GROUP-FFDHE3072', 'FFDHE-4096':'-GROUP-FFDHE4096', 'FFDHE-8192':'-GROUP-FFDHE8192' } sign_not_map = { 'RSA-MD5':'-SIGN-RSA-MD5', 'RSA-SHA1':'-SIGN-RSA-SHA1', 'DSA-SHA1':'-SIGN-DSA-SHA1', 'ECDSA-SHA1':'-SIGN-ECDSA-SHA1', 'RSA-SHA2-224':'-SIGN-RSA-SHA224', 'DSA-SHA2-224':'-SIGN-DSA-SHA224', 'ECDSA-SHA2-224':'-SIGN-ECDSA-SHA224', 'RSA-SHA2-256':'-SIGN-RSA-SHA256', 'DSA-SHA2-256':'-SIGN-DSA-SHA256', 'ECDSA-SHA2-256':'-SIGN-ECDSA-SHA256', 'RSA-SHA2-384':'-SIGN-RSA-SHA384', 'DSA-SHA2-384':'-SIGN-DSA-SHA384', 'ECDSA-SHA2-384':'-SIGN-ECDSA-SHA384', 'RSA-SHA2-512':'-SIGN-RSA-SHA512', 'DSA-SHA2-512':'-SIGN-DSA-SHA512', 'ECDSA-SHA2-512':'-SIGN-ECDSA-SHA512', # These are only available under 3.6.3+ 'RSA-PSS-SHA2-256':'-SIGN-RSA-PSS-SHA256:-SIGN-RSA-PSS-RSAE-SHA256', 'RSA-PSS-SHA2-384':'-SIGN-RSA-PSS-SHA384:-SIGN-RSA-PSS-RSAE-SHA384', 'RSA-PSS-SHA2-512':'-SIGN-RSA-PSS-SHA512:-SIGN-RSA-PSS-RSAE-SHA512', 'EDDSA-ED448':'-SIGN-EDDSA-ED448', 'EDDSA-ED25519':'-SIGN-EDDSA-ED25519' } legacy_sign_map = { 'DSA-SHA1':'+SIGN-DSA-SHA1', 'RSA-SHA1':'+SIGN-RSA-SHA1' } cipher_not_map = { 'AES-256-CTR':'', 'AES-128-CTR':'', 'AES-256-GCM':'-AES-256-GCM', 'AES-128-GCM':'-AES-128-GCM', 'AES-256-CCM':'-AES-256-CCM', 'AES-128-CCM':'-AES-128-CCM', 'AES-256-CBC':'-AES-256-CBC', 'AES-128-CBC':'-AES-128-CBC', 'CAMELLIA-256-GCM':'-CAMELLIA-256-GCM', 'CAMELLIA-128-GCM':'-CAMELLIA-128-GCM', 'CAMELLIA-256-CBC':'-CAMELLIA-256-CBC', 'CAMELLIA-128-CBC':'-CAMELLIA-128-CBC', 'CHACHA20-POLY1305':'-CHACHA20-POLY1305', '3DES-CBC':'-3DES-CBC', 'RC4-128':'-ARCFOUR-128' } cipher_force_map = { '3DES-CBC':'+3DES-CBC', 'RC4-128':'+ARCFOUR-128' } key_exchange_map = { 'RSA':'+RSA', 'ECDHE':'+ECDHE-RSA:+ECDHE-ECDSA', 'DHE-RSA':'+DHE-RSA', 'DHE-DSS':'+DHE-DSS', 'PSK':'', 'DHE-PSK':'', 'ECDHE-PSK':'' } protocol_not_map = { 'SSL3.0':'-VERS-SSL3.0', 'TLS1.0':'-VERS-TLS1.0', 'TLS1.1':'-VERS-TLS1.1', 'TLS1.2':'-VERS-TLS1.2', 'TLS1.3':'-VERS-TLS1.3', 'DTLS1.0':'-VERS-DTLS1.0', 'DTLS1.2':'-VERS-DTLS1.2' } @classmethod def generate_config(cls, policy): s = 'SYSTEM=NONE' p = policy.enabled ip = policy.disabled if p['mac']: s = cls.append(s, '+MAC-ALL') for i in ip['mac']: try: s = cls.append(s, cls.mac_not_map[i]) except KeyError: pass if p['group']: s = cls.append(s, '+GROUP-ALL') for i in ip['group']: try: s = cls.append(s, cls.group_not_map[i]) except KeyError: pass if p['sign']: s = cls.append(s, '+SIGN-ALL') for i in ip['sign']: try: s = cls.append(s, cls.sign_not_map[i]) except KeyError: pass for i in p['sign']: try: s = cls.append(s, cls.legacy_sign_map[i]) except KeyError: pass if policy.integers['sha1_in_certs']: s = cls.append(s, '%VERIFY_ALLOW_SIGN_WITH_SHA1') if p['cipher']: s = cls.append(s, '+CIPHER-ALL') for i in ip['cipher']: try: s = cls.append(s, cls.cipher_not_map[i]) except KeyError: pass for i in p['cipher']: try: s = cls.append(s, cls.cipher_force_map[i]) except KeyError: pass for i in p['key_exchange']: try: s = cls.append(s, cls.key_exchange_map[i]) except KeyError: pass if p['protocol']: s = cls.append(s, '+VERS-ALL:-VERS-DTLS0.9') for i in ip['protocol']: try: s = cls.append(s, cls.protocol_not_map[i]) except KeyError: pass s = cls.append(s, '+COMP-NULL') # We cannot separate RSA strength from DH params. min_rsa_size = policy.integers['min_rsa_size'] min_dh_size = policy.integers['min_dh_size'] if min_dh_size <= 768 or min_rsa_size <= 768: s = cls.append(s, '%PROFILE_VERY_WEAK') elif min_dh_size <= 1024 or min_rsa_size <= 1024: s = cls.append(s, '%PROFILE_LOW') elif min_dh_size <= 2048 or min_rsa_size <= 2048: s = cls.append(s, '%PROFILE_MEDIUM') elif min_dh_size <= 3072 or min_rsa_size <= 3072: s = cls.append(s, '%PROFILE_HIGH') elif min_dh_size <= 8192 or min_rsa_size <= 8192: s = cls.append(s, '%PROFILE_ULTRA') else: s = cls.append(s, '%PROFILE_FUTURE') s += '\n' return s @classmethod def test_config(cls, config): if not os.access('/usr/bin/gnutls-cli', os.X_OK): return True fd, path = mkstemp() ret = 255 try: with os.fdopen(fd, 'w') as f: f.write(config) try: ret = call('/usr/bin/gnutls-cli -l --priority $(cat ' + path + ' | sed \'s/SYSTEM=//g\' | tr --delete \'\n\') >/dev/null', shell=True) except CalledProcessError: cls.eprint("/usr/bin/gnutls-cli: Execution failed") finally: os.unlink(path) if ret: cls.eprint("There is an error in gnutls generated policy") cls.eprint("Policy:\n%s" % config) return False return True PK3] 6@policygenerators/libreswan.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from subprocess import call, CalledProcessError from tempfile import mkstemp import os from .configgenerator import ConfigGenerator class LibreswanGenerator(ConfigGenerator): CONFIG_NAME = 'libreswan' SCOPES = {'ipsec', 'ike', 'libreswan'} RELOAD_CMD = 'systemctl try-restart ipsec.service 2>/dev/null || :\n' group_map = { 'X448':'', 'X25519':'', # Disabled for now as it cannot be prioritized over others # 'X25519':'dh31', 'SECP256R1':'dh19', 'SECP384R1':'dh20', 'SECP521R1':'dh21', 'FFDHE-6144':'', 'FFDHE-1536':'dh5', 'FFDHE-2048':'dh14', 'FFDHE-3072':'dh15', 'FFDHE-4096':'dh16', 'FFDHE-8192':'dh18' } cipher_map = { 'AES-256-CBC':'aes256', 'AES-192-CBC':'aes192', 'AES-128-CBC':'aes128', 'AES-256-GCM':'aes_gcm256', 'AES-192-GCM':'aes_gcm192', 'AES-128-GCM':'aes_gcm128', 'CHACHA20-POLY1305':'chacha20_poly1305' # Unused for IKEv2 # '3DES-CBC':'3des' } cipher_prf_map = { 'AES-256-CBC-HMAC-SHA2-512':'sha2_512', 'AES-256-CBC-HMAC-SHA2-256':'sha2_256', 'AES-192-CBC-HMAC-SHA2-512':'sha2_512', 'AES-192-CBC-HMAC-SHA2-256':'sha2_256', 'AES-128-CBC-HMAC-SHA2-256':'sha2_256', # Not needed for IKEv2 # 'AES-256-CBC-HMAC-SHA1':'sha1', # 'AES-128-CBC-HMAC-SHA1':'sha1', 'AES-256-GCM-HMAC-SHA2-512':'sha2_512', 'AES-256-GCM-HMAC-SHA2-256':'sha2_256', 'AES-192-GCM-HMAC-SHA2-512':'sha2_512', 'AES-192-GCM-HMAC-SHA2-256':'sha2_256', 'AES-128-GCM-HMAC-SHA2-512':'sha2_512', 'AES-128-GCM-HMAC-SHA2-256':'sha2_256', 'CHACHA20-POLY1305-HMAC-SHA2-512':'sha2_512', 'CHACHA20-POLY1305-HMAC-SHA2-256':'sha2_256' # '3DES-CBC-HMAC-SHA1':'sha1' } cipher_mac_map = { 'AES-256-CBC-HMAC-SHA2-512':'sha2_512', 'AES-192-CBC-HMAC-SHA2-512':'sha2_512', 'AES-256-CBC-HMAC-SHA2-256':'sha2_256', 'AES-192-CBC-HMAC-SHA2-256':'sha2_256', 'AES-128-CBC-HMAC-SHA2-256':'sha2_256', 'AES-256-CBC-HMAC-SHA1':'sha1', 'AES-192-CBC-HMAC-SHA1':'sha1', 'AES-128-CBC-HMAC-SHA1':'sha1', 'AES-256-GCM-AEAD':'', 'AES-192-GCM-AEAD':'', 'AES-128-GCM-AEAD':'', 'CHACHA20-POLY1305-AEAD':'' # '3DES-CBC-HMAC-SHA1':'3des-sha1' } mac_ike_prio_map = { 'AEAD':0, 'HMAC-SHA2-512':1, 'HMAC-SHA2-256':2, 'HMAC-SHA1':3 } mac_esp_prio_map = { 'AEAD':0, 'HMAC-SHA2-512':1, 'HMAC-SHA1':2, 'HMAC-SHA2-256':3 } @classmethod def __get_ike_prio(cls, key): if key not in cls.mac_ike_prio_map: return 99 return cls.mac_ike_prio_map[key] @classmethod def __get_esp_prio(cls, key): if key not in cls.mac_esp_prio_map: return 99 return cls.mac_esp_prio_map[key] @classmethod def generate_config(cls, policy): cfg = 'conn %default\n' sep = ',' p = policy.enabled s = '' proto = p['protocol'] if 'IKEv2' in proto: s = 'ikev2=insist' elif 'IKEv1' in proto: # and 'IKEv2' not in proto s = 'ikev2=never' if s: cfg += '\t' + s + '\n' cfg += '\tpfs=yes\n' sorted_macs = sorted(p['mac'], key=cls.__get_ike_prio) tmp = '' for cipher in p['cipher']: try: cm = cls.cipher_map[cipher] except KeyError: continue combo = cm + '-' s = '' for mac in sorted_macs: try: mm = cls.cipher_prf_map[cipher + '-' + mac] except KeyError: continue s = cls.append(s, mm, '+') if not s: continue combo += s s = '' for i in p['group']: try: group = cls.group_map[i] except KeyError: continue s = cls.append(s, group, '+') combo = cls.append(combo, s, '-') tmp = cls.append(tmp, combo, sep) if tmp: cfg += '\tike=' + tmp + '\n' sorted_macs = sorted(p['mac'], key=cls.__get_esp_prio) tmp = '' for cipher in p['cipher']: try: cm = cls.cipher_map[cipher] except KeyError: continue combo = cm + '-' s = '' for mac in sorted_macs: try: mm = cls.cipher_mac_map[cipher + '-' + mac] except KeyError: continue if not mm: # Special handling for AEAD combo = cm break s = cls.append(s, mm, '+') combo += s if combo[-1:] == '-': continue tmp = cls.append(tmp, combo, sep) if tmp: cfg += '\tesp=' + tmp + '\n' return cfg @classmethod def test_config(cls, config): if not os.access('/usr/sbin/ipsec', os.X_OK): return True fd, path = mkstemp() ret = 255 try: with os.fdopen(fd, 'w') as f: f.write(config) try: ret = call('/usr/sbin/ipsec readwriteconf --config ' + path + ' >/dev/null', shell=True) except CalledProcessError: cls.eprint("/usr/sbin/ipsec: Execution failed") finally: os.unlink(path) if ret: cls.eprint("There is an error in libreswan generated policy") cls.eprint("Policy:\n%s" % config) return False return True PK3] policygenerators/openssh.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from subprocess import call, CalledProcessError from tempfile import mkstemp import os from .configgenerator import ConfigGenerator class OpenSSHGenerator(ConfigGenerator): _FORMAT_STRING = '' cipher_map = { 'AES-256-GCM':'aes256-gcm@openssh.com', 'AES-256-CTR':'aes256-ctr', 'AES-192-GCM':'', # not supported 'AES-192-CTR':'aes192-ctr', 'AES-128-GCM':'aes128-gcm@openssh.com', 'AES-128-CTR':'aes128-ctr', 'CHACHA20-POLY1305':'chacha20-poly1305@openssh.com', 'CAMELLIA-256-GCM':'', 'AES-256-CCM':'', 'AES-192-CCM':'', 'AES-128-CCM':'', 'CAMELLIA-128-GCM':'', 'AES-256-CBC':'aes256-cbc', 'AES-192-CBC':'aes192-cbc', 'AES-128-CBC':'aes128-cbc', 'CAMELLIA-256-CBC':'', 'CAMELLIA-128-CBC':'', 'RC4-128':'', 'DES-CBC':'', 'CAMELLIA-128-CTS':'', '3DES-CBC':'3des-cbc' } mac_map_etm = { 'HMAC-MD5':'hmac-md5-etm@openssh.com', 'UMAC-64':'umac-64-etm@openssh.com', 'UMAC-128':'umac-128-etm@openssh.com', 'HMAC-SHA1':'hmac-sha1-etm@openssh.com', 'HMAC-SHA2-256':'hmac-sha2-256-etm@openssh.com', 'HMAC-SHA2-512':'hmac-sha2-512-etm@openssh.com' } mac_map = { 'HMAC-MD5':'hmac-md5', 'UMAC-64':'umac-64@openssh.com', 'UMAC-128':'umac-128@openssh.com', 'HMAC-SHA1':'hmac-sha1', 'HMAC-SHA2-256':'hmac-sha2-256', 'HMAC-SHA2-512':'hmac-sha2-512' } kx_map = { 'ECDHE-SECP521R1-SHA2-512':'ecdh-sha2-nistp521', 'ECDHE-SECP384R1-SHA2-384':'ecdh-sha2-nistp384', 'ECDHE-SECP256R1-SHA2-256':'ecdh-sha2-nistp256', 'ECDHE-X25519-SHA2-256':'curve25519-sha256,curve25519-sha256@libssh.org', 'DHE-FFDHE-1024-SHA1':'diffie-hellman-group1-sha1', 'DHE-FFDHE-2048-SHA1':'diffie-hellman-group14-sha1', 'DHE-FFDHE-2048-SHA2-256':'diffie-hellman-group14-sha256', 'DHE-FFDHE-4096-SHA2-512':'diffie-hellman-group16-sha512', 'DHE-FFDHE-8192-SHA2-512':'diffie-hellman-group18-sha512', } gx_map = { 'DHE-SHA1':'diffie-hellman-group-exchange-sha1', 'DHE-SHA2-256':'diffie-hellman-group-exchange-sha256', } gss_kx_map = { 'DHE-GSS-SHA1':'gss-gex-sha1-', 'DHE-GSS-FFDHE-1024-SHA1':'gss-group1-sha1-', 'DHE-GSS-FFDHE-2048-SHA1':'gss-group14-sha1-', 'DHE-GSS-FFDHE-2048-SHA2-256':'gss-group14-sha256-', 'ECDHE-GSS-SECP256R1-SHA2-256':'gss-nistp256-sha256-', 'ECDHE-GSS-X25519-SHA2-256':'gss-curve25519-sha256-', 'DHE-GSS-FFDHE-4096-SHA2-512':'gss-group16-sha512-', } sign_map = { 'RSA-SHA1':'ssh-rsa', 'DSA-SHA1':'ssh-dss', 'RSA-SHA2-256':'rsa-sha2-256', 'RSA-SHA2-512':'rsa-sha2-512', 'ECDSA-SHA2-256':'ecdsa-sha2-nistp256', 'ECDSA-SHA2-384':'ecdsa-sha2-nistp384', 'ECDSA-SHA2-512':'ecdsa-sha2-nistp521', 'EDDSA-ED25519':'ssh-ed25519', } sign_map_certs = { 'RSA-SHA1':'ssh-rsa-cert-v01@openssh.com', 'DSA-SHA1':'ssh-dss-cert-v01@openssh.com', 'RSA-SHA2-256':'rsa-sha2-256-cert-v01@openssh.com', 'RSA-SHA2-512':'rsa-sha2-512-cert-v01@openssh.com', 'ECDSA-SHA2-256':'ecdsa-sha2-nistp256-cert-v01@openssh.com', 'ECDSA-SHA2-384':'ecdsa-sha2-nistp384-cert-v01@openssh.com', 'ECDSA-SHA2-512':'ecdsa-sha2-nistp521-cert-v01@openssh.com', 'EDDSA-ED25519':'ssh-ed25519-cert-v01@openssh.com', } @classmethod def generate_options(cls, policy, local_kx_map, local_gss_kx_map, do_host_key): p = policy.enabled cfg = '' sep = ',' s = '' for i in p['cipher']: try: s = cls.append(s, cls.cipher_map[i], sep) except KeyError: pass if s: cfg += cls._FORMAT_STRING.format('Ciphers', s) s = '' if policy.integers['ssh_etm']: for i in p['mac']: try: s = cls.append(s, cls.mac_map_etm[i], sep) except KeyError: pass for i in p['mac']: try: s = cls.append(s, cls.mac_map[i], sep) except KeyError: pass if s: cfg += cls._FORMAT_STRING.format('MACs', s) s = '' gss = '' for kx in p['key_exchange']: for h in p['hash']: if policy.integers['arbitrary_dh_groups']: try: val = cls.gx_map[kx + '-' + h] s = cls.append(s, val, sep) except KeyError: pass try: val = local_gss_kx_map[kx + '-' + h] gss = cls.append(gss, val, sep) except KeyError: pass for g in p['group']: try: val = local_kx_map[kx + '-' + g + '-' + h] s = cls.append(s, val, sep) except KeyError: pass try: val = local_gss_kx_map[kx + '-' + g + '-' + h] gss = cls.append(gss, val, sep) except KeyError: pass if gss: cfg += cls._FORMAT_STRING.format('GSSAPIKexAlgorithms', gss) else: cfg += cls._FORMAT_STRING.format('GSSAPIKeyExchange', 'no') if s: cfg += cls._FORMAT_STRING.format('KexAlgorithms', s) s = '' for i in p['sign']: try: s = cls.append(s, cls.sign_map[i], sep) except KeyError: pass if policy.integers['ssh_certs'] == 1: try: s = cls.append(s, cls.sign_map_certs[i], sep) except KeyError: pass if s: # As OpenSSH currently ignores existing known host # entries with this setting we cannot use it on client. # Otherwise we could break existing users. if do_host_key: cfg += cls._FORMAT_STRING.format('HostKeyAlgorithms', s) cfg += cls._FORMAT_STRING.format('PubkeyAcceptedKeyTypes', s) s = '' for i in p['sign']: try: s = cls.append(s, cls.sign_map[i], sep) except KeyError: pass if s: cfg += cls._FORMAT_STRING.format('CASignatureAlgorithms', s) return cfg class OpenSSHClientGenerator(OpenSSHGenerator): CONFIG_NAME = 'openssh' SCOPES = {'ssh', 'openssh', 'openssh-client'} _FORMAT_STRING = '{0} {1}\n' @classmethod def generate_config(cls, policy): local_kx_map = dict(cls.kx_map) local_gss_kx_map = dict(cls.gss_kx_map) return cls.generate_options(policy, local_kx_map, local_gss_kx_map, False) @classmethod def test_config(cls, config): if not os.access('/usr/bin/ssh', os.X_OK): return True fd, path = mkstemp() ret = 255 try: with os.fdopen(fd, 'w') as f: f.write(config) try: ret = call('/usr/bin/ssh -G -F ' + path + ' bogus654_server >/dev/null', shell=True) except CalledProcessError: cls.eprint("/usr/bin/ssh: Execution failed") finally: os.unlink(path) if ret: cls.eprint("There is an error in OpenSSH generated policy") cls.eprint("Policy:\n%s" % config) return False return True class OpenSSHServerGenerator(OpenSSHGenerator): CONFIG_NAME = 'opensshserver' SCOPES = {'ssh', 'openssh', 'openssh-server'} # We need restart here, since systemd needs to pick up new command line options RELOAD_CMD = 'systemctl try-restart sshd.service 2>/dev/null || :\n' _FORMAT_STRING = '-o{0}={1} ' @classmethod def generate_config(cls, policy): # Difference from client, keep group1 disabled on server local_kx_map = dict(cls.kx_map) local_gss_kx_map = dict(cls.gss_kx_map) del local_kx_map['DHE-FFDHE-1024-SHA1'] del local_gss_kx_map['DHE-GSS-FFDHE-1024-SHA1'] cfg = cls.generate_options(policy, local_kx_map, local_gss_kx_map, True) cfg = cfg.rstrip() return 'CRYPTO_POLICY=\'' + cfg + '\'' @classmethod def _test_setup(cls): _fd, path = mkstemp() os.unlink(path) ret = 255 try: ret = call('/usr/bin/ssh-keygen -t rsa -b 2048 -f ' + path + ' -N "" >/dev/null', shell=True) except CalledProcessError: cls.eprint("/usr/bin/ssh-keygen: Execution failed") if ret: cls.eprint("SSH Keygen failed when testing OpenSSH server policy") return '' return path @classmethod def _test_cleanup(cls, path): if path: os.unlink(path) @classmethod def test_config(cls, config): if not os.access('/usr/sbin/sshd', os.X_OK): return True host_key_filename = cls._test_setup() if not host_key_filename: return False fd, path = mkstemp() ret = 255 try: with os.fdopen(fd, 'w') as f: f.write(config) try: ret = call('/usr/bin/bash -c \'source ' + path + ' && /usr/sbin/sshd -T $CRYPTO_POLICY -h ' + host_key_filename + ' -f /dev/null\' >/dev/null', shell=True) except CalledProcessError: cls.eprint("/usr/sbin/sshd: Execution failed") finally: os.unlink(path) cls._test_cleanup(host_key_filename) if ret: cls.eprint("There is an error in OpenSSH server generated policy") cls.eprint("Policy:\n%s" % config) return False return True PK3]Ipolicygenerators/openssl.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from subprocess import check_output, CalledProcessError from .configgenerator import ConfigGenerator class OpenSSLGenerator(ConfigGenerator): CONFIG_NAME = 'openssl' SCOPES = {'tls', 'ssl', 'openssl'} cipher_not_map = { 'AES-256-CTR':'', 'AES-128-CTR':'', 'AES-256-GCM':'-AES256', 'AES-128-GCM':'-AES128', 'AES-256-CBC':'-SHA256', 'AES-128-CBC':'', 'CHACHA20-POLY1305':'-CHACHA20', 'SEED-CBC':'-SEED', 'IDEA-CBC':'!IDEA', 'DES-CBC':'!DES', 'RC4-40':'', 'DES40-CBC':'', '3DES-CBC':'-3DES', 'RC4-128':'!RC4', 'RC2-CBC':'!RC2', 'NULL':'!eNULL:!aNULL' } key_exchange_map = { 'RSA':'kRSA', 'ECDHE':'kEECDH', 'PSK':'kPSK', 'DHE-PSK':'kDHEPSK', 'DHE-RSA':'kEDH', 'DHE-DSS':'', 'ECDHE-PSK':'kECDHEPSK' } key_exchange_not_map = { 'ANON':'', 'DH':'', 'ECDH':'', 'RSA':'-kRSA', 'ECDHE':'-kEECDH', 'DHE-RSA':'-aRSA', 'DHE-DSS':'-aDSS', 'PSK':'-kPSK', 'DHE-PSK':'-kDHEPSK', 'ECDHE-PSK':'-kECDHEPSK' } mac_not_map = { 'HMAC-MD5':'!MD5', 'HMAC-SHA1':'-SHA1' } ciphersuite_map = { 'AES-256-GCM':'TLS_AES_256_GCM_SHA384', 'AES-128-GCM':'TLS_AES_128_GCM_SHA256', 'CHACHA20-POLY1305':'TLS_CHACHA20_POLY1305_SHA256', 'AES-128-CCM':'TLS_AES_128_CCM_SHA256', 'AES-128-CCM8':'TLS_AES_128_CCM_8_SHA256', } @classmethod def generate_ciphers(cls, policy): s = '' p = policy.enabled ip = policy.disabled # We cannot separate RSA strength from DH params. min_dh_size = policy.integers['min_dh_size'] min_rsa_size = policy.integers['min_rsa_size'] if min_dh_size < 1023 or min_rsa_size < 1023: s = cls.append(s, '@SECLEVEL=0') elif min_dh_size < 2048 or min_rsa_size < 2048: s = cls.append(s, '@SECLEVEL=1') elif min_dh_size < 3072 or min_rsa_size < 3072: s = cls.append(s, '@SECLEVEL=2') else: s = cls.append(s, '@SECLEVEL=3') for i in p['key_exchange']: try: s = cls.append(s, cls.key_exchange_map[i]) except KeyError: pass for i in ip['key_exchange']: try: s = cls.append(s, cls.key_exchange_not_map[i]) except KeyError: pass for i in ip['cipher']: try: s = cls.append(s, cls.cipher_not_map[i]) except KeyError: pass if 'AES-128-CCM' in ip['cipher'] and 'AES-256-CCM' in ip['cipher']: s = cls.append(s, '-AESCCM') for i in ip['mac']: try: s = cls.append(s, cls.mac_not_map[i]) except KeyError: pass # These ciphers are not necessary for any # policy level, and only increase the attack surface. # FIXME! must be fixed for custom policies s = cls.append(s, '-SHA384') s = cls.append(s, '-CAMELLIA') s = cls.append(s, '-ARIA') s = cls.append(s, '-AESCCM8') return s @classmethod def generate_ciphersuites(cls, policy): s = '' p = policy.enabled for i in p['cipher']: try: s = cls.append(s, cls.ciphersuite_map[i]) except KeyError: pass return s @classmethod def generate_config(cls, policy): return cls.generate_ciphers(policy) @classmethod def test_config(cls, config): output = b'' try: output = check_output(["openssl", "ciphers", config]) except CalledProcessError: cls.eprint("There is an error in openssl generated policy") cls.eprint("policy: %s" % config) return False except OSError: # Ignore missing openssl return True if b'NULL' in output or b'ADH' in output: cls.eprint("There is NULL or ADH in openssl generated policy") cls.eprint("Policy:\n%s" % config) return False return True class OpenSSLConfigGenerator(OpenSSLGenerator): CONFIG_NAME = 'opensslcnf' # has to cover everything c-p has protocol_map = { None: '', 'SSL3.0':'SSLv3', 'TLS1.0':'TLSv1', 'TLS1.1':'TLSv1.1', 'TLS1.2':'TLSv1.2', 'TLS1.3':'TLSv1.3', 'DTLS1.0':'DTLSv1', 'DTLS1.2':'DTLSv1.2' } sign_map = { 'RSA-SHA1':'RSA+SHA1', 'DSA-SHA1':'DSA+SHA1', 'ECDSA-SHA1':'ECDSA+SHA1', 'RSA-SHA2-224':'RSA+SHA224', 'DSA-SHA2-224':'DSA+SHA224', 'ECDSA-SHA2-224':'ECDSA+SHA224', 'RSA-SHA2-256':'RSA+SHA256', 'DSA-SHA2-256':'DSA+SHA256', 'ECDSA-SHA2-256':'ECDSA+SHA256', 'RSA-SHA2-384':'RSA+SHA384', 'DSA-SHA2-384':'DSA+SHA384', 'ECDSA-SHA2-384':'ECDSA+SHA384', 'RSA-SHA2-512':'RSA+SHA512', 'DSA-SHA2-512':'DSA+SHA512', 'ECDSA-SHA2-512':'ECDSA+SHA512', 'RSA-PSS-SHA2-256':'rsa_pss_pss_sha256:rsa_pss_rsae_sha256', 'RSA-PSS-SHA2-384':'rsa_pss_pss_sha384:rsa_pss_rsae_sha384', 'RSA-PSS-SHA2-512':'rsa_pss_pss_sha512:rsa_pss_rsae_sha512', 'EDDSA-ED25519':'ed25519', 'EDDSA-ED448':'ed448' } @classmethod def generate_config(cls, policy): p = policy.enabled s = 'CipherString = ' # This includes the seclevel s += cls.generate_ciphers(policy) s += '\n' s += 'Ciphersuites = ' s += cls.generate_ciphersuites(policy) s += '\n' if policy.min_tls_version: s += 'TLS.MinProtocol =' s += f' {cls.protocol_map[policy.min_tls_version]}\n' if policy.max_tls_version: s += 'TLS.MaxProtocol =' s += f' {cls.protocol_map[policy.max_tls_version]}\n' if policy.min_dtls_version: s += 'DTLS.MinProtocol =' s += f' {cls.protocol_map[policy.min_dtls_version]}\n' if policy.max_dtls_version: s += 'DTLS.MaxProtocol =' s += f' {cls.protocol_map[policy.max_dtls_version]}\n' sig_algs = [cls.sign_map[i] for i in p['sign'] if i in cls.sign_map] s += 'SignatureAlgorithms = ' + ':'.join(sig_algs) return s @classmethod def test_config(cls, config): # pylint: disable=unused-argument return True PK3]Yb@EEpolicygenerators/__init__.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz from .bind import BindGenerator from .gnutls import GnuTLSGenerator from .java import JavaGenerator from .krb5 import KRB5Generator from .libreswan import LibreswanGenerator from .libssh import LibsshGenerator from .nss import NSSGenerator from .openssh import OpenSSHClientGenerator from .openssh import OpenSSHServerGenerator from .openssl import OpenSSLConfigGenerator from .openssl import OpenSSLGenerator __all__ = [ 'BindGenerator', 'GnuTLSGenerator', 'JavaGenerator', 'KRB5Generator', 'LibreswanGenerator', 'LibsshGenerator', 'NSSGenerator', 'OpenSSHClientGenerator', 'OpenSSHServerGenerator', 'OpenSSLConfigGenerator', 'OpenSSLGenerator', ] PK3])0!0!update-crypto-policies.pynuȯ#!/usr/libexec/platform-python # SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz import sys import argparse import os import subprocess from tempfile import mkstemp import glob import warnings import cryptopolicies import cryptopolicies.validation import policygenerators warnings.formatwarning = lambda msg, category, *a, **kwa: \ f'{category.__name__}: {str(msg).capitalize()}\n' DEFAULT_PROFILE_DIR = '/usr/share/crypto-policies' DEFAULT_BASE_DIR = '/etc/crypto-policies' RELOAD_CMD_NAME = 'reload-cmds.sh' FIPS_MODE_FLAG = '/proc/sys/crypto/fips_enabled' def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) try: profile_dir = os.environ['profile_dir'] cryptopolicies.UnscopedCryptoPolicy.SHARE_DIR = profile_dir except KeyError: profile_dir = DEFAULT_PROFILE_DIR try: base_dir = os.environ['base_dir'] cryptopolicies.UnscopedCryptoPolicy.CONFIG_DIR = base_dir except KeyError: base_dir = DEFAULT_BASE_DIR local_dir = os.path.join(base_dir, 'local.d') backend_config_dir = os.path.join(base_dir, 'back-ends') state_dir = os.path.join(base_dir, 'state') reload_cmd_path = os.path.join(profile_dir, RELOAD_CMD_NAME) def parse_args(): "Parse the command line" parser = argparse.ArgumentParser(allow_abbrev=False) group = parser.add_mutually_exclusive_group() group.add_argument('--set', nargs='?', default='', metavar='POLICY', help='set the policy POLICY') group.add_argument('--show', action='store_true', help='show the current policy from the configuration') group.add_argument('--is-applied', action='store_true', help='check whether the current policy is applied') parser.add_argument('--no-check', action='store_true', help=argparse.SUPPRESS) parser.add_argument('--no-reload', action='store_true', help='do not run the reload scripts when setting a policy') return parser.parse_args() def is_applied(): try: time1 = os.stat(os.path.join(state_dir, 'current')).st_mtime time2 = os.stat(os.path.join(base_dir, 'config')).st_mtime except OSError: sys.exit(77) if time1 >= time2: print("The configured policy is applied") sys.exit(0) print("The configured policy is NOT applied") sys.exit(1) def setup_directories(): try: os.makedirs(backend_config_dir) os.makedirs(state_dir) except OSError: pass def fips_mode(): try: with open(FIPS_MODE_FLAG) as f: return int(f.read()) > 0 except OSError: return False def safe_write(directory, filename, contents): (fd, path) = mkstemp(prefix=filename, dir=directory) os.write(fd, bytes(contents, 'utf-8')) os.fsync(fd) os.fchmod(fd, 0o644) try: os.rename(path, os.path.join(directory, filename)) except OSError as e: os.unlink(path) os.close(fd) raise e finally: os.close(fd) def safe_symlink(directory, filename, target): (fd, path) = mkstemp(prefix=filename, dir=directory) os.close(fd) os.unlink(path) os.symlink(target, path) try: os.rename(path, os.path.join(directory, filename)) except OSError as e: os.unlink(path) raise e def save_config(pconfig, cfgname, cfgdata, cfgdir, localdir, profiledir, policy_was_empty): local_cfg_path = os.path.join(localdir, cfgname + '-*.config') local_cfgs = sorted(glob.glob(local_cfg_path)) local_cfg_present = False for lcfg in local_cfgs: if os.path.exists(lcfg): local_cfg_present = True profilepath = os.path.join(profiledir, str(pconfig), cfgname + '.txt') profilepath_exists = os.access(profilepath, os.R_OK) if not local_cfg_present and profilepath_exists: safe_symlink(cfgdir, cfgname + '.config', profilepath) return if profilepath_exists and not pconfig.subpolicies and policy_was_empty: # special case: if the policy has no directives, has files on disk, # and no subpolicy is used, but local.d modifications are present, # we'll concatenate the externally supplied policy with local.d# we'll concatenate the externally supplied policy with local.d with open(profilepath) as f_pre: cfgdata = f_pre.read() safe_write(cfgdir, cfgname + '.config', cfgdata) if local_cfg_present: cfgfile = os.path.join(cfgdir, cfgname + '.config') for lcfg in local_cfgs: try: with open(lcfg, 'r') as lf: local_data = lf.read() except OSError: eprint("Cannot read local policy file " + cfgname) continue try: with open(cfgfile, 'a') as cf: cf.write(local_data) except OSError: eprint("Error applying local configuration to " + cfgname) class ProfileConfig: def __init__(self): self.policy = '' self.subpolicies = [] def parse_string(self, s, subpolicy=False): l = s.upper().split(':') if l[0] and not subpolicy: self.policy = l[0] l = l[1:] l = [i for i in l if l] if subpolicy: self.subpolicies.append(l) else: self.subpolicies = l def parse_file(self, filename): subpolicy = False with open(filename) as f: for line in f: line = line.split('#', 1)[0] line = line.strip() if line: self.parse_string(line, subpolicy) subpolicy = True def remove_subpolicies(self, s): l = s.upper().split(':') self.subpolicies = [i for i in self.subpolicies if i not in l] def __str__(self): s = self.policy subs = ':'.join(self.subpolicies) if subs: s = s + ':' + subs return s def show(self): print(str(self)) def main(): "The actual command implementation" cmdline = parse_args() if cmdline.is_applied: is_applied() sys.exit(0) err = 0 setup_directories() pconfig = ProfileConfig() set_config = False configfile = os.path.join(base_dir, 'config') if os.access(configfile, os.R_OK): pconfig.parse_file(configfile) elif fips_mode(): pconfig.parse_string('FIPS') else: pconfig.parse_file(os.path.join(profile_dir, 'default-config')) if cmdline.show: pconfig.show() sys.exit(0) profile = cmdline.set if profile: oldpolicy = pconfig.policy pconfig.parse_string(profile) set_config = True # FIPS profile is a special case if pconfig.policy != oldpolicy: if pconfig.policy == 'FIPS': eprint("Warning: Using 'update-crypto-policies --set FIPS' is not sufficient for") eprint(" FIPS compliance.") eprint(" Use 'fips-mode-setup --enable' command instead.") elif fips_mode(): eprint("Warning: Using 'update-crypto-policies --set' in FIPS mode will make the system") eprint(" non-compliant with FIPS.") eprint(" It can also break the ssh access to the system.") eprint(" Use 'fips-mode-setup --disable' to disable the system FIPS mode.") if base_dir == DEFAULT_BASE_DIR: if not os.geteuid() == 0: eprint("You must be root to run update-crypto-policies.") sys.exit(1) try: cp = cryptopolicies.UnscopedCryptoPolicy(pconfig.policy, *pconfig.subpolicies) except cryptopolicies.validation.PolicyFileNotFoundError as ex: eprint(ex) sys.exit(1) except cryptopolicies.validation.PolicySyntaxError as ex: eprint(f'Errors found in policy, first one: \n{ex}') sys.exit(1) print("Setting system policy to " + str(pconfig)) generators = [g for g in dir(policygenerators) if 'Generator' in g] for g in generators: cls = policygenerators.__dict__[g] gen = cls() try: config = gen.generate_config(cp.scoped(gen.SCOPES)) except LookupError: eprint('Error generating config for ' + gen.CONFIG_NAME) eprint('Keeping original configuration') err = 1 try: save_config(pconfig, gen.CONFIG_NAME, config, backend_config_dir, local_dir, profile_dir, policy_was_empty=cp.is_empty()) except OSError: eprint('Error saving config for ' + gen.CONFIG_NAME) eprint('Keeping original configuration') err = 1 if set_config: try: safe_write(base_dir, 'config', str(pconfig) + '\n') except OSError: eprint('Error setting the current policy configuration') err = 3 try: safe_write(state_dir, 'current', str(pconfig) + '\n') except OSError: eprint('Error updating current policy marker') err = 2 try: safe_write(state_dir, 'CURRENT.pol', str(cp)) except OSError: eprint('Error updating current policy dump') err = 2 print("Note: System-wide crypto policies are applied on application start-up.") print("It is recommended to restart the system for the change of policies") print("to fully take place.") if not cmdline.no_reload: subprocess.call(['/bin/bash', reload_cmd_path]) sys.exit(err) # Entry point if __name__ == "__main__": main() PK3]u>""7__pycache__/update-crypto-policies.cpython-36.opt-1.pycnu[3 ."d$!@spddlZddlZddlZddlZddlmZddlZddlZddlZddl Zddl Z dde_ dZ dZ dZdZd d Zyejd Zeej_Wnek re ZYnXyejd Zeej_Wnek re ZYnXejjed ZejjedZejjedZejjeeZddZddZddZ ddZ!ddZ"ddZ#ddZ$GdddZ%d d!Z&e'd"krle&dS)#N)mkstempcOs|jdt|jdS)Nz:  )__name__str capitalize)msgcategoryaZkwar <./usr/share/crypto-policies/python/update-crypto-policies.pysr z/usr/share/crypto-policiesz/etc/crypto-policieszreload-cmds.shz/proc/sys/crypto/fips_enabledcOst|dtji|dS)Nfile)printsysstderr)argskwargsr r r eprint sr profile_dirbase_dirzlocal.dz back-endsstatecCsrtjdd}|j}|jdddddd|jd d d d |jd d dd |jdd tjd |jdd dd |jS)zParse the command lineF)Z allow_abbrevz--set?ZPOLICYzset the policy POLICY)nargsdefaultmetavarhelpz--show store_truez.show the current policy from the configuration)actionrz --is-appliedz+check whether the current policy is appliedz --no-checkz --no-reloadz3do not run the reload scripts when setting a policy)argparseArgumentParserZadd_mutually_exclusive_group add_argumentZSUPPRESS parse_args)parsergroupr r r r"8s   r"c Csy0tjtjjtdj}tjtjjtdj}Wntk rNtj dYnX||krjt dtj dt dtj ddS)NcurrentconfigMz The configured policy is appliedrz$The configured policy is NOT applied) osstatpathjoin state_dirst_mtimerOSErrorrexitr)Ztime1Ztime2r r r is_appliedIs r1c Cs2ytjttjtWntk r,YnXdS)N)r)makedirsbackend_config_dirr-r/r r r r setup_directoriesWs  r4cCs>y$tt}t|jdkSQRXWntk r8dSXdS)NrF)openFIPS_MODE_FLAGintreadr/)fr r r fips_mode_s  r:cCst||d\}}tj|t|dtj|tj|dzZytj|tjj||Wn:t k r}ztj |tj ||WYdd}~XnXWdtj |XdS)N)prefixdirzutf-8i) rr)writebytesfsyncfchmodrenamer+r,r/unlinkclose) directoryfilenamecontentsfdr+er r r safe_writegs    rIcCst||d\}}tj|tj|tj||ytj|tjj||Wn0tk rz}ztj||WYdd}~XnXdS)N)r;r<) rr)rCrBsymlinkrAr+r,r/)rDrEtargetrGr+rHr r r safe_symlinkvs    rLc$Cs|tjj||d}ttj|}d} x|D]} tjj| r*d} q*Wtjj|t||d} tj| tj} | r| rt ||d| dS| r|j r|rt | } | j }WdQRXt ||d|| rxtjj||d}x|D]} y"t | d}|j }WdQRXWn$tk r*td|wYnXy$t |d}|j|WdQRXWqtk rrtd |YqXqWdS) Nz -*.configFTz.txtz.configrzCannot read local policy file r z&Error applying local configuration to )r)r+r,sortedglobexistsraccessR_OKrL subpoliciesr5r8rIr/rr=)pconfigZcfgnameZcfgdataZcfgdirZlocaldirZ profiledirpolicy_was_emptyZlocal_cfg_pathZ local_cfgsZlocal_cfg_presentZlcfgZ profilepathZprofilepath_existsZf_preZcfgfileZlfZ local_dataZcfr r r save_configs:        rVc@s>eZdZddZdddZddZdd Zd d Zd d ZdS) ProfileConfigcCsd|_g|_dS)Nr)policyrS)selfr r r __init__szProfileConfig.__init__Fcs`|jjddr2| r2d|_ddfddD|rV|jjn|_dS)N:rr(csg|] }r|qSr r ).0i)lr r sz.ProfileConfig.parse_string..)uppersplitrXrSappend)rYs subpolicyr )r^r parse_strings  zProfileConfig.parse_stringc CsVd}t|@}x8|D]0}|jddd}|j}|r|j||d}qWWdQRXdS)NF#r(rT)r5rastripre)rYrErdr9liner r r parse_files   zProfileConfig.parse_filecs(|jjdfdd|jD|_dS)Nr[csg|]}|kr|qSr r )r\r])r^r r r_sz4ProfileConfig.remove_subpolicies..)r`rarS)rYrcr )r^r remove_subpoliciessz ProfileConfig.remove_subpoliciescCs&|j}dj|j}|r"|d|}|S)Nr[)rXr,rS)rYrcZsubsr r r __str__s   zProfileConfig.__str__cCstt|dS)N)rr)rYr r r showszProfileConfig.showN)F) r __module__ __qualname__rZrerirjrkrlr r r r rWs   rWc)Cst}|jrttjdd}tt}d}tjjt d}tj |tj rX|j |n&t rj|jdn|j tjjtd|jr|jtjd|j}|r|j}|j|d}|j|kr|jdkrtdtdtd n(t rtd td td td t tkr8tjdks8tdtjdytj|jf|j}Wnxtjjk r}zt|tjdWYdd}~Xn@tjjk r}ztd|tjdWYdd}~XnXtdt|ddttD} x| D]} tj | } | } y| j!|j"| j#} Wn0t$k rLtd| j%tdd}YnXy t&|| j%| t't(t|j)dWn0t*k rtd| j%tdd}YnXqW|ryt+t dt|dWn"t*k rtdd}YnXyt+t,dt|dWn"t*k r"tdd}YnXyt+t,dt|Wn"t*k rZtd d}YnXtd!td"td#|j-st.j/d$t0gtj|dS)%z!The actual command implementationrFr&ZFIPSzdefault-configTzHWarning: Using 'update-crypto-policies --set FIPS' is not sufficient forz FIPS compliance.z8 Use 'fips-mode-setup --enable' command instead.zOWarning: Using 'update-crypto-policies --set' in FIPS mode will make the systemz! non-compliant with FIPS.z8 It can also break the ssh access to the system.zI Use 'fips-mode-setup --disable' to disable the system FIPS mode.z/You must be root to run update-crypto-policies.r(Nz%Errors found in policy, first one: zSetting system policy to cSsg|]}d|kr|qS) Generatorr )r\gr r r r_szmain..zError generating config for zKeeping original configuration)rUzError saving config for rz.Error setting the current policy configurationr%z$Error updating current policy markerz CURRENT.polz"Error updating current policy dumpzFNote: System-wide crypto policies are applied on application start-up.zBIt is recommended to restart the system for the change of policieszto fully take place.z /bin/bash)1r"r1rr0r4rWr)r+r,rrQrRrir:rerrlsetrXrDEFAULT_BASE_DIRgeteuidcryptopoliciesUnscopedCryptoPolicyrSZ validationZPolicyFileNotFoundErrorZPolicySyntaxErrorrrr<policygenerators__dict__Zgenerate_configZscopedZSCOPES LookupErrorZ CONFIG_NAMErVr3 local_dirZis_emptyr/rIr-Z no_reload subprocessZcallreload_cmd_path)ZcmdlineerrrTZ set_configZ configfileZprofileZ oldpolicyZcpexZ generatorsrpclsgenr&r r r mains                  r__main__)(rrr)r|ZtempfilerrOwarningsrvZcryptopolicies.validationrx formatwarningZDEFAULT_PROFILE_DIRrtZRELOAD_CMD_NAMEr6renvironrrwZ SHARE_DIRKeyErrorrZ CONFIG_DIRr+r,r{r3r-r}r"r1r4r:rIrLrVrWrrr r r r sP         +)s PK3]ߺh0__pycache__/build-crypto-policies.cpython-36.pycnu[3 ."d@sxddlZddlZddlZddlZddlZddlZdZddZddZddZ dd d Z d d Z d dZ e dkrte dS)Nzreload-cmds.shcOst|dtji|dS)Nfile)printsysstderr)argskwargsr;./usr/share/crypto-policies/python/build-crypto-policies.pyeprintsr cCstjdd}|jdddd|jdddd|jd td d d |jd ddd|jdddd|jddd|jddd|jS)zParse the command lineF)Z allow_abbrevz--flat store_truez1put all the generated files in a single directory)actionhelpz--testz7compare the generated config file with the existing onez--policyZPOLICYz"generate the specified policy only)typemetavarr z --reloadcmdszDalso save reload cmds into reload-cmds.sh script in output directoryz--strictzfail on warnings policydirz5a directory with base policy definition files (*.pol))r outputdirz.a target directory with generated config files)argparseArgumentParser add_argumentstr parse_args)parserrrr rs   rcCs<|jr tjj|jdj||}n`tjj|j|}tjj|snytj|Wn"tk rlt dj|dSXtjj||d}|j ry@t |dd}|j }WdQRX||krt dj||dSdSt k rYn$tk rt d j|dSXtd j||t |d d}|j|WdQRXtdS) Nz {}-{}.txtz%Cannot create directory for policy {}Fz.txtr)modez9Config for {} for policy {} differs from the existing oneTzError reading generated file {}z"Saving config for {} for policy {}w)ZflatospathjoinrformatisdirmkdirOSErrorr ZtestopenreadFileNotFoundErrorrwrite)cmdline policy_nameZ config_nameconfigrdirpathfZ old_configrrr save_config-s8 r+c Cs(d}|dkrg}ytj|f||d|ji}Wn0tk r^}ztdt|dSd}~XnXddttD}x|D]}tj|}|} | j |j | j } |dks| j | ry(dj |f|} t|| | j| sd }Wn0tk r td | jtd d }YnXqxtd | jd}qxW|S)NrrzError: cSsg|]}d|kr|qS) Generatorr).0grrr \sz build_policy..ZEMPTY:zError saving config for zKeeping original configurationzError testing config for )cryptopoliciesZUnscopedCryptoPolicyr ValueErrorr rdirpolicygenerators__dict__Zgenerate_configZscopedZSCOPESZ test_configrr+Z CONFIG_NAMEr!) r&r'subpolicy_nameserrZcpe generatorsr/clsgenr(namerrr build_policyOs6   rAcCsd}ddttD}tjj|jt}y@t|dd*}x"|D]}tj|}|j |j q.r)rzError saving reload cmds) r7r8rrrrRELOAD_CMD_NAMEr"r9r%Z RELOAD_CMDr!r )r&r;r=rr*r/r>rrr save_reload_cmdsrs   rDc Cst}d}|jrtjd|jrHtd|jjjd^}}t|||}nft j |j T}xL|D]D}|j j d r\|jr\t jj|j \}}|dkr\t||}|r\Pq\WWdQRX| r|jrt|}tj|dS)z!The actual command implementationrerrorNr1.z.pol)rstrictwarningsfilterwarningsZpolicyfilteruppersplitrArscandirrr@ startswithis_filersplitextZ reloadcmdsrDrexit)r&r;r'r:ZsdiZextrrr mains$    rS__main__)N)rrrrHr5r8rCr rr+rArDrS__name__rrrr s" #PK3]ߺh6__pycache__/build-crypto-policies.cpython-36.opt-1.pycnu[3 ."d@sxddlZddlZddlZddlZddlZddlZdZddZddZddZ dd d Z d d Z d dZ e dkrte dS)Nzreload-cmds.shcOst|dtji|dS)Nfile)printsysstderr)argskwargsr;./usr/share/crypto-policies/python/build-crypto-policies.pyeprintsr cCstjdd}|jdddd|jdddd|jd td d d |jd ddd|jdddd|jddd|jddd|jS)zParse the command lineF)Z allow_abbrevz--flat store_truez1put all the generated files in a single directory)actionhelpz--testz7compare the generated config file with the existing onez--policyZPOLICYz"generate the specified policy only)typemetavarr z --reloadcmdszDalso save reload cmds into reload-cmds.sh script in output directoryz--strictzfail on warnings policydirz5a directory with base policy definition files (*.pol))r outputdirz.a target directory with generated config files)argparseArgumentParser add_argumentstr parse_args)parserrrr rs   rcCs<|jr tjj|jdj||}n`tjj|j|}tjj|snytj|Wn"tk rlt dj|dSXtjj||d}|j ry@t |dd}|j }WdQRX||krt dj||dSdSt k rYn$tk rt d j|dSXtd j||t |d d}|j|WdQRXtdS) Nz {}-{}.txtz%Cannot create directory for policy {}Fz.txtr)modez9Config for {} for policy {} differs from the existing oneTzError reading generated file {}z"Saving config for {} for policy {}w)ZflatospathjoinrformatisdirmkdirOSErrorr ZtestopenreadFileNotFoundErrorrwrite)cmdline policy_nameZ config_nameconfigrdirpathfZ old_configrrr save_config-s8 r+c Cs(d}|dkrg}ytj|f||d|ji}Wn0tk r^}ztdt|dSd}~XnXddttD}x|D]}tj|}|} | j |j | j } |dks| j | ry(dj |f|} t|| | j| sd }Wn0tk r td | jtd d }YnXqxtd | jd}qxW|S)NrrzError: cSsg|]}d|kr|qS) Generatorr).0grrr \sz build_policy..ZEMPTY:zError saving config for zKeeping original configurationzError testing config for )cryptopoliciesZUnscopedCryptoPolicyr ValueErrorr rdirpolicygenerators__dict__Zgenerate_configZscopedZSCOPESZ test_configrr+Z CONFIG_NAMEr!) r&r'subpolicy_nameserrZcpe generatorsr/clsgenr(namerrr build_policyOs6   rAcCsd}ddttD}tjj|jt}y@t|dd*}x"|D]}tj|}|j |j q.r)rzError saving reload cmds) r7r8rrrrRELOAD_CMD_NAMEr"r9r%Z RELOAD_CMDr!r )r&r;r=rr*r/r>rrr save_reload_cmdsrs   rDc Cst}d}|jrtjd|jrHtd|jjjd^}}t|||}nft j |j T}xL|D]D}|j j d r\|jr\t jj|j \}}|dkr\t||}|r\Pq\WWdQRX| r|jrt|}tj|dS)z!The actual command implementationrerrorNr1.z.pol)rstrictwarningsfilterwarningsZpolicyfilteruppersplitrArscandirrr@ startswithis_filersplitextZ reloadcmdsrDrexit)r&r;r'r:ZsdiZextrrr mains$    rS__main__)N)rrrrHr5r8rCr rr+rArDrS__name__rrrr s" #PK3]u>""1__pycache__/update-crypto-policies.cpython-36.pycnu[3 ."d$!@spddlZddlZddlZddlZddlmZddlZddlZddlZddl Zddl Z dde_ dZ dZ dZdZd d Zyejd Zeej_Wnek re ZYnXyejd Zeej_Wnek re ZYnXejjed ZejjedZejjedZejjeeZddZddZddZ ddZ!ddZ"ddZ#ddZ$GdddZ%d d!Z&e'd"krle&dS)#N)mkstempcOs|jdt|jdS)Nz:  )__name__str capitalize)msgcategoryaZkwar <./usr/share/crypto-policies/python/update-crypto-policies.pysr z/usr/share/crypto-policiesz/etc/crypto-policieszreload-cmds.shz/proc/sys/crypto/fips_enabledcOst|dtji|dS)Nfile)printsysstderr)argskwargsr r r eprint sr profile_dirbase_dirzlocal.dz back-endsstatecCsrtjdd}|j}|jdddddd|jd d d d |jd d dd |jdd tjd |jdd dd |jS)zParse the command lineF)Z allow_abbrevz--set?ZPOLICYzset the policy POLICY)nargsdefaultmetavarhelpz--show store_truez.show the current policy from the configuration)actionrz --is-appliedz+check whether the current policy is appliedz --no-checkz --no-reloadz3do not run the reload scripts when setting a policy)argparseArgumentParserZadd_mutually_exclusive_group add_argumentZSUPPRESS parse_args)parsergroupr r r r"8s   r"c Csy0tjtjjtdj}tjtjjtdj}Wntk rNtj dYnX||krjt dtj dt dtj ddS)NcurrentconfigMz The configured policy is appliedrz$The configured policy is NOT applied) osstatpathjoin state_dirst_mtimerOSErrorrexitr)Ztime1Ztime2r r r is_appliedIs r1c Cs2ytjttjtWntk r,YnXdS)N)r)makedirsbackend_config_dirr-r/r r r r setup_directoriesWs  r4cCs>y$tt}t|jdkSQRXWntk r8dSXdS)NrF)openFIPS_MODE_FLAGintreadr/)fr r r fips_mode_s  r:cCst||d\}}tj|t|dtj|tj|dzZytj|tjj||Wn:t k r}ztj |tj ||WYdd}~XnXWdtj |XdS)N)prefixdirzutf-8i) rr)writebytesfsyncfchmodrenamer+r,r/unlinkclose) directoryfilenamecontentsfdr+er r r safe_writegs    rIcCst||d\}}tj|tj|tj||ytj|tjj||Wn0tk rz}ztj||WYdd}~XnXdS)N)r;r<) rr)rCrBsymlinkrAr+r,r/)rDrEtargetrGr+rHr r r safe_symlinkvs    rLc$Cs|tjj||d}ttj|}d} x|D]} tjj| r*d} q*Wtjj|t||d} tj| tj} | r| rt ||d| dS| r|j r|rt | } | j }WdQRXt ||d|| rxtjj||d}x|D]} y"t | d}|j }WdQRXWn$tk r*td|wYnXy$t |d}|j|WdQRXWqtk rrtd |YqXqWdS) Nz -*.configFTz.txtz.configrzCannot read local policy file r z&Error applying local configuration to )r)r+r,sortedglobexistsraccessR_OKrL subpoliciesr5r8rIr/rr=)pconfigZcfgnameZcfgdataZcfgdirZlocaldirZ profiledirpolicy_was_emptyZlocal_cfg_pathZ local_cfgsZlocal_cfg_presentZlcfgZ profilepathZprofilepath_existsZf_preZcfgfileZlfZ local_dataZcfr r r save_configs:        rVc@s>eZdZddZdddZddZdd Zd d Zd d ZdS) ProfileConfigcCsd|_g|_dS)Nr)policyrS)selfr r r __init__szProfileConfig.__init__Fcs`|jjddr2| r2d|_ddfddD|rV|jjn|_dS)N:rr(csg|] }r|qSr r ).0i)lr r sz.ProfileConfig.parse_string..)uppersplitrXrSappend)rYs subpolicyr )r^r parse_strings  zProfileConfig.parse_stringc CsVd}t|@}x8|D]0}|jddd}|j}|r|j||d}qWWdQRXdS)NF#r(rT)r5rastripre)rYrErdr9liner r r parse_files   zProfileConfig.parse_filecs(|jjdfdd|jD|_dS)Nr[csg|]}|kr|qSr r )r\r])r^r r r_sz4ProfileConfig.remove_subpolicies..)r`rarS)rYrcr )r^r remove_subpoliciessz ProfileConfig.remove_subpoliciescCs&|j}dj|j}|r"|d|}|S)Nr[)rXr,rS)rYrcZsubsr r r __str__s   zProfileConfig.__str__cCstt|dS)N)rr)rYr r r showszProfileConfig.showN)F) r __module__ __qualname__rZrerirjrkrlr r r r rWs   rWc)Cst}|jrttjdd}tt}d}tjjt d}tj |tj rX|j |n&t rj|jdn|j tjjtd|jr|jtjd|j}|r|j}|j|d}|j|kr|jdkrtdtdtd n(t rtd td td td t tkr8tjdks8tdtjdytj|jf|j}Wnxtjjk r}zt|tjdWYdd}~Xn@tjjk r}ztd|tjdWYdd}~XnXtdt|ddttD} x| D]} tj | } | } y| j!|j"| j#} Wn0t$k rLtd| j%tdd}YnXy t&|| j%| t't(t|j)dWn0t*k rtd| j%tdd}YnXqW|ryt+t dt|dWn"t*k rtdd}YnXyt+t,dt|dWn"t*k r"tdd}YnXyt+t,dt|Wn"t*k rZtd d}YnXtd!td"td#|j-st.j/d$t0gtj|dS)%z!The actual command implementationrFr&ZFIPSzdefault-configTzHWarning: Using 'update-crypto-policies --set FIPS' is not sufficient forz FIPS compliance.z8 Use 'fips-mode-setup --enable' command instead.zOWarning: Using 'update-crypto-policies --set' in FIPS mode will make the systemz! non-compliant with FIPS.z8 It can also break the ssh access to the system.zI Use 'fips-mode-setup --disable' to disable the system FIPS mode.z/You must be root to run update-crypto-policies.r(Nz%Errors found in policy, first one: zSetting system policy to cSsg|]}d|kr|qS) Generatorr )r\gr r r r_szmain..zError generating config for zKeeping original configuration)rUzError saving config for rz.Error setting the current policy configurationr%z$Error updating current policy markerz CURRENT.polz"Error updating current policy dumpzFNote: System-wide crypto policies are applied on application start-up.zBIt is recommended to restart the system for the change of policieszto fully take place.z /bin/bash)1r"r1rr0r4rWr)r+r,rrQrRrir:rerrlsetrXrDEFAULT_BASE_DIRgeteuidcryptopoliciesUnscopedCryptoPolicyrSZ validationZPolicyFileNotFoundErrorZPolicySyntaxErrorrrr<policygenerators__dict__Zgenerate_configZscopedZSCOPES LookupErrorZ CONFIG_NAMErVr3 local_dirZis_emptyr/rIr-Z no_reload subprocessZcallreload_cmd_path)ZcmdlineerrrTZ set_configZ configfileZprofileZ oldpolicyZcpexZ generatorsrpclsgenr&r r r mains                  r__main__)(rrr)r|ZtempfilerrOwarningsrvZcryptopolicies.validationrx formatwarningZDEFAULT_PROFILE_DIRrtZRELOAD_CMD_NAMEr6renvironrrwZ SHARE_DIRKeyErrorrZ CONFIG_DIRr+r,r{r3r-r}r"r1r4r:rIrLrVrWrrr r r r sP         +)s PK3]build-crypto-policies.pynuȯ#!/usr/libexec/platform-python # SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz import argparse import os import sys import warnings import cryptopolicies import policygenerators RELOAD_CMD_NAME = 'reload-cmds.sh' def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) def parse_args(): "Parse the command line" parser = argparse.ArgumentParser(allow_abbrev=False) parser.add_argument('--flat', action='store_true', help='put all the generated files in a single directory') parser.add_argument('--test', action='store_true', help='compare the generated config file with the existing one') parser.add_argument('--policy', type=str, metavar='POLICY', help='generate the specified policy only') parser.add_argument('--reloadcmds', action='store_true', help='also save reload cmds into reload-cmds.sh script in output directory') parser.add_argument('--strict', action='store_true', help='fail on warnings') parser.add_argument('policydir', help='a directory with base policy definition files (*.pol)') parser.add_argument('outputdir', help='a target directory with generated config files') return parser.parse_args() def save_config(cmdline, policy_name, config_name, config): if cmdline.flat: path = os.path.join(cmdline.outputdir, '{}-{}.txt'.format(policy_name, config_name)) else: dirpath = os.path.join(cmdline.outputdir, policy_name) if not os.path.isdir(dirpath): try: os.mkdir(dirpath) except OSError: eprint('Cannot create directory for policy {}'.format(policy_name)) return False path = os.path.join(dirpath, config_name + '.txt') if cmdline.test: try: with open(path, mode='r') as f: old_config = f.read() if old_config != config: eprint('Config for {} for policy {} differs from the existing one'.format(config_name, policy_name)) return False return True except FileNotFoundError: pass except OSError: eprint('Error reading generated file {}'.format(path)) return False print('Saving config for {} for policy {}'.format(config_name, policy_name)) with open(path, mode='w') as f: f.write(config) print() return True def build_policy(cmdline, policy_name, subpolicy_names=None): err = 0 if subpolicy_names is None: subpolicy_names = [] try: cp = cryptopolicies.UnscopedCryptoPolicy(policy_name, *subpolicy_names,*subpolicy_names, policydir=cmdline.policydir) except ValueError as e: # TODO: catch specific thing eprint('Error: ' + str(e)) return 1 generators = [g for g in dir(policygenerators) if 'Generator' in g] for g in generators: cls = policygenerators.__dict__[g] gen = cls() config = gen.generate_config(cp.scoped(gen.SCOPES)) if policy_name == 'EMPTY' or gen.test_config(config): try: name = ':'.join([policy_name, *subpolicy_names]) if not save_config(cmdline, name, gen.CONFIG_NAME, config): err = 5 except OSError: eprint('Error saving config for ' + gen.CONFIG_NAME) eprint('Keeping original configuration') err = 4 else: eprint('Error testing config for ' + gen.CONFIG_NAME) err = 3 return err def save_reload_cmds(cmdline): err = 0 generators = [g for g in dir(policygenerators) if 'Generator' in g] path = os.path.join(cmdline.outputdir, RELOAD_CMD_NAME) try: with open(path, mode='w') as f: for g in generators: cls = policygenerators.__dict__[g] f.write(cls.RELOAD_CMD) except OSError: eprint('Error saving reload cmds') err = 6 return err def main(): "The actual command implementation" cmdline = parse_args() err = 0 if cmdline.strict: warnings.filterwarnings("error") if cmdline.policy: (policy_name, *subpolicy_names) = filter(None, cmdline.policy.upper().split(':')) err = build_policy(cmdline, policy_name, subpolicy_names) else: with os.scandir(cmdline.policydir) as sd: for i in sd: if not i.name.startswith('.') and i.is_file(): (policy_name, ext) = os.path.splitext(i.name) if ext == '.pol': err = build_policy(cmdline, policy_name) if err: break if not err and cmdline.reloadcmds: err = save_reload_cmds(cmdline) sys.exit(err) # Entry point if __name__ == "__main__": main() PK3]# CBCB cryptopolicies/cryptopolicies.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz import collections import enum import fnmatch import os import re import warnings from . import alg_lists from . import validation # moved out of the way to not obscure the flow # Defaults of integer property values (doubles as an allowlist) INT_DEFAULTS = {k: 0 for k in ( 'arbitrary_dh_groups', 'min_dh_size', 'min_dsa_size', 'min_rsa_size', 'sha1_in_certs', 'ssh_certs', 'ssh_etm', )} # Scopes (`@!ipsec`) and matching them SCOPE_ANY = '*' ALL_SCOPES = ( # defined explicitly to catch typos / globbing nothing 'tls', 'ssl', 'openssl', 'nss', 'gnutls', 'java-tls', 'ssh', 'openssh', 'openssh-server', 'openssh-client', 'libssh', 'ipsec', 'ike', 'libreswan', 'kerberos', 'krb5', 'dnssec', 'bind', ) DUMPABLE_SCOPES = { # TODO: fix duplication, backends specify same things 'bind': {'bind', 'dnssec'}, 'gnutls': {'gnutls', 'tls', 'ssl'}, 'java-tls': {'java-tls', 'tls', 'ssl'}, 'krb5': {'krb5', 'kerberos'}, 'libreswan': {'ipsec', 'ike', 'libreswan'}, 'libssh': {'libssh', 'openssh', 'ssh'}, 'nss': {'nss', 'tls', 'ssl'}, 'openssh-client': {'openssh-client', 'openssh', 'ssh'}, 'openssh-server': {'openssh-server', 'openssh', 'ssh'}, 'openssl': {'openssl', 'tls', 'ssl'}, } class ScopeSelector: def __init__(self, pattern=SCOPE_ANY): """ Initialize a scope selector. An example would be `ssh` in `ciphers@ssh = -NULL`. When openssh backend will request the configuration, it'll offer (`{'ssh', 'openssh'}`) as scopes and the rule above will be taken into account. Both patterns and scopes are cast to lowercase. For more examples, refer to tests/unit/parsing/test_scope_selector.py >>> ss = ScopeSelector('!{SSH,IPsec}') >>> ss.matches({'ipsec', 'libreswan'}) False >>> ss.matches({'tls', 'openssl'}) True """ self.pattern = pattern = pattern.lower() self._positive = not pattern.startswith('!') p = pattern if self._positive else pattern[1:] validation.scope.illegal_characters(p, original_pattern=self.pattern) validation.scope.curly_brackets(p, original_pattern=self.pattern) self._globs = p[1:-1].split(',') if p.startswith('{') else [p] validation.scope.resulting_globs(self._globs, ALL_SCOPES, original_pattern=self.pattern) def __str__(self): return f'' def matches(self, scopes): """ Checks whether ScopeSelector matches one of the scopes. For more examples, refer to tests/unit/parsing/test_scope_selector.py >>> ScopeSelector('{SSH,IPsec}').matches({'ipsec', 'libreswan'}) True >>> ScopeSelector('!{SSH,IPsec}').matches({'ipsec', 'libreswan'}) False """ if self.pattern == SCOPE_ANY: # matches even an empty set return True scopes = [s.lower() for s in scopes] assert all(s in ALL_SCOPES for s in scopes) # supplied by backends if self._positive: return any(fnmatch.filter(scopes, g) for g in self._globs) return all(not fnmatch.filter(scopes, g) for g in self._globs) # Operations: interpreting right hand sides of (sub)policy files class Operation(enum.Enum): """ An operation that comes with the right-hand value of the directive. """ RESET = 1 # cipher = PREPEND = 2 # cipher = +NULL APPEND = 3 # cipher = NULL+ OMIT = 4 # cipher = -NULL SET_INT = 5 # sha1_in_certs = 0; setting to something that's all digits def parse_rhs(rhs, prop_name): """ Parses right-hand parts of the directives into lists of operation/value pairs. For more examples, refer to tests/unit/test_parsing.py >>> parse_rhs('', 'cipher') [(, None)] >>> parse_rhs('IDEA-CBC SEED-CBC', 'cipher') [(, None), (, 'IDEA-CBC'), (, 'SEED-CBC')] >>> # 3DES-CBC gets prepended last for higher prio >>> parse_rhs('+*DES-CBC', 'cipher') [(, 'DES-CBC'), (, '3DES-CBC')] """ def differential(v): return v.startswith('+') or v.endswith('+') or v.startswith('-') if rhs.isdigit(): if prop_name not in alg_lists.ALL and prop_name in INT_DEFAULTS: return [(Operation.SET_INT, int(rhs))] elif prop_name in alg_lists.ALL: raise validation.rules.NonIntPropertyIntValueError(prop_name) else: assert prop_name not in alg_lists.ALL assert prop_name not in INT_DEFAULTS # pass for now, it's gonna be caught as non-existing algclass else: if prop_name in INT_DEFAULTS: raise validation.rules.IntPropertyNonIntValueError(prop_name) values = rhs.split() if not any(differential(v) for v in values): # Setting something anew values = sum([alg_lists.glob(v, prop_name) for v in values], []) return ([(Operation.RESET, None)] + [(Operation.APPEND, v) for v in values]) elif all(differential(v) for v in values): # Modifying an existing list operations = [] for value in values: if value.startswith('+'): op = Operation.PREPEND unglob = alg_lists.glob(value[1:], prop_name)[::-1] elif value.endswith('+'): op = Operation.APPEND unglob = alg_lists.glob(value[:-1], prop_name)[::-1] else: assert value.startswith('-') op = Operation.OMIT unglob = alg_lists.glob(value[1:], prop_name) operations.extend([(op, v) for v in unglob]) return operations else: # Forbidden to mix them on one line raise validation.rules.MixedDifferentialNonDifferentialError(rhs) # Directives: interpreting lines of (sub)policy files Directive = collections.namedtuple('Directive', ( 'prop_name', 'scope', 'operation', 'value' )) def parse_line(line): """ Parses configuration lines into tuples of directives. For more examples, refer to tests/unit/test_parsing.py >>> parse_line('cipher@TLS = RC4* NULL') [Directive(prop_name='cipher', scope='tls', operation=, value=None), Directive(prop_name='cipher', scope='tls', operation=, value='RC4-40'), Directive(prop_name='cipher', scope='tls', operation=, value='RC4-128'), Directive(prop_name='cipher', scope='tls', operation=, value='NULL')] """ if not line.strip(): return [] validation.rules.count_equals_signs(line) lhs, rhs = line.split('=') lhs, rhs = lhs.strip(), rhs.strip() validation.rules.empty_lhs(lhs, line) prop_name, scope = lhs.split('@', 1) if '@' in lhs else (lhs, SCOPE_ANY) return [Directive(prop_name=prop_name, scope=scope.lower(), operation=operation, value=value) for operation, value in parse_rhs(rhs, prop_name)] def syntax_check_line(line, warn=False): try: l = parse_line(line) for d in l: ScopeSelector(d.scope) # attempt parsing except validation.PolicySyntaxError as ex: if not warn: raise warnings.warn(ex) class PolicySyntaxDeprecationWarning(FutureWarning): def __init__(self, deprecated, replacement): replacement = replacement.replace('\n', ' and ') msg = f'option {deprecated} is deprecated' msg += f', please rewrite your rules using {replacement}; ' msg += 'be advised that it is not always a 1-1 replacement' super().__init__(msg) def preprocess_text(text): r""" Preprocesses text before parsing. Fixes line breaks, handles backwards compatibility. >>> preprocess_text('cipher = c1 \\ \nc2#x') 'cipher = c1 c2' >>> with warnings.catch_warnings(): ... warnings.simplefilter("ignore") ... preprocess_text('ike_protocol = IKEv2') 'protocol@IKE = IKEv2' >>> with warnings.catch_warnings(): ... warnings.simplefilter("ignore") ... preprocess_text('min_tls_version=TLS1.3') 'protocol@TLS = -SSL2.0 -SSL3.0 -TLS1.0 -TLS1.1 -TLS1.2' """ text = re.sub(r'#.*', '', text) text = text.replace('=', ' = ') text = '\n'.join((l.strip() for l in text.split('\n'))) text = text.replace('\\\n', '') text = '\n'.join((l.strip() for l in text.split('\n'))) text = '\n'.join((re.sub(r'\s+', ' ', l) for l in text.split('\n'))) text = re.sub('\n+', '\n', text).strip() if re.findall(r'\bprotocol\s*=', text): warnings.warn(PolicySyntaxDeprecationWarning('protocol', 'protocol@TLS')) POSTFIX_REPLACEMENTS = { 'tls_cipher': 'cipher@TLS', 'ssh_cipher': 'cipher@SSH', 'ssh_group': 'group@SSH', 'ike_protocol': 'protocol@IKE', } for fr, to in POSTFIX_REPLACEMENTS.items(): regex = r'\b' + fr + r'\s*=(.*)' ms = re.findall(regex, text) if ms: warnings.warn(PolicySyntaxDeprecationWarning(fr, to)) text = re.sub(regex, '', text) for m in ms: text += f'\n\n{to} ={m}' text = re.sub('\n+', '\n', text).strip() PLAIN_REPLACEMENTS = { 'sha1_in_dnssec = 0': 'hash@DNSSec = -SHA1\nsign@DNSSec = -RSA-SHA1 -ECDSA-SHA1', 'sha1_in_dnssec = 1': 'hash@DNSSec = SHA1+\nsign@DNSSec = RSA-SHA1+ ECDSA-SHA1+', } for fr, to in PLAIN_REPLACEMENTS.items(): regex = r'\b' + fr + r'\b' if re.search(regex, text): warnings.warn(PolicySyntaxDeprecationWarning(fr, to)) text = re.sub(regex, to, text) dtls_versions = list(alg_lists.DTLS_PROTOCOLS[::-1]) while dtls_versions: neg = " ".join(("-" + v for v in dtls_versions[:-1])) text = re.sub(r'\bmin_dtls_version = ' + dtls_versions[-1] + r'\b', f'protocol@TLS = {neg}' if neg else '', text) dtls_versions.pop() text = re.sub(r'\bmin_dtls_version = 0\b', '', text) tls_versions = list(alg_lists.TLS_PROTOCOLS[::-1]) while tls_versions: neg = " ".join(("-" + v for v in tls_versions[:-1])) text = re.sub(r'\bmin_tls_version = ' + tls_versions[-1] + r'\b', f'protocol@TLS = {neg}' if neg else '', text) tls_versions.pop() text = re.sub(r'\bmin_tls_version = 0\b', '', text) return text # Finally, constructing a policy class ScopedPolicy: """ An entity constructing lists of what's `.enabled` and what's `.disabled` when the given scopes are active. >>> sp = ScopedPolicy(parse_line('cipher@TLS = RC4* NULL'), {'tls'}) >>> 'AES-256-GCM' in sp.disabled['cipher'] True >>> sp.enabled['cipher'] ['RC4-40', 'RC4-128', 'NULL'] >>> ScopedPolicy(parse_line('min_dh_size=2048')).integers['min_dh_size'] 2048 """ def __init__(self, directives, relevant_scopes=None): relevant_scopes = relevant_scopes or set() self.integers = INT_DEFAULTS.copy() self.enabled = {prop_name: [] for prop_name in alg_lists.ALL} for directive in directives: # TODO: validate that the target exists ss = ScopeSelector(directive.scope) if ss.matches(relevant_scopes): if directive.operation == Operation.RESET: self.enabled[directive.prop_name] = [] elif directive.operation == Operation.APPEND: enabled = self.enabled[directive.prop_name] if directive.value not in enabled: enabled.append(directive.value) elif directive.operation == Operation.PREPEND: enabled = self.enabled[directive.prop_name] # in case of duplicates, remove the latter, lower-prio ones if directive.value in enabled: enabled.remove(directive.value) enabled.insert(0, directive.value) elif directive.operation == Operation.OMIT: self.enabled[directive.prop_name] = [ e for e in self.enabled[directive.prop_name] if e != directive.value ] else: assert directive.operation == Operation.SET_INT self.integers[directive.prop_name] = directive.value assert len(self.enabled) == len(set(self.enabled)) self.disabled = {prop_name: [e for e in alg_lists.ALL[prop_name] if e not in self.enabled[prop_name]] for prop_name in alg_lists.ALL} @property def min_tls_version(self): return alg_lists.min_tls_version(self.enabled['protocol']) @property def max_tls_version(self): return alg_lists.max_tls_version(self.enabled['protocol']) @property def min_dtls_version(self): return alg_lists.min_dtls_version(self.enabled['protocol']) @property def max_dtls_version(self): return alg_lists.max_dtls_version(self.enabled['protocol']) # Locating policy files def lookup_file(policyname, fname, paths): for d in paths: p = os.path.join(d, fname) if os.access(p, os.R_OK): return p raise validation.PolicyFileNotFoundError(policyname, fname, paths) # main class class UnscopedCryptoPolicy: CONFIG_DIR = '/etc/crypto-policies' SHARE_DIR = '/usr/share/crypto-policies' def __init__(self, policy_name, *subpolicy_names, policydir=None): self.policydir = policydir self.policyname = ':'.join((policy_name,) + subpolicy_names) self.lines = [] directives = self.read_policy_file(policy_name) for subpolicy_name in subpolicy_names: directives += self.read_policy_file(subpolicy_name, subpolicy=True) self._directives = directives def is_empty(self): return not self._directives def scoped(self, scopes=None): return ScopedPolicy(self._directives, scopes or {}) def read_policy_file(self, name, subpolicy=False): pdir = self.policydir or 'policies' if subpolicy: pdir = os.path.join(pdir, 'modules') p = lookup_file(name, name + ('.pol' if not subpolicy else '.pmod'), ( os.path.curdir, pdir, os.path.join(self.CONFIG_DIR, pdir), os.path.join(self.SHARE_DIR, pdir), )) # TODO: error handling with open(p) as f: text = f.read() text = preprocess_text(text) lines = text.split('\n') for l in lines: # display several warnings at once syntax_check_line(l, warn=True) for l in lines: # crash syntax_check_line(l) return sum([parse_line(l) for l in lines], []) def __str__(self): def fmt(key, value): s = ' '.join(value) if isinstance(value, list) else str(value) return f'{key} = {s}'.rstrip() + '\n' generic_scoped = self.scoped() s = f'# Policy {self.policyname} dump\n' s += '#\n' s += '# Do not parse the contents of this file with automated tools,\n' s += '# it is provided for review convenience only.\n' s += '#\n' s += '# Baseline values for all scopes:\n' generic_all = {**generic_scoped.enabled, **generic_scoped.integers} for prop_name, value in generic_all.items(): s += fmt(prop_name, value) anything_scope_specific = False for scope_name, scope_set in DUMPABLE_SCOPES.items(): specific_scoped = self.scoped(scopes=scope_set) specific_all = {**specific_scoped.enabled, **specific_scoped.integers} for prop_name, value in specific_all.items(): if value != generic_all[prop_name]: if not anything_scope_specific: s += ('# Scope-specific properties ' 'derived for select backends:\n') anything_scope_specific = True s += fmt(f'{prop_name}@{scope_name}', value) if not anything_scope_specific: s += '# No scope-specific properties found.\n' return s PK3]:E6..cryptopolicies/alg_lists.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2019 Red Hat, Inc. # Copyright (c) 2019 Tomáš Mráz """ Lists of algorithms and globbing among them. """ import fnmatch from . import validation ALL_CIPHERS = ( 'AES-256-GCM', 'AES-256-CCM', 'AES-192-GCM', 'AES-192-CCM', 'AES-128-GCM', 'AES-128-CCM', 'CHACHA20-POLY1305', 'CAMELLIA-256-GCM', 'CAMELLIA-128-GCM', 'AES-256-CTR', 'AES-256-CBC', 'AES-192-CTR', 'AES-192-CBC', 'AES-128-CTR', 'AES-128-CBC', 'CAMELLIA-256-CBC', 'CAMELLIA-128-CBC', '3DES-CBC', 'DES-CBC', 'RC4-40', 'RC4-128', 'DES40-CBC', 'RC2-CBC', 'IDEA-CBC', 'SEED-CBC', 'NULL', ) ALL_MACS = ( 'AEAD', 'UMAC-128', 'HMAC-SHA1', 'HMAC-SHA2-256', 'HMAC-SHA2-384', 'HMAC-SHA2-512', 'UMAC-64', 'HMAC-MD5', ) ALL_HASHES = ( 'SHA2-256', 'SHA2-384', 'SHA2-512', 'SHA3-256', 'SHA3-384', 'SHA3-512', 'SHA2-224', 'SHA1', 'MD5', 'GOST', ) # we disable curves <= 256 bits by default in Fedora ALL_GROUPS = ( 'X25519', 'SECP256R1', 'SECP384R1', 'SECP521R1', 'X448', 'FFDHE-1536', 'FFDHE-2048', 'FFDHE-3072', 'FFDHE-4096', 'FFDHE-6144', 'FFDHE-8192', 'FFDHE-1024', ) ALL_SIGN = ( 'RSA-MD5', 'RSA-SHA1', 'DSA-SHA1', 'ECDSA-SHA1', 'RSA-SHA2-224', 'DSA-SHA2-224', 'ECDSA-SHA2-224', 'RSA-SHA2-256', 'DSA-SHA2-256', 'ECDSA-SHA2-256', 'ECDSA-SHA2-256-FIDO', 'RSA-SHA2-384', 'DSA-SHA2-384', 'ECDSA-SHA2-384', 'RSA-SHA2-512', 'DSA-SHA2-512', 'ECDSA-SHA2-512', 'RSA-SHA3-256', 'DSA-SHA3-256', 'ECDSA-SHA3-256', 'RSA-SHA3-384', 'DSA-SHA3-384', 'ECDSA-SHA3-384', 'RSA-SHA3-512', 'DSA-SHA3-512', 'ECDSA-SHA3-512', 'EDDSA-ED25519', 'EDDSA-ED25519-FIDO', 'EDDSA-ED448', 'RSA-PSS-SHA1', 'RSA-PSS-SHA2-224', 'RSA-PSS-SHA2-256', 'RSA-PSS-SHA2-384', 'RSA-PSS-SHA2-512', 'RSA-PSS-RSAE-SHA1', 'RSA-PSS-RSAE-SHA2-224', 'RSA-PSS-RSAE-SHA2-256', 'RSA-PSS-RSAE-SHA2-384', 'RSA-PSS-RSAE-SHA2-512', ) ALL_KEY_EXCHANGES = ( 'PSK', 'DHE-PSK', 'ECDHE-PSK', 'ECDHE', 'RSA', 'DHE', 'DHE-RSA', 'DHE-DSS', 'EXPORT', 'ANON', 'DH', 'ECDH', 'DHE-GSS', 'ECDHE-GSS', ) # Order matters, see preprocess_text TLS_PROTOCOLS = ('TLS1.3', 'TLS1.2', 'TLS1.1', 'TLS1.0', 'SSL3.0', 'SSL2.0') DTLS_PROTOCOLS = ('DTLS1.2', 'DTLS1.0', 'DTLS0.9') IKE_PROTOCOLS = ('IKEv2', 'IKEv1') ALL_PROTOCOLS = TLS_PROTOCOLS + DTLS_PROTOCOLS + IKE_PROTOCOLS ALL = { 'cipher': ALL_CIPHERS, 'group': ALL_GROUPS, 'hash': ALL_HASHES, 'key_exchange': ALL_KEY_EXCHANGES, 'mac': ALL_MACS, 'protocol': ALL_PROTOCOLS, 'sign': ALL_SIGN, } def glob(pattern, alg_class): """ Lists algorithms matching a glob, in order of appearance in ALL[alg_class]. For more examples, refer to tests/unit/parsing/test_alg_lists.py >>> glob('RC4-*', 'cipher') ['RC4-40', 'RC4-128'] """ if alg_class not in ALL: raise validation.alg_lists.AlgorithmClassUnknownError(alg_class) r = fnmatch.filter(ALL[alg_class], pattern) if not r: raise validation.alg_lists.AlgorithmEmptyMatchError(pattern, alg_class) return r def earliest_occurrence(needles, ordered_haystack): """ >>> earliest_occurrence('test', 'abcdefghijklmnopqrstuvwxyz') 'e' """ intersection = [n for n in needles if n in ordered_haystack] if not intersection: return None indices = (ordered_haystack.index(n) for n in intersection) return ordered_haystack[min(indices)] def min_tls_version(versions): """ >>> min_tls_version(['SSL3.0', 'TLS1.2']) 'SSL3.0' """ return earliest_occurrence(versions, TLS_PROTOCOLS[::-1]) def min_dtls_version(versions): """ >>> min_dtls_version(['DTLS1.2', 'DTLS1.0']) 'DTLS1.0' """ return earliest_occurrence(versions, DTLS_PROTOCOLS[::-1]) def max_tls_version(versions): """ >>> max_tls_version(['SSL3.0', 'TLS1.2']) 'TLS1.2' """ return earliest_occurrence(versions, TLS_PROTOCOLS) def max_dtls_version(versions): """ >>> max_dtls_version(['DTLS1.2', 'DTLS1.0']) 'DTLS1.2' """ return earliest_occurrence(versions, DTLS_PROTOCOLS) PK3]"~8cryptopolicies/__pycache__/__init__.cpython-36.opt-1.pycnu[3 ."d@sddlmZdgZdS))UnscopedCryptoPolicyrN)Zcryptopoliciesr__all__rr=./usr/share/crypto-policies/python/cryptopolicies/__init__.pys PK3]>>>cryptopolicies/__pycache__/cryptopolicies.cpython-36.opt-1.pycnu[3 ."dCB@s6ddlZddlZddlZddlZddlZddlZddlmZddlmZdddZd-d.Zd?d0d1ZGd2d3d3eZd4d5ZGd6d7d7Zd8d9ZGd:d;d;ZdS)@N) alg_lists) validationcCsi|] }d|qS)r).0krrC./usr/share/crypto-policies/python/cryptopolicies/cryptopolicies.py sr arbitrary_dh_groups min_dh_size min_dsa_size min_rsa_size sha1_in_certs ssh_certsssh_etm*tlssslopensslnssgnutlsjava-tlssshopensshopenssh-serveropenssh-clientlibsshipsecike libreswankerberoskrb5dnssecbind) r#rzjava-tlsr!rrrzopenssh-clientzopenssh-serverrc@s(eZdZefddZddZddZdS) ScopeSelectorcCs|j|_}|jd |_|jr&|n |dd}tjj||jdtjj||jd|jdrr|ddjdn|g|_ tjj |j t |jddS)a= Initialize a scope selector. An example would be `ssh` in `ciphers@ssh = -NULL`. When openssh backend will request the configuration, it'll offer (`{'ssh', 'openssh'}`) as scopes and the rule above will be taken into account. Both patterns and scopes are cast to lowercase. For more examples, refer to tests/unit/parsing/test_scope_selector.py >>> ss = ScopeSelector('!{SSH,IPsec}') >>> ss.matches({'ipsec', 'libreswan'}) False >>> ss.matches({'tls', 'openssl'}) True !rN)Zoriginal_pattern{,) lowerpattern startswith _positiverscopeZillegal_charactersZcurly_bracketssplit_globsZresulting_globs ALL_SCOPES)selfr*prrr__init__5s$ zScopeSelector.__init__cCsdt|jdS)Nz)reprr*)r1rrr__str__PszScopeSelector.__str__csR|jtkrdSddD|jr:tfdd|jDStfdd|jDS)aE Checks whether ScopeSelector matches one of the scopes. For more examples, refer to tests/unit/parsing/test_scope_selector.py >>> ScopeSelector('{SSH,IPsec}').matches({'ipsec', 'libreswan'}) True >>> ScopeSelector('!{SSH,IPsec}').matches({'ipsec', 'libreswan'}) False TcSsg|] }|jqSr)r))rsrrr ^sz)ScopeSelector.matches..c3s|]}tj|VqdS)N)fnmatchfilter)rg)scopesrr asz(ScopeSelector.matches..c3s|]}tj| VqdS)N)r9r:)rr;)r<rrr=bs)r* SCOPE_ANYr,anyr/all)r1r<r)r<rmatchesSs zScopeSelector.matchesN)__name__ __module__ __qualname__r>r3r6rArrrrr$4s r$c@s$eZdZdZdZdZdZdZdZdS) OperationzM An operation that comes with the right-hand value of the directive. rN) rBrCrD__doc__RESETPREPENDAPPENDOMITSET_INTrrrrrEgs rEcsdd|jrLtjkr2tkr2tjt|fgStjkr`tjj q`ntkr`tjj |j }t fdd|Dst fdd|Dg}tjdfgdd|DStfd d|Drtg}x|D]}|jd rtjtj|d dddd }nL|jd r:tjtj|ddddd}ntjtj|d d}|jfd d|DqW|Stjj|dS)a7 Parses right-hand parts of the directives into lists of operation/value pairs. For more examples, refer to tests/unit/test_parsing.py >>> parse_rhs('', 'cipher') [(, None)] >>> parse_rhs('IDEA-CBC SEED-CBC', 'cipher') [(, None), (, 'IDEA-CBC'), (, 'SEED-CBC')] >>> # 3DES-CBC gets prepended last for higher prio >>> parse_rhs('+*DES-CBC', 'cipher') [(, 'DES-CBC'), (, '3DES-CBC')] cSs|jdp|jdp|jdS)N+-)r+endswith)vrrr differentialszparse_rhs..differentialc3s|]}|VqdS)Nr)rrS)rTrrr=szparse_rhs..csg|]}tj|qSr)rglob)rrS) prop_namerrr8szparse_rhs..NcSsg|]}tj|fqSr)rErM)rrSrrrr8sc3s|]}|VqdS)Nr)rrS)rTrrr=srPrcsg|] }|fqSrr)rrS)oprrr8sr(r(r()isdigitrALL INT_DEFAULTSrErOintrrulesZNonIntPropertyIntValueErrorZIntPropertyNonIntValueErrorr.r?sumrKr@r+rLrUrRrMrNextendZ%MixedDifferentialNonDifferentialError)rhsrVvaluesZ operationsvalueZunglobr)rTrWrVr parse_rhsrs8        rb DirectiverVr- operationracs|js gStjj||jd\}}|j|j}}tjj||d|krZ|jddn|tf\fddt|DS)ae Parses configuration lines into tuples of directives. For more examples, refer to tests/unit/test_parsing.py >>> parse_line('cipher@TLS = RC4* NULL') [Directive(prop_name='cipher', scope='tls', operation=, value=None), Directive(prop_name='cipher', scope='tls', operation=, value='RC4-40'), Directive(prop_name='cipher', scope='tls', operation=, value='RC4-128'), Directive(prop_name='cipher', scope='tls', operation=, value='NULL')] =@rcs$g|]\}}tj||dqS))rVr-rdra)rcr))rrdra)rVr-rrr8szparse_line..)striprr\Zcount_equals_signsr.Z empty_lhsr>rb)lineZlhsr_r)rVr-r parse_lines   riFcCs^y$t|}x|D]}t|jqWWn4tjk rX}z|s>tj|WYdd}~XnXdS)N)rir$r-rZPolicySyntaxErrorwarningswarn)rhrkldexrrrsyntax_check_lines rocseZdZfddZZS)PolicySyntaxDeprecationWarningcs@|jdd}d|d}|d|d7}|d7}tj|dS)N z and zoption z is deprecatedz", please rewrite your rules using z; z2be advised that it is not always a 1-1 replacement)replacesuperr3)r1Z deprecatedZ replacementmsg) __class__rrr3s   z'PolicySyntaxDeprecationWarning.__init__)rBrCrDr3 __classcell__rr)rurrpsrpc Cstjdd|}|jdd}djdd|jdD}|jdd}djd d|jdD}djd d|jdD}tjd d|j}tjd |rtjt d dddddd}xr|j D]f\}}d|d}tj||}|rtjt ||tj|d|}x"|D]}|d|d|7}qWqWtjd d|j}ddd}xN|j D]B\}}d|d}tj ||r|tjt ||tj|||}qJWt t jddd%}xZ|rdjdd|dd&D} tjd|d'd| rd | nd|}|jqWtjd!d|}t t jddd(} xZ| r|djd"d| dd)D} tjd#| d*d| rhd | nd|}| jq$Wtjd$d|}|S)+a Preprocesses text before parsing. Fixes line breaks, handles backwards compatibility. >>> preprocess_text('cipher = c1 \\ \nc2#x') 'cipher = c1 c2' >>> with warnings.catch_warnings(): ... warnings.simplefilter("ignore") ... preprocess_text('ike_protocol = IKEv2') 'protocol@IKE = IKEv2' >>> with warnings.catch_warnings(): ... warnings.simplefilter("ignore") ... preprocess_text('min_tls_version=TLS1.3') 'protocol@TLS = -SSL2.0 -SSL3.0 -TLS1.0 -TLS1.1 -TLS1.2' z#.*rez = rqcss|]}|jVqdS)N)rg)rrlrrrr=sz"preprocess_text..z\ css|]}|jVqdS)N)rg)rrlrrrr=scss|]}tjdd|VqdS)z\s+ N)resub)rrlrrrr=sz +z\bprotocol\s*=protocolz protocol@TLSz cipher@TLSz cipher@SSHz group@SSHz protocol@IKE)Z tls_cipherZ ssh_cipherZ ssh_groupZ ike_protocolz\bz\s*=(.*)z z =z7hash@DNSSec = -SHA1 sign@DNSSec = -RSA-SHA1 -ECDSA-SHA1z7hash@DNSSec = SHA1+ sign@DNSSec = RSA-SHA1+ ECDSA-SHA1+)zsha1_in_dnssec = 0zsha1_in_dnssec = 1Nrrxcss|]}d|VqdS)rQNr)rrSrrrr=sz\bmin_dtls_version = zprotocol@TLS = z\bmin_dtls_version = 0\bcss|]}d|VqdS)rQNr)rrSrrrr=$sz\bmin_tls_version = z\bmin_tls_version = 0\br(r(r(r(r(r()ryrzrrjoinr.rgfindallrjrkrpitemssearchlistrZDTLS_PROTOCOLSpopZ TLS_PROTOCOLS) textZPOSTFIX_REPLACEMENTSfrZtoZregexZmsmZPLAIN_REPLACEMENTSZ dtls_versionsnegZ tls_versionsrrrpreprocess_textsZ       rc@sJeZdZdZd ddZeddZeddZed d Zed d Z dS) ScopedPolicya An entity constructing lists of what's `.enabled` and what's `.disabled` when the given scopes are active. >>> sp = ScopedPolicy(parse_line('cipher@TLS = RC4* NULL'), {'tls'}) >>> 'AES-256-GCM' in sp.disabled['cipher'] True >>> sp.enabled['cipher'] ['RC4-40', 'RC4-128', 'NULL'] >>> ScopedPolicy(parse_line('min_dh_size=2048')).integers['min_dh_size'] 2048 Ncs(|pt}tj_ddtjD_x|D]މtj}|j |r,j t j kr^gjj <q,j t jkrjj }j|kr|jjq,j t jkr̈jj }j|kr|jj|jdjq,j t jkrfddjj Djj <q,jjj <q,WfddtjD_dS)NcSsi|] }g|qSrr)rrVrrrr >sz)ScopedPolicy.__init__..rcsg|]}|jkr|qSr)ra)re) directiverrr8Rsz)ScopedPolicy.__init__..cs(i|] fddtjDqS)csg|]}|jkr|qSr)enabled)rr)rVr1rrr8Zsz4ScopedPolicy.__init__...)rrY)r)r1)rVrr Zs)setrZcopyintegersrrYrr$r-rArdrErKrVrMraappendrLremoveinsertrNZdisabled)r1 directivesZrelevant_scopesZssrr)rr1rr3;s,              $ zScopedPolicy.__init__cCstj|jdS)Nr{)rmin_tls_versionr)r1rrrr^szScopedPolicy.min_tls_versioncCstj|jdS)Nr{)rmax_tls_versionr)r1rrrrbszScopedPolicy.max_tls_versioncCstj|jdS)Nr{)rmin_dtls_versionr)r1rrrrfszScopedPolicy.min_dtls_versioncCstj|jdS)Nr{)rmax_dtls_versionr)r1rrrrjszScopedPolicy.max_dtls_version)N) rBrCrDrJr3propertyrrrrrrrrr/s   #   rcCs@x,|D]$}tjj||}tj|tjr|SqWtj|||dS)N)ospathr|accessR_OKrZPolicyFileNotFoundError) policynamefnamepathsrmr2rrr lookup_fileqs  rc@sFeZdZdZdZddddZddZdd d Zdd d ZddZ dS)UnscopedCryptoPolicyz/etc/crypto-policiesz/usr/share/crypto-policiesN) policydircGsR||_dj|f||_g|_|j|}x|D]}||j|dd7}q.W||_dS)N:T) subpolicy)rr|rlinesread_policy_file _directives)r1Z policy_namerZsubpolicy_namesrZsubpolicy_namerrrr3s  zUnscopedCryptoPolicy.__init__cCs|j S)N)r)r1rrris_emptyszUnscopedCryptoPolicy.is_emptycCst|j|p iS)N)rr)r1r<rrrscopedszUnscopedCryptoPolicy.scopedFc Cs|jpd}|rtjj|d}t|||s*dndtjj|tjj|j|tjj|j|f}t|}|j }WdQRXt |}|j d}x|D]}t |ddqWx|D] }t |qWt dd |DgS) NZpoliciesmodulesz.polz.pmodrqT)rkcSsg|] }t|qSr)ri)rrlrrrr8sz9UnscopedCryptoPolicy.read_policy_file..)rrrr|rcurdir CONFIG_DIR SHARE_DIRopenreadrr.ror]) r1namerZpdirr2frrrlrrrrs$      z%UnscopedCryptoPolicy.read_policy_filec Csdd}|j}d|jd}|d7}|d7}|d7}|d7}|d7}|j|j}x"|jD]\}}||||7}q\Wd }xvtjD]j\}} |j| d } | j| j} xH| jD]<\}}|||kr|s|d 7}d }|||d ||7}qWqW|s|d7}|S)NcSs2t|trdj|nt|}|d|jdS)Nrxz = rq) isinstancerr|strrstrip)keyrar7rrrfmtsz)UnscopedCryptoPolicy.__str__..fmtz # Policy z dump z# z?# Do not parse the contents of this file with automated tools, z.# it is provided for review convenience only. z"# Baseline values for all scopes: F)r<z9# Scope-specific properties derived for select backends: Trfz&# No scope-specific properties found. )rrrrr~DUMPABLE_SCOPES) r1rZgeneric_scopedr7Z generic_allrVraZanything_scope_specificZ scope_nameZ scope_setZspecific_scopedZ specific_allrrrr6s2    zUnscopedCryptoPolicy.__str__)N)F) rBrCrDrrr3rrrr6rrrrr{s   r)r r r r rrr)rrrrrrrrrrrrrrr r!r"r#)rVr-rdra)F) collectionsenumr9rryrjrwrrrZr>r0rr$EnumrErb namedtuplercriro FutureWarningrprrrrrrrrsP  3 ;  LB PK3]U9cryptopolicies/__pycache__/alg_lists.cpython-36.opt-1.pycnu[3 ."d.'@sdZddlZddlmZdZdZdZdZdZdZ dZ dZ dZ e e e Z eeee ee ed}Zd~dZddZddZddZddZddZdS)z. Lists of algorithms and globbing among them. N) validation AES-256-GCM AES-256-CCM AES-192-GCM AES-192-CCM AES-128-GCM AES-128-CCMCHACHA20-POLY1305CAMELLIA-256-GCMCAMELLIA-128-GCM AES-256-CTR AES-256-CBC AES-192-CTR AES-192-CBC AES-128-CTR AES-128-CBCCAMELLIA-256-CBCCAMELLIA-128-CBC3DES-CBCDES-CBCRC4-40RC4-128 DES40-CBCRC2-CBCIDEA-CBCSEED-CBCNULLAEADUMAC-128 HMAC-SHA1 HMAC-SHA2-256 HMAC-SHA2-384 HMAC-SHA2-512UMAC-64HMAC-MD5SHA2-256SHA2-384SHA2-512SHA3-256SHA3-384SHA3-512SHA2-224SHA1MD5GOSTX25519 SECP256R1 SECP384R1 SECP521R1X448 FFDHE-1536 FFDHE-2048 FFDHE-3072 FFDHE-4096 FFDHE-6144 FFDHE-8192 FFDHE-1024RSA-MD5RSA-SHA1DSA-SHA1 ECDSA-SHA1 RSA-SHA2-224 DSA-SHA2-224ECDSA-SHA2-224 RSA-SHA2-256 DSA-SHA2-256ECDSA-SHA2-256ECDSA-SHA2-256-FIDO RSA-SHA2-384 DSA-SHA2-384ECDSA-SHA2-384 RSA-SHA2-512 DSA-SHA2-512ECDSA-SHA2-512 RSA-SHA3-256 DSA-SHA3-256ECDSA-SHA3-256 RSA-SHA3-384 DSA-SHA3-384ECDSA-SHA3-384 RSA-SHA3-512 DSA-SHA3-512ECDSA-SHA3-512 EDDSA-ED25519EDDSA-ED25519-FIDO EDDSA-ED448 RSA-PSS-SHA1RSA-PSS-SHA2-224RSA-PSS-SHA2-256RSA-PSS-SHA2-384RSA-PSS-SHA2-512RSA-PSS-RSAE-SHA1RSA-PSS-RSAE-SHA2-224RSA-PSS-RSAE-SHA2-256RSA-PSS-RSAE-SHA2-384RSA-PSS-RSAE-SHA2-512PSKDHE-PSK ECDHE-PSKECDHERSADHEDHE-RSADHE-DSSEXPORTANONDHECDHDHE-GSS ECDHE-GSSTLS1.3TLS1.2TLS1.1TLS1.0SSL3.0SSL2.0DTLS1.2DTLS1.0DTLS0.9IKEv2IKEv1)ZciphergrouphashZ key_exchangeZmacZprotocolZsigncCs:|tkrtjj|tjt||}|s6tjj|||S)z Lists algorithms matching a glob, in order of appearance in ALL[alg_class]. For more examples, refer to tests/unit/parsing/test_alg_lists.py >>> glob('RC4-*', 'cipher') ['RC4-40', 'RC4-128'] )ALLrZ alg_listsZAlgorithmClassUnknownErrorfnmatchfilterZAlgorithmEmptyMatchError)patternZ alg_classrr>./usr/share/crypto-policies/python/cryptopolicies/alg_lists.pyglobYs  rcs8fdd|D}|sdSfdd|D}t|S)zO >>> earliest_occurrence('test', 'abcdefghijklmnopqrstuvwxyz') 'e' csg|]}|kr|qSrr).0n)ordered_haystackrr nsz'earliest_occurrence..Nc3s|]}j|VqdS)N)index)rr)rrr qsz&earliest_occurrence..)min)Zneedlesr intersectionindicesr)rrearliest_occurrenceis rcCst|tdddS)z@ >>> min_tls_version(['SSL3.0', 'TLS1.2']) 'SSL3.0' Nr)r TLS_PROTOCOLS)versionsrrrmin_tls_versionusrcCst|tdddS)zD >>> min_dtls_version(['DTLS1.2', 'DTLS1.0']) 'DTLS1.0' Nrr)rDTLS_PROTOCOLS)rrrrmin_dtls_version}srcCs t|tS)z@ >>> max_tls_version(['SSL3.0', 'TLS1.2']) 'TLS1.2' )rr)rrrrmax_tls_versionsrcCs t|tS)zD >>> max_dtls_version(['DTLS1.2', 'DTLS1.0']) 'DTLS1.2' )rr)rrrrmax_dtls_versionsr)rrrrrr r r r r rrrrrrrrrrrrrrrr)rrr r!r"r#r$r%) r&r'r(r)r*r+r,r-r.r/) r0r1r2r3r4r5r6r7r8r9r:r;)'r<r=r>r?r@rArBrCrDrErFrGrHrIrJrKrLrMrNrOrPrQrRrSrTrUrVrWrXrYrZr[r\r]r^r_r`rarb)rcrdrerfrgrhrirjrkrlrmrnrorp)rqrrrsrtrurv)rwrxry)rzr{)__doc__rrZ ALL_CIPHERSZALL_MACSZ ALL_HASHESZ ALL_GROUPSZALL_SIGNZALL_KEY_EXCHANGESrrZ IKE_PROTOCOLSZ ALL_PROTOCOLSr~rrrrrrrrrrsn   PK3]q5]??8cryptopolicies/__pycache__/cryptopolicies.cpython-36.pycnu[3 ."dCB@s6ddlZddlZddlZddlZddlZddlZddlmZddlmZdddZd-d.Zd?d0d1ZGd2d3d3eZd4d5ZGd6d7d7Zd8d9ZGd:d;d;ZdS)@N) alg_lists) validationcCsi|] }d|qS)r).0krrC./usr/share/crypto-policies/python/cryptopolicies/cryptopolicies.py sr arbitrary_dh_groups min_dh_size min_dsa_size min_rsa_size sha1_in_certs ssh_certsssh_etm*tlssslopensslnssgnutlsjava-tlssshopensshopenssh-serveropenssh-clientlibsshipsecike libreswankerberoskrb5dnssecbind) r#rzjava-tlsr!rrrzopenssh-clientzopenssh-serverrc@s(eZdZefddZddZddZdS) ScopeSelectorcCs|j|_}|jd |_|jr&|n |dd}tjj||jdtjj||jd|jdrr|ddjdn|g|_ tjj |j t |jddS)a= Initialize a scope selector. An example would be `ssh` in `ciphers@ssh = -NULL`. When openssh backend will request the configuration, it'll offer (`{'ssh', 'openssh'}`) as scopes and the rule above will be taken into account. Both patterns and scopes are cast to lowercase. For more examples, refer to tests/unit/parsing/test_scope_selector.py >>> ss = ScopeSelector('!{SSH,IPsec}') >>> ss.matches({'ipsec', 'libreswan'}) False >>> ss.matches({'tls', 'openssl'}) True !rN)Zoriginal_pattern{,) lowerpattern startswith _positiverscopeZillegal_charactersZcurly_bracketssplit_globsZresulting_globs ALL_SCOPES)selfr*prrr__init__5s$ zScopeSelector.__init__cCsdt|jdS)Nz)reprr*)r1rrr__str__PszScopeSelector.__str__csh|jtkrdSddDtddDs2t|jrPtfdd|jDStfdd|jDS)aE Checks whether ScopeSelector matches one of the scopes. For more examples, refer to tests/unit/parsing/test_scope_selector.py >>> ScopeSelector('{SSH,IPsec}').matches({'ipsec', 'libreswan'}) True >>> ScopeSelector('!{SSH,IPsec}').matches({'ipsec', 'libreswan'}) False TcSsg|] }|jqSr)r))rsrrr ^sz)ScopeSelector.matches..css|]}|tkVqdS)N)r0)rr7rrr _sz(ScopeSelector.matches..c3s|]}tj|VqdS)N)fnmatchfilter)rg)scopesrrr9asc3s|]}tj| VqdS)N)r:r;)rr<)r=rrr9bs)r* SCOPE_ANYallAssertionErrorr,anyr/)r1r=r)r=rmatchesSs zScopeSelector.matchesN)__name__ __module__ __qualname__r>r3r6rBrrrrr$4s r$c@s$eZdZdZdZdZdZdZdZdS) OperationzM An operation that comes with the right-hand value of the directive. rN) rCrDrE__doc__RESETPREPENDAPPENDOMITSET_INTrrrrrFgs rFcsdd|jrftjkr2tkr2tjt|fgStjkrJtjj qztjksXt tkszt ntkrztjj |j }t fdd|Dstfdd|Dg}tjdfgdd|DStfd d|Drg}x|D]}|jd r"tjtj|d dddd}n\|jd rTtjtj|ddddd}n*|jd sdt tjtj|d d}|jfd d|DqW|Stjj|dS)a7 Parses right-hand parts of the directives into lists of operation/value pairs. For more examples, refer to tests/unit/test_parsing.py >>> parse_rhs('', 'cipher') [(, None)] >>> parse_rhs('IDEA-CBC SEED-CBC', 'cipher') [(, None), (, 'IDEA-CBC'), (, 'SEED-CBC')] >>> # 3DES-CBC gets prepended last for higher prio >>> parse_rhs('+*DES-CBC', 'cipher') [(, 'DES-CBC'), (, '3DES-CBC')] cSs|jdp|jdp|jdS)N+-)r+endswith)vrrr differentialszparse_rhs..differentialc3s|]}|VqdS)Nr)rrT)rUrrr9szparse_rhs..csg|]}tj|qSr)rglob)rrT) prop_namerrr8szparse_rhs..NcSsg|]}tj|fqSr)rFrN)rrTrrrr8sc3s|]}|VqdS)Nr)rrT)rUrrr9srQrrRcsg|] }|fqSrr)rrT)oprrr8sr(r(r()isdigitrALL INT_DEFAULTSrFrPintrrulesZNonIntPropertyIntValueErrorr@ZIntPropertyNonIntValueErrorr.rAsumrLr?r+rMrVrSrNrOextendZ%MixedDifferentialNonDifferentialError)rhsrWvaluesZ operationsvalueZunglobr)rUrXrWr parse_rhsrs<        rc DirectiverWr- operationrbcs|js gStjj||jd\}}|j|j}}tjj||d|krZ|jddn|tf\fddt|DS)ae Parses configuration lines into tuples of directives. For more examples, refer to tests/unit/test_parsing.py >>> parse_line('cipher@TLS = RC4* NULL') [Directive(prop_name='cipher', scope='tls', operation=, value=None), Directive(prop_name='cipher', scope='tls', operation=, value='RC4-40'), Directive(prop_name='cipher', scope='tls', operation=, value='RC4-128'), Directive(prop_name='cipher', scope='tls', operation=, value='NULL')] =@rcs$g|]\}}tj||dqS))rWr-rerb)rdr))rrerb)rWr-rrr8szparse_line..)striprr]Zcount_equals_signsr.Z empty_lhsr>rc)lineZlhsr`r)rWr-r parse_lines   rjFcCs^y$t|}x|D]}t|jqWWn4tjk rX}z|s>tj|WYdd}~XnXdS)N)rjr$r-rZPolicySyntaxErrorwarningswarn)rirlldexrrrsyntax_check_lines rpcseZdZfddZZS)PolicySyntaxDeprecationWarningcs@|jdd}d|d}|d|d7}|d7}tj|dS)N z and zoption z is deprecatedz", please rewrite your rules using z; z2be advised that it is not always a 1-1 replacement)replacesuperr3)r1Z deprecatedZ replacementmsg) __class__rrr3s   z'PolicySyntaxDeprecationWarning.__init__)rCrDrEr3 __classcell__rr)rvrrqsrqc Cstjdd|}|jdd}djdd|jdD}|jdd}djd d|jdD}djd d|jdD}tjd d|j}tjd |rtjt d dddddd}xr|j D]f\}}d|d}tj||}|rtjt ||tj|d|}x"|D]}|d|d|7}qWqWtjd d|j}ddd}xN|j D]B\}}d|d}tj ||r|tjt ||tj|||}qJWt t jddd%}xZ|rdjdd|dd&D} tjd|d'd| rd | nd|}|jqWtjd!d|}t t jddd(} xZ| r|djd"d| dd)D} tjd#| d*d| rhd | nd|}| jq$Wtjd$d|}|S)+a Preprocesses text before parsing. Fixes line breaks, handles backwards compatibility. >>> preprocess_text('cipher = c1 \\ \nc2#x') 'cipher = c1 c2' >>> with warnings.catch_warnings(): ... warnings.simplefilter("ignore") ... preprocess_text('ike_protocol = IKEv2') 'protocol@IKE = IKEv2' >>> with warnings.catch_warnings(): ... warnings.simplefilter("ignore") ... preprocess_text('min_tls_version=TLS1.3') 'protocol@TLS = -SSL2.0 -SSL3.0 -TLS1.0 -TLS1.1 -TLS1.2' z#.*rfz = rrcss|]}|jVqdS)N)rh)rrmrrrr9sz"preprocess_text..z\ css|]}|jVqdS)N)rh)rrmrrrr9scss|]}tjdd|VqdS)z\s+ N)resub)rrmrrrr9sz +z\bprotocol\s*=protocolz protocol@TLSz cipher@TLSz cipher@SSHz group@SSHz protocol@IKE)Z tls_cipherZ ssh_cipherZ ssh_groupZ ike_protocolz\bz\s*=(.*)z z =z7hash@DNSSec = -SHA1 sign@DNSSec = -RSA-SHA1 -ECDSA-SHA1z7hash@DNSSec = SHA1+ sign@DNSSec = RSA-SHA1+ ECDSA-SHA1+)zsha1_in_dnssec = 0zsha1_in_dnssec = 1Nrrycss|]}d|VqdS)rRNr)rrTrrrr9sz\bmin_dtls_version = zprotocol@TLS = z\bmin_dtls_version = 0\bcss|]}d|VqdS)rRNr)rrTrrrr9$sz\bmin_tls_version = z\bmin_tls_version = 0\br(r(r(r(r(r()rzr{rsjoinr.rhfindallrkrlrqitemssearchlistrZDTLS_PROTOCOLSpopZ TLS_PROTOCOLS) textZPOSTFIX_REPLACEMENTSfrZtoZregexZmsmZPLAIN_REPLACEMENTSZ dtls_versionsnegZ tls_versionsrrrpreprocess_textsZ       rc@sJeZdZdZd ddZeddZeddZed d Zed d Z dS) ScopedPolicya An entity constructing lists of what's `.enabled` and what's `.disabled` when the given scopes are active. >>> sp = ScopedPolicy(parse_line('cipher@TLS = RC4* NULL'), {'tls'}) >>> 'AES-256-GCM' in sp.disabled['cipher'] True >>> sp.enabled['cipher'] ['RC4-40', 'RC4-128', 'NULL'] >>> ScopedPolicy(parse_line('min_dh_size=2048')).integers['min_dh_size'] 2048 NcsX|pt}tj_ddtjD_x|D]tj}|j |r,j t j kr^gjj <q,j t jkrjj }j|kr|jjq,j t jkr̈jj }j|kr|jj|jdjq,j t jkrfddjj Djj <q,j t jkstjjj <q,Wtjttjks>tfddtjD_dS)NcSsi|] }g|qSrr)rrWrrrr >sz)ScopedPolicy.__init__..rcsg|]}|jkr|qSr)rb)re) directiverrr8Rsz)ScopedPolicy.__init__..cs(i|] fddtjDqS)csg|]}|jkr|qSr)enabled)rr)rWr1rrr8Zsz4ScopedPolicy.__init__...)rrZ)r)r1)rWrr Zs)setr[copyintegersrrZrr$r-rBrerFrLrWrNrbappendrMremoveinsertrOrPr@lenZdisabled)r1 directivesZrelevant_scopesZssrr)rr1rr3;s0              $ zScopedPolicy.__init__cCstj|jdS)Nr|)rmin_tls_versionr)r1rrrr^szScopedPolicy.min_tls_versioncCstj|jdS)Nr|)rmax_tls_versionr)r1rrrrbszScopedPolicy.max_tls_versioncCstj|jdS)Nr|)rmin_dtls_versionr)r1rrrrfszScopedPolicy.min_dtls_versioncCstj|jdS)Nr|)rmax_dtls_versionr)r1rrrrjszScopedPolicy.max_dtls_version)N) rCrDrErKr3propertyrrrrrrrrr/s   #   rcCs@x,|D]$}tjj||}tj|tjr|SqWtj|||dS)N)ospathr}accessR_OKrZPolicyFileNotFoundError) policynamefnamepathsrnr2rrr lookup_fileqs  rc@sFeZdZdZdZddddZddZdd d Zdd d ZddZ dS)UnscopedCryptoPolicyz/etc/crypto-policiesz/usr/share/crypto-policiesN) policydircGsR||_dj|f||_g|_|j|}x|D]}||j|dd7}q.W||_dS)N:T) subpolicy)rr}rlinesread_policy_file _directives)r1Z policy_namerZsubpolicy_namesrZsubpolicy_namerrrr3s  zUnscopedCryptoPolicy.__init__cCs|j S)N)r)r1rrris_emptyszUnscopedCryptoPolicy.is_emptycCst|j|p iS)N)rr)r1r=rrrscopedszUnscopedCryptoPolicy.scopedFc Cs|jpd}|rtjj|d}t|||s*dndtjj|tjj|j|tjj|j|f}t|}|j }WdQRXt |}|j d}x|D]}t |ddqWx|D] }t |qWt dd |DgS) NZpoliciesmodulesz.polz.pmodrrT)rlcSsg|] }t|qSr)rj)rrmrrrr8sz9UnscopedCryptoPolicy.read_policy_file..)rrrr}rcurdir CONFIG_DIR SHARE_DIRopenreadrr.rpr^) r1namerZpdirr2frrrmrrrrs$      z%UnscopedCryptoPolicy.read_policy_filec Csdd}|j}d|jd}|d7}|d7}|d7}|d7}|d7}|j|j}x"|jD]\}}||||7}q\Wd }xvtjD]j\}} |j| d } | j| j} xH| jD]<\}}|||kr|s|d 7}d }|||d ||7}qWqW|s|d7}|S)NcSs2t|trdj|nt|}|d|jdS)Nryz = rr) isinstancerr}strrstrip)keyrbr7rrrfmtsz)UnscopedCryptoPolicy.__str__..fmtz # Policy z dump z# z?# Do not parse the contents of this file with automated tools, z.# it is provided for review convenience only. z"# Baseline values for all scopes: F)r=z9# Scope-specific properties derived for select backends: Trgz&# No scope-specific properties found. )rrrrrDUMPABLE_SCOPES) r1rZgeneric_scopedr7Z generic_allrWrbZanything_scope_specificZ scope_nameZ scope_setZspecific_scopedZ specific_allrrrr6s2    zUnscopedCryptoPolicy.__str__)N)F) rCrDrErrr3rrrr6rrrrr{s   r)r r r r rrr)rrrrrrrrrrrrrrr r!r"r#)rWr-rerb)F) collectionsenumr:rrzrkrxrrr[r>r0rr$EnumrFrc namedtuplerdrjrp FutureWarningrqrrrrrrrrsP  3 ;  LB PK3]U3cryptopolicies/__pycache__/alg_lists.cpython-36.pycnu[3 ."d.'@sdZddlZddlmZdZdZdZdZdZdZ dZ dZ dZ e e e Z eeee ee ed}Zd~dZddZddZddZddZddZdS)z. Lists of algorithms and globbing among them. N) validation AES-256-GCM AES-256-CCM AES-192-GCM AES-192-CCM AES-128-GCM AES-128-CCMCHACHA20-POLY1305CAMELLIA-256-GCMCAMELLIA-128-GCM AES-256-CTR AES-256-CBC AES-192-CTR AES-192-CBC AES-128-CTR AES-128-CBCCAMELLIA-256-CBCCAMELLIA-128-CBC3DES-CBCDES-CBCRC4-40RC4-128 DES40-CBCRC2-CBCIDEA-CBCSEED-CBCNULLAEADUMAC-128 HMAC-SHA1 HMAC-SHA2-256 HMAC-SHA2-384 HMAC-SHA2-512UMAC-64HMAC-MD5SHA2-256SHA2-384SHA2-512SHA3-256SHA3-384SHA3-512SHA2-224SHA1MD5GOSTX25519 SECP256R1 SECP384R1 SECP521R1X448 FFDHE-1536 FFDHE-2048 FFDHE-3072 FFDHE-4096 FFDHE-6144 FFDHE-8192 FFDHE-1024RSA-MD5RSA-SHA1DSA-SHA1 ECDSA-SHA1 RSA-SHA2-224 DSA-SHA2-224ECDSA-SHA2-224 RSA-SHA2-256 DSA-SHA2-256ECDSA-SHA2-256ECDSA-SHA2-256-FIDO RSA-SHA2-384 DSA-SHA2-384ECDSA-SHA2-384 RSA-SHA2-512 DSA-SHA2-512ECDSA-SHA2-512 RSA-SHA3-256 DSA-SHA3-256ECDSA-SHA3-256 RSA-SHA3-384 DSA-SHA3-384ECDSA-SHA3-384 RSA-SHA3-512 DSA-SHA3-512ECDSA-SHA3-512 EDDSA-ED25519EDDSA-ED25519-FIDO EDDSA-ED448 RSA-PSS-SHA1RSA-PSS-SHA2-224RSA-PSS-SHA2-256RSA-PSS-SHA2-384RSA-PSS-SHA2-512RSA-PSS-RSAE-SHA1RSA-PSS-RSAE-SHA2-224RSA-PSS-RSAE-SHA2-256RSA-PSS-RSAE-SHA2-384RSA-PSS-RSAE-SHA2-512PSKDHE-PSK ECDHE-PSKECDHERSADHEDHE-RSADHE-DSSEXPORTANONDHECDHDHE-GSS ECDHE-GSSTLS1.3TLS1.2TLS1.1TLS1.0SSL3.0SSL2.0DTLS1.2DTLS1.0DTLS0.9IKEv2IKEv1)ZciphergrouphashZ key_exchangeZmacZprotocolZsigncCs:|tkrtjj|tjt||}|s6tjj|||S)z Lists algorithms matching a glob, in order of appearance in ALL[alg_class]. For more examples, refer to tests/unit/parsing/test_alg_lists.py >>> glob('RC4-*', 'cipher') ['RC4-40', 'RC4-128'] )ALLrZ alg_listsZAlgorithmClassUnknownErrorfnmatchfilterZAlgorithmEmptyMatchError)patternZ alg_classrr>./usr/share/crypto-policies/python/cryptopolicies/alg_lists.pyglobYs  rcs8fdd|D}|sdSfdd|D}t|S)zO >>> earliest_occurrence('test', 'abcdefghijklmnopqrstuvwxyz') 'e' csg|]}|kr|qSrr).0n)ordered_haystackrr nsz'earliest_occurrence..Nc3s|]}j|VqdS)N)index)rr)rrr qsz&earliest_occurrence..)min)Zneedlesr intersectionindicesr)rrearliest_occurrenceis rcCst|tdddS)z@ >>> min_tls_version(['SSL3.0', 'TLS1.2']) 'SSL3.0' Nr)r TLS_PROTOCOLS)versionsrrrmin_tls_versionusrcCst|tdddS)zD >>> min_dtls_version(['DTLS1.2', 'DTLS1.0']) 'DTLS1.0' Nrr)rDTLS_PROTOCOLS)rrrrmin_dtls_version}srcCs t|tS)z@ >>> max_tls_version(['SSL3.0', 'TLS1.2']) 'TLS1.2' )rr)rrrrmax_tls_versionsrcCs t|tS)zD >>> max_dtls_version(['DTLS1.2', 'DTLS1.0']) 'DTLS1.2' )rr)rrrrmax_dtls_versionsr)rrrrrr r r r r rrrrrrrrrrrrrrrr)rrr r!r"r#r$r%) r&r'r(r)r*r+r,r-r.r/) r0r1r2r3r4r5r6r7r8r9r:r;)'r<r=r>r?r@rArBrCrDrErFrGrHrIrJrKrLrMrNrOrPrQrRrSrTrUrVrWrXrYrZr[r\r]r^r_r`rarb)rcrdrerfrgrhrirjrkrlrmrnrorp)rqrrrsrtrurv)rwrxry)rzr{)__doc__rrZ ALL_CIPHERSZALL_MACSZ ALL_HASHESZ ALL_GROUPSZALL_SIGNZALL_KEY_EXCHANGESrrZ IKE_PROTOCOLSZ ALL_PROTOCOLSr~rrrrrrrrrrsn   PK3]"~2cryptopolicies/__pycache__/__init__.cpython-36.pycnu[3 ."d@sddlmZdgZdS))UnscopedCryptoPolicyrN)Zcryptopoliciesr__all__rr=./usr/share/crypto-policies/python/cryptopolicies/__init__.pys PK3]c&cryptopolicies/validation/alg_lists.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2021 Red Hat, Inc. from .general import PolicySyntaxError class AlgorithmClassSyntaxError(PolicySyntaxError): pass class AlgorithmClassUnknownError(AlgorithmClassSyntaxError): def __init__(self, alg_class): # The wording follows the previous versions super().__init__(f'Unknown policy property: `{alg_class}`') class AlgorithmEmptyMatchError(AlgorithmClassSyntaxError): def __init__(self, glob, alg_class): # The wording follows the previous versions super().__init__(f'Bad value of policy property `{alg_class}`: ' f'`{glob}`') PK3]@cryptopolicies/validation/__pycache__/rules.cpython-36.opt-1.pycnu[3 ."d@s`ddlmZGdddeZGdddeZGdddeZGdd d eZd d Zd d ZdS))PolicySyntaxErrorcseZdZfddZZS) MalformedLinecstjd|ddS)Nzmalformed line ``)super__init__)selfline) __class__E./usr/share/crypto-policies/python/cryptopolicies/validation/rules.pyr szMalformedLine.__init__)__name__ __module__ __qualname__r __classcell__r r )r r rsrcseZdZfddZZS)%MixedDifferentialNonDifferentialErrorcstjd|ddS)Nz/cannot initialize list and modify it at once (`z`))rr)rZrhs)r r r rsz.MixedDifferentialNonDifferentialError.__init__)r r rrrr r )r r r srcseZdZfddZZS)IntPropertyNonIntValueErrorcstjd|ddS)NzBad value of policy property `z`: value must be an integer)rr)rZint_property_name)r r r rsz$IntPropertyNonIntValueError.__init__)r r rrrr r )r r rsrcseZdZfddZZS)NonIntPropertyIntValueErrorcstjd|ddS)NzBad value of policy property `z`: value must not be an integer)rr)rZ alg_class)r r r rsz$NonIntPropertyIntValueError.__init__)r r rrrr r )r r rsrcCs|jddkrt|dS)N=r)countr)rr r r count_equals_signs!srcCs|s t|dS)N)r)Zlhsrr r r empty_lhs&srN)Zgeneralrrrrrrrr r r r s PK3]Xǭ @cryptopolicies/validation/__pycache__/scope.cpython-36.opt-1.pycnu[3 ."d@sddlZddlmZGdddeZGdddeZGdd d eZGd d d eZGd d d eZGdddeZGdddeZ ddZ ddZ ddZ dS)N)PolicySyntaxErrorc@s eZdZdS)ScopeSyntaxErrorN)__name__ __module__ __qualname__rrE./usr/share/crypto-policies/python/cryptopolicies/validation/scope.pyr srcseZdZfddZZS)ScopeUnknownErrorcstjd|dS)Nzunknown scope )super__init__)selfZ scope_glob) __class__rr r szScopeUnknownError.__init__)rrrr __classcell__rr)rr r sr cseZdZfddZZS)ScopeSelectorEmptyErrorcstjddS)Nzempty scope selector)r r )r )rrr r sz ScopeSelectorEmptyError.__init__)rrrr rrr)rr rsrcseZdZfddZZS)"ScopeSelectorIllegalCharacterErrorcstjd|ddS)Nz%illegal character in scope selector ``)r r )r Zselector)rrr r sz+ScopeSelectorIllegalCharacterError.__init__)rrrr rrr)rr rsrcseZdZfddZZS)ScopeSelectorCurlyBracketsErrorcstjd|ddS)Nz%unsupported curly brackets usage in `r)r r )r pattern)rrr r sz(ScopeSelectorCurlyBracketsError.__init__)rrrr rrr)rr rsrcseZdZfddZZS)ScopeSelectorCommaErrorcstjd|ddS)Nzunsupported comma usage in `r)r r )r r)rrr r #sz ScopeSelectorCommaError.__init__)rrrr rrr)rr r"srcseZdZfddZZS) ScopeSelectorMatchedNothingErrorcstjd|ddS)Nzscope selector `z` matches no scope)r r )r r)rrr r (sz)ScopeSelectorMatchedNothingError.__init__)rrrr rrr)rr r'srcCstdd|Dst|dS)Ncss|]}|jp|dkVqdS)z{,}*_-N)isalnum).0crrr -sz%illegal_characters..)allr)poriginal_patternrrr illegal_characters,srcCsP|jd|jdfdksD|jdr.|jd sD|jd rL|jdrLt|dS)N{}rrrrrr)r!r")count startswithendswithr)rrrrr curly_brackets1sr&cCsZtdd|Drt|x:|D]2}|s.ttj||s d|krJt|t|q WdS)Ncss|]}d|kVqdS),Nr)rgrrr r9sz"resulting_globs..*)anyrrfnmatchfilterrr )ZglobsZ all_scopesrr(rrr resulting_globs8s  r-) r+Zgeneralrrr rrrrrrr&r-rrrr s PK3]nddCcryptopolicies/validation/__pycache__/__init__.cpython-36.opt-1.pycnu[3 ."d@s6ddlmZmZmZddlmZmZdddddgZdS) ) alg_listsrulesscope)PolicySyntaxErrorPolicyFileNotFoundErrorrrrrrN)rrrZgeneralrr__all__r r H./usr/share/crypto-policies/python/cryptopolicies/validation/__init__.pysPK3]V&DBcryptopolicies/validation/__pycache__/general.cpython-36.opt-1.pycnu[3 ."ds@s&GdddeeZGdddeZdS)c@s eZdZdS)PolicySyntaxErrorN)__name__ __module__ __qualname__rrG./usr/share/crypto-policies/python/cryptopolicies/validation/general.pyrsrcseZdZfddZZS)PolicyFileNotFoundErrorcs*tjd|d|ddj|ddS)NzUnknown policy `z `: file `z` not found in (z, ))super__init__join)selfZpnamefnamepaths) __class__rrr sz PolicyFileNotFoundError.__init__)rrrr __classcell__rr)rrr srN) ValueError UserWarningrFileNotFoundErrorrrrrrsPK3]Xǭ :cryptopolicies/validation/__pycache__/scope.cpython-36.pycnu[3 ."d@sddlZddlmZGdddeZGdddeZGdd d eZGd d d eZGd d d eZGdddeZGdddeZ ddZ ddZ ddZ dS)N)PolicySyntaxErrorc@s eZdZdS)ScopeSyntaxErrorN)__name__ __module__ __qualname__rrE./usr/share/crypto-policies/python/cryptopolicies/validation/scope.pyr srcseZdZfddZZS)ScopeUnknownErrorcstjd|dS)Nzunknown scope )super__init__)selfZ scope_glob) __class__rr r szScopeUnknownError.__init__)rrrr __classcell__rr)rr r sr cseZdZfddZZS)ScopeSelectorEmptyErrorcstjddS)Nzempty scope selector)r r )r )rrr r sz ScopeSelectorEmptyError.__init__)rrrr rrr)rr rsrcseZdZfddZZS)"ScopeSelectorIllegalCharacterErrorcstjd|ddS)Nz%illegal character in scope selector ``)r r )r Zselector)rrr r sz+ScopeSelectorIllegalCharacterError.__init__)rrrr rrr)rr rsrcseZdZfddZZS)ScopeSelectorCurlyBracketsErrorcstjd|ddS)Nz%unsupported curly brackets usage in `r)r r )r pattern)rrr r sz(ScopeSelectorCurlyBracketsError.__init__)rrrr rrr)rr rsrcseZdZfddZZS)ScopeSelectorCommaErrorcstjd|ddS)Nzunsupported comma usage in `r)r r )r r)rrr r #sz ScopeSelectorCommaError.__init__)rrrr rrr)rr r"srcseZdZfddZZS) ScopeSelectorMatchedNothingErrorcstjd|ddS)Nzscope selector `z` matches no scope)r r )r r)rrr r (sz)ScopeSelectorMatchedNothingError.__init__)rrrr rrr)rr r'srcCstdd|Dst|dS)Ncss|]}|jp|dkVqdS)z{,}*_-N)isalnum).0crrr -sz%illegal_characters..)allr)poriginal_patternrrr illegal_characters,srcCsP|jd|jdfdksD|jdr.|jd sD|jd rL|jdrLt|dS)N{}rrrrrr)r!r")count startswithendswithr)rrrrr curly_brackets1sr&cCsZtdd|Drt|x:|D]2}|s.ttj||s d|krJt|t|q WdS)Ncss|]}d|kVqdS),Nr)rgrrr r9sz"resulting_globs..*)anyrrfnmatchfilterrr )ZglobsZ all_scopesrr(rrr resulting_globs8s  r-) r+Zgeneralrrr rrrrrrr&r-rrrr s PK3]V&D<cryptopolicies/validation/__pycache__/general.cpython-36.pycnu[3 ."ds@s&GdddeeZGdddeZdS)c@s eZdZdS)PolicySyntaxErrorN)__name__ __module__ __qualname__rrG./usr/share/crypto-policies/python/cryptopolicies/validation/general.pyrsrcseZdZfddZZS)PolicyFileNotFoundErrorcs*tjd|d|ddj|ddS)NzUnknown policy `z `: file `z` not found in (z, ))super__init__join)selfZpnamefnamepaths) __class__rrr sz PolicyFileNotFoundError.__init__)rrrr __classcell__rr)rrr srN) ValueError UserWarningrFileNotFoundErrorrrrrrsPK3]:cryptopolicies/validation/__pycache__/rules.cpython-36.pycnu[3 ."d@s`ddlmZGdddeZGdddeZGdddeZGdd d eZd d Zd d ZdS))PolicySyntaxErrorcseZdZfddZZS) MalformedLinecstjd|ddS)Nzmalformed line ``)super__init__)selfline) __class__E./usr/share/crypto-policies/python/cryptopolicies/validation/rules.pyr szMalformedLine.__init__)__name__ __module__ __qualname__r __classcell__r r )r r rsrcseZdZfddZZS)%MixedDifferentialNonDifferentialErrorcstjd|ddS)Nz/cannot initialize list and modify it at once (`z`))rr)rZrhs)r r r rsz.MixedDifferentialNonDifferentialError.__init__)r r rrrr r )r r r srcseZdZfddZZS)IntPropertyNonIntValueErrorcstjd|ddS)NzBad value of policy property `z`: value must be an integer)rr)rZint_property_name)r r r rsz$IntPropertyNonIntValueError.__init__)r r rrrr r )r r rsrcseZdZfddZZS)NonIntPropertyIntValueErrorcstjd|ddS)NzBad value of policy property `z`: value must not be an integer)rr)rZ alg_class)r r r rsz$NonIntPropertyIntValueError.__init__)r r rrrr r )r r rsrcCs|jddkrt|dS)N=r)countr)rr r r count_equals_signs!srcCs|s t|dS)N)r)Zlhsrr r r empty_lhs&srN)Zgeneralrrrrrrrr r r r s PK3]BrooDcryptopolicies/validation/__pycache__/alg_lists.cpython-36.opt-1.pycnu[3 ."d@s@ddlmZGdddeZGdddeZGdddeZdS) )PolicySyntaxErrorc@s eZdZdS)AlgorithmClassSyntaxErrorN)__name__ __module__ __qualname__rrI./usr/share/crypto-policies/python/cryptopolicies/validation/alg_lists.pyrsrcseZdZfddZZS)AlgorithmClassUnknownErrorcstjd|ddS)NzUnknown policy property: ``)super__init__)self alg_class) __class__rrr sz#AlgorithmClassUnknownError.__init__)rrrr __classcell__rr)rrr sr cseZdZfddZZS)AlgorithmEmptyMatchErrorcstjd|d|ddS)NzBad value of policy property `z`: `r )r r )r Zglobr)rrrr sz!AlgorithmEmptyMatchError.__init__)rrrr rrr)rrrsrN)Zgeneralrrr rrrrrs PK3]Broo>cryptopolicies/validation/__pycache__/alg_lists.cpython-36.pycnu[3 ."d@s@ddlmZGdddeZGdddeZGdddeZdS) )PolicySyntaxErrorc@s eZdZdS)AlgorithmClassSyntaxErrorN)__name__ __module__ __qualname__rrI./usr/share/crypto-policies/python/cryptopolicies/validation/alg_lists.pyrsrcseZdZfddZZS)AlgorithmClassUnknownErrorcstjd|ddS)NzUnknown policy property: ``)super__init__)self alg_class) __class__rrr sz#AlgorithmClassUnknownError.__init__)rrrr __classcell__rr)rrr sr cseZdZfddZZS)AlgorithmEmptyMatchErrorcstjd|d|ddS)NzBad value of policy property `z`: `r )r r )r Zglobr)rrrr sz!AlgorithmEmptyMatchError.__init__)rrrr rrr)rrrsrN)Zgeneralrrr rrrrrs PK3]ndd=cryptopolicies/validation/__pycache__/__init__.cpython-36.pycnu[3 ."d@s6ddlmZmZmZddlmZmZdddddgZdS) ) alg_listsrulesscope)PolicySyntaxErrorPolicyFileNotFoundErrorrrrrrN)rrrZgeneralrr__all__r r H./usr/share/crypto-policies/python/cryptopolicies/validation/__init__.pysPK3]6F"cryptopolicies/validation/scope.pynu[# SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (c) 2021 Red Hat, Inc. import fnmatch from .general import PolicySyntaxError class ScopeSyntaxError(PolicySyntaxError): pass class ScopeUnknownError(ScopeSyntaxError): def __init__(self, scope_glob): super().__init__(f'unknown scope {scope_glob}') class ScopeSelectorEmptyError(ScopeSyntaxError): def __init__(self): super().__init__('empty scope selector') class ScopeSelectorIllegalCharacterError(ScopeSyntaxError): def __init__(self, selector): super().__init__(f'illegal character in scope selector `{selector}`') class ScopeSelectorCurlyBracketsError(ScopeSyntaxError): def __init__(self, pattern): super().__init__(f'unsupported curly brackets usage in `{pattern}`') class ScopeSelectorCommaError(ScopeSyntaxError): def __init__(self, pattern): super().__init__(f'unsupported comma usage in `{pattern}`') class ScopeSelectorMatchedNothingError(ScopeSyntaxError): def __init__(self, pattern): super().__init__(f'scope selector `{pattern}` matches no scope') def illegal_characters(p, original_pattern): if not all(c.isalnum() or c in '{,}*_-' for c in p): raise ScopeSelectorIllegalCharacterError(original_pattern) def curly_brackets(p, original_pattern): if ((p.count('{'), p.count('}')) not in [(0, 0), (1, 1)] or p.startswith('{') and not p.endswith('}') or not p.startswith('{') and p.endswith('}')): raise ScopeSelectorCurlyBracketsError(original_pattern) def resulting_globs(globs, all_scopes, original_pattern): if any(',' in g for g in globs): raise ScopeSelectorCommaError(original_pattern) for g in globs: if not g: raise ScopeSelectorEmptyError() if not fnmatch.filter(all_scopes, g): if '*' in g: raise ScopeSelectorMatchedNothingError(g) raise ScopeUnknownError(g) PK3] from .cryptopolicies import UnscopedCryptoPolicy __all__ = ['UnscopedCryptoPolicy'] PKPD4]VB3__5gdb/printer/__pycache__/__init__.cpython-36.opt-1.pycnu[3 `@sdS)Nrrr /__init__.pysPKPD4]5<gdb/printer/__pycache__/bound_registers.cpython-36.opt-1.pycnu[3 `@sHddlZddlZejddkr&eZeZGdddZej j ddedS)Nc@s eZdZdZddZddZdS)MpxBound128Printerz:Adds size field to a mpx __gdb_builtin_type_bound128 type.cCs ||_dS)N)val)selfrr/bound_registers.py__init__szMpxBound128Printer.__init__cCsB|jd}|jd}t||}|dkr0|d}d|||f}|S)NZuboundZlboundz${lbound = %s, ubound = %s} : size %s)rlong)rupperlowersizeresultrrr to_string s   zMpxBound128Printer.to_stringN)__name__ __module__ __qualname____doc__rrrrrrrsrZ mpx_bound128z^builtin_type_bound128) sysZ gdb.printingZgdb version_infostrZ basestringintr rZprintingZadd_builtin_pretty_printerrrrrsPKPD4]56gdb/printer/__pycache__/bound_registers.cpython-36.pycnu[3 `@sHddlZddlZejddkr&eZeZGdddZej j ddedS)Nc@s eZdZdZddZddZdS)MpxBound128Printerz:Adds size field to a mpx __gdb_builtin_type_bound128 type.cCs ||_dS)N)val)selfrr/bound_registers.py__init__szMpxBound128Printer.__init__cCsB|jd}|jd}t||}|dkr0|d}d|||f}|S)NZuboundZlboundz${lbound = %s, ubound = %s} : size %s)rlong)rupperlowersizeresultrrr to_string s   zMpxBound128Printer.to_stringN)__name__ __module__ __qualname____doc__rrrrrrrsrZ mpx_bound128z^builtin_type_bound128) sysZ gdb.printingZgdb version_infostrZ basestringintr rZprintingZadd_builtin_pretty_printerrrrrsPKPD4]VB3__/gdb/printer/__pycache__/__init__.cpython-36.pycnu[3 `@sdS)Nrrr /__init__.pysPKPD4]gdb/printer/bound_registers.pynu[# Pretty-printers for bounds registers. # Copyright (C) 2013-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import gdb.printing if sys.version_info[0] > 2: # Python 3 removed basestring and long basestring = str long = int class MpxBound128Printer: """Adds size field to a mpx __gdb_builtin_type_bound128 type.""" def __init__ (self, val): self.val = val def to_string (self): upper = self.val["ubound"] lower = self.val["lbound"] size = (long) ((upper) - (lower)) if size > -1: size = size + 1 result = '{lbound = %s, ubound = %s} : size %s' % (lower, upper, size) return result gdb.printing.add_builtin_pretty_printer ('mpx_bound128', '^builtin_type_bound128', MpxBound128Printer) PKPD4]ƴgdb/printer/__init__.pynu[# Copyright (C) 2014-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . PKPD4]M!**gdb/printing.pynu[# Pretty-printer utilities. # Copyright (C) 2010-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Utilities for working with pretty-printers.""" import gdb import gdb.types import re import sys if sys.version_info[0] > 2: # Python 3 removed basestring and long basestring = str long = int class PrettyPrinter(object): """A basic pretty-printer. Attributes: name: A unique string among all printers for the context in which it is defined (objfile, progspace, or global(gdb)), and should meaningfully describe what can be pretty-printed. E.g., "StringPiece" or "protobufs". subprinters: An iterable object with each element having a `name' attribute, and, potentially, "enabled" attribute. Or this is None if there are no subprinters. enabled: A boolean indicating if the printer is enabled. Subprinters are for situations where "one" pretty-printer is actually a collection of several printers. E.g., The libstdc++ pretty-printer has a pretty-printer for each of several different types, based on regexps. """ # While one might want to push subprinters into the subclass, it's # present here to formalize such support to simplify # commands/pretty_printers.py. def __init__(self, name, subprinters=None): self.name = name self.subprinters = subprinters self.enabled = True def __call__(self, val): # The subclass must define this. raise NotImplementedError("PrettyPrinter __call__") class SubPrettyPrinter(object): """Baseclass for sub-pretty-printers. Sub-pretty-printers needn't use this, but it formalizes what's needed. Attributes: name: The name of the subprinter. enabled: A boolean indicating if the subprinter is enabled. """ def __init__(self, name): self.name = name self.enabled = True def register_pretty_printer(obj, printer, replace=False): """Register pretty-printer PRINTER with OBJ. The printer is added to the front of the search list, thus one can override an existing printer if one needs to. Use a different name when overriding an existing printer, otherwise an exception will be raised; multiple printers with the same name are disallowed. Arguments: obj: Either an objfile, progspace, or None (in which case the printer is registered globally). printer: Either a function of one argument (old way) or any object which has attributes: name, enabled, __call__. replace: If True replace any existing copy of the printer. Otherwise if the printer already exists raise an exception. Returns: Nothing. Raises: TypeError: A problem with the type of the printer. ValueError: The printer's name contains a semicolon ";". RuntimeError: A printer with the same name is already registered. If the caller wants the printer to be listable and disableable, it must follow the PrettyPrinter API. This applies to the old way (functions) too. If printer is an object, __call__ is a method of two arguments: self, and the value to be pretty-printed. See PrettyPrinter. """ # Watch for both __name__ and name. # Functions get the former for free, but we don't want to use an # attribute named __foo__ for pretty-printers-as-objects. # If printer has both, we use `name'. if not hasattr(printer, "__name__") and not hasattr(printer, "name"): raise TypeError("printer missing attribute: name") if hasattr(printer, "name") and not hasattr(printer, "enabled"): raise TypeError("printer missing attribute: enabled") if not hasattr(printer, "__call__"): raise TypeError("printer missing attribute: __call__") if hasattr(printer, "name"): name = printer.name else: name = printer.__name__ if obj is None or obj is gdb: if gdb.parameter("verbose"): gdb.write("Registering global %s pretty-printer ...\n" % name) obj = gdb else: if gdb.parameter("verbose"): gdb.write("Registering %s pretty-printer for %s ...\n" % ( name, obj.filename)) # Printers implemented as functions are old-style. In order to not risk # breaking anything we do not check __name__ here. if hasattr(printer, "name"): if not isinstance(printer.name, basestring): raise TypeError("printer name is not a string") # If printer provides a name, make sure it doesn't contain ";". # Semicolon is used by the info/enable/disable pretty-printer commands # to delimit subprinters. if printer.name.find(";") >= 0: raise ValueError("semicolon ';' in printer name") # Also make sure the name is unique. # Alas, we can't do the same for functions and __name__, they could # all have a canonical name like "lookup_function". # PERF: gdb records printers in a list, making this inefficient. i = 0 for p in obj.pretty_printers: if hasattr(p, "name") and p.name == printer.name: if replace: del obj.pretty_printers[i] break else: raise RuntimeError("pretty-printer already registered: %s" % printer.name) i = i + 1 obj.pretty_printers.insert(0, printer) class RegexpCollectionPrettyPrinter(PrettyPrinter): """Class for implementing a collection of regular-expression based pretty-printers. Intended usage: pretty_printer = RegexpCollectionPrettyPrinter("my_library") pretty_printer.add_printer("myclass1", "^myclass1$", MyClass1Printer) ... pretty_printer.add_printer("myclassN", "^myclassN$", MyClassNPrinter) register_pretty_printer(obj, pretty_printer) """ class RegexpSubprinter(SubPrettyPrinter): def __init__(self, name, regexp, gen_printer): super(RegexpCollectionPrettyPrinter.RegexpSubprinter, self).__init__(name) self.regexp = regexp self.gen_printer = gen_printer self.compiled_re = re.compile(regexp) def __init__(self, name): super(RegexpCollectionPrettyPrinter, self).__init__(name, []) def add_printer(self, name, regexp, gen_printer): """Add a printer to the list. The printer is added to the end of the list. Arguments: name: The name of the subprinter. regexp: The regular expression, as a string. gen_printer: A function/method that given a value returns an object to pretty-print it. Returns: Nothing. """ # NOTE: A previous version made the name of each printer the regexp. # That makes it awkward to pass to the enable/disable commands (it's # cumbersome to make a regexp of a regexp). So now the name is a # separate parameter. self.subprinters.append(self.RegexpSubprinter(name, regexp, gen_printer)) def __call__(self, val): """Lookup the pretty-printer for the provided value.""" # Get the type name. typename = gdb.types.get_basic_type(val.type).tag if not typename: typename = val.type.name if not typename: return None # Iterate over table of type regexps to determine # if a printer is registered for that type. # Return an instantiation of the printer if found. for printer in self.subprinters: if printer.enabled and printer.compiled_re.search(typename): return printer.gen_printer(val) # Cannot find a pretty printer. Return None. return None # A helper class for printing enum types. This class is instantiated # with a list of enumerators to print a particular Value. class _EnumInstance: def __init__(self, enumerators, val): self.enumerators = enumerators self.val = val def to_string(self): flag_list = [] v = long(self.val) any_found = False for (e_name, e_value) in self.enumerators: if v & e_value != 0: flag_list.append(e_name) v = v & ~e_value any_found = True if not any_found or v != 0: # Leftover value. flag_list.append('' % v) return "0x%x [%s]" % (int(self.val), " | ".join(flag_list)) class FlagEnumerationPrinter(PrettyPrinter): """A pretty-printer which can be used to print a flag-style enumeration. A flag-style enumeration is one where the enumerators are or'd together to create values. The new printer will print these symbolically using '|' notation. The printer must be registered manually. This printer is most useful when an enum is flag-like, but has some overlap. GDB's built-in printing will not handle this case, but this printer will attempt to.""" def __init__(self, enum_type): super(FlagEnumerationPrinter, self).__init__(enum_type) self.initialized = False def __call__(self, val): if not self.initialized: self.initialized = True flags = gdb.lookup_type(self.name) self.enumerators = [] for field in flags.fields(): self.enumerators.append((field.name, field.enumval)) # Sorting the enumerators by value usually does the right # thing. self.enumerators.sort(key = lambda x: x[1]) if self.enabled: return _EnumInstance(self.enumerators, val) else: return None # Builtin pretty-printers. # The set is defined as empty, and files in printing/*.py add their printers # to this with add_builtin_pretty_printer. _builtin_pretty_printers = RegexpCollectionPrettyPrinter("builtin") register_pretty_printer(None, _builtin_pretty_printers) # Add a builtin pretty-printer. def add_builtin_pretty_printer(name, regexp, printer): _builtin_pretty_printers.add_printer(name, regexp, printer) PKPD4]Ɂ__ gdb/frames.pynu[# Frame-filter commands. # Copyright (C) 2013-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Internal functions for working with frame-filters.""" import gdb from gdb.FrameIterator import FrameIterator from gdb.FrameDecorator import FrameDecorator import itertools import collections def get_priority(filter_item): """ Internal worker function to return the frame-filter's priority from a frame filter object. This is a fail free function as it is used in sorting and filtering. If a badly implemented frame filter does not implement the priority attribute, return zero (otherwise sorting/filtering will fail and prevent other frame filters from executing). Arguments: filter_item: An object conforming to the frame filter interface. Returns: The priority of the frame filter from the "priority" attribute, or zero. """ # Do not fail here, as the sort will fail. If a filter has not # (incorrectly) set a priority, set it to zero. return getattr(filter_item, "priority", 0) def set_priority(filter_item, priority): """ Internal worker function to set the frame-filter's priority. Arguments: filter_item: An object conforming to the frame filter interface. priority: The priority to assign as an integer. """ filter_item.priority = priority def get_enabled(filter_item): """ Internal worker function to return a filter's enabled state from a frame filter object. This is a fail free function as it is used in sorting and filtering. If a badly implemented frame filter does not implement the enabled attribute, return False (otherwise sorting/filtering will fail and prevent other frame filters from executing). Arguments: filter_item: An object conforming to the frame filter interface. Returns: The enabled state of the frame filter from the "enabled" attribute, or False. """ # If the filter class is badly implemented when called from the # Python filter command, do not cease filter operations, just set # enabled to False. return getattr(filter_item, "enabled", False) def set_enabled(filter_item, state): """ Internal Worker function to set the frame-filter's enabled state. Arguments: filter_item: An object conforming to the frame filter interface. state: True or False, depending on desired state. """ filter_item.enabled = state def return_list(name): """ Internal Worker function to return the frame filter dictionary, depending on the name supplied as an argument. If the name is not "all", "global" or "progspace", it is assumed to name an object-file. Arguments: name: The name of the list, as specified by GDB user commands. Returns: A dictionary object for a single specified dictionary, or a list containing all the items for "all" Raises: gdb.GdbError: A dictionary of that name cannot be found. """ # If all dictionaries are wanted in the case of "all" we # cannot return a combined dictionary as keys() may clash in # between different dictionaries. As we just want all the frame # filters to enable/disable them all, just return the combined # items() as a chained iterator of dictionary values. if name == "all": glob = gdb.frame_filters.values() prog = gdb.current_progspace().frame_filters.values() return_iter = itertools.chain(glob, prog) for objfile in gdb.objfiles(): return_iter = itertools.chain(return_iter, objfile.frame_filters.values()) return return_iter if name == "global": return gdb.frame_filters else: if name == "progspace": cp = gdb.current_progspace() return cp.frame_filters else: for objfile in gdb.objfiles(): if name == objfile.filename: return objfile.frame_filters msg = "Cannot find frame-filter dictionary for '" + name + "'" raise gdb.GdbError(msg) def _sort_list(): """ Internal Worker function to merge all known frame-filter lists, prune any filters with the state set to "disabled", and sort the list on the frame-filter's "priority" attribute. Returns: sorted_list: A sorted, pruned list of frame filters to execute. """ all_filters = return_list("all") sorted_frame_filters = sorted(all_filters, key = get_priority, reverse = True) sorted_frame_filters = filter(get_enabled, sorted_frame_filters) return sorted_frame_filters def execute_frame_filters(frame, frame_low, frame_high): """ Internal function called from GDB that will execute the chain of frame filters. Each filter is executed in priority order. After the execution completes, slice the iterator to frame_low - frame_high range. Arguments: frame: The initial frame. frame_low: The low range of the slice. If this is a negative integer then it indicates a backward slice (ie bt -4) which counts backward from the last frame in the backtrace. frame_high: The high range of the slice. If this is -1 then it indicates all frames until the end of the stack from frame_low. Returns: frame_iterator: The sliced iterator after all frame filters have had a change to execute, or None if no frame filters are registered. """ # Get a sorted list of frame filters. sorted_list = list(_sort_list()) # Check to see if there are any frame-filters. If not, just # return None and let default backtrace printing occur. if len(sorted_list) == 0: return None frame_iterator = FrameIterator(frame) # Apply a basic frame decorator to all gdb.Frames. This unifies # the interface. Python 3.x moved the itertools.imap # functionality to map(), so check if it is available. if hasattr(itertools,"imap"): frame_iterator = itertools.imap(FrameDecorator, frame_iterator) else: frame_iterator = map(FrameDecorator, frame_iterator) for ff in sorted_list: frame_iterator = ff.filter(frame_iterator) # Slicing # Is this a slice from the end of the backtrace, ie bt -2? if frame_low < 0: count = 0 slice_length = abs(frame_low) # We cannot use MAXLEN argument for deque as it is 2.6 onwards # and some GDB versions might be < 2.6. sliced = collections.deque() for frame_item in frame_iterator: if count >= slice_length: sliced.popleft(); count = count + 1 sliced.append(frame_item) return iter(sliced) # -1 for frame_high means until the end of the backtrace. Set to # None if that is the case, to indicate to itertools.islice to # slice to the end of the iterator. if frame_high == -1: frame_high = None else: # As frames start from 0, add one to frame_high so islice # correctly finds the end frame_high = frame_high + 1; sliced = itertools.islice(frame_iterator, frame_low, frame_high) return sliced PKPD4]C)),gdb/__pycache__/xmethod.cpython-36.opt-1.pycnu[3 `E+@sdZddlZddlZddlZejddkr2eZeZGddde Z Gddde Z Gdd d e Z Gd d d e Z d d ZddZdddZdS)zUtilities for defining xmethodsNc@seZdZdZddZdS)XMethodaBase class (or a template) for an xmethod description. Currently, the description requires only the 'name' and 'enabled' attributes. Description objects are managed by 'XMethodMatcher' objects (see below). Note that this is only a template for the interface of the XMethodMatcher.methods objects. One could use this class or choose to use an object which supports this exact same interface. Also, an XMethodMatcher can choose not use it 'methods' attribute. In such cases this class (or an equivalent) is not used. Attributes: name: The name of the xmethod. enabled: A boolean indicating if the xmethod is enabled. cCs||_d|_dS)NT)nameenabled)selfrr /xmethod.py__init__.szXMethod.__init__N)__name__ __module__ __qualname____doc__r rrrrrsrc@s eZdZdZddZddZdS)XMethodMatcheraAbstract base class for matching an xmethod. When looking for xmethods, GDB invokes the `match' method of a registered xmethod matcher to match the object type and method name. The `match' method in concrete classes derived from this class should return an `XMethodWorker' object, or a list of `XMethodWorker' objects if there is a match (see below for 'XMethodWorker' class). Attributes: name: The name of the matcher. enabled: A boolean indicating if the matcher is enabled. methods: A sequence of objects of type 'XMethod', or objects which have at least the attributes of an 'XMethod' object. This list is used by the 'enable'/'disable'/'info' commands to enable/disable/list the xmethods registered with GDB. See the 'match' method below to know how this sequence is used. This attribute is None if the matcher chooses not have any xmethods managed by it. cCs||_d|_d|_dS)z Args: name: An identifying name for the xmethod or the group of xmethods returned by the `match' method. TN)rrmethods)rrrrrr HszXMethodMatcher.__init__cCs tddS)aMatch class type and method name. In derived classes, it should return an XMethodWorker object, or a sequence of 'XMethodWorker' objects. Only those xmethod workers whose corresponding 'XMethod' descriptor object is enabled should be returned. Args: class_type: The class type (gdb.Type object) to match. method_name: The name (string) of the method to match. zXMethodMatcher matchN)NotImplementedError)r class_type method_namerrrmatchRs zXMethodMatcher.matchN)r r r r r rrrrrr3s rc@s(eZdZdZddZddZddZdS) XMethodWorkera8Base class for all xmethod workers defined in Python. An xmethod worker is an object which matches the method arguments, and invokes the method when GDB wants it to. Internally, GDB first invokes the 'get_arg_types' method to perform overload resolution. If GDB selects to invoke this Python xmethod, then it invokes it via the overridden '__call__' method. The 'get_result_type' method is used to implement 'ptype' on the xmethod. Derived classes should override the 'get_arg_types', 'get_result_type' and '__call__' methods. cCs tddS)aReturn arguments types of an xmethod. A sequence of gdb.Type objects corresponding to the arguments of the xmethod are returned. If the xmethod takes no arguments, then 'None' or an empty sequence is returned. If the xmethod takes only a single argument, then a gdb.Type object or a sequence with a single gdb.Type element is returned. zXMethodWorker get_arg_typesN)r)rrrr get_arg_typesos zXMethodWorker.get_arg_typescGs tddS)aReturn the type of the result of the xmethod. Args: args: Arguments to the method. Each element of the tuple is a gdb.Value object. The first element is the 'this' pointer value. These are the same arguments passed to '__call__'. Returns: A gdb.Type object representing the type of the result of the xmethod. zXMethodWorker get_result_typeN)r)rargsrrrget_result_typezs zXMethodWorker.get_result_typecGs tddS)ayInvoke the xmethod. Args: args: Arguments to the method. Each element of the tuple is a gdb.Value object. The first element is the 'this' pointer value. Returns: A gdb.Value corresponding to the value returned by the xmethod. Returns 'None' if the method does not return anything. zXMethodWorker __call__N)r)rrrrr__call__s zXMethodWorker.__call__N)r r r r rrrrrrrras  rc@s0eZdZdZGdddeZddZddZdS) SimpleXMethodMatcheraA utility class to implement simple xmethod mathers and workers. See the __init__ method below for information on how instances of this class can be used. For simple classes and methods, one can choose to use this class. For complex xmethods, which need to replace/implement template methods on possibly template classes, one should implement their own xmethod matchers and workers. See py-xmethods.py in testsuite/gdb.python directory of the GDB source tree for examples. c@s$eZdZddZddZddZdS)z(SimpleXMethodMatcher.SimpleXMethodWorkercCs||_||_dS)N) _arg_types_method_function)rmethod_function arg_typesrrrr sz1SimpleXMethodMatcher.SimpleXMethodWorker.__init__cCs|jS)N)r)rrrrrsz6SimpleXMethodMatcher.SimpleXMethodWorker.get_arg_typescGs |j|S)N)r)rrrrrrsz1SimpleXMethodMatcher.SimpleXMethodWorker.__call__N)r r r r rrrrrrSimpleXMethodWorkersrcGs(tj||||_||_||_||_dS)a Args: name: Name of the xmethod matcher. class_matcher: A regular expression used to match the name of the class whose method this xmethod is implementing/replacing. method_matcher: A regular expression used to match the name of the method this xmethod is implementing/replacing. method_function: A Python callable which would be called via the 'invoke' method of the worker returned by the objects of this class. This callable should accept the object (*this) as the first argument followed by the rest of the arguments to the method. All arguments to this function should be gdb.Value objects. arg_types: The gdb.Type objects corresponding to the arguments that this xmethod takes. It can be None, or an empty sequence, or a single gdb.Type object, or a sequence of gdb.Type objects. N)rr r_class_matcher_method_matcherr)rrZ class_matcherZmethod_matcherrrrrrr s  zSimpleXMethodMatcher.__init__cCsBtj|jt|jj}tj|j|}|r>|r>tj|j |j SdS)N) rerrstrZ unqualifiedtagr rrrr)rrrcmZmmrrrrs zSimpleXMethodMatcher.matchN)r r r r rrr rrrrrrs  rcCsft|dstdSt|ds$tdSt|ds6tdSt|jtsJtdS|jjdd krbtd SdS) Nrz(Xmethod matcher is missing method: matchrz*Xmethod matcher is missing attribute: namerz-Xmethod matcher is missing attribute: enabledz3Attribute 'name' of xmethod matcher is not a string;rz-Xmethod matcher name cannot contain ';' in it)hasattr TypeError isinstancer basestringfind ValueError)matcherrrr_validate_xmethod_matchers    r-cCs2x,tdt|jD]}|j|j|kr|SqWdS)Nr)rangelenxmethodsr)locusrirrr_lookup_xmethod_matchersr5FcCst|}|r||st}|tkr&d}n|j}t||j}|dkr`|rN|j|=ntd||jftjdrttjd|jj d|dS)aRegisters a xmethod matcher MATCHER with a LOCUS. Arguments: locus: The locus in which the xmethods should be registered. It can be 'None' to indicate that the xmethods should be registered globally. Or, it could be a gdb.Objfile or a gdb.Progspace object in which the xmethods should be registered. matcher: The xmethod matcher to register with the LOCUS. It should be an instance of 'XMethodMatcher' class. replace: If True, replace any existing xmethod matcher with the same name in the locus. Otherwise, if a matcher with the same name exists in the locus, raise an exception. globalrz.Xmethod matcher already registered with %s: %sverbosez.Registering xmethod matcher '%s' with %s' ... N) r-gdbfilenamer5rr2 RuntimeErrorZ parameterwriteinsert)r3r,replaceerrZ locus_nameindexrrrregister_xmethod_matchers"    r@)F)r r8r!sys version_infor"r)intZlongobjectrrrrr-r5r@rrrrs.6APKPD4]~<<%gdb/__pycache__/frames.cpython-36.pycnu[3 `_@spdZddlZddlmZddlmZddlZddlZddZddZ d d Z d d Z d dZ ddZ ddZdS)z2Internal functions for working with frame-filters.N) FrameIterator)FrameDecoratorcCs t|ddS)aC Internal worker function to return the frame-filter's priority from a frame filter object. This is a fail free function as it is used in sorting and filtering. If a badly implemented frame filter does not implement the priority attribute, return zero (otherwise sorting/filtering will fail and prevent other frame filters from executing). Arguments: filter_item: An object conforming to the frame filter interface. Returns: The priority of the frame filter from the "priority" attribute, or zero. priorityr)getattr) filter_itemr /frames.py get_prioritysr cCs ||_dS)z Internal worker function to set the frame-filter's priority. Arguments: filter_item: An object conforming to the frame filter interface. priority: The priority to assign as an integer. N)r)rrrrr set_priority-s r cCs t|ddS)aE Internal worker function to return a filter's enabled state from a frame filter object. This is a fail free function as it is used in sorting and filtering. If a badly implemented frame filter does not implement the enabled attribute, return False (otherwise sorting/filtering will fail and prevent other frame filters from executing). Arguments: filter_item: An object conforming to the frame filter interface. Returns: The enabled state of the frame filter from the "enabled" attribute, or False. enabledF)r)rrrr get_enabled8sr cCs ||_dS)z Internal Worker function to set the frame-filter's enabled state. Arguments: filter_item: An object conforming to the frame filter interface. state: True or False, depending on desired state. N)r )rstaterrr set_enabledNs rcCs|dkrTtjj}tjjj}tj||}x"tjD]}tj||jj}q6W|S|dkrbtjS|dkrxtj}|jSx tjD]}||jkr|jSqWd|d}tj|dS)a Internal Worker function to return the frame filter dictionary, depending on the name supplied as an argument. If the name is not "all", "global" or "progspace", it is assumed to name an object-file. Arguments: name: The name of the list, as specified by GDB user commands. Returns: A dictionary object for a single specified dictionary, or a list containing all the items for "all" Raises: gdb.GdbError: A dictionary of that name cannot be found. allglobalZ progspacez)Cannot find frame-filter dictionary for ''N) gdbZ frame_filtersvaluesZcurrent_progspace itertoolschainZobjfilesfilenameZGdbError)nameZglobprogZ return_iterZobjfileZcpmsgrrr return_listZs"     rcCs$td}t|tdd}tt|}|S)a* Internal Worker function to merge all known frame-filter lists, prune any filters with the state set to "disabled", and sort the list on the frame-filter's "priority" attribute. Returns: sorted_list: A sorted, pruned list of frame filters to execute. rT)keyreverse)rsortedr filterr )Z all_filtersZsorted_frame_filtersrrr _sort_lists rc Cstt}t|dkrdSt|}ttdr:tjt|}n tt|}x|D]}|j |}qJW|dkrd}t |}t j }x.|D]&} ||kr|j |d}|j| q~Wt|S|dkrd}n|d}tj|||}|S)a  Internal function called from GDB that will execute the chain of frame filters. Each filter is executed in priority order. After the execution completes, slice the iterator to frame_low - frame_high range. Arguments: frame: The initial frame. frame_low: The low range of the slice. If this is a negative integer then it indicates a backward slice (ie bt -4) which counts backward from the last frame in the backtrace. frame_high: The high range of the slice. If this is -1 then it indicates all frames until the end of the stack from frame_low. Returns: frame_iterator: The sliced iterator after all frame filters have had a change to execute, or None if no frame filters are registered. rNimap)listrlenrhasattrrr rmaprabs collectionsdequepopleftappenditerislice) frameZ frame_lowZ frame_highZ sorted_listZframe_iteratorZffcountZ slice_lengthZslicedZ frame_itemrrrexecute_frame_filterss0      r0)__doc__rZgdb.FrameIteratorrZgdb.FrameDecoratorrrr(r r r rrrr0rrrrs    -PKPD4]8hA A +gdb/__pycache__/prompt.cpython-36.opt-1.pycnu[3 `q @sdZddlZddlZddZddZddZd d Zd d Zd dZddZ ddZ ddZ ddZ ddZ ddZee e e eeeee e ed ZddZddZdS) z# Extended prompt library functions.NcCstjS)zThe current working directory.)osgetcwd)ignorer /prompt.py _prompt_pwdsrc Csh|dkr |}y |}Wntjk r0d|SXt||rXt||}t|rT|}|Sd||fSdS)z,Internal worker for fetching GDB attributes.Nzz)gdberrorhasattrgetattrcallable)funcZwhatattrZnattrobjresultrrr_prompt_object_attrs    rcCsttjd|dS)z8The selected frame; an argument names a frame parameter.framename)rrZselected_frame)rrrr _prompt_frame*srcCsttjd|dS)z:The selected thread; an argument names a thread parameter.ZthreadZnum)rrZselected_thread)rrrr_prompt_thread.srcCstjS)zThe version of GDB.)rVERSION)rrrr_prompt_version2srcCsdS)zThe ESC character.r)rrrr _prompt_esc6srcCsdS)z A backslash.\r)rrrr _prompt_bs:srcCsdS)z A newline. r)rrrr _prompt_n>srcCsdS)zA carriage return. r)rrrr _prompt_rBsrcCs tj|S)z6A parameter's value; the argument names the parameter.)rZ parameter)rrrr _prompt_paramFsr cCsdS)z-Begins a sequence of non-printing characters.r)rrrr_prompt_noprint_beginJsr"cCsdS)z+Ends a sequence of non-printing characters.r)rrrr_prompt_noprint_endNsr$) ernrvwftp[]cCs@d}ttj}x"|D]}|d|t|jf7}qW|d7}|S)zNGenerate help dynamically from the __doc__ strings of attribute functions.z \%s %s z A substitution can be used in a simple form, like "\f". An argument can also be passed to it, like "\f{name}". The meaning of the argument depends on the particular substitution.)sortedprompt_substitutionskeys__doc__)rr2keyrrr prompt_help`s  r5cCsd}t|}d}x||kr||dkr|d}||kr:P||}|tkrt|}|d|kr||ddkr|d}x ||kr||dkr|d}qxW||ks||dkrd}q||d|}|}nd}|t||7}q|||7}n |||7}|d}qW|S) z Perform substitutions on PROMPT.r/rr{}N)lenr1str)promptrZpleniZcmdchcmdjargrrrsubstitute_promptns2     rA)r3rrrrrrrrrrrr r"r$r1r5rArrrrs6PKPD4]T`$gdb/__pycache__/types.cpython-36.pycnu[3 `@s`dZddlZddZddZddZd d ZGd d d eZd dZddZ ddZ ddZ dS)z%Utilities for working with gdb.Types.NcCs\xR|jtjks&|jtjks&|jtjkrR|jtjks>|jtjkrH|j}q|j}qW|jS)zReturn the "basic" type of a type. Arguments: type_: The type to reduce to its basic type. Returns: type_ with const/volatile is stripped away, and typedefs/references converted to the underlying type. )codegdbZ TYPE_CODE_REFZTYPE_CODE_RVALUE_REFZTYPE_CODE_TYPEDEFtargetZstrip_typedefsZ unqualified)type_r /types.pyget_basic_types       rcCsdt|}|jtjkr(|jtjkr(tdx6|jD]*}|jrNt|j |r\dSq2|j |kr2dSq2WdS)ayReturn True if a type has the specified field. Arguments: type_: The type to examine. It must be one of gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION. field: The name of the field to look up. Returns: True if the field is present either in type_ or any baseclass. Raises: TypeError: The type is not a struct or union. znot a struct or unionTF) rrrZTYPE_CODE_STRUCTZTYPE_CODE_UNION TypeErrorfieldsZ is_base_class has_fieldtypename)rfieldfrrrr ,s    r cCs:|jtjkrtdi}x|jD]}|j||j<q"W|S)zReturn a dictionary from a program's enum type. Arguments: enum_type: The enum to compute the dictionary for. Returns: The dictionary of the enum. Raises: TypeError: The type is not an enum. znot an enum type)rrZTYPE_CODE_ENUMr r Zenumvalr )Z enum_type enum_dictrrrrmake_enum_dictJs rccsDx>|jD]2\}}|r"||fVq xt|jD] }|Vq.Wq WdS)aReturn an iterator that recursively traverses anonymous fields. Arguments: type_: The type to traverse. It should be one of gdb.TYPE_CODE_STRUCT or gdb.TYPE_CODE_UNION. Returns: an iterator similar to gdb.Type.iteritems(), i.e., it returns pairs of key, value, but for any anonymous struct or union field that field is traversed recursively, depth-first. N)Z iteritems deep_itemsr )rkvirrrr`s  rc@s eZdZdZddZddZdS) TypePrinteraThe base class for type printers. Instances of this type can be used to substitute type names during 'ptype'. A type printer must have at least 'name' and 'enabled' attributes, and supply an 'instantiate' method. The 'instantiate' method must either return None, or return an object which has a 'recognize' method. This method must accept a gdb.Type argument and either return None, meaning that the type was not recognized, or a string naming the type. cCs||_d|_dS)NT)r enabled)selfr rrr__init__szTypePrinter.__init__cCsdS)Nr)rrrr instantiateszTypePrinter.instantiateN)__name__ __module__ __qualname____doc__rrrrrrrss rcCs2x,|D]$}|jr|j}|dk r|j|qWdS)N)rrappend)resultZplistprinterZinstrrr_get_some_type_recognizerss  r"cCsBg}xtjD]}t||jqWt|tjjt|tj|S)zFReturn a list of the enabled type recognizers for the current context.)rZobjfilesr" type_printersZcurrent_progspace)r Zobjfilerrrget_type_recognizerss  r$cCs(x"|D]}|j|}|dk r|SqWdS)zApply the given list of type recognizers to the type TYPE_OBJ. If any recognizer in the list recognizes TYPE_OBJ, returns the name given by the recognizer. Otherwise, this returns None.N)Z recognize)Z recognizersZtype_objrr rrrapply_type_recognizerss   r&cCs|dkr t}|jjd|dS)zRegister a type printer. PRINTER is the type printer instance. LOCUS is either an objfile, a program space, or None, indicating global registration.Nr)rr#insert)Zlocusr!rrrregister_type_printersr() rrrr rrobjectrr"r$r&r(rrrrs PKPD4]ep-gdb/__pycache__/__init__.cpython-36.opt-1.pycnu[3 `f @sHddlZddlZddlZddlZejddkr:ddlmZddlTGdddeZGdddeZ e e_ Gd d d eZ e e_ dZ d ge_gZgZgZiZgZd d ZddZejjejjeadddgZddZeddZddZddZddZddZ dd Z!y dd!l"m#Z#m$Z$m%Z%d"d#Z&Wnd$d#Z&YnXdS)%N)reload)*c@s4eZdZdZdZddZddZddZd d Zd S) _GdbFilezUTF-8strictcCsdS)N)selfrr /__init__.pyclose sz_GdbFile.closecCsdS)NFr)rrrr isatty$sz_GdbFile.isattycCsx|D]}|j|qWdS)N)write)riterablelinerrr writelines's z_GdbFile.writelinescCs tdS)N)flush)rrrr r+sz_GdbFile.flushN) __name__ __module__ __qualname__encodingerrorsr r rrrrrr rs rc@seZdZddZdS)_GdbOutputFilecCst|tddS)N)stream)r ZSTDOUT)rsrrr r /sz_GdbOutputFile.writeN)rrrr rrrr r.src@seZdZddZdS)_GdbOutputErrorFilecCst|tddS)N)r)r ZSTDERR)rrrrr r 5sz_GdbOutputErrorFile.writeN)rrrr rrrr r4srcCsx8tD].}x(|jD]}|jr||}|dk r|SqWqWx*tjD]}|jrD||}|dk rD|SqDWx&tD]}|jrl||}|dk rl|SqlWdS)aInternal function called from GDB to execute all unwinders. Runs each currently enabled unwinder until it finds the one that can unwind given frame. Arguments: pending_frame: gdb.PendingFrame instance. Returns: gdb.UnwindInfo instance or None. N)objfilesframe_unwindersZenabledcurrent_progspace)Z pending_frameZobjfileZunwinderZ unwind_inforrr _execute_unwindersMs"    rcCsntjdj}d}t|ds&||d<d}z6t|d"}t|j|d}t|||WdQRXWd|rh|d=XdS)aBThis function is used to replace Python 2's PyRun_SimpleFile. Loads and executes the given file. We could use the runpy module, but its documentation says: "Furthermore, any functions and classes defined by the executed code are not guaranteed to work correctly after a runpy function has returned." __main__F__file__TrbexecN)sysmodules__dict__hasattropencompilereadr")filepathglobalsZset_filefileZcompiledrrr _execute_filems   r-ZfunctionZcommandZprinterc CsxtD]}tjjtjjt|}tjj|rtddtj|}xh|D]`}dt ||ddf}y$|t j krzt t |nt |WqFt jjtjdYqFXqFWqWdS)NcSs|jdo|dkS)Nz.pyz __init__.py)endswith)xrrr s z%_auto_load_packages..z%s.%s.%s )packagesospathjoindirnamer existsfilterlistdirrr#r$r __import__stderrr traceback format_exc)packagelocationZpy_filesZpy_filemodnamerrr _auto_load_packagess      rCc CsNytjjtWntk r$YnXtjjd||atttt dS)z3Update sys.path, reload gdb and auto-load packages.rN) r#r6remove PYTHONDIR ValueErrorinsertrr<rrC)dirrrr GdbSetPythonDirectorys rIcCstjS)zReturn the current Progspace.)Zselected_inferiorZ progspacerrrr rsrcCs tjS)z:Return a sequence of the current program space's objfiles.)rrrrrr rsrcCs tj|S)zdsolib_name (Long) -> String. Return the name of the shared library holding a given address, or None.)r solib_name)Zaddrrrr rJsrJcCs tj|S)z8Return the block containing the given pc value, or None.)r block_for_pc)pcrrr rKsrKcCs tj|S)zjfind_pc_line (pc) -> Symtab_and_line. Return the gdb.Symtab_and_line object corresponding to the pc value.)r find_pc_line)rLrrr rMsrM) formatterslexers highlightc Cs2y"tj|dd}tj}t|||SdSdS)NF)Zstripnl)rOZget_lexer_for_filenamerNZTerminalFormatterrP)filenamecontentsZlexerZ formatterrrr colorizes  rScCsdS)Nr)rQrRrrr rSs)'r>r5r#Z_gdb version_infoZimprobjectrrstdoutrr=Z prompt_hookargvZpretty_printersZ type_printersZxmethodsZ frame_filtersrrr-r6r8r rEr4rCrIrrrJrKrMZpygmentsrNrOrPrSrrrr sJ   PKPD4]47R -gdb/__pycache__/unwinder.cpython-36.opt-1.pycnu[3 `A @s*dZddlZGdddeZdddZdS) z.Unwinder class and register_unwinder function.Nc@s eZdZdZddZddZdS)UnwinderaBase class (or a template) for frame unwinders written in Python. An unwinder has a single method __call__ and the attributes described below. Attributes: name: The name of the unwinder. enabled: A boolean indicating whether the unwinder is enabled. cCs||_d|_dS)z\Constructor. Args: name: An identifying name for the unwinder. TN)nameZenabled)selfrr /unwinder.py__init__ szUnwinder.__init__cCs tddS)zGDB calls this method to unwind a frame. Arguments: pending_frame: gdb.PendingFrame instance. Returns: gdb.UnwindInfo instance. zUnwinder __call__.N)NotImplementedError)rZ pending_framerrr__call__)s zUnwinder.__call__N)__name__ __module__ __qualname____doc__rr rrrrrs  rFcCs|dkr(tjdr"tjd|jt}nBt|tjs@t|tjrbtjdrjtjd|j|jfntdd}x>|j D]4}|j|jkr|r|j |=nt d|j|d7}qvW|j j d|tj dS) a~Register unwinder in given locus. The unwinder is prepended to the locus's unwinders list. Unwinder name should be unique. Arguments: locus: Either an objfile, progspace, or None (in which case the unwinder is registered globally). unwinder: An object of a gdb.Unwinder subclass replace: If True, replaces existing unwinder with the same name. Otherwise, raises exception if unwinder with the same name already exists. Returns: Nothing. Raises: RuntimeError: Unwinder name is not unique TypeError: Bad locus type Nverbosez#Registering global %s unwinder ... z#Registering %s unwinder for %s ... z4locus should be gdb.Objfile or gdb.Progspace or NonerzUnwinder %s already exists.) gdbZ parameterwriter isinstanceZObjfileZ Progspacefilename TypeErrorZframe_unwinders RuntimeErrorinsertZinvalidate_cached_frames)ZlocusZunwinderreplaceiZneedlerrrregister_unwinder5s&       r)F)r robjectrrrrrrs PKPD4]~<<+gdb/__pycache__/frames.cpython-36.opt-1.pycnu[3 `_@spdZddlZddlmZddlmZddlZddlZddZddZ d d Z d d Z d dZ ddZ ddZdS)z2Internal functions for working with frame-filters.N) FrameIterator)FrameDecoratorcCs t|ddS)aC Internal worker function to return the frame-filter's priority from a frame filter object. This is a fail free function as it is used in sorting and filtering. If a badly implemented frame filter does not implement the priority attribute, return zero (otherwise sorting/filtering will fail and prevent other frame filters from executing). Arguments: filter_item: An object conforming to the frame filter interface. Returns: The priority of the frame filter from the "priority" attribute, or zero. priorityr)getattr) filter_itemr /frames.py get_prioritysr cCs ||_dS)z Internal worker function to set the frame-filter's priority. Arguments: filter_item: An object conforming to the frame filter interface. priority: The priority to assign as an integer. N)r)rrrrr set_priority-s r cCs t|ddS)aE Internal worker function to return a filter's enabled state from a frame filter object. This is a fail free function as it is used in sorting and filtering. If a badly implemented frame filter does not implement the enabled attribute, return False (otherwise sorting/filtering will fail and prevent other frame filters from executing). Arguments: filter_item: An object conforming to the frame filter interface. Returns: The enabled state of the frame filter from the "enabled" attribute, or False. enabledF)r)rrrr get_enabled8sr cCs ||_dS)z Internal Worker function to set the frame-filter's enabled state. Arguments: filter_item: An object conforming to the frame filter interface. state: True or False, depending on desired state. N)r )rstaterrr set_enabledNs rcCs|dkrTtjj}tjjj}tj||}x"tjD]}tj||jj}q6W|S|dkrbtjS|dkrxtj}|jSx tjD]}||jkr|jSqWd|d}tj|dS)a Internal Worker function to return the frame filter dictionary, depending on the name supplied as an argument. If the name is not "all", "global" or "progspace", it is assumed to name an object-file. Arguments: name: The name of the list, as specified by GDB user commands. Returns: A dictionary object for a single specified dictionary, or a list containing all the items for "all" Raises: gdb.GdbError: A dictionary of that name cannot be found. allglobalZ progspacez)Cannot find frame-filter dictionary for ''N) gdbZ frame_filtersvaluesZcurrent_progspace itertoolschainZobjfilesfilenameZGdbError)nameZglobprogZ return_iterZobjfileZcpmsgrrr return_listZs"     rcCs$td}t|tdd}tt|}|S)a* Internal Worker function to merge all known frame-filter lists, prune any filters with the state set to "disabled", and sort the list on the frame-filter's "priority" attribute. Returns: sorted_list: A sorted, pruned list of frame filters to execute. rT)keyreverse)rsortedr filterr )Z all_filtersZsorted_frame_filtersrrr _sort_lists rc Cstt}t|dkrdSt|}ttdr:tjt|}n tt|}x|D]}|j |}qJW|dkrd}t |}t j }x.|D]&} ||kr|j |d}|j| q~Wt|S|dkrd}n|d}tj|||}|S)a  Internal function called from GDB that will execute the chain of frame filters. Each filter is executed in priority order. After the execution completes, slice the iterator to frame_low - frame_high range. Arguments: frame: The initial frame. frame_low: The low range of the slice. If this is a negative integer then it indicates a backward slice (ie bt -4) which counts backward from the last frame in the backtrace. frame_high: The high range of the slice. If this is -1 then it indicates all frames until the end of the stack from frame_low. Returns: frame_iterator: The sliced iterator after all frame filters have had a change to execute, or None if no frame filters are registered. rNimap)listrlenrhasattrrr rmaprabs collectionsdequepopleftappenditerislice) frameZ frame_lowZ frame_highZ sorted_listZframe_iteratorZffcountZ slice_lengthZslicedZ frame_itemrrrexecute_frame_filterss0      r0)__doc__rZgdb.FrameIteratorrZgdb.FrameDecoratorrrr(r r r rrrr0rrrrs    -PKPD4]'C"C"-gdb/__pycache__/printing.cpython-36.opt-1.pycnu[3 `*@sdZddlZddlZddlZddlZejddkr:eZeZ Gddde Z Gddde Z dd d Z Gd d d e ZGd ddZGddde ZedZe deddZdS)z+Utilities for working with pretty-printers.Nc@s"eZdZdZdddZddZdS) PrettyPrinteraA basic pretty-printer. Attributes: name: A unique string among all printers for the context in which it is defined (objfile, progspace, or global(gdb)), and should meaningfully describe what can be pretty-printed. E.g., "StringPiece" or "protobufs". subprinters: An iterable object with each element having a `name' attribute, and, potentially, "enabled" attribute. Or this is None if there are no subprinters. enabled: A boolean indicating if the printer is enabled. Subprinters are for situations where "one" pretty-printer is actually a collection of several printers. E.g., The libstdc++ pretty-printer has a pretty-printer for each of several different types, based on regexps. NcCs||_||_d|_dS)NT)name subprintersenabled)selfrrr /printing.py__init__3szPrettyPrinter.__init__cCs tddS)NzPrettyPrinter __call__)NotImplementedError)rvalrrr __call__8szPrettyPrinter.__call__)N)__name__ __module__ __qualname____doc__r r rrrr rs rc@seZdZdZddZdS)SubPrettyPrinterzBaseclass for sub-pretty-printers. Sub-pretty-printers needn't use this, but it formalizes what's needed. Attributes: name: The name of the subprinter. enabled: A boolean indicating if the subprinter is enabled. cCs||_d|_dS)NT)rr)rrrrr r GszSubPrettyPrinter.__init__N)rrrrr rrrr r=srFcCsTt|d r t|d r tdt|dr>t|d r>tdt|dsPtdt|drb|j}n|j}|dksx|tkrtjd rtjd |t}ntjd rtjd ||jft|drBt|jt std |jj d dkrt dd}xP|j D]F}t|dr6|j|jkr6|r(|j |=Pnt d|j|d}qW|j jd|dS)aRegister pretty-printer PRINTER with OBJ. The printer is added to the front of the search list, thus one can override an existing printer if one needs to. Use a different name when overriding an existing printer, otherwise an exception will be raised; multiple printers with the same name are disallowed. Arguments: obj: Either an objfile, progspace, or None (in which case the printer is registered globally). printer: Either a function of one argument (old way) or any object which has attributes: name, enabled, __call__. replace: If True replace any existing copy of the printer. Otherwise if the printer already exists raise an exception. Returns: Nothing. Raises: TypeError: A problem with the type of the printer. ValueError: The printer's name contains a semicolon ";". RuntimeError: A printer with the same name is already registered. If the caller wants the printer to be listable and disableable, it must follow the PrettyPrinter API. This applies to the old way (functions) too. If printer is an object, __call__ is a method of two arguments: self, and the value to be pretty-printed. See PrettyPrinter. rrzprinter missing attribute: namerz"printer missing attribute: enabledr z#printer missing attribute: __call__Nverbosez)Registering global %s pretty-printer ... z)Registering %s pretty-printer for %s ... zprinter name is not a string;rzsemicolon ';' in printer namez%pretty-printer already registered: %s)hasattr TypeErrorrrgdbZ parameterwritefilename isinstance basestringfind ValueErrorZpretty_printers RuntimeErrorinsert)objprinterreplaceriprrr register_pretty_printerLs>"         r&cs@eZdZdZGdddeZfddZddZdd ZZ S) RegexpCollectionPrettyPrinterayClass for implementing a collection of regular-expression based pretty-printers. Intended usage: pretty_printer = RegexpCollectionPrettyPrinter("my_library") pretty_printer.add_printer("myclass1", "^myclass1$", MyClass1Printer) ... pretty_printer.add_printer("myclassN", "^myclassN$", MyClassNPrinter) register_pretty_printer(obj, pretty_printer) cseZdZfddZZS)z.RegexpCollectionPrettyPrinter.RegexpSubprintercs.ttj|j|||_||_tj||_dS)N) superr'RegexpSubprinterr regexp gen_printerrecompile compiled_re)rrr*r+) __class__rr r sz7RegexpCollectionPrettyPrinter.RegexpSubprinter.__init__)rrrr __classcell__rr)r/r r)sr)cstt|j|gdS)N)r(r'r )rr)r/rr r sz&RegexpCollectionPrettyPrinter.__init__cCs|jj|j|||dS)aoAdd a printer to the list. The printer is added to the end of the list. Arguments: name: The name of the subprinter. regexp: The regular expression, as a string. gen_printer: A function/method that given a value returns an object to pretty-print it. Returns: Nothing. N)rappendr))rrr*r+rrr add_printersz)RegexpCollectionPrettyPrinter.add_printercCsTtjj|jj}|s|jj}|s$dSx*|jD] }|jr,|jj |r,|j |Sq,WdS)z1Lookup the pretty-printer for the provided value.N) rtypesZget_basic_typetypetagrrrr.searchr+)rr typenamer"rrr r s z&RegexpCollectionPrettyPrinter.__call__) rrrrrr)r r2r r0rr)r/r r's   r'c@seZdZddZddZdS) _EnumInstancecCs||_||_dS)N) enumeratorsr )rr9r rrr r sz_EnumInstance.__init__cCs~g}t|j}d}x6|jD],\}}||@dkr|j|||@}d}qW| sX|dkrf|jd|dt|jdj|fS)NFrTzz 0x%x [%s]z | )longr r9r1intjoin)rZ flag_listvZ any_foundZe_nameZe_valuerrr to_strings    z_EnumInstance.to_stringN)rrrr r>rrrr r8sr8cs(eZdZdZfddZddZZS)FlagEnumerationPrinteraA pretty-printer which can be used to print a flag-style enumeration. A flag-style enumeration is one where the enumerators are or'd together to create values. The new printer will print these symbolically using '|' notation. The printer must be registered manually. This printer is most useful when an enum is flag-like, but has some overlap. GDB's built-in printing will not handle this case, but this printer will attempt to.cstt|j|d|_dS)NF)r(r?r initialized)rZ enum_type)r/rr r szFlagEnumerationPrinter.__init__cCsp|jsVd|_tj|j}g|_x$|jD]}|jj|j|jfq(W|jjddd|j rht |j|SdSdS)NTcSs|dS)Nrr)xrrr  sz1FlagEnumerationPrinter.__call__..)key) r@rZ lookup_typerr9Zfieldsr1Zenumvalsortrr8)rr flagsZfieldrrr r s  zFlagEnumerationPrinter.__call__)rrrrr r r0rr)r/r r?s r?ZbuiltincCstj|||dS)N)_builtin_pretty_printersr2)rr*r"rrr add_builtin_pretty_printersrG)F)rrZ gdb.typesr,sys version_infostrrr;r:objectrrr&r'r8r?rFrGrrrr s   RC" PKPD4]H$*$*&gdb/__pycache__/xmethod.cpython-36.pycnu[3 `E+@sdZddlZddlZddlZejddkr2eZeZGddde Z Gddde Z Gdd d e Z Gd d d e Z d d ZddZdddZdS)zUtilities for defining xmethodsNc@seZdZdZddZdS)XMethodaBase class (or a template) for an xmethod description. Currently, the description requires only the 'name' and 'enabled' attributes. Description objects are managed by 'XMethodMatcher' objects (see below). Note that this is only a template for the interface of the XMethodMatcher.methods objects. One could use this class or choose to use an object which supports this exact same interface. Also, an XMethodMatcher can choose not use it 'methods' attribute. In such cases this class (or an equivalent) is not used. Attributes: name: The name of the xmethod. enabled: A boolean indicating if the xmethod is enabled. cCs||_d|_dS)NT)nameenabled)selfrr /xmethod.py__init__.szXMethod.__init__N)__name__ __module__ __qualname____doc__r rrrrrsrc@s eZdZdZddZddZdS)XMethodMatcheraAbstract base class for matching an xmethod. When looking for xmethods, GDB invokes the `match' method of a registered xmethod matcher to match the object type and method name. The `match' method in concrete classes derived from this class should return an `XMethodWorker' object, or a list of `XMethodWorker' objects if there is a match (see below for 'XMethodWorker' class). Attributes: name: The name of the matcher. enabled: A boolean indicating if the matcher is enabled. methods: A sequence of objects of type 'XMethod', or objects which have at least the attributes of an 'XMethod' object. This list is used by the 'enable'/'disable'/'info' commands to enable/disable/list the xmethods registered with GDB. See the 'match' method below to know how this sequence is used. This attribute is None if the matcher chooses not have any xmethods managed by it. cCs||_d|_d|_dS)z Args: name: An identifying name for the xmethod or the group of xmethods returned by the `match' method. TN)rrmethods)rrrrrr HszXMethodMatcher.__init__cCs tddS)aMatch class type and method name. In derived classes, it should return an XMethodWorker object, or a sequence of 'XMethodWorker' objects. Only those xmethod workers whose corresponding 'XMethod' descriptor object is enabled should be returned. Args: class_type: The class type (gdb.Type object) to match. method_name: The name (string) of the method to match. zXMethodMatcher matchN)NotImplementedError)r class_type method_namerrrmatchRs zXMethodMatcher.matchN)r r r r r rrrrrr3s rc@s(eZdZdZddZddZddZdS) XMethodWorkera8Base class for all xmethod workers defined in Python. An xmethod worker is an object which matches the method arguments, and invokes the method when GDB wants it to. Internally, GDB first invokes the 'get_arg_types' method to perform overload resolution. If GDB selects to invoke this Python xmethod, then it invokes it via the overridden '__call__' method. The 'get_result_type' method is used to implement 'ptype' on the xmethod. Derived classes should override the 'get_arg_types', 'get_result_type' and '__call__' methods. cCs tddS)aReturn arguments types of an xmethod. A sequence of gdb.Type objects corresponding to the arguments of the xmethod are returned. If the xmethod takes no arguments, then 'None' or an empty sequence is returned. If the xmethod takes only a single argument, then a gdb.Type object or a sequence with a single gdb.Type element is returned. zXMethodWorker get_arg_typesN)r)rrrr get_arg_typesos zXMethodWorker.get_arg_typescGs tddS)aReturn the type of the result of the xmethod. Args: args: Arguments to the method. Each element of the tuple is a gdb.Value object. The first element is the 'this' pointer value. These are the same arguments passed to '__call__'. Returns: A gdb.Type object representing the type of the result of the xmethod. zXMethodWorker get_result_typeN)r)rargsrrrget_result_typezs zXMethodWorker.get_result_typecGs tddS)ayInvoke the xmethod. Args: args: Arguments to the method. Each element of the tuple is a gdb.Value object. The first element is the 'this' pointer value. Returns: A gdb.Value corresponding to the value returned by the xmethod. Returns 'None' if the method does not return anything. zXMethodWorker __call__N)r)rrrrr__call__s zXMethodWorker.__call__N)r r r r rrrrrrrras  rc@s0eZdZdZGdddeZddZddZdS) SimpleXMethodMatcheraA utility class to implement simple xmethod mathers and workers. See the __init__ method below for information on how instances of this class can be used. For simple classes and methods, one can choose to use this class. For complex xmethods, which need to replace/implement template methods on possibly template classes, one should implement their own xmethod matchers and workers. See py-xmethods.py in testsuite/gdb.python directory of the GDB source tree for examples. c@s$eZdZddZddZddZdS)z(SimpleXMethodMatcher.SimpleXMethodWorkercCs||_||_dS)N) _arg_types_method_function)rmethod_function arg_typesrrrr sz1SimpleXMethodMatcher.SimpleXMethodWorker.__init__cCs|jS)N)r)rrrrrsz6SimpleXMethodMatcher.SimpleXMethodWorker.get_arg_typescGs |j|S)N)r)rrrrrrsz1SimpleXMethodMatcher.SimpleXMethodWorker.__call__N)r r r r rrrrrrSimpleXMethodWorkersrcGs8tj||t|std||_||_||_||_dS)a Args: name: Name of the xmethod matcher. class_matcher: A regular expression used to match the name of the class whose method this xmethod is implementing/replacing. method_matcher: A regular expression used to match the name of the method this xmethod is implementing/replacing. method_function: A Python callable which would be called via the 'invoke' method of the worker returned by the objects of this class. This callable should accept the object (*this) as the first argument followed by the rest of the arguments to the method. All arguments to this function should be gdb.Value objects. arg_types: The gdb.Type objects corresponding to the arguments that this xmethod takes. It can be None, or an empty sequence, or a single gdb.Type object, or a sequence of gdb.Type objects. z^The 'method_function' argument to 'SimpleXMethodMatcher' __init__ method should be a callable.N)rr callableAssertionErrorr_class_matcher_method_matcherr)rrZ class_matcherZmethod_matcherrrrrrr s  zSimpleXMethodMatcher.__init__cCsBtj|jt|jj}tj|j|}|r>|r>tj|j |j SdS)N) rerr!strZ unqualifiedtagr"rrrr)rrrcmZmmrrrrs zSimpleXMethodMatcher.matchN)r r r r rrr rrrrrrs  rcCsft|dstdSt|ds$tdSt|ds6tdSt|jtsJtdS|jjdd krbtd SdS) Nrz(Xmethod matcher is missing method: matchrz*Xmethod matcher is missing attribute: namerz-Xmethod matcher is missing attribute: enabledz3Attribute 'name' of xmethod matcher is not a string;rz-Xmethod matcher name cannot contain ';' in it)hasattr TypeError isinstancer basestringfind ValueError)matcherrrr_validate_xmethod_matchers    r/cCs2x,tdt|jD]}|j|j|kr|SqWdS)Nr)rangelenxmethodsr)locusrirrr_lookup_xmethod_matchersr7FcCst|}|r||st}|tkr&d}n|j}t||j}|dkr`|rN|j|=ntd||jftjdrttjd|jj d|dS)aRegisters a xmethod matcher MATCHER with a LOCUS. Arguments: locus: The locus in which the xmethods should be registered. It can be 'None' to indicate that the xmethods should be registered globally. Or, it could be a gdb.Objfile or a gdb.Progspace object in which the xmethods should be registered. matcher: The xmethod matcher to register with the LOCUS. It should be an instance of 'XMethodMatcher' class. replace: If True, replace any existing xmethod matcher with the same name in the locus. Otherwise, if a matcher with the same name exists in the locus, raise an exception. globalrz.Xmethod matcher already registered with %s: %sverbosez.Registering xmethod matcher '%s' with %s' ... N) r/gdbfilenamer7rr4 RuntimeErrorZ parameterwriteinsert)r5r.replaceerrZ locus_nameindexrrrregister_xmethod_matchers"    rB)F)r r:r#sys version_infor$r+intZlongobjectrrrrr/r7rBrrrrs.6APKPD4]J,gdb/__pycache__/FrameIterator.cpython-36.pycnu[3 `)@s$ddlZddlZGdddeZdS)Ncs8eZdZdZfddZddZddZdd ZZS) FrameIteratorz^A gdb.Frame iterator. Iterates over gdb.Frames or objects that conform to that interface.cstt|j||_dS)zYInitialize a FrameIterator. Arguments: frame_obj the starting frame.N)superr__init__frame)selfZ frame_obj) __class__/FrameIterator.pyrszFrameIterator.__init__cCs|S)Nr)rrrr __iter__ szFrameIterator.__iter__cCs |j}|dkrt|j|_|S)zInext implementation. Returns: The next oldest frame.N)r StopIterationZolder)rresultrrr next#s  zFrameIterator.nextcCs|jS)N)r )rrrr __next__2szFrameIterator.__next__) __name__ __module__ __qualname____doc__rr r r __classcell__rr)rr rs  r)Zgdb itertoolsobjectrrrrr sPKPD4]47R 'gdb/__pycache__/unwinder.cpython-36.pycnu[3 `A @s*dZddlZGdddeZdddZdS) z.Unwinder class and register_unwinder function.Nc@s eZdZdZddZddZdS)UnwinderaBase class (or a template) for frame unwinders written in Python. An unwinder has a single method __call__ and the attributes described below. Attributes: name: The name of the unwinder. enabled: A boolean indicating whether the unwinder is enabled. cCs||_d|_dS)z\Constructor. Args: name: An identifying name for the unwinder. TN)nameZenabled)selfrr /unwinder.py__init__ szUnwinder.__init__cCs tddS)zGDB calls this method to unwind a frame. Arguments: pending_frame: gdb.PendingFrame instance. Returns: gdb.UnwindInfo instance. zUnwinder __call__.N)NotImplementedError)rZ pending_framerrr__call__)s zUnwinder.__call__N)__name__ __module__ __qualname____doc__rr rrrrrs  rFcCs|dkr(tjdr"tjd|jt}nBt|tjs@t|tjrbtjdrjtjd|j|jfntdd}x>|j D]4}|j|jkr|r|j |=nt d|j|d7}qvW|j j d|tj dS) a~Register unwinder in given locus. The unwinder is prepended to the locus's unwinders list. Unwinder name should be unique. Arguments: locus: Either an objfile, progspace, or None (in which case the unwinder is registered globally). unwinder: An object of a gdb.Unwinder subclass replace: If True, replaces existing unwinder with the same name. Otherwise, raises exception if unwinder with the same name already exists. Returns: Nothing. Raises: RuntimeError: Unwinder name is not unique TypeError: Bad locus type Nverbosez#Registering global %s unwinder ... z#Registering %s unwinder for %s ... z4locus should be gdb.Objfile or gdb.Progspace or NonerzUnwinder %s already exists.) gdbZ parameterwriter isinstanceZObjfileZ Progspacefilename TypeErrorZframe_unwinders RuntimeErrorinsertZinvalidate_cached_frames)ZlocusZunwinderreplaceiZneedlerrrregister_unwinder5s&       r)F)r robjectrrrrrrs PKPD4]'C"C"'gdb/__pycache__/printing.cpython-36.pycnu[3 `*@sdZddlZddlZddlZddlZejddkr:eZeZ Gddde Z Gddde Z dd d Z Gd d d e ZGd ddZGddde ZedZe deddZdS)z+Utilities for working with pretty-printers.Nc@s"eZdZdZdddZddZdS) PrettyPrinteraA basic pretty-printer. Attributes: name: A unique string among all printers for the context in which it is defined (objfile, progspace, or global(gdb)), and should meaningfully describe what can be pretty-printed. E.g., "StringPiece" or "protobufs". subprinters: An iterable object with each element having a `name' attribute, and, potentially, "enabled" attribute. Or this is None if there are no subprinters. enabled: A boolean indicating if the printer is enabled. Subprinters are for situations where "one" pretty-printer is actually a collection of several printers. E.g., The libstdc++ pretty-printer has a pretty-printer for each of several different types, based on regexps. NcCs||_||_d|_dS)NT)name subprintersenabled)selfrrr /printing.py__init__3szPrettyPrinter.__init__cCs tddS)NzPrettyPrinter __call__)NotImplementedError)rvalrrr __call__8szPrettyPrinter.__call__)N)__name__ __module__ __qualname____doc__r r rrrr rs rc@seZdZdZddZdS)SubPrettyPrinterzBaseclass for sub-pretty-printers. Sub-pretty-printers needn't use this, but it formalizes what's needed. Attributes: name: The name of the subprinter. enabled: A boolean indicating if the subprinter is enabled. cCs||_d|_dS)NT)rr)rrrrr r GszSubPrettyPrinter.__init__N)rrrrr rrrr r=srFcCsTt|d r t|d r tdt|dr>t|d r>tdt|dsPtdt|drb|j}n|j}|dksx|tkrtjd rtjd |t}ntjd rtjd ||jft|drBt|jt std |jj d dkrt dd}xP|j D]F}t|dr6|j|jkr6|r(|j |=Pnt d|j|d}qW|j jd|dS)aRegister pretty-printer PRINTER with OBJ. The printer is added to the front of the search list, thus one can override an existing printer if one needs to. Use a different name when overriding an existing printer, otherwise an exception will be raised; multiple printers with the same name are disallowed. Arguments: obj: Either an objfile, progspace, or None (in which case the printer is registered globally). printer: Either a function of one argument (old way) or any object which has attributes: name, enabled, __call__. replace: If True replace any existing copy of the printer. Otherwise if the printer already exists raise an exception. Returns: Nothing. Raises: TypeError: A problem with the type of the printer. ValueError: The printer's name contains a semicolon ";". RuntimeError: A printer with the same name is already registered. If the caller wants the printer to be listable and disableable, it must follow the PrettyPrinter API. This applies to the old way (functions) too. If printer is an object, __call__ is a method of two arguments: self, and the value to be pretty-printed. See PrettyPrinter. rrzprinter missing attribute: namerz"printer missing attribute: enabledr z#printer missing attribute: __call__Nverbosez)Registering global %s pretty-printer ... z)Registering %s pretty-printer for %s ... zprinter name is not a string;rzsemicolon ';' in printer namez%pretty-printer already registered: %s)hasattr TypeErrorrrgdbZ parameterwritefilename isinstance basestringfind ValueErrorZpretty_printers RuntimeErrorinsert)objprinterreplaceriprrr register_pretty_printerLs>"         r&cs@eZdZdZGdddeZfddZddZdd ZZ S) RegexpCollectionPrettyPrinterayClass for implementing a collection of regular-expression based pretty-printers. Intended usage: pretty_printer = RegexpCollectionPrettyPrinter("my_library") pretty_printer.add_printer("myclass1", "^myclass1$", MyClass1Printer) ... pretty_printer.add_printer("myclassN", "^myclassN$", MyClassNPrinter) register_pretty_printer(obj, pretty_printer) cseZdZfddZZS)z.RegexpCollectionPrettyPrinter.RegexpSubprintercs.ttj|j|||_||_tj||_dS)N) superr'RegexpSubprinterr regexp gen_printerrecompile compiled_re)rrr*r+) __class__rr r sz7RegexpCollectionPrettyPrinter.RegexpSubprinter.__init__)rrrr __classcell__rr)r/r r)sr)cstt|j|gdS)N)r(r'r )rr)r/rr r sz&RegexpCollectionPrettyPrinter.__init__cCs|jj|j|||dS)aoAdd a printer to the list. The printer is added to the end of the list. Arguments: name: The name of the subprinter. regexp: The regular expression, as a string. gen_printer: A function/method that given a value returns an object to pretty-print it. Returns: Nothing. N)rappendr))rrr*r+rrr add_printersz)RegexpCollectionPrettyPrinter.add_printercCsTtjj|jj}|s|jj}|s$dSx*|jD] }|jr,|jj |r,|j |Sq,WdS)z1Lookup the pretty-printer for the provided value.N) rtypesZget_basic_typetypetagrrrr.searchr+)rr typenamer"rrr r s z&RegexpCollectionPrettyPrinter.__call__) rrrrrr)r r2r r0rr)r/r r's   r'c@seZdZddZddZdS) _EnumInstancecCs||_||_dS)N) enumeratorsr )rr9r rrr r sz_EnumInstance.__init__cCs~g}t|j}d}x6|jD],\}}||@dkr|j|||@}d}qW| sX|dkrf|jd|dt|jdj|fS)NFrTzz 0x%x [%s]z | )longr r9r1intjoin)rZ flag_listvZ any_foundZe_nameZe_valuerrr to_strings    z_EnumInstance.to_stringN)rrrr r>rrrr r8sr8cs(eZdZdZfddZddZZS)FlagEnumerationPrinteraA pretty-printer which can be used to print a flag-style enumeration. A flag-style enumeration is one where the enumerators are or'd together to create values. The new printer will print these symbolically using '|' notation. The printer must be registered manually. This printer is most useful when an enum is flag-like, but has some overlap. GDB's built-in printing will not handle this case, but this printer will attempt to.cstt|j|d|_dS)NF)r(r?r initialized)rZ enum_type)r/rr r szFlagEnumerationPrinter.__init__cCsp|jsVd|_tj|j}g|_x$|jD]}|jj|j|jfq(W|jjddd|j rht |j|SdSdS)NTcSs|dS)Nrr)xrrr  sz1FlagEnumerationPrinter.__call__..)key) r@rZ lookup_typerr9Zfieldsr1Zenumvalsortrr8)rr flagsZfieldrrr r s  zFlagEnumerationPrinter.__call__)rrrrr r r0rr)r/r r?s r?ZbuiltincCstj|||dS)N)_builtin_pretty_printersr2)rr*r"rrr add_builtin_pretty_printersrG)F)rrZ gdb.typesr,sys version_infostrrr;r:objectrrr&r'r8r?rFrGrrrr s   RC" PKPD4]J2gdb/__pycache__/FrameIterator.cpython-36.opt-1.pycnu[3 `)@s$ddlZddlZGdddeZdS)Ncs8eZdZdZfddZddZddZdd ZZS) FrameIteratorz^A gdb.Frame iterator. Iterates over gdb.Frames or objects that conform to that interface.cstt|j||_dS)zYInitialize a FrameIterator. Arguments: frame_obj the starting frame.N)superr__init__frame)selfZ frame_obj) __class__/FrameIterator.pyrszFrameIterator.__init__cCs|S)Nr)rrrr __iter__ szFrameIterator.__iter__cCs |j}|dkrt|j|_|S)zInext implementation. Returns: The next oldest frame.N)r StopIterationZolder)rresultrrr next#s  zFrameIterator.nextcCs|jS)N)r )rrrr __next__2szFrameIterator.__next__) __name__ __module__ __qualname____doc__rr r r __classcell__rr)rr rs  r)Zgdb itertoolsobjectrrrrr sPKPD4]Ql'3gdb/__pycache__/FrameDecorator.cpython-36.opt-1.pycnu[3 `( @s^ddlZyeWnek r(eZYnXGdddeZGdddeZGdddeZdS)Nc@sdeZdZdZddZeddZddZdd Zd d Z d d Z ddZ ddZ ddZ ddZdS)FrameDecoratorz)Basic implementation of a Frame DecoratorcCs ||_dS)N)_base)selfbaser/FrameDecorator.py__init__<szFrameDecorator.__init__cCs>|j}|j s6|jj s6|jtjks6|jtjkr:dSdS)zIInternal utility to determine if the frame is special or limited.TF)find_salsymtabfilenametypegdb DUMMY_FRAMESIGTRAMP_FRAME)framesalrrr_is_limited_frame?s z FrameDecorator._is_limited_framecCst|jdr|jjSdS)zLReturn any elided frames that this class might be wrapping, or None.elidedN)hasattrrr)rrrrrMs  zFrameDecorator.elidedcCstt|jtjs$t|jdr$|jjS|j}|jtjkr>dS|jtj krPdS|j}|dkrl|j }|St |S)a Return the name of the frame's function or an address of the function of the frame. First determine if this is a special frame. If not, try to determine filename from GDB's frame internal function API. Finally, if a name cannot be determined return the address. If this function returns an address, GDB will attempt to determine the function name from its internal minimal symbols store (for example, for inferiors without debug-info).functionzzN) isinstancerr ZFramerrinferior_framer rrpcstr)rrfuncrrrrrUs   zFrameDecorator.functioncCs&t|jdr|jjS|j}|jS)z% Return the address of the frame's pcaddress)rrrrr)rrrrrrzs  zFrameDecorator.addresscCsVt|jdr|jjS|j}|j}|j s8|jj rJ|j}tj|S|jjSdS)z Return the filename associated with this frame, detecting and returning the appropriate library name is this is a shared library.r N) rrr rr r rr Z solib_name)rrrrrrrr s   zFrameDecorator.filenamecCs<t|jdr|jjS|j}|j|r,dSt|}|jS)a Return an iterable of frame arguments for this frame, if any. The iterable object contains objects conforming with the Symbol/Value interface. If there are no frame arguments, or if this frame is deemed to be a special case, return None. frame_argsN)rrrrr FrameVarsfetch_frame_args)rrargsrrrrs   zFrameDecorator.frame_argscCs<t|jdr|jjS|j}|j|r,dSt|}|jS)a Return an iterable of local variables for this frame, if any. The iterable object contains objects conforming with the Symbol/Value interface. If there are no frame locals, or if this frame is deemed to be a special case, return None. frame_localsN)rrr rrrfetch_frame_locals)rrrrrrr s   zFrameDecorator.frame_localscCsFt|jdr|jjS|j}|j|r,dS|j}|r>|jSdSdS)z Return line number information associated with the frame's pc. If symbol table/line information does not exist, or if this frame is deemed to be a special case, return NonelineN)rrr"rrr )rrrrrrr"s   zFrameDecorator.linecCst|jdr|jjS|jS)z8 Return the gdb.Frame underpinning this frame decorator.r)rrr)rrrrrs  zFrameDecorator.inferior_frameN)__name__ __module__ __qualname____doc__r staticmethodrrrrr rr r"rrrrrrs  % rc@s(eZdZdZddZddZddZdS) SymValueWrapperzkA container class conforming to the Symbol/Value interface which holds frame locals or frame arguments.cCs||_||_dS)N)symval)rsymbolvaluerrrrszSymValueWrapper.__init__cCs|jS)z6 Return the value associated with this symbol, or None)r*)rrrrr,szSymValueWrapper.valuecCs|jS)zP Return the symbol, or Python text, associated with this symbol, or None)r))rrrrr+szSymValueWrapper.symbolN)r#r$r%r&rr,r+rrrrr(sr(c@s0eZdZdZddZddZddZdd Zd S) rzOUtility class to fetch and store frame local variables, or frame arguments.cCs:||_tjdtjdtjdtjdtjdtjdtjdi|_ dS)NT) rr ZSYMBOL_LOC_STATICZSYMBOL_LOC_REGISTERZSYMBOL_LOC_ARGZSYMBOL_LOC_REF_ARGZSYMBOL_LOC_LOCALZSYMBOL_LOC_REGPARM_ADDRZSYMBOL_LOC_COMPUTED symbol_class)rrrrrrszFrameVars.__init__cCs"t|trdS|j}|jj|dS)z Local utility method to determine if according to Symbol type whether it should be included in the iterator. Not all symbols are fetched, and only symbols that return True from this method should be fetched.TF)r basestringZ addr_classr-get)rr)Zsym_typerrrfetch_bs zFrameVars.fetch_bc Csg}y|jj}Wntk r*d}YnXxP|dkr||jsB|jrDPx.|D]&}|jrVqJ|j|rJ|jt|dqJW|j }q.W|S)zPublic utility method to fetch frame local variables for the stored frame. Frame arguments are not fetched. If there are no frame local variables, return an empty list.N) rblock RuntimeErrorZ is_globalZ is_static is_argumentr0appendr( superblock)rZlvarsr1r)rrrr!s      zFrameVars.fetch_frame_localsc Cs~g}y|jj}Wntk r*d}YnXx|dkrJ|jdkrBP|j}q.W|dkrzx$|D]}|jsfqZ|jt|dqZW|S)zPublic utility method to fetch frame arguments for the stored frame. Frame arguments are the only type fetched. If there are no frame argument variables, return an empty list.N)rr1r2rr5r3r4r()rrr1r)rrrrs     zFrameVars.fetch_frame_argsN)r#r$r%r&rr0r!rrrrrrs  r)r r. NameErrorrobjectrr(rrrrrs 4PKPD4]T`*gdb/__pycache__/types.cpython-36.opt-1.pycnu[3 `@s`dZddlZddZddZddZd d ZGd d d eZd dZddZ ddZ ddZ dS)z%Utilities for working with gdb.Types.NcCs\xR|jtjks&|jtjks&|jtjkrR|jtjks>|jtjkrH|j}q|j}qW|jS)zReturn the "basic" type of a type. Arguments: type_: The type to reduce to its basic type. Returns: type_ with const/volatile is stripped away, and typedefs/references converted to the underlying type. )codegdbZ TYPE_CODE_REFZTYPE_CODE_RVALUE_REFZTYPE_CODE_TYPEDEFtargetZstrip_typedefsZ unqualified)type_r /types.pyget_basic_types       rcCsdt|}|jtjkr(|jtjkr(tdx6|jD]*}|jrNt|j |r\dSq2|j |kr2dSq2WdS)ayReturn True if a type has the specified field. Arguments: type_: The type to examine. It must be one of gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION. field: The name of the field to look up. Returns: True if the field is present either in type_ or any baseclass. Raises: TypeError: The type is not a struct or union. znot a struct or unionTF) rrrZTYPE_CODE_STRUCTZTYPE_CODE_UNION TypeErrorfieldsZ is_base_class has_fieldtypename)rfieldfrrrr ,s    r cCs:|jtjkrtdi}x|jD]}|j||j<q"W|S)zReturn a dictionary from a program's enum type. Arguments: enum_type: The enum to compute the dictionary for. Returns: The dictionary of the enum. Raises: TypeError: The type is not an enum. znot an enum type)rrZTYPE_CODE_ENUMr r Zenumvalr )Z enum_type enum_dictrrrrmake_enum_dictJs rccsDx>|jD]2\}}|r"||fVq xt|jD] }|Vq.Wq WdS)aReturn an iterator that recursively traverses anonymous fields. Arguments: type_: The type to traverse. It should be one of gdb.TYPE_CODE_STRUCT or gdb.TYPE_CODE_UNION. Returns: an iterator similar to gdb.Type.iteritems(), i.e., it returns pairs of key, value, but for any anonymous struct or union field that field is traversed recursively, depth-first. N)Z iteritems deep_itemsr )rkvirrrr`s  rc@s eZdZdZddZddZdS) TypePrinteraThe base class for type printers. Instances of this type can be used to substitute type names during 'ptype'. A type printer must have at least 'name' and 'enabled' attributes, and supply an 'instantiate' method. The 'instantiate' method must either return None, or return an object which has a 'recognize' method. This method must accept a gdb.Type argument and either return None, meaning that the type was not recognized, or a string naming the type. cCs||_d|_dS)NT)r enabled)selfr rrr__init__szTypePrinter.__init__cCsdS)Nr)rrrr instantiateszTypePrinter.instantiateN)__name__ __module__ __qualname____doc__rrrrrrrss rcCs2x,|D]$}|jr|j}|dk r|j|qWdS)N)rrappend)resultZplistprinterZinstrrr_get_some_type_recognizerss  r"cCsBg}xtjD]}t||jqWt|tjjt|tj|S)zFReturn a list of the enabled type recognizers for the current context.)rZobjfilesr" type_printersZcurrent_progspace)r Zobjfilerrrget_type_recognizerss  r$cCs(x"|D]}|j|}|dk r|SqWdS)zApply the given list of type recognizers to the type TYPE_OBJ. If any recognizer in the list recognizes TYPE_OBJ, returns the name given by the recognizer. Otherwise, this returns None.N)Z recognize)Z recognizersZtype_objrr rrrapply_type_recognizerss   r&cCs|dkr t}|jjd|dS)zRegister a type printer. PRINTER is the type printer instance. LOCUS is either an objfile, a program space, or None, indicating global registration.Nr)rr#insert)Zlocusr!rrrregister_type_printersr() rrrr rrobjectrr"r$r&r(rrrrs PKPD4]Ql'-gdb/__pycache__/FrameDecorator.cpython-36.pycnu[3 `( @s^ddlZyeWnek r(eZYnXGdddeZGdddeZGdddeZdS)Nc@sdeZdZdZddZeddZddZdd Zd d Z d d Z ddZ ddZ ddZ ddZdS)FrameDecoratorz)Basic implementation of a Frame DecoratorcCs ||_dS)N)_base)selfbaser/FrameDecorator.py__init__<szFrameDecorator.__init__cCs>|j}|j s6|jj s6|jtjks6|jtjkr:dSdS)zIInternal utility to determine if the frame is special or limited.TF)find_salsymtabfilenametypegdb DUMMY_FRAMESIGTRAMP_FRAME)framesalrrr_is_limited_frame?s z FrameDecorator._is_limited_framecCst|jdr|jjSdS)zLReturn any elided frames that this class might be wrapping, or None.elidedN)hasattrrr)rrrrrMs  zFrameDecorator.elidedcCstt|jtjs$t|jdr$|jjS|j}|jtjkr>dS|jtj krPdS|j}|dkrl|j }|St |S)a Return the name of the frame's function or an address of the function of the frame. First determine if this is a special frame. If not, try to determine filename from GDB's frame internal function API. Finally, if a name cannot be determined return the address. If this function returns an address, GDB will attempt to determine the function name from its internal minimal symbols store (for example, for inferiors without debug-info).functionzzN) isinstancerr ZFramerrinferior_framer rrpcstr)rrfuncrrrrrUs   zFrameDecorator.functioncCs&t|jdr|jjS|j}|jS)z% Return the address of the frame's pcaddress)rrrrr)rrrrrrzs  zFrameDecorator.addresscCsVt|jdr|jjS|j}|j}|j s8|jj rJ|j}tj|S|jjSdS)z Return the filename associated with this frame, detecting and returning the appropriate library name is this is a shared library.r N) rrr rr r rr Z solib_name)rrrrrrrr s   zFrameDecorator.filenamecCs<t|jdr|jjS|j}|j|r,dSt|}|jS)a Return an iterable of frame arguments for this frame, if any. The iterable object contains objects conforming with the Symbol/Value interface. If there are no frame arguments, or if this frame is deemed to be a special case, return None. frame_argsN)rrrrr FrameVarsfetch_frame_args)rrargsrrrrs   zFrameDecorator.frame_argscCs<t|jdr|jjS|j}|j|r,dSt|}|jS)a Return an iterable of local variables for this frame, if any. The iterable object contains objects conforming with the Symbol/Value interface. If there are no frame locals, or if this frame is deemed to be a special case, return None. frame_localsN)rrr rrrfetch_frame_locals)rrrrrrr s   zFrameDecorator.frame_localscCsFt|jdr|jjS|j}|j|r,dS|j}|r>|jSdSdS)z Return line number information associated with the frame's pc. If symbol table/line information does not exist, or if this frame is deemed to be a special case, return NonelineN)rrr"rrr )rrrrrrr"s   zFrameDecorator.linecCst|jdr|jjS|jS)z8 Return the gdb.Frame underpinning this frame decorator.r)rrr)rrrrrs  zFrameDecorator.inferior_frameN)__name__ __module__ __qualname____doc__r staticmethodrrrrr rr r"rrrrrrs  % rc@s(eZdZdZddZddZddZdS) SymValueWrapperzkA container class conforming to the Symbol/Value interface which holds frame locals or frame arguments.cCs||_||_dS)N)symval)rsymbolvaluerrrrszSymValueWrapper.__init__cCs|jS)z6 Return the value associated with this symbol, or None)r*)rrrrr,szSymValueWrapper.valuecCs|jS)zP Return the symbol, or Python text, associated with this symbol, or None)r))rrrrr+szSymValueWrapper.symbolN)r#r$r%r&rr,r+rrrrr(sr(c@s0eZdZdZddZddZddZdd Zd S) rzOUtility class to fetch and store frame local variables, or frame arguments.cCs:||_tjdtjdtjdtjdtjdtjdtjdi|_ dS)NT) rr ZSYMBOL_LOC_STATICZSYMBOL_LOC_REGISTERZSYMBOL_LOC_ARGZSYMBOL_LOC_REF_ARGZSYMBOL_LOC_LOCALZSYMBOL_LOC_REGPARM_ADDRZSYMBOL_LOC_COMPUTED symbol_class)rrrrrrszFrameVars.__init__cCs"t|trdS|j}|jj|dS)z Local utility method to determine if according to Symbol type whether it should be included in the iterator. Not all symbols are fetched, and only symbols that return True from this method should be fetched.TF)r basestringZ addr_classr-get)rr)Zsym_typerrrfetch_bs zFrameVars.fetch_bc Csg}y|jj}Wntk r*d}YnXxP|dkr||jsB|jrDPx.|D]&}|jrVqJ|j|rJ|jt|dqJW|j }q.W|S)zPublic utility method to fetch frame local variables for the stored frame. Frame arguments are not fetched. If there are no frame local variables, return an empty list.N) rblock RuntimeErrorZ is_globalZ is_static is_argumentr0appendr( superblock)rZlvarsr1r)rrrr!s      zFrameVars.fetch_frame_localsc Cs~g}y|jj}Wntk r*d}YnXx|dkrJ|jdkrBP|j}q.W|dkrzx$|D]}|jsfqZ|jt|dqZW|S)zPublic utility method to fetch frame arguments for the stored frame. Frame arguments are the only type fetched. If there are no frame argument variables, return an empty list.N)rr1r2rr5r3r4r()rrr1r)rrrrs     zFrameVars.fetch_frame_argsN)r#r$r%r&rr0r!rrrrrrs  r)r r. NameErrorrobjectrr(rrrrrs 4PKPD4]8hA A %gdb/__pycache__/prompt.cpython-36.pycnu[3 `q @sdZddlZddlZddZddZddZd d Zd d Zd dZddZ ddZ ddZ ddZ ddZ ddZee e e eeeee e ed ZddZddZdS) z# Extended prompt library functions.NcCstjS)zThe current working directory.)osgetcwd)ignorer /prompt.py _prompt_pwdsrc Csh|dkr |}y |}Wntjk r0d|SXt||rXt||}t|rT|}|Sd||fSdS)z,Internal worker for fetching GDB attributes.Nzz)gdberrorhasattrgetattrcallable)funcZwhatattrZnattrobjresultrrr_prompt_object_attrs    rcCsttjd|dS)z8The selected frame; an argument names a frame parameter.framename)rrZselected_frame)rrrr _prompt_frame*srcCsttjd|dS)z:The selected thread; an argument names a thread parameter.ZthreadZnum)rrZselected_thread)rrrr_prompt_thread.srcCstjS)zThe version of GDB.)rVERSION)rrrr_prompt_version2srcCsdS)zThe ESC character.r)rrrr _prompt_esc6srcCsdS)z A backslash.\r)rrrr _prompt_bs:srcCsdS)z A newline. r)rrrr _prompt_n>srcCsdS)zA carriage return. r)rrrr _prompt_rBsrcCs tj|S)z6A parameter's value; the argument names the parameter.)rZ parameter)rrrr _prompt_paramFsr cCsdS)z-Begins a sequence of non-printing characters.r)rrrr_prompt_noprint_beginJsr"cCsdS)z+Ends a sequence of non-printing characters.r)rrrr_prompt_noprint_endNsr$) ernrvwftp[]cCs@d}ttj}x"|D]}|d|t|jf7}qW|d7}|S)zNGenerate help dynamically from the __doc__ strings of attribute functions.z \%s %s z A substitution can be used in a simple form, like "\f". An argument can also be passed to it, like "\f{name}". The meaning of the argument depends on the particular substitution.)sortedprompt_substitutionskeys__doc__)rr2keyrrr prompt_help`s  r5cCsd}t|}d}x||kr||dkr|d}||kr:P||}|tkrt|}|d|kr||ddkr|d}x ||kr||dkr|d}qxW||ks||dkrd}q||d|}|}nd}|t||7}q|||7}n |||7}|d}qW|S) z Perform substitutions on PROMPT.r/rr{}N)lenr1str)promptrZpleniZcmdchcmdjargrrrsubstitute_promptns2     rA)r3rrrrrrrrrrrr r"r$r1r5rArrrrs6PKPD4]ep'gdb/__pycache__/__init__.cpython-36.pycnu[3 `f @sHddlZddlZddlZddlZejddkr:ddlmZddlTGdddeZGdddeZ e e_ Gd d d eZ e e_ dZ d ge_gZgZgZiZgZd d ZddZejjejjeadddgZddZeddZddZddZddZddZ dd Z!y dd!l"m#Z#m$Z$m%Z%d"d#Z&Wnd$d#Z&YnXdS)%N)reload)*c@s4eZdZdZdZddZddZddZd d Zd S) _GdbFilezUTF-8strictcCsdS)N)selfrr /__init__.pyclose sz_GdbFile.closecCsdS)NFr)rrrr isatty$sz_GdbFile.isattycCsx|D]}|j|qWdS)N)write)riterablelinerrr writelines's z_GdbFile.writelinescCs tdS)N)flush)rrrr r+sz_GdbFile.flushN) __name__ __module__ __qualname__encodingerrorsr r rrrrrr rs rc@seZdZddZdS)_GdbOutputFilecCst|tddS)N)stream)r ZSTDOUT)rsrrr r /sz_GdbOutputFile.writeN)rrrr rrrr r.src@seZdZddZdS)_GdbOutputErrorFilecCst|tddS)N)r)r ZSTDERR)rrrrr r 5sz_GdbOutputErrorFile.writeN)rrrr rrrr r4srcCsx8tD].}x(|jD]}|jr||}|dk r|SqWqWx*tjD]}|jrD||}|dk rD|SqDWx&tD]}|jrl||}|dk rl|SqlWdS)aInternal function called from GDB to execute all unwinders. Runs each currently enabled unwinder until it finds the one that can unwind given frame. Arguments: pending_frame: gdb.PendingFrame instance. Returns: gdb.UnwindInfo instance or None. N)objfilesframe_unwindersZenabledcurrent_progspace)Z pending_frameZobjfileZunwinderZ unwind_inforrr _execute_unwindersMs"    rcCsntjdj}d}t|ds&||d<d}z6t|d"}t|j|d}t|||WdQRXWd|rh|d=XdS)aBThis function is used to replace Python 2's PyRun_SimpleFile. Loads and executes the given file. We could use the runpy module, but its documentation says: "Furthermore, any functions and classes defined by the executed code are not guaranteed to work correctly after a runpy function has returned." __main__F__file__TrbexecN)sysmodules__dict__hasattropencompilereadr")filepathglobalsZset_filefileZcompiledrrr _execute_filems   r-ZfunctionZcommandZprinterc CsxtD]}tjjtjjt|}tjj|rtddtj|}xh|D]`}dt ||ddf}y$|t j krzt t |nt |WqFt jjtjdYqFXqFWqWdS)NcSs|jdo|dkS)Nz.pyz __init__.py)endswith)xrrr s z%_auto_load_packages..z%s.%s.%s )packagesospathjoindirnamer existsfilterlistdirrr#r$r __import__stderrr traceback format_exc)packagelocationZpy_filesZpy_filemodnamerrr _auto_load_packagess      rCc CsNytjjtWntk r$YnXtjjd||atttt dS)z3Update sys.path, reload gdb and auto-load packages.rN) r#r6remove PYTHONDIR ValueErrorinsertrr<rrC)dirrrr GdbSetPythonDirectorys rIcCstjS)zReturn the current Progspace.)Zselected_inferiorZ progspacerrrr rsrcCs tjS)z:Return a sequence of the current program space's objfiles.)rrrrrr rsrcCs tj|S)zdsolib_name (Long) -> String. Return the name of the shared library holding a given address, or None.)r solib_name)Zaddrrrr rJsrJcCs tj|S)z8Return the block containing the given pc value, or None.)r block_for_pc)pcrrr rKsrKcCs tj|S)zjfind_pc_line (pc) -> Symtab_and_line. Return the gdb.Symtab_and_line object corresponding to the pc value.)r find_pc_line)rLrrr rMsrM) formatterslexers highlightc Cs2y"tj|dd}tj}t|||SdSdS)NF)Zstripnl)rOZget_lexer_for_filenamerNZTerminalFormatterrP)filenamecontentsZlexerZ formatterrrr colorizes  rScCsdS)Nr)rQrRrrr rSs)'r>r5r#Z_gdb version_infoZimprobjectrrstdoutrr=Z prompt_hookargvZpretty_printersZ type_printersZxmethodsZ frame_filtersrrr-r6r8r rEr4rCrIrrrJrKrMZpygmentsrNrOrPrSrrrr sJ   PKPD4]%0eqq gdb/prompt.pynu[# Extended prompt utilities. # Copyright (C) 2011-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ Extended prompt library functions.""" import gdb import os def _prompt_pwd(ignore): "The current working directory." return os.getcwd() def _prompt_object_attr(func, what, attr, nattr): """Internal worker for fetching GDB attributes.""" if attr is None: attr = nattr try: obj = func() except gdb.error: return '' % what if hasattr(obj, attr): result = getattr(obj, attr) if callable(result): result = result() return result else: return '' % (attr, what) def _prompt_frame(attr): "The selected frame; an argument names a frame parameter." return _prompt_object_attr(gdb.selected_frame, 'frame', attr, 'name') def _prompt_thread(attr): "The selected thread; an argument names a thread parameter." return _prompt_object_attr(gdb.selected_thread, 'thread', attr, 'num') def _prompt_version(attr): "The version of GDB." return gdb.VERSION def _prompt_esc(attr): "The ESC character." return '\033' def _prompt_bs(attr): "A backslash." return '\\' def _prompt_n(attr): "A newline." return '\n' def _prompt_r(attr): "A carriage return." return '\r' def _prompt_param(attr): "A parameter's value; the argument names the parameter." return gdb.parameter(attr) def _prompt_noprint_begin(attr): "Begins a sequence of non-printing characters." return '\001' def _prompt_noprint_end(attr): "Ends a sequence of non-printing characters." return '\002' prompt_substitutions = { 'e': _prompt_esc, '\\': _prompt_bs, 'n': _prompt_n, 'r': _prompt_r, 'v': _prompt_version, 'w': _prompt_pwd, 'f': _prompt_frame, 't': _prompt_thread, 'p': _prompt_param, '[': _prompt_noprint_begin, ']': _prompt_noprint_end } def prompt_help(): """Generate help dynamically from the __doc__ strings of attribute functions.""" result = '' keys = sorted (prompt_substitutions.keys()) for key in keys: result += ' \\%s\t%s\n' % (key, prompt_substitutions[key].__doc__) result += """ A substitution can be used in a simple form, like "\\f". An argument can also be passed to it, like "\\f{name}". The meaning of the argument depends on the particular substitution.""" return result def substitute_prompt(prompt): "Perform substitutions on PROMPT." result = '' plen = len(prompt) i = 0 while i < plen: if prompt[i] == '\\': i = i + 1 if i >= plen: break cmdch = prompt[i] if cmdch in prompt_substitutions: cmd = prompt_substitutions[cmdch] if i + 1 < plen and prompt[i + 1] == '{': j = i + 1 while j < plen and prompt[j] != '}': j = j + 1 # Just ignore formatting errors. if j >= plen or prompt[j] != '}': arg = None else: arg = prompt[i + 2 : j] i = j else: arg = None result += str(cmd(arg)) else: # Unrecognized escapes are turned into the escaped # character itself. result += prompt[i] else: result += prompt[i] i = i + 1 return result PKPD4]H))gdb/FrameIterator.pynu[# Copyright (C) 2013-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gdb import itertools class FrameIterator(object): """A gdb.Frame iterator. Iterates over gdb.Frames or objects that conform to that interface.""" def __init__(self, frame_obj): """Initialize a FrameIterator. Arguments: frame_obj the starting frame.""" super(FrameIterator, self).__init__() self.frame = frame_obj def __iter__(self): return self def next(self): """next implementation. Returns: The next oldest frame.""" result = self.frame if result is None: raise StopIteration self.frame = result.older() return result # Python 3.x requires __next__(self) while Python 2.x requires # next(self). Define next(self), and for Python 3.x create this # wrapper. def __next__(self): return self.next() PKPD4][˚ gdb/types.pynu[# Type utilities. # Copyright (C) 2010-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Utilities for working with gdb.Types.""" import gdb def get_basic_type(type_): """Return the "basic" type of a type. Arguments: type_: The type to reduce to its basic type. Returns: type_ with const/volatile is stripped away, and typedefs/references converted to the underlying type. """ while (type_.code == gdb.TYPE_CODE_REF or type_.code == gdb.TYPE_CODE_RVALUE_REF or type_.code == gdb.TYPE_CODE_TYPEDEF): if (type_.code == gdb.TYPE_CODE_REF or type_.code == gdb.TYPE_CODE_RVALUE_REF): type_ = type_.target() else: type_ = type_.strip_typedefs() return type_.unqualified() def has_field(type_, field): """Return True if a type has the specified field. Arguments: type_: The type to examine. It must be one of gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION. field: The name of the field to look up. Returns: True if the field is present either in type_ or any baseclass. Raises: TypeError: The type is not a struct or union. """ type_ = get_basic_type(type_) if (type_.code != gdb.TYPE_CODE_STRUCT and type_.code != gdb.TYPE_CODE_UNION): raise TypeError("not a struct or union") for f in type_.fields(): if f.is_base_class: if has_field(f.type, field): return True else: # NOTE: f.name could be None if f.name == field: return True return False def make_enum_dict(enum_type): """Return a dictionary from a program's enum type. Arguments: enum_type: The enum to compute the dictionary for. Returns: The dictionary of the enum. Raises: TypeError: The type is not an enum. """ if enum_type.code != gdb.TYPE_CODE_ENUM: raise TypeError("not an enum type") enum_dict = {} for field in enum_type.fields(): # The enum's value is stored in "enumval". enum_dict[field.name] = field.enumval return enum_dict def deep_items (type_): """Return an iterator that recursively traverses anonymous fields. Arguments: type_: The type to traverse. It should be one of gdb.TYPE_CODE_STRUCT or gdb.TYPE_CODE_UNION. Returns: an iterator similar to gdb.Type.iteritems(), i.e., it returns pairs of key, value, but for any anonymous struct or union field that field is traversed recursively, depth-first. """ for k, v in type_.iteritems (): if k: yield k, v else: for i in deep_items (v.type): yield i class TypePrinter(object): """The base class for type printers. Instances of this type can be used to substitute type names during 'ptype'. A type printer must have at least 'name' and 'enabled' attributes, and supply an 'instantiate' method. The 'instantiate' method must either return None, or return an object which has a 'recognize' method. This method must accept a gdb.Type argument and either return None, meaning that the type was not recognized, or a string naming the type. """ def __init__(self, name): self.name = name self.enabled = True def instantiate(self): return None # Helper function for computing the list of type recognizers. def _get_some_type_recognizers(result, plist): for printer in plist: if printer.enabled: inst = printer.instantiate() if inst is not None: result.append(inst) return None def get_type_recognizers(): "Return a list of the enabled type recognizers for the current context." result = [] # First try the objfiles. for objfile in gdb.objfiles(): _get_some_type_recognizers(result, objfile.type_printers) # Now try the program space. _get_some_type_recognizers(result, gdb.current_progspace().type_printers) # Finally, globals. _get_some_type_recognizers(result, gdb.type_printers) return result def apply_type_recognizers(recognizers, type_obj): """Apply the given list of type recognizers to the type TYPE_OBJ. If any recognizer in the list recognizes TYPE_OBJ, returns the name given by the recognizer. Otherwise, this returns None.""" for r in recognizers: result = r.recognize(type_obj) if result is not None: return result return None def register_type_printer(locus, printer): """Register a type printer. PRINTER is the type printer instance. LOCUS is either an objfile, a program space, or None, indicating global registration.""" if locus is None: locus = gdb locus.type_printers.insert(0, printer) PKPD4]-Ysgdb/function/as_string.pynu[# Copyright (C) 2016-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gdb class _AsString(gdb.Function): """Return the string representation of a value. Usage: $_as_string (VALUE) Arguments: VALUE: any value Returns: The string representation of the value.""" def __init__(self): super(_AsString, self).__init__("_as_string") def invoke(self, val): return str(val) _AsString() PKPD4]zgdb/function/caller_is.pynu[# Caller-is functions. # Copyright (C) 2008-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gdb import re class CallerIs(gdb.Function): """Check the calling function's name. Usage: $_caller_is (NAME [, NUMBER-OF-FRAMES]) Arguments: NAME: The name of the function to search for. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if the function's name at the specified frame is equal to NAME.""" def __init__(self): super(CallerIs, self).__init__("_caller_is") def invoke(self, name, nframes = 1): if nframes < 0: raise ValueError("nframes must be >= 0") frame = gdb.selected_frame() while nframes > 0: frame = frame.older() if frame is None: return False nframes = nframes - 1 return frame.name() == name.string() class CallerMatches(gdb.Function): """Compare the calling function's name with a regexp. Usage: $_caller_matches (REGEX [, NUMBER-OF-FRAMES]) Arguments: REGEX: The regular expression to compare the function's name with. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if the function's name at the specified frame matches REGEX.""" def __init__(self): super(CallerMatches, self).__init__("_caller_matches") def invoke(self, name, nframes = 1): if nframes < 0: raise ValueError("nframes must be >= 0") frame = gdb.selected_frame() while nframes > 0: frame = frame.older() if frame is None: return False nframes = nframes - 1 return re.match(name.string(), frame.name()) is not None class AnyCallerIs(gdb.Function): """Check all calling function's names. Usage: $_any_caller_is (NAME [, NUMBER-OF-FRAMES]) Arguments: NAME: The name of the function to search for. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if any function's name is equal to NAME.""" def __init__(self): super(AnyCallerIs, self).__init__("_any_caller_is") def invoke(self, name, nframes = 1): if nframes < 0: raise ValueError("nframes must be >= 0") frame = gdb.selected_frame() while nframes >= 0: if frame.name() == name.string(): return True frame = frame.older() if frame is None: return False nframes = nframes - 1 return False class AnyCallerMatches(gdb.Function): """Compare all calling function's names with a regexp. Usage: $_any_caller_matches (REGEX [, NUMBER-OF-FRAMES]) Arguments: REGEX: The regular expression to compare the function's name with. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if any function's name matches REGEX.""" def __init__(self): super(AnyCallerMatches, self).__init__("_any_caller_matches") def invoke(self, name, nframes = 1): if nframes < 0: raise ValueError("nframes must be >= 0") frame = gdb.selected_frame() name_re = re.compile(name.string()) while nframes >= 0: if name_re.match(frame.name()) is not None: return True frame = frame.older() if frame is None: return False nframes = nframes - 1 return False CallerIs() CallerMatches() AnyCallerIs() AnyCallerMatches() PKPD4]~{ { gdb/function/strfns.pynu[# Useful gdb string convenience functions. # Copyright (C) 2012-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """$_memeq, $_strlen, $_streq, $_regex""" import gdb import re class _MemEq(gdb.Function): """$_memeq - compare bytes of memory. Usage: $_memeq (A, B, LEN) Returns: True if LEN bytes at A and B compare equally.""" def __init__(self): super(_MemEq, self).__init__("_memeq") def invoke(self, a, b, length): if length < 0: raise ValueError("length must be non-negative") if length == 0: return True # The argument(s) to vector are [low_bound,]high_bound. byte_vector = gdb.lookup_type("char").vector(length - 1) ptr_byte_vector = byte_vector.pointer() a_ptr = a.reinterpret_cast(ptr_byte_vector) b_ptr = b.reinterpret_cast(ptr_byte_vector) return a_ptr.dereference() == b_ptr.dereference() class _StrLen(gdb.Function): """$_strlen - compute string length. Usage: $_strlen (A) Returns: Length of string A, assumed to be a string in the current language.""" def __init__(self): super(_StrLen, self).__init__("_strlen") def invoke(self, a): s = a.string() return len(s) class _StrEq(gdb.Function): """$_streq - check string equality. Usage: $_streq (A, B) Returns: True if A and B are identical strings in the current language. Example (amd64-linux): catch syscall open cond $bpnum $_streq((char*) $rdi, "foo")""" def __init__(self): super(_StrEq, self).__init__("_streq") def invoke(self, a, b): return a.string() == b.string() class _RegEx(gdb.Function): """$_regex - check if a string matches a regular expression. Usage: $_regex (STRING, REGEX) Returns: True if string STRING (in the current language) matches the regular expression REGEX.""" def __init__(self): super(_RegEx, self).__init__("_regex") def invoke(self, string, regex): s = string.string() r = re.compile(regex.string()) return bool(r.match(s)) # GDB will import us automagically via gdb/__init__.py. _MemEq() _StrLen() _StrEq() _RegEx() PKPD4]H1gdb/function/__pycache__/as_string.cpython-36.pycnu[3 `@s$ddlZGdddejZedS)Ncs(eZdZdZfddZddZZS) _AsStringzReturn the string representation of a value. Usage: $_as_string (VALUE) Arguments: VALUE: any value Returns: The string representation of the value.cstt|jddS)NZ _as_string)superr__init__)self) __class__ /as_string.pyrsz_AsString.__init__cCst|S)N)str)rvalrrrinvoke"sz_AsString.invoke)__name__ __module__ __qualname____doc__rr __classcell__rr)rrrs  r)ZgdbZFunctionrrrrrsPKPD4]VB3__6gdb/function/__pycache__/__init__.cpython-36.opt-1.pycnu[3 `@sdS)Nrrr /__init__.pysPKPD4]%`- .gdb/function/__pycache__/strfns.cpython-36.pycnu[3 `{ @sxdZddlZddlZGdddejZGdddejZGdddejZGd d d ejZeeeedS) z#$_memeq, $_strlen, $_streq, $_regexNcs(eZdZdZfddZddZZS)_MemEqzx$_memeq - compare bytes of memory. Usage: $_memeq (A, B, LEN) Returns: True if LEN bytes at A and B compare equally.cstt|jddS)NZ_memeq)superr__init__)self) __class__ /strfns.pyrsz_MemEq.__init__cCs\|dkrtd|dkrdStjdj|d}|j}|j|}|j|}|j|jkS)Nrzlength must be non-negativeTchar) ValueErrorgdbZ lookup_typeZvectorZpointerZreinterpret_castZ dereference)rabZlengthZ byte_vectorZptr_byte_vectorZa_ptrZb_ptrrrrinvoke!s  z _MemEq.invoke)__name__ __module__ __qualname____doc__rr __classcell__rr)rrrs rcs(eZdZdZfddZddZZS)_StrLenz$_strlen - compute string length. Usage: $_strlen (A) Returns: Length of string A, assumed to be a string in the current language.cstt|jddS)NZ_strlen)rrr)r)rrrr5sz_StrLen.__init__cCs|j}t|S)N)stringlen)rr srrrr8sz_StrLen.invoke)rrrrrrrrr)rrr.s rcs(eZdZdZfddZddZZS)_StrEqz$_streq - check string equality. Usage: $_streq (A, B) Returns: True if A and B are identical strings in the current language. Example (amd64-linux): catch syscall open cond $bpnum $_streq((char*) $rdi, "foo")cstt|jddS)NZ_streq)rrr)r)rrrrHsz_StrEq.__init__cCs|j|jkS)N)r)rr rrrrrKsz _StrEq.invoke)rrrrrrrrr)rrr=s  rcs(eZdZdZfddZddZZS)_RegExz$_regex - check if a string matches a regular expression. Usage: $_regex (STRING, REGEX) Returns: True if string STRING (in the current language) matches the regular expression REGEX.cstt|jddS)NZ_regex)rrr)r)rrrrWsz_RegEx.__init__cCs$|j}tj|j}t|j|S)N)rrecompileboolmatch)rrZregexrrrrrrZsz _RegEx.invoke)rrrrrrrrr)rrrOs r)rr rZFunctionrrrrrrrrsPKPD4]%`- 4gdb/function/__pycache__/strfns.cpython-36.opt-1.pycnu[3 `{ @sxdZddlZddlZGdddejZGdddejZGdddejZGd d d ejZeeeedS) z#$_memeq, $_strlen, $_streq, $_regexNcs(eZdZdZfddZddZZS)_MemEqzx$_memeq - compare bytes of memory. Usage: $_memeq (A, B, LEN) Returns: True if LEN bytes at A and B compare equally.cstt|jddS)NZ_memeq)superr__init__)self) __class__ /strfns.pyrsz_MemEq.__init__cCs\|dkrtd|dkrdStjdj|d}|j}|j|}|j|}|j|jkS)Nrzlength must be non-negativeTchar) ValueErrorgdbZ lookup_typeZvectorZpointerZreinterpret_castZ dereference)rabZlengthZ byte_vectorZptr_byte_vectorZa_ptrZb_ptrrrrinvoke!s  z _MemEq.invoke)__name__ __module__ __qualname____doc__rr __classcell__rr)rrrs rcs(eZdZdZfddZddZZS)_StrLenz$_strlen - compute string length. Usage: $_strlen (A) Returns: Length of string A, assumed to be a string in the current language.cstt|jddS)NZ_strlen)rrr)r)rrrr5sz_StrLen.__init__cCs|j}t|S)N)stringlen)rr srrrr8sz_StrLen.invoke)rrrrrrrrr)rrr.s rcs(eZdZdZfddZddZZS)_StrEqz$_streq - check string equality. Usage: $_streq (A, B) Returns: True if A and B are identical strings in the current language. Example (amd64-linux): catch syscall open cond $bpnum $_streq((char*) $rdi, "foo")cstt|jddS)NZ_streq)rrr)r)rrrrHsz_StrEq.__init__cCs|j|jkS)N)r)rr rrrrrKsz _StrEq.invoke)rrrrrrrrr)rrr=s  rcs(eZdZdZfddZddZZS)_RegExz$_regex - check if a string matches a regular expression. Usage: $_regex (STRING, REGEX) Returns: True if string STRING (in the current language) matches the regular expression REGEX.cstt|jddS)NZ_regex)rrr)r)rrrrWsz_RegEx.__init__cCs$|j}tj|j}t|j|S)N)rrecompileboolmatch)rrZregexrrrrrrZsz _RegEx.invoke)rrrrrrrrr)rrrOs r)rr rZFunctionrrrrrrrrsPKPD4]H7gdb/function/__pycache__/as_string.cpython-36.opt-1.pycnu[3 `@s$ddlZGdddejZedS)Ncs(eZdZdZfddZddZZS) _AsStringzReturn the string representation of a value. Usage: $_as_string (VALUE) Arguments: VALUE: any value Returns: The string representation of the value.cstt|jddS)NZ _as_string)superr__init__)self) __class__ /as_string.pyrsz_AsString.__init__cCst|S)N)str)rvalrrrinvoke"sz_AsString.invoke)__name__ __module__ __qualname____doc__rr __classcell__rr)rrrs  r)ZgdbZFunctionrrrrrsPKPD4];gg1gdb/function/__pycache__/caller_is.cpython-36.pycnu[3 `@stddlZddlZGdddejZGdddejZGdddejZGdd d ejZeeeedS) Ncs*eZdZdZfddZdddZZS)CallerIsaCheck the calling function's name. Usage: $_caller_is (NAME [, NUMBER-OF-FRAMES]) Arguments: NAME: The name of the function to search for. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if the function's name at the specified frame is equal to NAME.cstt|jddS)NZ _caller_is)superr__init__)self) __class__ /caller_is.pyr%szCallerIs.__init__cCsR|dkrtdtj}x(|dkr@|j}|dkr6dS|d}qW|j|jkS)Nrznframes must be >= 0Fr ) ValueErrorgdbselected_frameoldernamestring)rrnframesframerrrinvoke(s  zCallerIs.invoke)r )__name__ __module__ __qualname____doc__rr __classcell__rr)rrrs rcs*eZdZdZfddZdddZZS) CallerMatchesaCompare the calling function's name with a regexp. Usage: $_caller_matches (REGEX [, NUMBER-OF-FRAMES]) Arguments: REGEX: The regular expression to compare the function's name with. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if the function's name at the specified frame matches REGEX.cstt|jddS)NZ_caller_matches)rrr)r)rrrrDszCallerMatches.__init__r cCsZ|dkrtdtj}x(|dkr@|j}|dkr6dS|d}qWtj|j|jdk S)Nrznframes must be >= 0Fr )r r r r rematchrr)rrrrrrrrGs  zCallerMatches.invoke)r )rrrrrrrrr)rrr3s rcs*eZdZdZfddZdddZZS) AnyCallerIsaCheck all calling function's names. Usage: $_any_caller_is (NAME [, NUMBER-OF-FRAMES]) Arguments: NAME: The name of the function to search for. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if any function's name is equal to NAME.cstt|jddS)NZ_any_caller_is)rrr)r)rrrrcszAnyCallerIs.__init__r cCsZ|dkrtdtj}x<|dkrT|j|jkr6dS|j}|dkrJdS|d}qWdS)Nrznframes must be >= 0TFr )r r r rrr )rrrrrrrrfs  zAnyCallerIs.invoke)r )rrrrrrrrr)rrrRs rcs*eZdZdZfddZdddZZS)AnyCallerMatchesaCompare all calling function's names with a regexp. Usage: $_any_caller_matches (REGEX [, NUMBER-OF-FRAMES]) Arguments: REGEX: The regular expression to compare the function's name with. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if any function's name matches REGEX.cstt|jddS)NZ_any_caller_matches)rrr)r)rrrrszAnyCallerMatches.__init__r cCsj|dkrtdtj}tj|j}x>|dkrd|j|jdk rFdS|j}|dkrZdS|d}q(WdS)Nrznframes must be >= 0TFr ) r r r rcompilerrrr )rrrrZname_rerrrrs  zAnyCallerMatches.invoke)r )rrrrrrrrr)rrrss r)r rZFunctionrrrrrrrrs!"PKPD4];gg7gdb/function/__pycache__/caller_is.cpython-36.opt-1.pycnu[3 `@stddlZddlZGdddejZGdddejZGdddejZGdd d ejZeeeedS) Ncs*eZdZdZfddZdddZZS)CallerIsaCheck the calling function's name. Usage: $_caller_is (NAME [, NUMBER-OF-FRAMES]) Arguments: NAME: The name of the function to search for. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if the function's name at the specified frame is equal to NAME.cstt|jddS)NZ _caller_is)superr__init__)self) __class__ /caller_is.pyr%szCallerIs.__init__cCsR|dkrtdtj}x(|dkr@|j}|dkr6dS|d}qW|j|jkS)Nrznframes must be >= 0Fr ) ValueErrorgdbselected_frameoldernamestring)rrnframesframerrrinvoke(s  zCallerIs.invoke)r )__name__ __module__ __qualname____doc__rr __classcell__rr)rrrs rcs*eZdZdZfddZdddZZS) CallerMatchesaCompare the calling function's name with a regexp. Usage: $_caller_matches (REGEX [, NUMBER-OF-FRAMES]) Arguments: REGEX: The regular expression to compare the function's name with. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if the function's name at the specified frame matches REGEX.cstt|jddS)NZ_caller_matches)rrr)r)rrrrDszCallerMatches.__init__r cCsZ|dkrtdtj}x(|dkr@|j}|dkr6dS|d}qWtj|j|jdk S)Nrznframes must be >= 0Fr )r r r r rematchrr)rrrrrrrrGs  zCallerMatches.invoke)r )rrrrrrrrr)rrr3s rcs*eZdZdZfddZdddZZS) AnyCallerIsaCheck all calling function's names. Usage: $_any_caller_is (NAME [, NUMBER-OF-FRAMES]) Arguments: NAME: The name of the function to search for. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if any function's name is equal to NAME.cstt|jddS)NZ_any_caller_is)rrr)r)rrrrcszAnyCallerIs.__init__r cCsZ|dkrtdtj}x<|dkrT|j|jkr6dS|j}|dkrJdS|d}qWdS)Nrznframes must be >= 0TFr )r r r rrr )rrrrrrrrfs  zAnyCallerIs.invoke)r )rrrrrrrrr)rrrRs rcs*eZdZdZfddZdddZZS)AnyCallerMatchesaCompare all calling function's names with a regexp. Usage: $_any_caller_matches (REGEX [, NUMBER-OF-FRAMES]) Arguments: REGEX: The regular expression to compare the function's name with. NUMBER-OF-FRAMES: How many stack frames to traverse back from the currently selected frame to compare with. If the value is greater than the depth of the stack from that point then the result is False. The default is 1. Returns: True if any function's name matches REGEX.cstt|jddS)NZ_any_caller_matches)rrr)r)rrrrszAnyCallerMatches.__init__r cCsj|dkrtdtj}tj|j}x>|dkrd|j|jdk rFdS|j}|dkrZdS|d}q(WdS)Nrznframes must be >= 0TFr ) r r r rcompilerrrr )rrrrZname_rerrrrs  zAnyCallerMatches.invoke)r )rrrrrrrrr)rrrss r)r rZFunctionrrrrrrrrs!"PKPD4]VB3__0gdb/function/__pycache__/__init__.cpython-36.pycnu[3 `@sdS)Nrrr /__init__.pysPKPD4]P|Ngdb/function/__init__.pynu[# Copyright (C) 2012-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . PKPD4])ت((gdb/FrameDecorator.pynu[# Copyright (C) 2013-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gdb # This small code snippet deals with problem of strings in Python 2.x # and Python 3.x. Python 2.x has str and unicode classes which are # sub-classes of basestring. In Python 3.x all strings are encoded # and basestring has been removed. try: basestring except NameError: basestring = str class FrameDecorator(object): """Basic implementation of a Frame Decorator""" """ This base frame decorator decorates a frame or another frame decorator, and provides convenience methods. If this object is wrapping a frame decorator, defer to that wrapped object's method if it has one. This allows for frame decorators that have sub-classed FrameDecorator object, but also wrap other frame decorators on the same frame to correctly execute. E.g If the result of frame filters running means we have one gdb.Frame wrapped by multiple frame decorators, all sub-classed from FrameDecorator, the resulting hierarchy will be: Decorator1 -- (wraps) Decorator2 -- (wraps) FrameDecorator -- (wraps) gdb.Frame In this case we have two frame decorators, both of which are sub-classed from FrameDecorator. If Decorator1 just overrides the 'function' method, then all of the other methods are carried out by the super-class FrameDecorator. But Decorator2 may have overriden other methods, so FrameDecorator will look at the 'base' parameter and defer to that class's methods. And so on, down the chain.""" # 'base' can refer to a gdb.Frame or another frame decorator. In # the latter case, the child class will have called the super # method and _base will be an object conforming to the Frame Filter # class. def __init__(self, base): self._base = base @staticmethod def _is_limited_frame(frame): """Internal utility to determine if the frame is special or limited.""" sal = frame.find_sal() if (not sal.symtab or not sal.symtab.filename or frame.type() == gdb.DUMMY_FRAME or frame.type() == gdb.SIGTRAMP_FRAME): return True return False def elided(self): """Return any elided frames that this class might be wrapping, or None.""" if hasattr(self._base, "elided"): return self._base.elided() return None def function(self): """ Return the name of the frame's function or an address of the function of the frame. First determine if this is a special frame. If not, try to determine filename from GDB's frame internal function API. Finally, if a name cannot be determined return the address. If this function returns an address, GDB will attempt to determine the function name from its internal minimal symbols store (for example, for inferiors without debug-info).""" # Both gdb.Frame, and FrameDecorator have a method called # "function", so determine which object this is. if not isinstance(self._base, gdb.Frame): if hasattr(self._base, "function"): # If it is not a gdb.Frame, and there is already a # "function" method, use that. return self._base.function() frame = self.inferior_frame() if frame.type() == gdb.DUMMY_FRAME: return "" elif frame.type() == gdb.SIGTRAMP_FRAME: return "" func = frame.function() # If we cannot determine the function name, return the # address. If GDB detects an integer value from this function # it will attempt to find the function name from minimal # symbols via its own internal functions. if func == None: pc = frame.pc() return pc return str(func) def address(self): """ Return the address of the frame's pc""" if hasattr(self._base, "address"): return self._base.address() frame = self.inferior_frame() return frame.pc() def filename(self): """ Return the filename associated with this frame, detecting and returning the appropriate library name is this is a shared library.""" if hasattr(self._base, "filename"): return self._base.filename() frame = self.inferior_frame() sal = frame.find_sal() if not sal.symtab or not sal.symtab.filename: pc = frame.pc() return gdb.solib_name(pc) else: return sal.symtab.filename def frame_args(self): """ Return an iterable of frame arguments for this frame, if any. The iterable object contains objects conforming with the Symbol/Value interface. If there are no frame arguments, or if this frame is deemed to be a special case, return None.""" if hasattr(self._base, "frame_args"): return self._base.frame_args() frame = self.inferior_frame() if self._is_limited_frame(frame): return None args = FrameVars(frame) return args.fetch_frame_args() def frame_locals(self): """ Return an iterable of local variables for this frame, if any. The iterable object contains objects conforming with the Symbol/Value interface. If there are no frame locals, or if this frame is deemed to be a special case, return None.""" if hasattr(self._base, "frame_locals"): return self._base.frame_locals() frame = self.inferior_frame() if self._is_limited_frame(frame): return None args = FrameVars(frame) return args.fetch_frame_locals() def line(self): """ Return line number information associated with the frame's pc. If symbol table/line information does not exist, or if this frame is deemed to be a special case, return None""" if hasattr(self._base, "line"): return self._base.line() frame = self.inferior_frame() if self._is_limited_frame(frame): return None sal = frame.find_sal() if (sal): return sal.line else: return None def inferior_frame(self): """ Return the gdb.Frame underpinning this frame decorator.""" # If 'base' is a frame decorator, we want to call its inferior # frame method. If '_base' is a gdb.Frame, just return that. if hasattr(self._base, "inferior_frame"): return self._base.inferior_frame() return self._base class SymValueWrapper(object): """A container class conforming to the Symbol/Value interface which holds frame locals or frame arguments.""" def __init__(self, symbol, value): self.sym = symbol self.val = value def value(self): """ Return the value associated with this symbol, or None""" return self.val def symbol(self): """ Return the symbol, or Python text, associated with this symbol, or None""" return self.sym class FrameVars(object): """Utility class to fetch and store frame local variables, or frame arguments.""" def __init__(self, frame): self.frame = frame self.symbol_class = { gdb.SYMBOL_LOC_STATIC: True, gdb.SYMBOL_LOC_REGISTER: True, gdb.SYMBOL_LOC_ARG: True, gdb.SYMBOL_LOC_REF_ARG: True, gdb.SYMBOL_LOC_LOCAL: True, gdb.SYMBOL_LOC_REGPARM_ADDR: True, gdb.SYMBOL_LOC_COMPUTED: True } def fetch_b(self, sym): """ Local utility method to determine if according to Symbol type whether it should be included in the iterator. Not all symbols are fetched, and only symbols that return True from this method should be fetched.""" # SYM may be a string instead of a symbol in the case of # synthetic local arguments or locals. If that is the case, # always fetch. if isinstance(sym, basestring): return True sym_type = sym.addr_class return self.symbol_class.get(sym_type, False) def fetch_frame_locals(self): """Public utility method to fetch frame local variables for the stored frame. Frame arguments are not fetched. If there are no frame local variables, return an empty list.""" lvars = [] try: block = self.frame.block() except RuntimeError: block = None while block != None: if block.is_global or block.is_static: break for sym in block: if sym.is_argument: continue; if self.fetch_b(sym): lvars.append(SymValueWrapper(sym, None)) block = block.superblock return lvars def fetch_frame_args(self): """Public utility method to fetch frame arguments for the stored frame. Frame arguments are the only type fetched. If there are no frame argument variables, return an empty list.""" args = [] try: block = self.frame.block() except RuntimeError: block = None while block != None: if block.function != None: break block = block.superblock if block != None: for sym in block: if not sym.is_argument: continue; args.append(SymValueWrapper(sym, None)) return args PKPD4]`;;4gdb/command/__pycache__/frame_filters.cpython-36.pycnu[3 `?@sdZddlZddlZddlZddlmZddlmZddlZddl Z Gdddej Z Gdddej Z Gd d d ej Z d d Zd dZddZddZGdddej ZGdddej ZGdddej ZGdddej Ze e e eeeedS)z,GDB commands for working with frame-filters.N) FrameIterator)FrameDecoratorcs eZdZdZfddZZS)SetFilterPrefixCmdz9Prefix command for 'set' frame-filter related operations.cstt|jdtjtjddS)Nzset frame-filterT)superr__init__gdbCOMMAND_OBSCURE COMPLETE_NONE)self) __class__/frame_filters.pyrs zSetFilterPrefixCmd.__init__)__name__ __module__ __qualname____doc__r __classcell__r r )r r rsrcs eZdZdZfddZZS)ShowFilterPrefixCmdz:Prefix command for 'show' frame-filter related operations.cstt|jdtjtjddS)Nzshow frame-filterT)rrrrrr )r )r r r r&s zShowFilterPrefixCmd.__init__)rrrrrrr r )r r r$srcs<eZdZdZfddZeddZddZdd ZZ S) InfoFrameFilterzDList all registered Python frame-filters. Usage: info frame-filterscstt|jdtjdS)Nzinfo frame-filter)rrrr COMMAND_DATA)r )r r r r/s zInfoFrameFilter.__init__cCs|rdSdSdS)z2Return "Yes" if filter is enabled, otherwise "No".ZYesZNoNr )stater r r enabled_string2szInfoFrameFilter.enabled_stringc Cst|jdddd}t|dkr&dSt|tdx|D]}|d}yLdjttjj|d}d j|j tjj |d}td |||fWq<t k rt j d} td |d t| Yq<sz,InfoFrameFilter.print_list..T)keyreverserz Priority Enabled Namez{:<8}rz{:<7}z %s %s %sz Error printing filter 'z': )sorteditemslenprintformatstrrrrrZ get_enabled Exceptionsysexc_info) r title frame_filtersZ blank_lineZsorted_frame_filters frame_filternamepriorityZenableder r r print_list:s*   "zInfoFrameFilter.print_listcCsr|jdtjd}tj}||jd|j|jd7}x*tjD]}||jd|j|jd7}q.rrN)rr1appendr0filterr")textwordZall_flagZfilter_locationsr4flistr r r _complete_frame_filter_lists    rQcCs*|j}|dkr|St|fdd|}|S)aWorker for frame filter name completion. Arguments: word: The most recent word of the command line. printer_dict: The frame filter dictionary to search for frame filter name completions. Returns: A list of suggested frame filter name completions from word analysis of the frame filter dictionary. This list can be empty when there are no suggestions for completion. rcSs |j|S)N)rI)rJrKr r r rsz-_complete_frame_filter_name..)keysrM)rOZ printer_dictZ printer_keysrPr r r _complete_frame_filter_names rScs0eZdZdZfddZddZddZZS)EnableFrameFilteraYGDB command to enable the specified frame-filter. Usage: enable frame-filter DICTIONARY [NAME] DICTIONARY is the name of the frame filter dictionary on which to operate. If dictionary is set to "all", perform operations on all dictionaries. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's frame filter dictionary. If either all, or the two named dictionaries are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame-filter to operate on.cstt|jdtjdS)Nzenable frame-filter)rrTrrr)r )r r r rs zEnableFrameFilter.__init__cCs@|jddkrt||dStjj|jdj}t||SdS)zTCompletion function for both frame filter dictionary, and frame filter name. rTN)countrQrrr>splitrstriprS)r rNrO printer_listr r r completes zEnableFrameFilter.completecCstd|}t|ddS)Nzenable frame-filterT)r=rG)r r2r3r@r r r r5s zEnableFrameFilter.invoke)rrrrrrZr5rr r )r r rTs   rTcs0eZdZdZfddZddZddZZS)DisableFrameFiltera[GDB command to disable the specified frame-filter. Usage: disable frame-filter DICTIONARY [NAME] DICTIONARY is the name of the frame filter dictionary on which to operate. If dictionary is set to "all", perform operations on all dictionaries. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's frame filter dictionary. If either all, or the two named dictionaries are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame-filter to operate on.cstt|jdtjdS)Nzdisable frame-filter)rr[rrr)r )r r r rs zDisableFrameFilter.__init__cCs@|jddkrt||dStjj|jdj}t||SdS)zTCompletion function for both frame filter dictionary, and frame filter name.rUrTN)rVrQrrr>rWrXrS)r rNrOrYr r r rZs zDisableFrameFilter.completecCstd|}t|ddS)Nzdisable frame-filterF)r=rG)r r2r3r@r r r r5 s zDisableFrameFilter.invoke)rrrrrrZr5rr r )r r r[s   r[cs@eZdZdZfddZddZddZdd Zd d ZZ S) SetFrameFilterPrioritya`GDB command to set the priority of the specified frame-filter. Usage: set frame-filter priority DICTIONARY NAME PRIORITY DICTIONARY is the name of the frame filter dictionary on which to operate. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's framefilter dictionary. If either of these two are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame filter to operate on. PRIORITY is the an integer to assign the new priority to the frame filter.cstt|jdtjdS)Nzset frame-filter priority)rr\rrr)r )r r r r!s zSetFrameFilterPriority.__init__cCs*tj|}t|}|dkr&tddS|S)aRInternal worker to parse a priority from a tuple. Arguments: arg: Tuple which contains the arguments from the command. Returns: A tuple containing the dictionary, name and priority from the arguments. Raises: gdb.GdbError: An error parsing the arguments. z8set frame-filter priority takes exactly three arguments.N)rr9r"r#)r r2r;r<r r r _parse_pri_arg&s  z%SetFrameFilterPriority._parse_pri_argc Csv|d}|d}t|d}tjj|}y ||}Wn.tk rbdt|d}tj|YnXtjj||dS)aInternal worker for setting priority of frame-filters, by parsing a tuple and calling _set_priority with the parsed tuple. Arguments: command_tuple: Tuple which contains the arguments from the command. rrr8zframe-filter 'z ' not found.N)intrrr>r?r%r:Z set_priority)r r@rBr+r-rCrErFr r r _set_filter_priority=s    z+SetFrameFilterPriority._set_filter_prioritycCs@|jddkrt||dStjj|jdj}t||SdS)zTCompletion function for both frame filter dictionary, and frame filter name.rUrFN)rVrQrrr>rWrXrS)r rNrOrYr r r rZXs zSetFrameFilterPriority.completecCs |j|}|dkr|j|dS)N)r^r`)r r2r3r@r r r r5as zSetFrameFilterPriority.invoke) rrrrrr^r`rZr5rr r )r r r\s   r\cs@eZdZdZfddZddZddZdd Zd d ZZ S) ShowFrameFilterPrioritya GDB command to show the priority of the specified frame-filter. Usage: show frame-filter priority DICTIONARY NAME DICTIONARY is the name of the frame filter dictionary on which to operate. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's framefilter dictionary. If either of these two are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame-filter to operate on.cstt|jdtjdS)Nzshow frame-filter priority)rrarrr)r )r r r rts z ShowFrameFilterPriority.__init__cCs*tj|}t|}|dkr&tddS|S)aKInternal worker to parse a dictionary and name from a tuple. Arguments: arg: Tuple which contains the arguments from the command. Returns: A tuple containing the dictionary, and frame filter name. Raises: gdb.GdbError: An error parsing the arguments. r8z7show frame-filter priority takes exactly two arguments.N)rr9r"r#)r r2r;r<r r r r^ys  z&ShowFrameFilterPriority._parse_pri_argc CsTtjj|}y ||}Wn.tk rFdt|d}tj|YnXtjj|S)aEWorker for retrieving the priority of frame_filters. Arguments: frame_filters: Name of frame filter dictionary. name: object to select printers. Returns: The priority of the frame filter. Raises: gdb.GdbError: A frame filter cannot be found. zframe-filter 'z ' not found.)rrr>r?r%r:r)r r*r,rCrErFr r r get_filter_prioritys  z+ShowFrameFilterPriority.get_filter_prioritycCs>|jddkrt||dStj|jdj}t||SdS)zTCompletion function for both frame filter dictionary, and frame filter name.rUrFN)rVrQframeZ _return_listrWrXrS)r rNrOrYr r r rZs z ShowFrameFilterPriority.completec Cs|j|}|dkrdS|d}|d}y|j||}Wn8tk rntjd}tdtdt|Yn"Xtd|d|dt|dS)Nrrz$Error printing filter priority for 'z':zPriority of filter 'z ' in list 'z' is: )r^rbr&r'r(r#r,r%)r r2r3r@Z filter_nameZ list_namer-r.r r r r5s  zShowFrameFilterPriority.invoke) rrrrrr^rbrZr5rr r )r r rafs    ra)rr'rcopyZgdb.FrameIteratorrZgdb.FrameDecoratorrZ gdb.frames itertoolsZCommandrrrr=rGrQrSrTr[r\rar r r r s2  9%V\PKPD4] GG3gdb/command/__pycache__/prompt.cpython-36.opt-1.pycnu[3 ` @s0dZddlZddlZGdddejZedS)z.GDB command for working with extended prompts.NcsNeZdZdZeejjZdZdZfddZ ddZ dd Z d d Z Z S) _ExtendedPromptzSet the extended prompt. Usage: set extended-prompt VALUE Substitutions are applied to VALUE to compute the real prompt. The currently defined substitutions are: zSet the extended prompt.zShow the extended prompt.cs(tt|jdtjtjd|_d|_dS)Nzextended-promptF)superr__init__gdbZCOMMAND_SUPPORTZPARAM_STRING_NOESCAPEvaluehook_set)self) __class__ /prompt.pyr(s  z_ExtendedPrompt.__init__cCs|jrd|jSdSdS)NzThe extended prompt is: zThe extended prompt is not set.)r)r Zpvaluer r r get_show_string/s z_ExtendedPrompt.get_show_stringcCs|jdkr|jt_d|_dS)NFTr)rbefore_prompt_hookrZ prompt_hook)r r r r get_set_string5s z_ExtendedPrompt.get_set_stringcCs|jrtjj|jSdSdS)N)rrpromptZsubstitute_prompt)r Zcurrentr r r r;sz"_ExtendedPrompt.before_prompt_hook)__name__ __module__ __qualname____doc__rrZ prompt_helpZset_docZshow_docrr rr __classcell__r r )r r rs  r)rrZ gdb.promptZ Parameterrr r r r s+PKPD4]|/0gdb/command/__pycache__/unwinders.cpython-36.pycnu[3 `y@sxddlZddlZddZddZGdddejZdd Zd d ZGd d d ejZGdddejZ ddZ e dS)Nc Cs4y tj|Stk r.td||fYnXdS)NzInvalid %s regexp: %s.)recompile SyntaxError)ZexpZidstringr /unwinders.pyvalidate_regexps rcCs^tj|}t|}|dkr"tdd}d}|dkrJ|d}|dkrJ|d}t|dt|dfS)a$Internal utility to parse unwinder command argv. Arguments: arg: The arguments to the command. The format is: [locus-regexp [name-regexp]] Returns: A 2-tuple of compiled regular expressions. Raises: SyntaxError: an error processing ARG zToo many arguments.rZlocusunwinder)gdbZstring_to_argvlenrr)argargvZargcZ locus_regexpZ name_regexprrrparse_unwinder_command_argss rcs0eZdZdZfddZddZddZZS) InfoUnwinderaGDB command to list unwinders. Usage: info unwinder [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the unwinder. If it is omitted, all registered unwinders from all loci are listed. A locus can be 'global', 'progspace' to list the unwinders from the current progspace, or a regular expression matching filenames of objfiles. NAME-REGEXP is a regular expression to filter unwinder names. If this omitted for a specified locus, then all registered unwinders in the locus are listed.cstt|jdtjdS)Nz info unwinder)superr__init__r COMMAND_STACK)self) __class__rrrGs zInfoUnwinder.__init__cCsJ|sdSt|x4|D],}|j|jrtd|j|jr8dndfqWdS)zLists the unwinders whose name matches regexp. Arguments: title: The line to print before the list. unwinders: The list of the unwinders. name_re: unwinder name filter. Nz %s%sr z [disabled])printmatchnameenabled)rtitle unwindersname_rer rrrlist_unwindersKs  zInfoUnwinder.list_unwinderscCst|\}}|jdr&|jdtj||jdrNtj}|jd|j|j|x2tjD]&}|j|jrX|jd|j|j|qXWdS)NglobalzGlobal: progspacez Progspace %s:z Objfile %s:)rrrr frame_unwinderscurrent_progspacefilenameobjfiles)rrfrom_ttylocus_rerZcpobjfilerrrinvoke[s        zInfoUnwinder.invoke)__name__ __module__ __qualname____doc__rrr( __classcell__rr)rrr8s  rcCs0d}x&|D]}|j|jr ||_|d7}q W|S)zEnable/disable unwinders whose names match given regex. Arguments: unwinders: The list of unwinders. name_re: Unwinder name filter. flag: Enable/disable. Returns: The number of unwinders affected. rr )rrr)rrflagtotalr rrrdo_enable_unwinder1js    r0cCst|\}}d}|jdr,|ttj||7}|jdrL|ttjj||7}x.tjD]"}|j|jrV|t|j||7}qVW|dkrtjt d||dkrdnd|rdnd fd S) zEnable/disable unwinder(s).rrr z%d unwinder%s %sr r srZdisabledN) rrr0r r!r"r$r#Zinvalidate_cached_framesr)rr.r&rr/r'rrrdo_enable_unwinder}s        r2cs(eZdZdZfddZddZZS)EnableUnwinderaGDB command to enable unwinders. Usage: enable unwinder [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression specifying the unwinders to enable. It can 'global', 'progspace', or the name of an objfile within that progspace. NAME_REGEXP is a regular expression to filter unwinder names. If this omitted for a specified locus, then all registered unwinders in the locus are affected.cstt|jdtjdS)Nzenable unwinder)rr3rr r)r)rrrrs zEnableUnwinder.__init__cCst|ddS)z&GDB calls this to perform the command.TN)r2)rrr%rrrr(szEnableUnwinder.invoke)r)r*r+r,rr(r-rr)rrr3s  r3cs(eZdZdZfddZddZZS)DisableUnwinderaGDB command to disable the specified unwinder. Usage: disable unwinder [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression specifying the unwinders to disable. It can 'global', 'progspace', or the name of an objfile within that progspace. NAME_REGEXP is a regular expression to filter unwinder names. If this omitted for a specified locus, then all registered unwinders in the locus are affected.cstt|jdtjdS)Nzdisable unwinder)rr4rr r)r)rrrrs zDisableUnwinder.__init__cCst|ddS)z&GDB calls this to perform the command.FN)r2)rrr%rrrr(szDisableUnwinder.invoke)r)r*r+r,rr(r-rr)rrr4s  r4cCstttdS)zInstalls the unwinder commands.N)rr3r4rrrrregister_unwinder_commandssr5) r rrrZCommandrr0r2r3r4r5rrrrs2PKPD4]w,eOO4gdb/command/__pycache__/explore.cpython-36.opt-1.pycnu[3 `Dh@sdZddlZddlZejddkr&eZGdddeZGdddeZGdd d eZ Gd d d eZ Gd d d eZ GdddeZ GdddeZ GdddeZGdddejZGdddejZGdddejZejeeedS)zEImplementation of the GDB 'explore' command using the GDB Python API.Nc@seZdZdZiZejejejej ej ej fZ e ddZe ddZe ddZe dd Ze d d Ze d d Ze ddZe ddZe ddZdS)Explorerz-Internal class which invokes other explorers.cCst|}d}|ddkr*||ddkr*nbd}x\||kr||}|dksd|krX|dksd |krh|d ksd |krz|d krznd }P|d7}q0W|rd|dS|SdS)NFr()_azAZ09T)len)exprZlengthZguardicr /explore.py guard_expr)s     zExplorer.guard_exprcCsH|jj}|tjkr2tj|}x&|j|||r.qWntdt|jdS)aMain function to explore an expression value. Arguments: expr: The expression string that is being explored. value: The gdb.Value value of the expression. is_child: Boolean value to indicate if the expression is a child. An expression is a child if it is derived from the main expression entered by the user. For example, if the user entered an expression which evaluates to a struct, then when exploring the fields of the struct, is_child is set to True internally. Returns: No return value. z*Explorer for type '%s' not yet available. N)typecodertype_code_to_explorer_map explore_exprprintstr)rvalueis_child type_codeexplorer_classrrrrAs  zExplorer.explore_exprcCsD|j}|tjkr0tj|}x$|j|||r,qWntdt|dS)aMain function to explore a data type. Arguments: name: The string representing the path to the data type being explored. datatype: The gdb.Type value of the data type being explored. is_child: Boolean value to indicate if the name is a child. A name is a child if it is derived from the main name entered by the user. For example, if the user entered the name of struct type, then when exploring the fields of the struct, is_child is set to True internally. Returns: No return value. z*Explorer for type '%s' not yet available. N)rrr explore_typerr)namedatatyperrrrrrr[s  zExplorer.explore_typecCsXtjttjttjttjttjttjttjt tj t tj t tj ttjttjttjti t_dS)zInitializes the Explorer environment. This function should be invoked before starting any exploration. If invoked before an exploration, it need not be invoked for subsequent explorations. N)gdbTYPE_CODE_CHARScalarExplorer TYPE_CODE_INTTYPE_CODE_BOOL TYPE_CODE_FLTTYPE_CODE_VOIDTYPE_CODE_ENUMTYPE_CODE_STRUCTCompoundExplorerTYPE_CODE_UNIONZ TYPE_CODE_PTRPointerExplorerZ TYPE_CODE_REFReferenceExplorerZTYPE_CODE_RVALUE_REFZTYPE_CODE_TYPEDEFTypedefExplorerZTYPE_CODE_ARRAY ArrayExplorerrrrrrrinit_envuszExplorer.init_envcCs |jtjkS)aChecks whether a type is a scalar type. A type is a scalar type of its type is gdb.TYPE_CODE_CHAR or gdb.TYPE_CODE_INT or gdb.TYPE_CODE_BOOL or gdb.TYPE_CODE_FLT or gdb.TYPE_CODE_VOID or gdb.TYPE_CODE_ENUM. Arguments: type: The type to be checked. Returns: 'True' if 'type' is a scalar type. 'False' otherwise. )rr_SCALAR_TYPE_LIST)rrrris_scalar_typeszExplorer.is_scalar_typecCs tddS)zA utility function which prints that the current exploration session is returning to the parent value. Useful when exploring values. z Returning to parent value... N)rrrrrreturn_to_parent_valueszExplorer.return_to_parent_valuecCs tddS)zA utility function which prompts the user to press the 'enter' key so that the exploration session can shift back to the parent value. Useful when exploring values. z( Press enter to return to parent value: N) raw_inputrrrrreturn_to_parent_value_promptsz&Explorer.return_to_parent_value_promptcCs tddS)zA utility function which prints that the current exploration session is returning to the enclosing type. Useful when exploring types. z Returning to enclosing type... N)rrrrrreturn_to_enclosing_typesz!Explorer.return_to_enclosing_typecCs tddS)zA utility function which prompts the user to press the 'enter' key so that the exploration session can shift back to the enclosing type. Useful when exploring types. z* Press enter to return to enclosing type: N)r5rrrrreturn_to_enclosing_type_promptsz(Explorer.return_to_enclosing_type_promptN)__name__ __module__ __qualname____doc__rr"r#r%r&r'r(r)r2 staticmethodrrrr1r3r4r6r7r8rrrrrs"        rc@s(eZdZdZeddZeddZdS)r$z-Internal class used to explore scalar values.cCs>td||jftd|t|f|r:tjtjdS)zFunction to explore scalar values. See Explorer.explore_expr and Explorer.is_scalar_type for more information. z$'%s' is a scalar value of type '%s'.z%s = %sF)rrrrr6r4)rrrrrrrszScalarExplorer.explore_exprcCsr|jtjkr4|r&td|t|fqZtd|n&|rNtd|t|fn td||rntjtjdS)zFunction to explore scalar types. See Explorer.explore_type and Explorer.is_scalar_type for more information. z!%s is of an enumerated type '%s'.z'%s' is an enumerated type.z%s is of a scalar type '%s'.z'%s' is a scalar type.F)rr"r)rrrr8r7)r r!rrrrrs  zScalarExplorer.explore_typeN)r9r:r;r<r=rrrrrrr$s r$c@s(eZdZdZeddZeddZdS)r-z.Internal class used to explore pointer values.cCsHtd|t|jjftd}|dkrd}y|j}t|Wn.tjk rptd||rltj dSXtj dtj |||dStd}|dkr6xd }yt td |}Wnt k rPYnXd tj ||f}||}y t|Wn&tjk rtd |wYnXtj ||d qWdS|rDtjdS)zdFunction to explore pointer values. See Explorer.explore_expr for more information. z)'%s' is a pointer to a value of type '%s'zTz%s .. (Value of type '%s')z base classrKz*rz"Enter the field number of choice: )rrrJr"r*r+rLrrrr6rIrr is_base_classcastr,r3appendrHr5rr4)rrrr!rrJ type_deschas_explorable_fieldschoice_to_compound_field_mapcurrent_choicerGrKZfield_full_nameZ field_valueZ literal_value field_descchoicerrrrsr        zCompoundExplorer.explore_exprcCs|j}d}|tjkrd}nd}|j}tj|dkrl|rXtd||t|ftj ntd||fdS|rtd||t|fntd ||fd}d}i}g} xf|D]^} | j rq| j rd } nd } d || t| j f} | j | j| f| j| j | f|t|<|d }qWtj| tdt|dkrtd} | |kr|rhd|| d|| d|f}nd|| d|| d|f}tj||| d ddS|rtjn|rtj dS)zrFunction to explore struct/class and union types. See Explorer.explore_type for more information. rOz struct/classrMrz'%s is a %s of type '%s' with no fields.z'%s' is a %s with no fields.Fz3%s is a %s of type '%s' with the following fields: z('%s' is a %s with the following fields: z base classrKz*rz"Enter the field number of choice: z %s '%s' of %srz%s '%s' of '%s'T)rr"r*rJr+rLrrrr8rIrPrrRr rHrr5rr7)r r!rrrSrJrTrVrUrGrKrWZrhsrXnew_namerrrrsn             zCompoundExplorer.explore_typeN) r9r:r;r<r=rHrLrrrrrrr+os  Qr+c@s(eZdZdZeddZeddZdS)r/z>Internal class used to explore values whose type is a typedef.cCs>|jj}td|t|jt|ftj||j||dS)zdFunction to explore typedef values. See Explorer.explore_expr for more information. zAThe value of '%s' is of type '%s' which is a typedef of type '%s'F)rstrip_typedefsrrrrrQ)rrr actual_typerrrr)s  zTypedefExplorer.explore_exprcCsH|j}|r"td|t|fntd|t|ftj|||dS)zcFunction to explore typedef types. See Explorer.explore_type for more information. z)The type of %s is a typedef of type '%s'.z(The type '%s' is a typedef of type '%s'.F)rZrrrr)r r!rr[rrrr6szTypedefExplorer.explore_typeN)r9r:r;r<r=rrrrrrr/&s r/c@s4eZdZdZeddZeddZeddZdS) ExploreUtilszEInternal class which provides utilities for the main command classes.cCs&t|dkrtjd|dSdSdS)aUtility to check if adequate number of arguments are passed to an explore command. Arguments: name: The name of the explore command. arg_str: The argument string passed to the explore command. Returns: True if adequate arguments are passed, false otherwise. Raises: gdb.GdbError if adequate arguments are not passed. rz!ERROR: '%s' requires an argument.FTN)rr"GdbError)r arg_strrrr check_argsJs  zExploreUtils.check_argscCsNytjd|jjStk rHy tj|Stk rBdSXYnXdS)a<A utility function to deduce the gdb.Type value from a string representing the type. Arguments: type_str: The type string from which the gdb.Type value should be deduced. Returns: The deduced gdb.Type value if possible, None otherwise. z(%s *)0N)r"parse_and_evalrr? RuntimeErrorZ lookup_type)Ztype_strrrrget_type_from_str`s  zExploreUtils.get_type_from_strc Cs$y tj|Stk rdSXdS)aCA utility function to deduce the gdb.Value value from a string representing the value. Arguments: value_str: The value string from which the gdb.Value value should be deduced. Returns: The deduced gdb.Value value if possible, None otherwise. N)r"r`ra)Z value_strrrrget_value_from_strws  zExploreUtils.get_value_from_strN)r9r:r;r<r=r_rbrcrrrrr\Gs  r\cs(eZdZdZfddZddZZS)ExploreCommandzExplore a value or a type valid in the current context. Usage: explore ARG - ARG is either a valid expression or a type name. - At any stage of exploration, hit the return key (instead of a choice, if any) to return to the enclosing type or value.cstt|jdtjdddS)NexploreT)r command_classprefix)superrd__init__r" COMMAND_DATA)self) __class__rrris zExploreCommand.__init__cCsntjd|dkrdStj|}|dk r8tj||ddStj|}|dk r\tj||ddStjd|dS)NreFzG'%s' neither evaluates to a value nor is a type in the current context.) r\r_rcrrrbrr"r])rkr^from_ttyrr!rrrinvokes  zExploreCommand.invoke)r9r:r;r<rirn __classcell__rr)rlrrds rdcs(eZdZdZfddZddZZS)ExploreValueCommandzExplore value of an expression valid in the current context. Usage: explore value ARG - ARG is a valid expression. - At any stage of exploration, hit the return key (instead of a choice, if any) to return to the enclosing value.cstt|jdtjddS)Nz explore value)r rf)rhrprir"rj)rk)rlrrris zExploreValueCommand.__init__cCsJtjd|dkrdStj|}|dkr8tjd|dStj||ddS)Nz explore valueFz: '%s' does not evaluate to a value in the current context.)r\r_rcr"r]rr)rkr^rmrrrrrns zExploreValueCommand.invoke)r9r:r;r<rirnrorr)rlrrps rpcs(eZdZdZfddZddZZS)ExploreTypeCommandzExplore a type or the type of an expression. Usage: explore type ARG - ARG is a valid expression or a type name. - At any stage of exploration, hit the return key (instead of a choice, if any) to return to the enclosing type.cstt|jdtjddS)Nz explore type)r rf)rhrqrir"rj)rk)rlrrris zExploreTypeCommand.__init__cCstjd|dkrdStj|}|dk r8tj||ddStj|}|dk rztd|t|jftjt|j|jddSt j d|dS)Nz explore typeFz'%s' is of type '%s'.z3'%s' is not a type or value in the current context.) r\r_rbrrrcrrrr"r])rkr^rmr!rrrrrns  zExploreTypeCommand.invoke)r9r:r;r<rirnrorr)rlrrqs rq)r<r"sys version_infoinputr5objectrr$r-r.r0r+r/r\ZCommandrdrprqr1rrrrs*%-B-8!B% PKPD4]GQv##/gdb/command/__pycache__/xmethods.cpython-36.pycnu[3 `0'@sddlZddlZddZddZddZdd Zd d Zd d ZddZGdddej Z Gdddej Z Gdddej Z ddZ e dS)Nc Cs0y tj|Stk r*td||YnXdS)NzInvalid %s regexp: %s)recompile SyntaxError)Z part_nameZregexpr /xmethods.pyvalidate_xm_regexps rcCstj|}t|}|dkr"tdd}d}d}|dkr>|d}|dkrr|djdd}|d}t|dkrr|d}|rtd|}nd}td |td ||fS) a?Parses the arguments passed to a xmethod command. Arguments: arg: The argument string passed to a xmethod command. Returns: A 3-tuple: (, , ) zToo many arguments to command.Nr;z xmethod namelocusz matcher name)gdbZstring_to_argvlenrsplitr)argargvZargcZ locus_regexpZmatcher_name_regexpZxm_name_regexppartsname_rerrrparse_xm_command_argss(   rcs8d}|gi}|jdr4||jfddtjD|S)aReturns a dict of matching globally registered xmethods. Arguments: locus_re: Even though only globally registered xmethods are looked up, they will be looked up only if 'global' matches LOCUS_RE. matcher_re: The regular expression matching the names of xmethods. Returns: A dict of matching globally registered xmethod matchers. The only key in the dict will be 'global'. globalcsg|]}j|jr|qSr)matchname).0m) matcher_rerr Qsz.get_global_method_matchers..)rextendr xmethods)locus_rer locus_strxm_dictr)rrget_global_method_matchers@s  r!csli}xb|D]Z}t|tjr,|jds&q d}n|j|js:q d}d||jf}fdd|jD||<q W|S)aReturns a dict of matching registered xmethods in the LOCI. Arguments: loci: The list of loci to lookup matching xmethods in. locus_re: If a locus is an objfile, then xmethod matchers will be looked up in it only if its filename matches the regular expression LOCUS_RE. If a locus is the current progspace, then xmethod matchers will be looked up in it only if the string "progspace" matches LOCUS_RE. matcher_re: The regular expression to match the xmethod matcher names. Returns: A dict of matching xmethod matchers. The keys of the dict are the filenames of the loci the xmethod matchers belong to. Z progspaceZobjfilez%s %scsg|]}j|jr|qSr)rr)rr)rrrrrsz/get_method_matchers_in_loci..) isinstancer Z Progspacerfilenamer)Zlocirrr r Z locus_typerr)rrget_method_matchers_in_lociUs    r$cCsdd}|sdSx|D]}||s$qtd|xh||D]\}td|j||f|js\q:x8|jD].}|dks||j|jrdtd|j||fqdWq:WqWdS)zPrint a dictionary of xmethods.cSs|js dSdSdS)Nz [disabled]r )enabled)rrrrget_status_stringxsz(print_xm_info..get_status_stringNzXmethods in %s:z %s%sz %s%s)printrmethodsr)r rr&rmatcherrrrr print_xm_infovs   r*cCs^xX|jD]L\}}xB|D]:}|s(||_q|js0qx |jD]}|j|jr8||_q8WqWq WdS)z>Set the status (enabled/disabled) of a dictionary of xmethods.N)itemsr%r(rr)r rstatusrZmatchersr)rrrrset_xm_status1s   r-cCsVt|\}}}tt||||tttjg||||tttj||||dS)zSet the status (enabled/disabled) of xmethods matching ARG. This is a helper function for enable/disable commands. ARG is the argument string passed to the commands. N)rr-r!r$r current_progspaceobjfiles)rr,rrrrrr set_xm_statuss r0cs(eZdZdZfddZddZZS) InfoXMethoda9GDB command to list registered xmethod matchers. Usage: info xmethod [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the xmethod matchers. If it is omitted, all registered xmethod matchers from all loci are listed. A locus could be 'global', a regular expression matching the current program space's filename, or a regular expression matching filenames of objfiles. Locus could be 'progspace' to specify that only xmethods from the current progspace should be listed. NAME-REGEXP is a regular expression matching the names of xmethod matchers. If this omitted for a specified locus, then all registered xmethods in the locus are listed. To list only a certain xmethods managed by a single matcher, the name regexp can be specified as matcher-name-regexp;xmethod-name-regexp.cstt|jdtjdS)Nz info xmethod)superr1__init__r COMMAND_DATA)self) __class__rrr3s zInfoXMethod.__init__cCsPt|\}}}tt|||tttjg|||tttj|||dS)N)rr*r!r$r r.r/)r5rfrom_ttyrrrrrrinvokes zInfoXMethod.invoke)__name__ __module__ __qualname____doc__r3r8 __classcell__rr)r6rr1s r1cs(eZdZdZfddZddZZS) EnableXMethoda^GDB command to enable a specified (group of) xmethod(s). Usage: enable xmethod [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the xmethod matchers. If it is omitted, all registered xmethods matchers from all loci are enabled. A locus could be 'global', a regular expression matching the current program space's filename, or a regular expression matching filenames of objfiles. Locus could be 'progspace' to specify that only xmethods from the current progspace should be enabled. NAME-REGEXP is a regular expression matching the names of xmethods within a given locus. If this omitted for a specified locus, then all registered xmethod matchers in the locus are enabled. To enable only a certain xmethods managed by a single matcher, the name regexp can be specified as matcher-name-regexp;xmethod-name-regexp.cstt|jdtjdS)Nzenable xmethod)r2r>r3r r4)r5)r6rrr3s zEnableXMethod.__init__cCst|ddS)NT)r0)r5rr7rrrr8szEnableXMethod.invoke)r9r:r;r<r3r8r=rr)r6rr>s r>cs(eZdZdZfddZddZZS)DisableXMethodaYGDB command to disable a specified (group of) xmethod(s). Usage: disable xmethod [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the xmethod matchers. If it is omitted, all registered xmethod matchers from all loci are disabled. A locus could be 'global', a regular expression matching the current program space's filename, or a regular expression filenames of objfiles. Locus could be 'progspace' to specify that only xmethods from the current progspace should be disabled. NAME-REGEXP is a regular expression matching the names of xmethods within a given locus. If this omitted for a specified locus, then all registered xmethod matchers in the locus are disabled. To disable only a certain xmethods managed by a single matcher, the name regexp can be specified as matcher-name-regexp;xmethod-name-regexp.cstt|jdtjdS)Nzdisable xmethod)r2r?r3r r4)r5)r6rrr3s zDisableXMethod.__init__cCst|ddS)NF)r0)r5rr7rrrr8szDisableXMethod.invoke)r9r:r;r<r3r8r=rr)r6rr?s r?cCstttdS)zInstalls the xmethod commands.N)r1r>r?rrrrregister_xmethod_commandssr@)r rrrr!r$r*r-r0ZCommandr1r>r?r@rrrrs"!#PKPD4]sPKPD4]/4ۥ4gdb/command/__pycache__/type_printers.cpython-36.pycnu[3 `)@sjddlZddlZGdddejZGdddejZGdddeZGdd d eZeeedS) Ncs0eZdZdZfddZddZddZZS)InfoTypePrinterzLGDB command to list all registered type-printers. Usage: info type-printerscstt|jdtjdS)Nzinfo type-printers)superr__init__gdb COMMAND_DATA)self) __class__/type_printers.pyrs zInfoTypePrinter.__init__cCsJttj|ddd}x.|D]&}|jr,d}nd}td|j|fqWdS)zPrint a list of type printers.cSs|jS)N)name)xr r r $sz4InfoTypePrinter.list_type_printers..)keyz [disabled]z %s%sN)sortedcopyenabledprintr )r type_printersZsorted_type_printersZprinterrr r r list_type_printerss   z"InfoTypePrinter.list_type_printerscCsd}x8tjD],}|jrtd||jf|j|jd}qWtjjrhtd||jtjjd}tjrtd||jtjdS)z&GDB calls this to perform the command.rz%sType printers for %s: z"%sType printers for program space:z%sGlobal type printers:N)robjfilesrrfilenamercurrent_progspace)rargfrom_ttysepobjfiler r r invoke,s    zInfoTypePrinter.invoke)__name__ __module__ __qualname____doc__rrr __classcell__r r )rr rs  rcs<eZdZfddZddZddZddZd d ZZS) _EnableOrDisableCommandcstt|j|tj||_dS)N)rr$rrrsetting)rr%r )rr r r=sz _EnableOrDisableCommand.__init__cCs,d}x"|D]}||jkr |j|_d}q W|S)NFT)r r%r)rr printersresultpr r r set_someAs   z _EnableOrDisableCommand.set_somecCsvxp|jD]d}d}x"tjD]}|j||jrd}qW|j|tjjrLd}|j|tjr^d}|s td|q WdS)z&GDB calls this to perform the command.FTzNo type printer named '%s'N)splitrrr)rrr)rrrr okrr r r rIsz_EnableOrDisableCommand.invokecCs*x$|D]}|jj|r|j|jqWdS)N)r startswithappend)rr'wordr&r(r r r add_someWs  z _EnableOrDisableCommand.add_somecCsNg}x tjD]}|j|||jqW|j||tjj|j||tj|S)N)rrr/rr)rtextr.r'rr r r complete\s z _EnableOrDisableCommand.complete) rr r!rr)rr/r1r#r r )rr r$<s  r$cs eZdZdZfddZZS)EnableTypePrinterzyGDB command to enable the specified type printer. Usage: enable type-printer NAME NAME is the name of the type-printer.cstt|jdddS)NTzenable type-printer)rr2r)r)rr r rkszEnableTypePrinter.__init__)rr r!r"rr#r r )rr r2dsr2cs eZdZdZfddZZS)DisableTypePrinterz{GDB command to disable the specified type-printer. Usage: disable type-printer NAME NAME is the name of the type-printer.cstt|jdddS)NFzdisable type-printer)rr3r)r)rr r ruszDisableTypePrinter.__init__)rr r!r"rr#r r )rr r3nsr3)rrZCommandrr$r2r3r r r r s&(  PKPD4]y2E<$<$<gdb/command/__pycache__/pretty_printers.cpython-36.opt-1.pycnu[3 `%8@sdZddlZddlZddlZddZddZGdddejZd d Zd d Z dddZ ddZ ddZ ddZ GdddejZGdddejZddZedS)z.GDB commands for working with pretty-printers.Nc Cstj|}t|}d}d}d}|dkr.td|dkr>|d}|dkrr|djdd}|d}t|dkrr|d}ytj|}Wn tk rtd |YnXytj|}Wn tk rtd |YnX|dk rytj|} Wn"tk r td |YnXnd} ||| fS) aInternal utility to parse a pretty-printer command argv. Arguments: arg: The arguments to the command. The format is: [object-regexp [name-regexp]]. Individual printers in a collection are named as printer-name;subprinter-name. Returns: The result is a 3-tuple of compiled regular expressions, except that the resulting compiled subprinter regexp is None if not provided. Raises: SyntaxError: an error processing ARG Nztoo many argumentsr;zinvalid object regexp: %szinvalid name regexp: %szinvalid subname regexp: %s)gdbZstring_to_argvlen SyntaxErrorsplitrecompile) argargvZargcZ object_regexpZ name_regexpZsubname_regexpZ name_subname object_rename_re subname_rer/pretty_printers.pyparse_printer_regexpss:   rcCst|dr|jSdSdS)z>Internal utility to see if printer (or subprinter) is enabled.enabledTN)hasattrr)printerrrrprinter_enabled_pLs rcsPeZdZdZfddZeddZeddZdd Zd d Z d d Z Z S)InfoPrettyPrinteraGDB command to list all registered pretty-printers. Usage: info pretty-printer [OBJECT-REGEXP [NAME-REGEXP]] OBJECT-REGEXP is a regular expression matching the objects to list. Objects are "global", the program space's file, and the objfiles within that program space. NAME-REGEXP matches the name of the pretty-printer. Individual printers in a collection are named as printer-name;subprinter-name.cstt|jdtjdS)Nzinfo pretty-printer)superr__init__r COMMAND_DATA)self) __class__rrras zInfoPrettyPrinter.__init__cCst|r dSdSdS)z9Return "" if PRINTER is enabled, otherwise " [disabled]".rz [disabled]N)r)rrrrenabled_stringesz InfoPrettyPrinter.enabled_stringcCs$t|dr|jSt|dr |jSdS)zReturn the printer's name.name__name__unknown)rr r!)rrrr printer_namems   zInfoPrettyPrinter.printer_namec Csttj||jd}x|D]}|j|}|j|}|j|rtd||ft|dr|jdk rttj|j|jd}x6|D].} | s|j| jr|td| j|j| fq|WqWdS)z Print a list of pretty-printers.)keyz %s%s subprintersNz %s%s) sortedcopyr#rmatchprintrr%r ) rpretty_printersrrZsorted_pretty_printersrr rZsorted_subprinters subprinterrrrlist_pretty_printerszs"            z&InfoPrettyPrinter.list_pretty_printerscCs(|r$|j|r$t||j|||dS)z$Subroutine of invoke to simplify it.N)r(r)r,)rtitleZ printer_listZobj_name_to_matchrrrrrrinvoke1szInfoPrettyPrinter.invoke1cCs|t|\}}}|jdtjd|||tj}|jd|j|jd|||x.tjD]"}|jd|j|j|j|||qRWdS)z&GDB calls this to perform the command.zglobal pretty-printers:globalzprogspace %s pretty-printers: progspacezobjfile %s pretty-printers:N)rr.rr*current_progspacefilenameobjfiles)rr from_ttyrrrcpobjfilerrrinvokes     zInfoPrettyPrinter.invoke) r! __module__ __qualname____doc__r staticmethodrr#r,r.r7 __classcell__rr)rrrTs    rcCsd}d}xp|D]h}t|dr^|jdk r^t|rNx|jD]}t|r6|d7}q6W|t|j7}qt|rn|d7}|d7}qW||fS)z9Return a 2-tuple of number of enabled and total printers.rr%Nr)rr%rr)r*rtotalrr+rrrcount_enabled_printerss      r>cCsd}d}ttj\}}||7}||7}ttjj\}}||7}||7}x.tjD]"}t|j\}}||7}||7}qRW||fS)zkReturn a 2-tuble of the enabled state and total number of all printers. This includes subprinters. r)r>rr*r1r3) enabled_count total_countZ t_enabledZt_totalr6rrrcount_all_enabled_printerss rAscCs|dkrd||fS|SdS)z!Return TEXT pluralized if N != 1.rz%s%sNr)textnsuffixrrr pluralizes rFcCst\}}td||fdS)zZPrint the number of printers enabled/disabled. We count subprinters individually. z%d of %d printers enabledN)rAr))r?r@rrr#show_pretty_printer_enabled_summarys rGcCsd}x|D]}t|dr$|j|js:t|dr |j|jr t|dr|jdk r|st||kr~x|jD]}t|rf|d7}qfW||_qx\|jD]2}|j|jrt|rt||kr|d7}||_qWq |s t||kr|d7}||_q W|S)aWorker for enabling/disabling pretty-printers. Arguments: pretty_printers: list of pretty-printers name_re: regular-expression object to select printers subname_re: regular expression object to select subprinters or None if all are affected flag: True for Enable, False for Disable Returns: The number of printers affected. This is just for informational purposes for the user. rr r!r%Nr)rr(r r!r%rr)r*rrflagr=rr+rrrdo_enable_pretty_printer_1s.            rIc Cst|\}}}d}|jdr0|ttj|||7}tj}|jdrV|t|j|||7}x0tjD]$}|j|jr`|t|j|||7}q`W|rd}nd}td|t d||ft dS) z7Internal worker for enabling/disabling pretty-printers.rr/r0rZdisabledz%d %s %srN) rr(rIrr*r1r3r2r)rFrG) r rHrrrr=r5r6staterrrdo_enable_pretty_printers$     rKcs(eZdZdZfddZddZZS)EnablePrettyPrinteraGDB command to enable the specified pretty-printer. Usage: enable pretty-printer [OBJECT-REGEXP [NAME-REGEXP]] OBJECT-REGEXP is a regular expression matching the objects to examine. Objects are "global", the program space's file, and the objfiles within that program space. NAME-REGEXP matches the name of the pretty-printer. Individual printers in a collection are named as printer-name;subprinter-name.cstt|jdtjdS)Nzenable pretty-printer)rrLrrr)r)rrrrHs zEnablePrettyPrinter.__init__cCst|ddS)z&GDB calls this to perform the command.TN)rK)rr r4rrrr7LszEnablePrettyPrinter.invoke)r!r8r9r:rr7r<rr)rrrL;s  rLcs(eZdZdZfddZddZZS)DisablePrettyPrinteraGDB command to disable the specified pretty-printer. Usage: disable pretty-printer [OBJECT-REGEXP [NAME-REGEXP]] OBJECT-REGEXP is a regular expression matching the objects to examine. Objects are "global", the program space's file, and the objfiles within that program space. NAME-REGEXP matches the name of the pretty-printer. Individual printers in a collection are named as printer-name;subprinter-name.cstt|jdtjdS)Nzdisable pretty-printer)rrMrrr)r)rrrr^s zDisablePrettyPrinter.__init__cCst|ddS)z&GDB calls this to perform the command.FN)rK)rr r4rrrr7bszDisablePrettyPrinter.invoke)r!r8r9r:rr7r<rr)rrrMQs  rMcCstttdS)zDCall from a top level script to install the pretty-printer commands.N)rrLrMrrrr register_pretty_printer_commandsgsrN)rB)r:r'rr rrZCommandrr>rArFrGrIrKrLrMrNrrrrs 4R :%PKPD4]w,eOO.gdb/command/__pycache__/explore.cpython-36.pycnu[3 `Dh@sdZddlZddlZejddkr&eZGdddeZGdddeZGdd d eZ Gd d d eZ Gd d d eZ GdddeZ GdddeZ GdddeZGdddejZGdddejZGdddejZejeeedS)zEImplementation of the GDB 'explore' command using the GDB Python API.Nc@seZdZdZiZejejejej ej ej fZ e ddZe ddZe ddZe dd Ze d d Ze d d Ze ddZe ddZe ddZdS)Explorerz-Internal class which invokes other explorers.cCst|}d}|ddkr*||ddkr*nbd}x\||kr||}|dksd|krX|dksd |krh|d ksd |krz|d krznd }P|d7}q0W|rd|dS|SdS)NFr()_azAZ09T)len)exprZlengthZguardicr /explore.py guard_expr)s     zExplorer.guard_exprcCsH|jj}|tjkr2tj|}x&|j|||r.qWntdt|jdS)aMain function to explore an expression value. Arguments: expr: The expression string that is being explored. value: The gdb.Value value of the expression. is_child: Boolean value to indicate if the expression is a child. An expression is a child if it is derived from the main expression entered by the user. For example, if the user entered an expression which evaluates to a struct, then when exploring the fields of the struct, is_child is set to True internally. Returns: No return value. z*Explorer for type '%s' not yet available. N)typecodertype_code_to_explorer_map explore_exprprintstr)rvalueis_child type_codeexplorer_classrrrrAs  zExplorer.explore_exprcCsD|j}|tjkr0tj|}x$|j|||r,qWntdt|dS)aMain function to explore a data type. Arguments: name: The string representing the path to the data type being explored. datatype: The gdb.Type value of the data type being explored. is_child: Boolean value to indicate if the name is a child. A name is a child if it is derived from the main name entered by the user. For example, if the user entered the name of struct type, then when exploring the fields of the struct, is_child is set to True internally. Returns: No return value. z*Explorer for type '%s' not yet available. N)rrr explore_typerr)namedatatyperrrrrrr[s  zExplorer.explore_typecCsXtjttjttjttjttjttjttjt tj t tj t tj ttjttjttjti t_dS)zInitializes the Explorer environment. This function should be invoked before starting any exploration. If invoked before an exploration, it need not be invoked for subsequent explorations. N)gdbTYPE_CODE_CHARScalarExplorer TYPE_CODE_INTTYPE_CODE_BOOL TYPE_CODE_FLTTYPE_CODE_VOIDTYPE_CODE_ENUMTYPE_CODE_STRUCTCompoundExplorerTYPE_CODE_UNIONZ TYPE_CODE_PTRPointerExplorerZ TYPE_CODE_REFReferenceExplorerZTYPE_CODE_RVALUE_REFZTYPE_CODE_TYPEDEFTypedefExplorerZTYPE_CODE_ARRAY ArrayExplorerrrrrrrinit_envuszExplorer.init_envcCs |jtjkS)aChecks whether a type is a scalar type. A type is a scalar type of its type is gdb.TYPE_CODE_CHAR or gdb.TYPE_CODE_INT or gdb.TYPE_CODE_BOOL or gdb.TYPE_CODE_FLT or gdb.TYPE_CODE_VOID or gdb.TYPE_CODE_ENUM. Arguments: type: The type to be checked. Returns: 'True' if 'type' is a scalar type. 'False' otherwise. )rr_SCALAR_TYPE_LIST)rrrris_scalar_typeszExplorer.is_scalar_typecCs tddS)zA utility function which prints that the current exploration session is returning to the parent value. Useful when exploring values. z Returning to parent value... N)rrrrrreturn_to_parent_valueszExplorer.return_to_parent_valuecCs tddS)zA utility function which prompts the user to press the 'enter' key so that the exploration session can shift back to the parent value. Useful when exploring values. z( Press enter to return to parent value: N) raw_inputrrrrreturn_to_parent_value_promptsz&Explorer.return_to_parent_value_promptcCs tddS)zA utility function which prints that the current exploration session is returning to the enclosing type. Useful when exploring types. z Returning to enclosing type... N)rrrrrreturn_to_enclosing_typesz!Explorer.return_to_enclosing_typecCs tddS)zA utility function which prompts the user to press the 'enter' key so that the exploration session can shift back to the enclosing type. Useful when exploring types. z* Press enter to return to enclosing type: N)r5rrrrreturn_to_enclosing_type_promptsz(Explorer.return_to_enclosing_type_promptN)__name__ __module__ __qualname____doc__rr"r#r%r&r'r(r)r2 staticmethodrrrr1r3r4r6r7r8rrrrrs"        rc@s(eZdZdZeddZeddZdS)r$z-Internal class used to explore scalar values.cCs>td||jftd|t|f|r:tjtjdS)zFunction to explore scalar values. See Explorer.explore_expr and Explorer.is_scalar_type for more information. z$'%s' is a scalar value of type '%s'.z%s = %sF)rrrrr6r4)rrrrrrrszScalarExplorer.explore_exprcCsr|jtjkr4|r&td|t|fqZtd|n&|rNtd|t|fn td||rntjtjdS)zFunction to explore scalar types. See Explorer.explore_type and Explorer.is_scalar_type for more information. z!%s is of an enumerated type '%s'.z'%s' is an enumerated type.z%s is of a scalar type '%s'.z'%s' is a scalar type.F)rr"r)rrrr8r7)r r!rrrrrs  zScalarExplorer.explore_typeN)r9r:r;r<r=rrrrrrr$s r$c@s(eZdZdZeddZeddZdS)r-z.Internal class used to explore pointer values.cCsHtd|t|jjftd}|dkrd}y|j}t|Wn.tjk rptd||rltj dSXtj dtj |||dStd}|dkr6xd }yt td |}Wnt k rPYnXd tj ||f}||}y t|Wn&tjk rtd |wYnXtj ||d qWdS|rDtjdS)zdFunction to explore pointer values. See Explorer.explore_expr for more information. z)'%s' is a pointer to a value of type '%s'zTz%s .. (Value of type '%s')z base classrKz*rz"Enter the field number of choice: )rrrJr"r*r+rLrrrr6rIrr is_base_classcastr,r3appendrHr5rr4)rrrr!rrJ type_deschas_explorable_fieldschoice_to_compound_field_mapcurrent_choicerGrKZfield_full_nameZ field_valueZ literal_value field_descchoicerrrrsr        zCompoundExplorer.explore_exprcCs|j}d}|tjkrd}nd}|j}tj|dkrl|rXtd||t|ftj ntd||fdS|rtd||t|fntd ||fd}d}i}g} xf|D]^} | j rq| j rd } nd } d || t| j f} | j | j| f| j| j | f|t|<|d }qWtj| tdt|dkrtd} | |kr|rhd|| d|| d|f}nd|| d|| d|f}tj||| d ddS|rtjn|rtj dS)zrFunction to explore struct/class and union types. See Explorer.explore_type for more information. rOz struct/classrMrz'%s is a %s of type '%s' with no fields.z'%s' is a %s with no fields.Fz3%s is a %s of type '%s' with the following fields: z('%s' is a %s with the following fields: z base classrKz*rz"Enter the field number of choice: z %s '%s' of %srz%s '%s' of '%s'T)rr"r*rJr+rLrrrr8rIrPrrRr rHrr5rr7)r r!rrrSrJrTrVrUrGrKrWZrhsrXnew_namerrrrsn             zCompoundExplorer.explore_typeN) r9r:r;r<r=rHrLrrrrrrr+os  Qr+c@s(eZdZdZeddZeddZdS)r/z>Internal class used to explore values whose type is a typedef.cCs>|jj}td|t|jt|ftj||j||dS)zdFunction to explore typedef values. See Explorer.explore_expr for more information. zAThe value of '%s' is of type '%s' which is a typedef of type '%s'F)rstrip_typedefsrrrrrQ)rrr actual_typerrrr)s  zTypedefExplorer.explore_exprcCsH|j}|r"td|t|fntd|t|ftj|||dS)zcFunction to explore typedef types. See Explorer.explore_type for more information. z)The type of %s is a typedef of type '%s'.z(The type '%s' is a typedef of type '%s'.F)rZrrrr)r r!rr[rrrr6szTypedefExplorer.explore_typeN)r9r:r;r<r=rrrrrrr/&s r/c@s4eZdZdZeddZeddZeddZdS) ExploreUtilszEInternal class which provides utilities for the main command classes.cCs&t|dkrtjd|dSdSdS)aUtility to check if adequate number of arguments are passed to an explore command. Arguments: name: The name of the explore command. arg_str: The argument string passed to the explore command. Returns: True if adequate arguments are passed, false otherwise. Raises: gdb.GdbError if adequate arguments are not passed. rz!ERROR: '%s' requires an argument.FTN)rr"GdbError)r arg_strrrr check_argsJs  zExploreUtils.check_argscCsNytjd|jjStk rHy tj|Stk rBdSXYnXdS)a<A utility function to deduce the gdb.Type value from a string representing the type. Arguments: type_str: The type string from which the gdb.Type value should be deduced. Returns: The deduced gdb.Type value if possible, None otherwise. z(%s *)0N)r"parse_and_evalrr? RuntimeErrorZ lookup_type)Ztype_strrrrget_type_from_str`s  zExploreUtils.get_type_from_strc Cs$y tj|Stk rdSXdS)aCA utility function to deduce the gdb.Value value from a string representing the value. Arguments: value_str: The value string from which the gdb.Value value should be deduced. Returns: The deduced gdb.Value value if possible, None otherwise. N)r"r`ra)Z value_strrrrget_value_from_strws  zExploreUtils.get_value_from_strN)r9r:r;r<r=r_rbrcrrrrr\Gs  r\cs(eZdZdZfddZddZZS)ExploreCommandzExplore a value or a type valid in the current context. Usage: explore ARG - ARG is either a valid expression or a type name. - At any stage of exploration, hit the return key (instead of a choice, if any) to return to the enclosing type or value.cstt|jdtjdddS)NexploreT)r command_classprefix)superrd__init__r" COMMAND_DATA)self) __class__rrris zExploreCommand.__init__cCsntjd|dkrdStj|}|dk r8tj||ddStj|}|dk r\tj||ddStjd|dS)NreFzG'%s' neither evaluates to a value nor is a type in the current context.) r\r_rcrrrbrr"r])rkr^from_ttyrr!rrrinvokes  zExploreCommand.invoke)r9r:r;r<rirn __classcell__rr)rlrrds rdcs(eZdZdZfddZddZZS)ExploreValueCommandzExplore value of an expression valid in the current context. Usage: explore value ARG - ARG is a valid expression. - At any stage of exploration, hit the return key (instead of a choice, if any) to return to the enclosing value.cstt|jdtjddS)Nz explore value)r rf)rhrprir"rj)rk)rlrrris zExploreValueCommand.__init__cCsJtjd|dkrdStj|}|dkr8tjd|dStj||ddS)Nz explore valueFz: '%s' does not evaluate to a value in the current context.)r\r_rcr"r]rr)rkr^rmrrrrrns zExploreValueCommand.invoke)r9r:r;r<rirnrorr)rlrrps rpcs(eZdZdZfddZddZZS)ExploreTypeCommandzExplore a type or the type of an expression. Usage: explore type ARG - ARG is a valid expression or a type name. - At any stage of exploration, hit the return key (instead of a choice, if any) to return to the enclosing type.cstt|jdtjddS)Nz explore type)r rf)rhrqrir"rj)rk)rlrrris zExploreTypeCommand.__init__cCstjd|dkrdStj|}|dk r8tj||ddStj|}|dk rztd|t|jftjt|j|jddSt j d|dS)Nz explore typeFz'%s' is of type '%s'.z3'%s' is not a type or value in the current context.) r\r_rbrrrcrrrr"r])rkr^rmr!rrrrrns  zExploreTypeCommand.invoke)r9r:r;r<rirnrorr)rlrrqs rq)r<r"sys version_infoinputr5objectrr$r-r.r0r+r/r\ZCommandrdrprqr1rrrrs*%-B-8!B% PKPD4]/4ۥ:gdb/command/__pycache__/type_printers.cpython-36.opt-1.pycnu[3 `)@sjddlZddlZGdddejZGdddejZGdddeZGdd d eZeeedS) Ncs0eZdZdZfddZddZddZZS)InfoTypePrinterzLGDB command to list all registered type-printers. Usage: info type-printerscstt|jdtjdS)Nzinfo type-printers)superr__init__gdb COMMAND_DATA)self) __class__/type_printers.pyrs zInfoTypePrinter.__init__cCsJttj|ddd}x.|D]&}|jr,d}nd}td|j|fqWdS)zPrint a list of type printers.cSs|jS)N)name)xr r r $sz4InfoTypePrinter.list_type_printers..)keyz [disabled]z %s%sN)sortedcopyenabledprintr )r type_printersZsorted_type_printersZprinterrr r r list_type_printerss   z"InfoTypePrinter.list_type_printerscCsd}x8tjD],}|jrtd||jf|j|jd}qWtjjrhtd||jtjjd}tjrtd||jtjdS)z&GDB calls this to perform the command.rz%sType printers for %s: z"%sType printers for program space:z%sGlobal type printers:N)robjfilesrrfilenamercurrent_progspace)rargfrom_ttysepobjfiler r r invoke,s    zInfoTypePrinter.invoke)__name__ __module__ __qualname____doc__rrr __classcell__r r )rr rs  rcs<eZdZfddZddZddZddZd d ZZS) _EnableOrDisableCommandcstt|j|tj||_dS)N)rr$rrrsetting)rr%r )rr r r=sz _EnableOrDisableCommand.__init__cCs,d}x"|D]}||jkr |j|_d}q W|S)NFT)r r%r)rr printersresultpr r r set_someAs   z _EnableOrDisableCommand.set_somecCsvxp|jD]d}d}x"tjD]}|j||jrd}qW|j|tjjrLd}|j|tjr^d}|s td|q WdS)z&GDB calls this to perform the command.FTzNo type printer named '%s'N)splitrrr)rrr)rrrr okrr r r rIsz_EnableOrDisableCommand.invokecCs*x$|D]}|jj|r|j|jqWdS)N)r startswithappend)rr'wordr&r(r r r add_someWs  z _EnableOrDisableCommand.add_somecCsNg}x tjD]}|j|||jqW|j||tjj|j||tj|S)N)rrr/rr)rtextr.r'rr r r complete\s z _EnableOrDisableCommand.complete) rr r!rr)rr/r1r#r r )rr r$<s  r$cs eZdZdZfddZZS)EnableTypePrinterzyGDB command to enable the specified type printer. Usage: enable type-printer NAME NAME is the name of the type-printer.cstt|jdddS)NTzenable type-printer)rr2r)r)rr r rkszEnableTypePrinter.__init__)rr r!r"rr#r r )rr r2dsr2cs eZdZdZfddZZS)DisableTypePrinterz{GDB command to disable the specified type-printer. Usage: disable type-printer NAME NAME is the name of the type-printer.cstt|jdddS)NFzdisable type-printer)rr3r)r)rr r ruszDisableTypePrinter.__init__)rr r!r"rr#r r )rr r3nsr3)rrZCommandrr$r2r3r r r r s&(  PKPD4]`;;:gdb/command/__pycache__/frame_filters.cpython-36.opt-1.pycnu[3 `?@sdZddlZddlZddlZddlmZddlmZddlZddl Z Gdddej Z Gdddej Z Gd d d ej Z d d Zd dZddZddZGdddej ZGdddej ZGdddej ZGdddej Ze e e eeeedS)z,GDB commands for working with frame-filters.N) FrameIterator)FrameDecoratorcs eZdZdZfddZZS)SetFilterPrefixCmdz9Prefix command for 'set' frame-filter related operations.cstt|jdtjtjddS)Nzset frame-filterT)superr__init__gdbCOMMAND_OBSCURE COMPLETE_NONE)self) __class__/frame_filters.pyrs zSetFilterPrefixCmd.__init__)__name__ __module__ __qualname____doc__r __classcell__r r )r r rsrcs eZdZdZfddZZS)ShowFilterPrefixCmdz:Prefix command for 'show' frame-filter related operations.cstt|jdtjtjddS)Nzshow frame-filterT)rrrrrr )r )r r r r&s zShowFilterPrefixCmd.__init__)rrrrrrr r )r r r$srcs<eZdZdZfddZeddZddZdd ZZ S) InfoFrameFilterzDList all registered Python frame-filters. Usage: info frame-filterscstt|jdtjdS)Nzinfo frame-filter)rrrr COMMAND_DATA)r )r r r r/s zInfoFrameFilter.__init__cCs|rdSdSdS)z2Return "Yes" if filter is enabled, otherwise "No".ZYesZNoNr )stater r r enabled_string2szInfoFrameFilter.enabled_stringc Cst|jdddd}t|dkr&dSt|tdx|D]}|d}yLdjttjj|d}d j|j tjj |d}td |||fWq<t k rt j d} td |d t| Yq<sz,InfoFrameFilter.print_list..T)keyreverserz Priority Enabled Namez{:<8}rz{:<7}z %s %s %sz Error printing filter 'z': )sorteditemslenprintformatstrrrrrZ get_enabled Exceptionsysexc_info) r title frame_filtersZ blank_lineZsorted_frame_filters frame_filternamepriorityZenableder r r print_list:s*   "zInfoFrameFilter.print_listcCsr|jdtjd}tj}||jd|j|jd7}x*tjD]}||jd|j|jd7}q.rrN)rr1appendr0filterr")textwordZall_flagZfilter_locationsr4flistr r r _complete_frame_filter_lists    rQcCs*|j}|dkr|St|fdd|}|S)aWorker for frame filter name completion. Arguments: word: The most recent word of the command line. printer_dict: The frame filter dictionary to search for frame filter name completions. Returns: A list of suggested frame filter name completions from word analysis of the frame filter dictionary. This list can be empty when there are no suggestions for completion. rcSs |j|S)N)rI)rJrKr r r rsz-_complete_frame_filter_name..)keysrM)rOZ printer_dictZ printer_keysrPr r r _complete_frame_filter_names rScs0eZdZdZfddZddZddZZS)EnableFrameFilteraYGDB command to enable the specified frame-filter. Usage: enable frame-filter DICTIONARY [NAME] DICTIONARY is the name of the frame filter dictionary on which to operate. If dictionary is set to "all", perform operations on all dictionaries. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's frame filter dictionary. If either all, or the two named dictionaries are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame-filter to operate on.cstt|jdtjdS)Nzenable frame-filter)rrTrrr)r )r r r rs zEnableFrameFilter.__init__cCs@|jddkrt||dStjj|jdj}t||SdS)zTCompletion function for both frame filter dictionary, and frame filter name. rTN)countrQrrr>splitrstriprS)r rNrO printer_listr r r completes zEnableFrameFilter.completecCstd|}t|ddS)Nzenable frame-filterT)r=rG)r r2r3r@r r r r5s zEnableFrameFilter.invoke)rrrrrrZr5rr r )r r rTs   rTcs0eZdZdZfddZddZddZZS)DisableFrameFiltera[GDB command to disable the specified frame-filter. Usage: disable frame-filter DICTIONARY [NAME] DICTIONARY is the name of the frame filter dictionary on which to operate. If dictionary is set to "all", perform operations on all dictionaries. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's frame filter dictionary. If either all, or the two named dictionaries are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame-filter to operate on.cstt|jdtjdS)Nzdisable frame-filter)rr[rrr)r )r r r rs zDisableFrameFilter.__init__cCs@|jddkrt||dStjj|jdj}t||SdS)zTCompletion function for both frame filter dictionary, and frame filter name.rUrTN)rVrQrrr>rWrXrS)r rNrOrYr r r rZs zDisableFrameFilter.completecCstd|}t|ddS)Nzdisable frame-filterF)r=rG)r r2r3r@r r r r5 s zDisableFrameFilter.invoke)rrrrrrZr5rr r )r r r[s   r[cs@eZdZdZfddZddZddZdd Zd d ZZ S) SetFrameFilterPrioritya`GDB command to set the priority of the specified frame-filter. Usage: set frame-filter priority DICTIONARY NAME PRIORITY DICTIONARY is the name of the frame filter dictionary on which to operate. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's framefilter dictionary. If either of these two are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame filter to operate on. PRIORITY is the an integer to assign the new priority to the frame filter.cstt|jdtjdS)Nzset frame-filter priority)rr\rrr)r )r r r r!s zSetFrameFilterPriority.__init__cCs*tj|}t|}|dkr&tddS|S)aRInternal worker to parse a priority from a tuple. Arguments: arg: Tuple which contains the arguments from the command. Returns: A tuple containing the dictionary, name and priority from the arguments. Raises: gdb.GdbError: An error parsing the arguments. z8set frame-filter priority takes exactly three arguments.N)rr9r"r#)r r2r;r<r r r _parse_pri_arg&s  z%SetFrameFilterPriority._parse_pri_argc Csv|d}|d}t|d}tjj|}y ||}Wn.tk rbdt|d}tj|YnXtjj||dS)aInternal worker for setting priority of frame-filters, by parsing a tuple and calling _set_priority with the parsed tuple. Arguments: command_tuple: Tuple which contains the arguments from the command. rrr8zframe-filter 'z ' not found.N)intrrr>r?r%r:Z set_priority)r r@rBr+r-rCrErFr r r _set_filter_priority=s    z+SetFrameFilterPriority._set_filter_prioritycCs@|jddkrt||dStjj|jdj}t||SdS)zTCompletion function for both frame filter dictionary, and frame filter name.rUrFN)rVrQrrr>rWrXrS)r rNrOrYr r r rZXs zSetFrameFilterPriority.completecCs |j|}|dkr|j|dS)N)r^r`)r r2r3r@r r r r5as zSetFrameFilterPriority.invoke) rrrrrr^r`rZr5rr r )r r r\s   r\cs@eZdZdZfddZddZddZdd Zd d ZZ S) ShowFrameFilterPrioritya GDB command to show the priority of the specified frame-filter. Usage: show frame-filter priority DICTIONARY NAME DICTIONARY is the name of the frame filter dictionary on which to operate. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's framefilter dictionary. If either of these two are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame-filter to operate on.cstt|jdtjdS)Nzshow frame-filter priority)rrarrr)r )r r r rts z ShowFrameFilterPriority.__init__cCs*tj|}t|}|dkr&tddS|S)aKInternal worker to parse a dictionary and name from a tuple. Arguments: arg: Tuple which contains the arguments from the command. Returns: A tuple containing the dictionary, and frame filter name. Raises: gdb.GdbError: An error parsing the arguments. r8z7show frame-filter priority takes exactly two arguments.N)rr9r"r#)r r2r;r<r r r r^ys  z&ShowFrameFilterPriority._parse_pri_argc CsTtjj|}y ||}Wn.tk rFdt|d}tj|YnXtjj|S)aEWorker for retrieving the priority of frame_filters. Arguments: frame_filters: Name of frame filter dictionary. name: object to select printers. Returns: The priority of the frame filter. Raises: gdb.GdbError: A frame filter cannot be found. zframe-filter 'z ' not found.)rrr>r?r%r:r)r r*r,rCrErFr r r get_filter_prioritys  z+ShowFrameFilterPriority.get_filter_prioritycCs>|jddkrt||dStj|jdj}t||SdS)zTCompletion function for both frame filter dictionary, and frame filter name.rUrFN)rVrQframeZ _return_listrWrXrS)r rNrOrYr r r rZs z ShowFrameFilterPriority.completec Cs|j|}|dkrdS|d}|d}y|j||}Wn8tk rntjd}tdtdt|Yn"Xtd|d|dt|dS)Nrrz$Error printing filter priority for 'z':zPriority of filter 'z ' in list 'z' is: )r^rbr&r'r(r#r,r%)r r2r3r@Z filter_nameZ list_namer-r.r r r r5s  zShowFrameFilterPriority.invoke) rrrrrr^rbrZr5rr r )r r rafs    ra)rr'rcopyZgdb.FrameIteratorrZgdb.FrameDecoratorrZ gdb.frames itertoolsZCommandrrrr=rGrQrSrTr[r\rar r r r s2  9%V\PKPD4]GQv##5gdb/command/__pycache__/xmethods.cpython-36.opt-1.pycnu[3 `0'@sddlZddlZddZddZddZdd Zd d Zd d ZddZGdddej Z Gdddej Z Gdddej Z ddZ e dS)Nc Cs0y tj|Stk r*td||YnXdS)NzInvalid %s regexp: %s)recompile SyntaxError)Z part_nameZregexpr /xmethods.pyvalidate_xm_regexps rcCstj|}t|}|dkr"tdd}d}d}|dkr>|d}|dkrr|djdd}|d}t|dkrr|d}|rtd|}nd}td |td ||fS) a?Parses the arguments passed to a xmethod command. Arguments: arg: The argument string passed to a xmethod command. Returns: A 3-tuple: (, , ) zToo many arguments to command.Nr;z xmethod namelocusz matcher name)gdbZstring_to_argvlenrsplitr)argargvZargcZ locus_regexpZmatcher_name_regexpZxm_name_regexppartsname_rerrrparse_xm_command_argss(   rcs8d}|gi}|jdr4||jfddtjD|S)aReturns a dict of matching globally registered xmethods. Arguments: locus_re: Even though only globally registered xmethods are looked up, they will be looked up only if 'global' matches LOCUS_RE. matcher_re: The regular expression matching the names of xmethods. Returns: A dict of matching globally registered xmethod matchers. The only key in the dict will be 'global'. globalcsg|]}j|jr|qSr)matchname).0m) matcher_rerr Qsz.get_global_method_matchers..)rextendr xmethods)locus_rer locus_strxm_dictr)rrget_global_method_matchers@s  r!csli}xb|D]Z}t|tjr,|jds&q d}n|j|js:q d}d||jf}fdd|jD||<q W|S)aReturns a dict of matching registered xmethods in the LOCI. Arguments: loci: The list of loci to lookup matching xmethods in. locus_re: If a locus is an objfile, then xmethod matchers will be looked up in it only if its filename matches the regular expression LOCUS_RE. If a locus is the current progspace, then xmethod matchers will be looked up in it only if the string "progspace" matches LOCUS_RE. matcher_re: The regular expression to match the xmethod matcher names. Returns: A dict of matching xmethod matchers. The keys of the dict are the filenames of the loci the xmethod matchers belong to. Z progspaceZobjfilez%s %scsg|]}j|jr|qSr)rr)rr)rrrrrsz/get_method_matchers_in_loci..) isinstancer Z Progspacerfilenamer)Zlocirrr r Z locus_typerr)rrget_method_matchers_in_lociUs    r$cCsdd}|sdSx|D]}||s$qtd|xh||D]\}td|j||f|js\q:x8|jD].}|dks||j|jrdtd|j||fqdWq:WqWdS)zPrint a dictionary of xmethods.cSs|js dSdSdS)Nz [disabled]r )enabled)rrrrget_status_stringxsz(print_xm_info..get_status_stringNzXmethods in %s:z %s%sz %s%s)printrmethodsr)r rr&rmatcherrrrr print_xm_infovs   r*cCs^xX|jD]L\}}xB|D]:}|s(||_q|js0qx |jD]}|j|jr8||_q8WqWq WdS)z>Set the status (enabled/disabled) of a dictionary of xmethods.N)itemsr%r(rr)r rstatusrZmatchersr)rrrrset_xm_status1s   r-cCsVt|\}}}tt||||tttjg||||tttj||||dS)zSet the status (enabled/disabled) of xmethods matching ARG. This is a helper function for enable/disable commands. ARG is the argument string passed to the commands. N)rr-r!r$r current_progspaceobjfiles)rr,rrrrrr set_xm_statuss r0cs(eZdZdZfddZddZZS) InfoXMethoda9GDB command to list registered xmethod matchers. Usage: info xmethod [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the xmethod matchers. If it is omitted, all registered xmethod matchers from all loci are listed. A locus could be 'global', a regular expression matching the current program space's filename, or a regular expression matching filenames of objfiles. Locus could be 'progspace' to specify that only xmethods from the current progspace should be listed. NAME-REGEXP is a regular expression matching the names of xmethod matchers. If this omitted for a specified locus, then all registered xmethods in the locus are listed. To list only a certain xmethods managed by a single matcher, the name regexp can be specified as matcher-name-regexp;xmethod-name-regexp.cstt|jdtjdS)Nz info xmethod)superr1__init__r COMMAND_DATA)self) __class__rrr3s zInfoXMethod.__init__cCsPt|\}}}tt|||tttjg|||tttj|||dS)N)rr*r!r$r r.r/)r5rfrom_ttyrrrrrrinvokes zInfoXMethod.invoke)__name__ __module__ __qualname____doc__r3r8 __classcell__rr)r6rr1s r1cs(eZdZdZfddZddZZS) EnableXMethoda^GDB command to enable a specified (group of) xmethod(s). Usage: enable xmethod [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the xmethod matchers. If it is omitted, all registered xmethods matchers from all loci are enabled. A locus could be 'global', a regular expression matching the current program space's filename, or a regular expression matching filenames of objfiles. Locus could be 'progspace' to specify that only xmethods from the current progspace should be enabled. NAME-REGEXP is a regular expression matching the names of xmethods within a given locus. If this omitted for a specified locus, then all registered xmethod matchers in the locus are enabled. To enable only a certain xmethods managed by a single matcher, the name regexp can be specified as matcher-name-regexp;xmethod-name-regexp.cstt|jdtjdS)Nzenable xmethod)r2r>r3r r4)r5)r6rrr3s zEnableXMethod.__init__cCst|ddS)NT)r0)r5rr7rrrr8szEnableXMethod.invoke)r9r:r;r<r3r8r=rr)r6rr>s r>cs(eZdZdZfddZddZZS)DisableXMethodaYGDB command to disable a specified (group of) xmethod(s). Usage: disable xmethod [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the xmethod matchers. If it is omitted, all registered xmethod matchers from all loci are disabled. A locus could be 'global', a regular expression matching the current program space's filename, or a regular expression filenames of objfiles. Locus could be 'progspace' to specify that only xmethods from the current progspace should be disabled. NAME-REGEXP is a regular expression matching the names of xmethods within a given locus. If this omitted for a specified locus, then all registered xmethod matchers in the locus are disabled. To disable only a certain xmethods managed by a single matcher, the name regexp can be specified as matcher-name-regexp;xmethod-name-regexp.cstt|jdtjdS)Nzdisable xmethod)r2r?r3r r4)r5)r6rrr3s zDisableXMethod.__init__cCst|ddS)NF)r0)r5rr7rrrr8szDisableXMethod.invoke)r9r:r;r<r3r8r=rr)r6rr?s r?cCstttdS)zInstalls the xmethod commands.N)r1r>r?rrrrregister_xmethod_commandssr@)r rrrr!r$r*r-r0ZCommandr1r>r?r@rrrrs"!#PKPD4]|/6gdb/command/__pycache__/unwinders.cpython-36.opt-1.pycnu[3 `y@sxddlZddlZddZddZGdddejZdd Zd d ZGd d d ejZGdddejZ ddZ e dS)Nc Cs4y tj|Stk r.td||fYnXdS)NzInvalid %s regexp: %s.)recompile SyntaxError)ZexpZidstringr /unwinders.pyvalidate_regexps rcCs^tj|}t|}|dkr"tdd}d}|dkrJ|d}|dkrJ|d}t|dt|dfS)a$Internal utility to parse unwinder command argv. Arguments: arg: The arguments to the command. The format is: [locus-regexp [name-regexp]] Returns: A 2-tuple of compiled regular expressions. Raises: SyntaxError: an error processing ARG zToo many arguments.rZlocusunwinder)gdbZstring_to_argvlenrr)argargvZargcZ locus_regexpZ name_regexprrrparse_unwinder_command_argss rcs0eZdZdZfddZddZddZZS) InfoUnwinderaGDB command to list unwinders. Usage: info unwinder [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the unwinder. If it is omitted, all registered unwinders from all loci are listed. A locus can be 'global', 'progspace' to list the unwinders from the current progspace, or a regular expression matching filenames of objfiles. NAME-REGEXP is a regular expression to filter unwinder names. If this omitted for a specified locus, then all registered unwinders in the locus are listed.cstt|jdtjdS)Nz info unwinder)superr__init__r COMMAND_STACK)self) __class__rrrGs zInfoUnwinder.__init__cCsJ|sdSt|x4|D],}|j|jrtd|j|jr8dndfqWdS)zLists the unwinders whose name matches regexp. Arguments: title: The line to print before the list. unwinders: The list of the unwinders. name_re: unwinder name filter. Nz %s%sr z [disabled])printmatchnameenabled)rtitle unwindersname_rer rrrlist_unwindersKs  zInfoUnwinder.list_unwinderscCst|\}}|jdr&|jdtj||jdrNtj}|jd|j|j|x2tjD]&}|j|jrX|jd|j|j|qXWdS)NglobalzGlobal: progspacez Progspace %s:z Objfile %s:)rrrr frame_unwinderscurrent_progspacefilenameobjfiles)rrfrom_ttylocus_rerZcpobjfilerrrinvoke[s        zInfoUnwinder.invoke)__name__ __module__ __qualname____doc__rrr( __classcell__rr)rrr8s  rcCs0d}x&|D]}|j|jr ||_|d7}q W|S)zEnable/disable unwinders whose names match given regex. Arguments: unwinders: The list of unwinders. name_re: Unwinder name filter. flag: Enable/disable. Returns: The number of unwinders affected. rr )rrr)rrflagtotalr rrrdo_enable_unwinder1js    r0cCst|\}}d}|jdr,|ttj||7}|jdrL|ttjj||7}x.tjD]"}|j|jrV|t|j||7}qVW|dkrtjt d||dkrdnd|rdnd fd S) zEnable/disable unwinder(s).rrr z%d unwinder%s %sr r srZdisabledN) rrr0r r!r"r$r#Zinvalidate_cached_framesr)rr.r&rr/r'rrrdo_enable_unwinder}s        r2cs(eZdZdZfddZddZZS)EnableUnwinderaGDB command to enable unwinders. Usage: enable unwinder [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression specifying the unwinders to enable. It can 'global', 'progspace', or the name of an objfile within that progspace. NAME_REGEXP is a regular expression to filter unwinder names. If this omitted for a specified locus, then all registered unwinders in the locus are affected.cstt|jdtjdS)Nzenable unwinder)rr3rr r)r)rrrrs zEnableUnwinder.__init__cCst|ddS)z&GDB calls this to perform the command.TN)r2)rrr%rrrr(szEnableUnwinder.invoke)r)r*r+r,rr(r-rr)rrr3s  r3cs(eZdZdZfddZddZZS)DisableUnwinderaGDB command to disable the specified unwinder. Usage: disable unwinder [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression specifying the unwinders to disable. It can 'global', 'progspace', or the name of an objfile within that progspace. NAME_REGEXP is a regular expression to filter unwinder names. If this omitted for a specified locus, then all registered unwinders in the locus are affected.cstt|jdtjdS)Nzdisable unwinder)rr4rr r)r)rrrrs zDisableUnwinder.__init__cCst|ddS)z&GDB calls this to perform the command.FN)r2)rrr%rrrr(szDisableUnwinder.invoke)r)r*r+r,rr(r-rr)rrr4s  r4cCstttdS)zInstalls the unwinder commands.N)rr3r4rrrrregister_unwinder_commandssr5) r rrrZCommandrr0r2r3r4r5rrrrs2PKPD4]y2E<$<$6gdb/command/__pycache__/pretty_printers.cpython-36.pycnu[3 `%8@sdZddlZddlZddlZddZddZGdddejZd d Zd d Z dddZ ddZ ddZ ddZ GdddejZGdddejZddZedS)z.GDB commands for working with pretty-printers.Nc Cstj|}t|}d}d}d}|dkr.td|dkr>|d}|dkrr|djdd}|d}t|dkrr|d}ytj|}Wn tk rtd |YnXytj|}Wn tk rtd |YnX|dk rytj|} Wn"tk r td |YnXnd} ||| fS) aInternal utility to parse a pretty-printer command argv. Arguments: arg: The arguments to the command. The format is: [object-regexp [name-regexp]]. Individual printers in a collection are named as printer-name;subprinter-name. Returns: The result is a 3-tuple of compiled regular expressions, except that the resulting compiled subprinter regexp is None if not provided. Raises: SyntaxError: an error processing ARG Nztoo many argumentsr;zinvalid object regexp: %szinvalid name regexp: %szinvalid subname regexp: %s)gdbZstring_to_argvlen SyntaxErrorsplitrecompile) argargvZargcZ object_regexpZ name_regexpZsubname_regexpZ name_subname object_rename_re subname_rer/pretty_printers.pyparse_printer_regexpss:   rcCst|dr|jSdSdS)z>Internal utility to see if printer (or subprinter) is enabled.enabledTN)hasattrr)printerrrrprinter_enabled_pLs rcsPeZdZdZfddZeddZeddZdd Zd d Z d d Z Z S)InfoPrettyPrinteraGDB command to list all registered pretty-printers. Usage: info pretty-printer [OBJECT-REGEXP [NAME-REGEXP]] OBJECT-REGEXP is a regular expression matching the objects to list. Objects are "global", the program space's file, and the objfiles within that program space. NAME-REGEXP matches the name of the pretty-printer. Individual printers in a collection are named as printer-name;subprinter-name.cstt|jdtjdS)Nzinfo pretty-printer)superr__init__r COMMAND_DATA)self) __class__rrras zInfoPrettyPrinter.__init__cCst|r dSdSdS)z9Return "" if PRINTER is enabled, otherwise " [disabled]".rz [disabled]N)r)rrrrenabled_stringesz InfoPrettyPrinter.enabled_stringcCs$t|dr|jSt|dr |jSdS)zReturn the printer's name.name__name__unknown)rr r!)rrrr printer_namems   zInfoPrettyPrinter.printer_namec Csttj||jd}x|D]}|j|}|j|}|j|rtd||ft|dr|jdk rttj|j|jd}x6|D].} | s|j| jr|td| j|j| fq|WqWdS)z Print a list of pretty-printers.)keyz %s%s subprintersNz %s%s) sortedcopyr#rmatchprintrr%r ) rpretty_printersrrZsorted_pretty_printersrr rZsorted_subprinters subprinterrrrlist_pretty_printerszs"            z&InfoPrettyPrinter.list_pretty_printerscCs(|r$|j|r$t||j|||dS)z$Subroutine of invoke to simplify it.N)r(r)r,)rtitleZ printer_listZobj_name_to_matchrrrrrrinvoke1szInfoPrettyPrinter.invoke1cCs|t|\}}}|jdtjd|||tj}|jd|j|jd|||x.tjD]"}|jd|j|j|j|||qRWdS)z&GDB calls this to perform the command.zglobal pretty-printers:globalzprogspace %s pretty-printers: progspacezobjfile %s pretty-printers:N)rr.rr*current_progspacefilenameobjfiles)rr from_ttyrrrcpobjfilerrrinvokes     zInfoPrettyPrinter.invoke) r! __module__ __qualname____doc__r staticmethodrr#r,r.r7 __classcell__rr)rrrTs    rcCsd}d}xp|D]h}t|dr^|jdk r^t|rNx|jD]}t|r6|d7}q6W|t|j7}qt|rn|d7}|d7}qW||fS)z9Return a 2-tuple of number of enabled and total printers.rr%Nr)rr%rr)r*rtotalrr+rrrcount_enabled_printerss      r>cCsd}d}ttj\}}||7}||7}ttjj\}}||7}||7}x.tjD]"}t|j\}}||7}||7}qRW||fS)zkReturn a 2-tuble of the enabled state and total number of all printers. This includes subprinters. r)r>rr*r1r3) enabled_count total_countZ t_enabledZt_totalr6rrrcount_all_enabled_printerss rAscCs|dkrd||fS|SdS)z!Return TEXT pluralized if N != 1.rz%s%sNr)textnsuffixrrr pluralizes rFcCst\}}td||fdS)zZPrint the number of printers enabled/disabled. We count subprinters individually. z%d of %d printers enabledN)rAr))r?r@rrr#show_pretty_printer_enabled_summarys rGcCsd}x|D]}t|dr$|j|js:t|dr |j|jr t|dr|jdk r|st||kr~x|jD]}t|rf|d7}qfW||_qx\|jD]2}|j|jrt|rt||kr|d7}||_qWq |s t||kr|d7}||_q W|S)aWorker for enabling/disabling pretty-printers. Arguments: pretty_printers: list of pretty-printers name_re: regular-expression object to select printers subname_re: regular expression object to select subprinters or None if all are affected flag: True for Enable, False for Disable Returns: The number of printers affected. This is just for informational purposes for the user. rr r!r%Nr)rr(r r!r%rr)r*rrflagr=rr+rrrdo_enable_pretty_printer_1s.            rIc Cst|\}}}d}|jdr0|ttj|||7}tj}|jdrV|t|j|||7}x0tjD]$}|j|jr`|t|j|||7}q`W|rd}nd}td|t d||ft dS) z7Internal worker for enabling/disabling pretty-printers.rr/r0rZdisabledz%d %s %srN) rr(rIrr*r1r3r2r)rFrG) r rHrrrr=r5r6staterrrdo_enable_pretty_printers$     rKcs(eZdZdZfddZddZZS)EnablePrettyPrinteraGDB command to enable the specified pretty-printer. Usage: enable pretty-printer [OBJECT-REGEXP [NAME-REGEXP]] OBJECT-REGEXP is a regular expression matching the objects to examine. Objects are "global", the program space's file, and the objfiles within that program space. NAME-REGEXP matches the name of the pretty-printer. Individual printers in a collection are named as printer-name;subprinter-name.cstt|jdtjdS)Nzenable pretty-printer)rrLrrr)r)rrrrHs zEnablePrettyPrinter.__init__cCst|ddS)z&GDB calls this to perform the command.TN)rK)rr r4rrrr7LszEnablePrettyPrinter.invoke)r!r8r9r:rr7r<rr)rrrL;s  rLcs(eZdZdZfddZddZZS)DisablePrettyPrinteraGDB command to disable the specified pretty-printer. Usage: disable pretty-printer [OBJECT-REGEXP [NAME-REGEXP]] OBJECT-REGEXP is a regular expression matching the objects to examine. Objects are "global", the program space's file, and the objfiles within that program space. NAME-REGEXP matches the name of the pretty-printer. Individual printers in a collection are named as printer-name;subprinter-name.cstt|jdtjdS)Nzdisable pretty-printer)rrMrrr)r)rrrr^s zDisablePrettyPrinter.__init__cCst|ddS)z&GDB calls this to perform the command.FN)rK)rr r4rrrr7bszDisablePrettyPrinter.invoke)r!r8r9r:rr7r<rr)rrrMQs  rMcCstttdS)zDCall from a top level script to install the pretty-printer commands.N)rrLrMrrrr register_pretty_printer_commandsgsrN)rB)r:r'rr rrZCommandrr>rArFrGrIrKrLrMrNrrrrs 4R :%PKPD4] GG-gdb/command/__pycache__/prompt.cpython-36.pycnu[3 ` @s0dZddlZddlZGdddejZedS)z.GDB command for working with extended prompts.NcsNeZdZdZeejjZdZdZfddZ ddZ dd Z d d Z Z S) _ExtendedPromptzSet the extended prompt. Usage: set extended-prompt VALUE Substitutions are applied to VALUE to compute the real prompt. The currently defined substitutions are: zSet the extended prompt.zShow the extended prompt.cs(tt|jdtjtjd|_d|_dS)Nzextended-promptF)superr__init__gdbZCOMMAND_SUPPORTZPARAM_STRING_NOESCAPEvaluehook_set)self) __class__ /prompt.pyr(s  z_ExtendedPrompt.__init__cCs|jrd|jSdSdS)NzThe extended prompt is: zThe extended prompt is not set.)r)r Zpvaluer r r get_show_string/s z_ExtendedPrompt.get_show_stringcCs|jdkr|jt_d|_dS)NFTr)rbefore_prompt_hookrZ prompt_hook)r r r r get_set_string5s z_ExtendedPrompt.get_set_stringcCs|jrtjj|jSdSdS)N)rrpromptZsubstitute_prompt)r Zcurrentr r r r;sz"_ExtendedPrompt.before_prompt_hook)__name__ __module__ __qualname____doc__rrZ prompt_helpZset_docZshow_docrr rr __classcell__r r )r r rs  r)rrZ gdb.promptZ Parameterrr r r r s+PKPD4]sPKPD4]b  gdb/command/prompt.pynu[# Extended prompt. # Copyright (C) 2011-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """GDB command for working with extended prompts.""" import gdb import gdb.prompt class _ExtendedPrompt(gdb.Parameter): """Set the extended prompt. Usage: set extended-prompt VALUE Substitutions are applied to VALUE to compute the real prompt. The currently defined substitutions are: """ # Add the prompt library's dynamically generated help to the # __doc__ string. __doc__ = __doc__ + gdb.prompt.prompt_help() set_doc = "Set the extended prompt." show_doc = "Show the extended prompt." def __init__(self): super(_ExtendedPrompt, self).__init__("extended-prompt", gdb.COMMAND_SUPPORT, gdb.PARAM_STRING_NOESCAPE) self.value = '' self.hook_set = False def get_show_string (self, pvalue): if self.value: return "The extended prompt is: " + self.value else: return "The extended prompt is not set." def get_set_string (self): if self.hook_set == False: gdb.prompt_hook = self.before_prompt_hook self.hook_set = True return "" def before_prompt_hook(self, current): if self.value: return gdb.prompt.substitute_prompt(self.value) else: return None _ExtendedPrompt() PKPD4]UQ??gdb/command/frame_filters.pynu[# Frame-filter commands. # Copyright (C) 2013-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """GDB commands for working with frame-filters.""" import sys import gdb import copy from gdb.FrameIterator import FrameIterator from gdb.FrameDecorator import FrameDecorator import gdb.frames import itertools # GDB Commands. class SetFilterPrefixCmd(gdb.Command): """Prefix command for 'set' frame-filter related operations.""" def __init__(self): super(SetFilterPrefixCmd, self).__init__("set frame-filter", gdb.COMMAND_OBSCURE, gdb.COMPLETE_NONE, True) class ShowFilterPrefixCmd(gdb.Command): """Prefix command for 'show' frame-filter related operations.""" def __init__(self): super(ShowFilterPrefixCmd, self).__init__("show frame-filter", gdb.COMMAND_OBSCURE, gdb.COMPLETE_NONE, True) class InfoFrameFilter(gdb.Command): """List all registered Python frame-filters. Usage: info frame-filters""" def __init__(self): super(InfoFrameFilter, self).__init__("info frame-filter", gdb.COMMAND_DATA) @staticmethod def enabled_string(state): """Return "Yes" if filter is enabled, otherwise "No".""" if state: return "Yes" else: return "No" def print_list(self, title, frame_filters, blank_line): sorted_frame_filters = sorted(frame_filters.items(), key=lambda i: gdb.frames.get_priority(i[1]), reverse=True) if len(sorted_frame_filters) == 0: return 0 print(title) print(" Priority Enabled Name") for frame_filter in sorted_frame_filters: name = frame_filter[0] try: priority = '{:<8}'.format( str(gdb.frames.get_priority(frame_filter[1]))) enabled = '{:<7}'.format( self.enabled_string(gdb.frames.get_enabled(frame_filter[1]))) print(" %s %s %s" % (priority, enabled, name)) except Exception: e = sys.exc_info()[1] print(" Error printing filter '"+name+"': "+str(e)) if blank_line: print("") return 1 def invoke(self, arg, from_tty): any_printed = self.print_list("global frame-filters:", gdb.frame_filters, True) cp = gdb.current_progspace() any_printed += self.print_list("progspace %s frame-filters:" % cp.filename, cp.frame_filters, True) for objfile in gdb.objfiles(): any_printed += self.print_list("objfile %s frame-filters:" % objfile.filename, objfile.frame_filters, False) if any_printed == 0: print ("No frame filters.") # Internal enable/disable functions. def _enable_parse_arg(cmd_name, arg): """ Internal worker function to take an argument from enable/disable and return a tuple of arguments. Arguments: cmd_name: Name of the command invoking this function. args: The argument as a string. Returns: A tuple containing the dictionary, and the argument, or just the dictionary in the case of "all". """ argv = gdb.string_to_argv(arg); argc = len(argv) if argc == 0: raise gdb.GdbError(cmd_name + " requires an argument") if argv[0] == "all": if argc > 1: raise gdb.GdbError(cmd_name + ": with 'all' " \ "you may not specify a filter.") elif argc != 2: raise gdb.GdbError(cmd_name + " takes exactly two arguments.") return argv def _do_enable_frame_filter(command_tuple, flag): """Worker for enabling/disabling frame_filters. Arguments: command_type: A tuple with the first element being the frame filter dictionary, and the second being the frame filter name. flag: True for Enable, False for Disable. """ list_op = command_tuple[0] op_list = gdb.frames.return_list(list_op) if list_op == "all": for item in op_list: gdb.frames.set_enabled(item, flag) else: frame_filter = command_tuple[1] try: ff = op_list[frame_filter] except KeyError: msg = "frame-filter '" + str(frame_filter) + "' not found." raise gdb.GdbError(msg) gdb.frames.set_enabled(ff, flag) def _complete_frame_filter_list(text, word, all_flag): """Worker for frame filter dictionary name completion. Arguments: text: The full text of the command line. word: The most recent word of the command line. all_flag: Whether to include the word "all" in completion. Returns: A list of suggested frame filter dictionary name completions from text/word analysis. This list can be empty when there are no suggestions for completion. """ if all_flag == True: filter_locations = ["all", "global", "progspace"] else: filter_locations = ["global", "progspace"] for objfile in gdb.objfiles(): filter_locations.append(objfile.filename) # If the user just asked for completions with no completion # hints, just return all the frame filter dictionaries we know # about. if (text == ""): return filter_locations # Otherwise filter on what we know. flist = filter(lambda x,y=text:x.startswith(y), filter_locations) # If we only have one completion, complete it and return it. if len(flist) == 1: flist[0] = flist[0][len(text)-len(word):] # Otherwise, return an empty list, or a list of frame filter # dictionaries that the previous filter operation returned. return flist def _complete_frame_filter_name(word, printer_dict): """Worker for frame filter name completion. Arguments: word: The most recent word of the command line. printer_dict: The frame filter dictionary to search for frame filter name completions. Returns: A list of suggested frame filter name completions from word analysis of the frame filter dictionary. This list can be empty when there are no suggestions for completion. """ printer_keys = printer_dict.keys() if (word == ""): return printer_keys flist = filter(lambda x,y=word:x.startswith(y), printer_keys) return flist class EnableFrameFilter(gdb.Command): """GDB command to enable the specified frame-filter. Usage: enable frame-filter DICTIONARY [NAME] DICTIONARY is the name of the frame filter dictionary on which to operate. If dictionary is set to "all", perform operations on all dictionaries. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's frame filter dictionary. If either all, or the two named dictionaries are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame-filter to operate on.""" def __init__(self): super(EnableFrameFilter, self).__init__("enable frame-filter", gdb.COMMAND_DATA) def complete(self, text, word): """Completion function for both frame filter dictionary, and frame filter name.""" if text.count(" ") == 0: return _complete_frame_filter_list(text, word, True) else: printer_list = gdb.frames.return_list(text.split()[0].rstrip()) return _complete_frame_filter_name(word, printer_list) def invoke(self, arg, from_tty): command_tuple = _enable_parse_arg("enable frame-filter", arg) _do_enable_frame_filter(command_tuple, True) class DisableFrameFilter(gdb.Command): """GDB command to disable the specified frame-filter. Usage: disable frame-filter DICTIONARY [NAME] DICTIONARY is the name of the frame filter dictionary on which to operate. If dictionary is set to "all", perform operations on all dictionaries. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's frame filter dictionary. If either all, or the two named dictionaries are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame-filter to operate on.""" def __init__(self): super(DisableFrameFilter, self).__init__("disable frame-filter", gdb.COMMAND_DATA) def complete(self, text, word): """Completion function for both frame filter dictionary, and frame filter name.""" if text.count(" ") == 0: return _complete_frame_filter_list(text, word, True) else: printer_list = gdb.frames.return_list(text.split()[0].rstrip()) return _complete_frame_filter_name(word, printer_list) def invoke(self, arg, from_tty): command_tuple = _enable_parse_arg("disable frame-filter", arg) _do_enable_frame_filter(command_tuple, False) class SetFrameFilterPriority(gdb.Command): """GDB command to set the priority of the specified frame-filter. Usage: set frame-filter priority DICTIONARY NAME PRIORITY DICTIONARY is the name of the frame filter dictionary on which to operate. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's framefilter dictionary. If either of these two are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame filter to operate on. PRIORITY is the an integer to assign the new priority to the frame filter.""" def __init__(self): super(SetFrameFilterPriority, self).__init__("set frame-filter " \ "priority", gdb.COMMAND_DATA) def _parse_pri_arg(self, arg): """Internal worker to parse a priority from a tuple. Arguments: arg: Tuple which contains the arguments from the command. Returns: A tuple containing the dictionary, name and priority from the arguments. Raises: gdb.GdbError: An error parsing the arguments. """ argv = gdb.string_to_argv(arg); argc = len(argv) if argc != 3: print("set frame-filter priority " \ "takes exactly three arguments.") return None return argv def _set_filter_priority(self, command_tuple): """Internal worker for setting priority of frame-filters, by parsing a tuple and calling _set_priority with the parsed tuple. Arguments: command_tuple: Tuple which contains the arguments from the command. """ list_op = command_tuple[0] frame_filter = command_tuple[1] # GDB returns arguments as a string, so convert priority to # a number. priority = int(command_tuple[2]) op_list = gdb.frames.return_list(list_op) try: ff = op_list[frame_filter] except KeyError: msg = "frame-filter '" + str(frame_filter) + "' not found." raise gdb.GdbError(msg) gdb.frames.set_priority(ff, priority) def complete(self, text, word): """Completion function for both frame filter dictionary, and frame filter name.""" if text.count(" ") == 0: return _complete_frame_filter_list(text, word, False) else: printer_list = gdb.frames.return_list(text.split()[0].rstrip()) return _complete_frame_filter_name(word, printer_list) def invoke(self, arg, from_tty): command_tuple = self._parse_pri_arg(arg) if command_tuple != None: self._set_filter_priority(command_tuple) class ShowFrameFilterPriority(gdb.Command): """GDB command to show the priority of the specified frame-filter. Usage: show frame-filter priority DICTIONARY NAME DICTIONARY is the name of the frame filter dictionary on which to operate. Named dictionaries are: "global" for the global frame filter dictionary, "progspace" for the program space's framefilter dictionary. If either of these two are not specified, the dictionary name is assumed to be the name of an "objfile" -- a shared library or an executable. NAME matches the name of the frame-filter to operate on.""" def __init__(self): super(ShowFrameFilterPriority, self).__init__("show frame-filter " \ "priority", gdb.COMMAND_DATA) def _parse_pri_arg(self, arg): """Internal worker to parse a dictionary and name from a tuple. Arguments: arg: Tuple which contains the arguments from the command. Returns: A tuple containing the dictionary, and frame filter name. Raises: gdb.GdbError: An error parsing the arguments. """ argv = gdb.string_to_argv(arg); argc = len(argv) if argc != 2: print("show frame-filter priority " \ "takes exactly two arguments.") return None return argv def get_filter_priority(self, frame_filters, name): """Worker for retrieving the priority of frame_filters. Arguments: frame_filters: Name of frame filter dictionary. name: object to select printers. Returns: The priority of the frame filter. Raises: gdb.GdbError: A frame filter cannot be found. """ op_list = gdb.frames.return_list(frame_filters) try: ff = op_list[name] except KeyError: msg = "frame-filter '" + str(name) + "' not found." raise gdb.GdbError(msg) return gdb.frames.get_priority(ff) def complete(self, text, word): """Completion function for both frame filter dictionary, and frame filter name.""" if text.count(" ") == 0: return _complete_frame_filter_list(text, word, False) else: printer_list = frame._return_list(text.split()[0].rstrip()) return _complete_frame_filter_name(word, printer_list) def invoke(self, arg, from_tty): command_tuple = self._parse_pri_arg(arg) if command_tuple == None: return filter_name = command_tuple[1] list_name = command_tuple[0] try: priority = self.get_filter_priority(list_name, filter_name); except Exception: e = sys.exc_info()[1] print("Error printing filter priority for '"+name+"':"+str(e)) else: print("Priority of filter '" + filter_name + "' in list '" \ + list_name + "' is: " + str(priority)) # Register commands SetFilterPrefixCmd() ShowFilterPrefixCmd() InfoFrameFilter() EnableFrameFilter() DisableFrameFilter() SetFrameFilterPriority() ShowFrameFilterPriority() PKPD4]h0'0'gdb/command/xmethods.pynu[# Xmethod commands. # Copyright 2013-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gdb import re """GDB commands for working with xmethods.""" def validate_xm_regexp(part_name, regexp): try: return re.compile(regexp) except SyntaxError: raise SyntaxError("Invalid %s regexp: %s", part_name, regexp) def parse_xm_command_args(arg): """Parses the arguments passed to a xmethod command. Arguments: arg: The argument string passed to a xmethod command. Returns: A 3-tuple: (, , ) """ argv = gdb.string_to_argv(arg) argc = len(argv) if argc > 2: raise SyntaxError("Too many arguments to command.") locus_regexp = "" matcher_name_regexp = "" xm_name_regexp = None if argc >= 1: locus_regexp = argv[0] if argc == 2: parts = argv[1].split(";", 1) matcher_name_regexp = parts[0] if len(parts) > 1: xm_name_regexp = parts[1] if xm_name_regexp: name_re = validate_xm_regexp("xmethod name", xm_name_regexp) else: name_re = None return (validate_xm_regexp("locus", locus_regexp), validate_xm_regexp("matcher name", matcher_name_regexp), name_re) def get_global_method_matchers(locus_re, matcher_re): """Returns a dict of matching globally registered xmethods. Arguments: locus_re: Even though only globally registered xmethods are looked up, they will be looked up only if 'global' matches LOCUS_RE. matcher_re: The regular expression matching the names of xmethods. Returns: A dict of matching globally registered xmethod matchers. The only key in the dict will be 'global'. """ locus_str = "global" xm_dict = { locus_str: [] } if locus_re.match("global"): xm_dict[locus_str].extend( [m for m in gdb.xmethods if matcher_re.match(m.name)]) return xm_dict def get_method_matchers_in_loci(loci, locus_re, matcher_re): """Returns a dict of matching registered xmethods in the LOCI. Arguments: loci: The list of loci to lookup matching xmethods in. locus_re: If a locus is an objfile, then xmethod matchers will be looked up in it only if its filename matches the regular expression LOCUS_RE. If a locus is the current progspace, then xmethod matchers will be looked up in it only if the string "progspace" matches LOCUS_RE. matcher_re: The regular expression to match the xmethod matcher names. Returns: A dict of matching xmethod matchers. The keys of the dict are the filenames of the loci the xmethod matchers belong to. """ xm_dict = {} for locus in loci: if isinstance(locus, gdb.Progspace): if not locus_re.match('progspace'): continue locus_type = "progspace" else: if not locus_re.match(locus.filename): continue locus_type = "objfile" locus_str = "%s %s" % (locus_type, locus.filename) xm_dict[locus_str] = [ m for m in locus.xmethods if matcher_re.match(m.name)] return xm_dict def print_xm_info(xm_dict, name_re): """Print a dictionary of xmethods.""" def get_status_string(m): if not m.enabled: return " [disabled]" else: return "" if not xm_dict: return for locus_str in xm_dict: if not xm_dict[locus_str]: continue print ("Xmethods in %s:" % locus_str) for matcher in xm_dict[locus_str]: print (" %s%s" % (matcher.name, get_status_string(matcher))) if not matcher.methods: continue for m in matcher.methods: if name_re is None or name_re.match(m.name): print (" %s%s" % (m.name, get_status_string(m))) def set_xm_status1(xm_dict, name_re, status): """Set the status (enabled/disabled) of a dictionary of xmethods.""" for locus_str, matchers in xm_dict.items(): for matcher in matchers: if not name_re: # If the name regex is missing, then set the status of the # matcher and move on. matcher.enabled = status continue if not matcher.methods: # The methods attribute could be None. Move on. continue for m in matcher.methods: if name_re.match(m.name): m.enabled = status def set_xm_status(arg, status): """Set the status (enabled/disabled) of xmethods matching ARG. This is a helper function for enable/disable commands. ARG is the argument string passed to the commands. """ locus_re, matcher_re, name_re = parse_xm_command_args(arg) set_xm_status1(get_global_method_matchers(locus_re, matcher_re), name_re, status) set_xm_status1( get_method_matchers_in_loci( [gdb.current_progspace()], locus_re, matcher_re), name_re, status) set_xm_status1( get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re), name_re, status) class InfoXMethod(gdb.Command): """GDB command to list registered xmethod matchers. Usage: info xmethod [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the xmethod matchers. If it is omitted, all registered xmethod matchers from all loci are listed. A locus could be 'global', a regular expression matching the current program space's filename, or a regular expression matching filenames of objfiles. Locus could be 'progspace' to specify that only xmethods from the current progspace should be listed. NAME-REGEXP is a regular expression matching the names of xmethod matchers. If this omitted for a specified locus, then all registered xmethods in the locus are listed. To list only a certain xmethods managed by a single matcher, the name regexp can be specified as matcher-name-regexp;xmethod-name-regexp.""" def __init__(self): super(InfoXMethod, self).__init__("info xmethod", gdb.COMMAND_DATA) def invoke(self, arg, from_tty): locus_re, matcher_re, name_re = parse_xm_command_args(arg) print_xm_info(get_global_method_matchers(locus_re, matcher_re), name_re) print_xm_info( get_method_matchers_in_loci( [gdb.current_progspace()], locus_re, matcher_re), name_re) print_xm_info( get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re), name_re) class EnableXMethod(gdb.Command): """GDB command to enable a specified (group of) xmethod(s). Usage: enable xmethod [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the xmethod matchers. If it is omitted, all registered xmethods matchers from all loci are enabled. A locus could be 'global', a regular expression matching the current program space's filename, or a regular expression matching filenames of objfiles. Locus could be 'progspace' to specify that only xmethods from the current progspace should be enabled. NAME-REGEXP is a regular expression matching the names of xmethods within a given locus. If this omitted for a specified locus, then all registered xmethod matchers in the locus are enabled. To enable only a certain xmethods managed by a single matcher, the name regexp can be specified as matcher-name-regexp;xmethod-name-regexp.""" def __init__(self): super(EnableXMethod, self).__init__("enable xmethod", gdb.COMMAND_DATA) def invoke(self, arg, from_tty): set_xm_status(arg, True) class DisableXMethod(gdb.Command): """GDB command to disable a specified (group of) xmethod(s). Usage: disable xmethod [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the xmethod matchers. If it is omitted, all registered xmethod matchers from all loci are disabled. A locus could be 'global', a regular expression matching the current program space's filename, or a regular expression filenames of objfiles. Locus could be 'progspace' to specify that only xmethods from the current progspace should be disabled. NAME-REGEXP is a regular expression matching the names of xmethods within a given locus. If this omitted for a specified locus, then all registered xmethod matchers in the locus are disabled. To disable only a certain xmethods managed by a single matcher, the name regexp can be specified as matcher-name-regexp;xmethod-name-regexp.""" def __init__(self): super(DisableXMethod, self).__init__("disable xmethod", gdb.COMMAND_DATA) def invoke(self, arg, from_tty): set_xm_status(arg, False) def register_xmethod_commands(): """Installs the xmethod commands.""" InfoXMethod() EnableXMethod() DisableXMethod() register_xmethod_commands() PKPD4]_Vyygdb/command/unwinders.pynu[# Unwinder commands. # Copyright 2015-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gdb import re def validate_regexp(exp, idstring): try: return re.compile(exp) except SyntaxError: raise SyntaxError("Invalid %s regexp: %s." % (idstring, exp)) def parse_unwinder_command_args(arg): """Internal utility to parse unwinder command argv. Arguments: arg: The arguments to the command. The format is: [locus-regexp [name-regexp]] Returns: A 2-tuple of compiled regular expressions. Raises: SyntaxError: an error processing ARG """ argv = gdb.string_to_argv(arg) argc = len(argv) if argc > 2: raise SyntaxError("Too many arguments.") locus_regexp = "" name_regexp = "" if argc >= 1: locus_regexp = argv[0] if argc >= 2: name_regexp = argv[1] return (validate_regexp(locus_regexp, "locus"), validate_regexp(name_regexp, "unwinder")) class InfoUnwinder(gdb.Command): """GDB command to list unwinders. Usage: info unwinder [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression matching the location of the unwinder. If it is omitted, all registered unwinders from all loci are listed. A locus can be 'global', 'progspace' to list the unwinders from the current progspace, or a regular expression matching filenames of objfiles. NAME-REGEXP is a regular expression to filter unwinder names. If this omitted for a specified locus, then all registered unwinders in the locus are listed.""" def __init__(self): super(InfoUnwinder, self).__init__("info unwinder", gdb.COMMAND_STACK) def list_unwinders(self, title, unwinders, name_re): """Lists the unwinders whose name matches regexp. Arguments: title: The line to print before the list. unwinders: The list of the unwinders. name_re: unwinder name filter. """ if not unwinders: return print(title) for unwinder in unwinders: if name_re.match(unwinder.name): print(" %s%s" % (unwinder.name, "" if unwinder.enabled else " [disabled]")) def invoke(self, arg, from_tty): locus_re, name_re = parse_unwinder_command_args(arg) if locus_re.match("global"): self.list_unwinders("Global:", gdb.frame_unwinders, name_re) if locus_re.match("progspace"): cp = gdb.current_progspace() self.list_unwinders("Progspace %s:" % cp.filename, cp.frame_unwinders, name_re) for objfile in gdb.objfiles(): if locus_re.match(objfile.filename): self.list_unwinders("Objfile %s:" % objfile.filename, objfile.frame_unwinders, name_re) def do_enable_unwinder1(unwinders, name_re, flag): """Enable/disable unwinders whose names match given regex. Arguments: unwinders: The list of unwinders. name_re: Unwinder name filter. flag: Enable/disable. Returns: The number of unwinders affected. """ total = 0 for unwinder in unwinders: if name_re.match(unwinder.name): unwinder.enabled = flag total += 1 return total def do_enable_unwinder(arg, flag): """Enable/disable unwinder(s).""" (locus_re, name_re) = parse_unwinder_command_args(arg) total = 0 if locus_re.match("global"): total += do_enable_unwinder1(gdb.frame_unwinders, name_re, flag) if locus_re.match("progspace"): total += do_enable_unwinder1(gdb.current_progspace().frame_unwinders, name_re, flag) for objfile in gdb.objfiles(): if locus_re.match(objfile.filename): total += do_enable_unwinder1(objfile.frame_unwinders, name_re, flag) if total > 0: gdb.invalidate_cached_frames() print("%d unwinder%s %s" % (total, "" if total == 1 else "s", "enabled" if flag else "disabled")) class EnableUnwinder(gdb.Command): """GDB command to enable unwinders. Usage: enable unwinder [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression specifying the unwinders to enable. It can 'global', 'progspace', or the name of an objfile within that progspace. NAME_REGEXP is a regular expression to filter unwinder names. If this omitted for a specified locus, then all registered unwinders in the locus are affected.""" def __init__(self): super(EnableUnwinder, self).__init__("enable unwinder", gdb.COMMAND_STACK) def invoke(self, arg, from_tty): """GDB calls this to perform the command.""" do_enable_unwinder(arg, True) class DisableUnwinder(gdb.Command): """GDB command to disable the specified unwinder. Usage: disable unwinder [LOCUS-REGEXP [NAME-REGEXP]] LOCUS-REGEXP is a regular expression specifying the unwinders to disable. It can 'global', 'progspace', or the name of an objfile within that progspace. NAME_REGEXP is a regular expression to filter unwinder names. If this omitted for a specified locus, then all registered unwinders in the locus are affected.""" def __init__(self): super(DisableUnwinder, self).__init__("disable unwinder", gdb.COMMAND_STACK) def invoke(self, arg, from_tty): """GDB calls this to perform the command.""" do_enable_unwinder(arg, False) def register_unwinder_commands(): """Installs the unwinder commands.""" InfoUnwinder() EnableUnwinder() DisableUnwinder() register_unwinder_commands() PKPD4]=6%8%8gdb/command/pretty_printers.pynu[# Pretty-printer commands. # Copyright (C) 2010-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """GDB commands for working with pretty-printers.""" import copy import gdb import re def parse_printer_regexps(arg): """Internal utility to parse a pretty-printer command argv. Arguments: arg: The arguments to the command. The format is: [object-regexp [name-regexp]]. Individual printers in a collection are named as printer-name;subprinter-name. Returns: The result is a 3-tuple of compiled regular expressions, except that the resulting compiled subprinter regexp is None if not provided. Raises: SyntaxError: an error processing ARG """ argv = gdb.string_to_argv(arg); argc = len(argv) object_regexp = "" # match everything name_regexp = "" # match everything subname_regexp = None if argc > 3: raise SyntaxError("too many arguments") if argc >= 1: object_regexp = argv[0] if argc >= 2: name_subname = argv[1].split(";", 1) name_regexp = name_subname[0] if len(name_subname) == 2: subname_regexp = name_subname[1] # That re.compile raises SyntaxError was determined empirically. # We catch it and reraise it to provide a slightly more useful # error message for the user. try: object_re = re.compile(object_regexp) except SyntaxError: raise SyntaxError("invalid object regexp: %s" % object_regexp) try: name_re = re.compile (name_regexp) except SyntaxError: raise SyntaxError("invalid name regexp: %s" % name_regexp) if subname_regexp is not None: try: subname_re = re.compile(subname_regexp) except SyntaxError: raise SyntaxError("invalid subname regexp: %s" % subname_regexp) else: subname_re = None return(object_re, name_re, subname_re) def printer_enabled_p(printer): """Internal utility to see if printer (or subprinter) is enabled.""" if hasattr(printer, "enabled"): return printer.enabled else: return True class InfoPrettyPrinter(gdb.Command): """GDB command to list all registered pretty-printers. Usage: info pretty-printer [OBJECT-REGEXP [NAME-REGEXP]] OBJECT-REGEXP is a regular expression matching the objects to list. Objects are "global", the program space's file, and the objfiles within that program space. NAME-REGEXP matches the name of the pretty-printer. Individual printers in a collection are named as printer-name;subprinter-name.""" def __init__ (self): super(InfoPrettyPrinter, self).__init__("info pretty-printer", gdb.COMMAND_DATA) @staticmethod def enabled_string(printer): """Return "" if PRINTER is enabled, otherwise " [disabled]".""" if printer_enabled_p(printer): return "" else: return " [disabled]" @staticmethod def printer_name(printer): """Return the printer's name.""" if hasattr(printer, "name"): return printer.name if hasattr(printer, "__name__"): return printer.__name__ # This "shouldn't happen", but the public API allows for # direct additions to the pretty-printer list, and we shouldn't # crash because someone added a bogus printer. # Plus we want to give the user a way to list unknown printers. return "unknown" def list_pretty_printers(self, pretty_printers, name_re, subname_re): """Print a list of pretty-printers.""" # A potential enhancement is to provide an option to list printers in # "lookup order" (i.e. unsorted). sorted_pretty_printers = sorted (copy.copy(pretty_printers), key = self.printer_name) for printer in sorted_pretty_printers: name = self.printer_name(printer) enabled = self.enabled_string(printer) if name_re.match(name): print (" %s%s" % (name, enabled)) if (hasattr(printer, "subprinters") and printer.subprinters is not None): sorted_subprinters = sorted (copy.copy(printer.subprinters), key = self.printer_name) for subprinter in sorted_subprinters: if (not subname_re or subname_re.match(subprinter.name)): print (" %s%s" % (subprinter.name, self.enabled_string(subprinter))) def invoke1(self, title, printer_list, obj_name_to_match, object_re, name_re, subname_re): """Subroutine of invoke to simplify it.""" if printer_list and object_re.match(obj_name_to_match): print (title) self.list_pretty_printers(printer_list, name_re, subname_re) def invoke(self, arg, from_tty): """GDB calls this to perform the command.""" (object_re, name_re, subname_re) = parse_printer_regexps(arg) self.invoke1("global pretty-printers:", gdb.pretty_printers, "global", object_re, name_re, subname_re) cp = gdb.current_progspace() self.invoke1("progspace %s pretty-printers:" % cp.filename, cp.pretty_printers, "progspace", object_re, name_re, subname_re) for objfile in gdb.objfiles(): self.invoke1("objfile %s pretty-printers:" % objfile.filename, objfile.pretty_printers, objfile.filename, object_re, name_re, subname_re) def count_enabled_printers(pretty_printers): """Return a 2-tuple of number of enabled and total printers.""" enabled = 0 total = 0 for printer in pretty_printers: if (hasattr(printer, "subprinters") and printer.subprinters is not None): if printer_enabled_p(printer): for subprinter in printer.subprinters: if printer_enabled_p(subprinter): enabled += 1 total += len(printer.subprinters) else: if printer_enabled_p(printer): enabled += 1 total += 1 return (enabled, total) def count_all_enabled_printers(): """Return a 2-tuble of the enabled state and total number of all printers. This includes subprinters. """ enabled_count = 0 total_count = 0 (t_enabled, t_total) = count_enabled_printers(gdb.pretty_printers) enabled_count += t_enabled total_count += t_total (t_enabled, t_total) = count_enabled_printers(gdb.current_progspace().pretty_printers) enabled_count += t_enabled total_count += t_total for objfile in gdb.objfiles(): (t_enabled, t_total) = count_enabled_printers(objfile.pretty_printers) enabled_count += t_enabled total_count += t_total return (enabled_count, total_count) def pluralize(text, n, suffix="s"): """Return TEXT pluralized if N != 1.""" if n != 1: return "%s%s" % (text, suffix) else: return text def show_pretty_printer_enabled_summary(): """Print the number of printers enabled/disabled. We count subprinters individually. """ (enabled_count, total_count) = count_all_enabled_printers() print ("%d of %d printers enabled" % (enabled_count, total_count)) def do_enable_pretty_printer_1 (pretty_printers, name_re, subname_re, flag): """Worker for enabling/disabling pretty-printers. Arguments: pretty_printers: list of pretty-printers name_re: regular-expression object to select printers subname_re: regular expression object to select subprinters or None if all are affected flag: True for Enable, False for Disable Returns: The number of printers affected. This is just for informational purposes for the user. """ total = 0 for printer in pretty_printers: if (hasattr(printer, "name") and name_re.match(printer.name) or hasattr(printer, "__name__") and name_re.match(printer.__name__)): if (hasattr(printer, "subprinters") and printer.subprinters is not None): if not subname_re: # Only record printers that change state. if printer_enabled_p(printer) != flag: for subprinter in printer.subprinters: if printer_enabled_p(subprinter): total += 1 # NOTE: We preserve individual subprinter settings. printer.enabled = flag else: # NOTE: Whether this actually disables the subprinter # depends on whether the printer's lookup function supports # the "enable" API. We can only assume it does. for subprinter in printer.subprinters: if subname_re.match(subprinter.name): # Only record printers that change state. if (printer_enabled_p(printer) and printer_enabled_p(subprinter) != flag): total += 1 subprinter.enabled = flag else: # This printer has no subprinters. # If the user does "disable pretty-printer .* .* foo" # should we disable printers that don't have subprinters? # How do we apply "foo" in this context? Since there is no # "foo" subprinter it feels like we should skip this printer. # There's still the issue of how to handle # "disable pretty-printer .* .* .*", and every other variation # that can match everything. For now punt and only support # "disable pretty-printer .* .*" (i.e. subname is elided) # to disable everything. if not subname_re: # Only record printers that change state. if printer_enabled_p(printer) != flag: total += 1 printer.enabled = flag return total def do_enable_pretty_printer (arg, flag): """Internal worker for enabling/disabling pretty-printers.""" (object_re, name_re, subname_re) = parse_printer_regexps(arg) total = 0 if object_re.match("global"): total += do_enable_pretty_printer_1(gdb.pretty_printers, name_re, subname_re, flag) cp = gdb.current_progspace() if object_re.match("progspace"): total += do_enable_pretty_printer_1(cp.pretty_printers, name_re, subname_re, flag) for objfile in gdb.objfiles(): if object_re.match(objfile.filename): total += do_enable_pretty_printer_1(objfile.pretty_printers, name_re, subname_re, flag) if flag: state = "enabled" else: state = "disabled" print ("%d %s %s" % (total, pluralize("printer", total), state)) # Print the total list of printers currently enabled/disabled. # This is to further assist the user in determining whether the result # is expected. Since we use regexps to select it's useful. show_pretty_printer_enabled_summary() # Enable/Disable one or more pretty-printers. # # This is intended for use when a broken pretty-printer is shipped/installed # and the user wants to disable that printer without disabling all the other # printers. # # A useful addition would be -v (verbose) to show each printer affected. class EnablePrettyPrinter (gdb.Command): """GDB command to enable the specified pretty-printer. Usage: enable pretty-printer [OBJECT-REGEXP [NAME-REGEXP]] OBJECT-REGEXP is a regular expression matching the objects to examine. Objects are "global", the program space's file, and the objfiles within that program space. NAME-REGEXP matches the name of the pretty-printer. Individual printers in a collection are named as printer-name;subprinter-name.""" def __init__(self): super(EnablePrettyPrinter, self).__init__("enable pretty-printer", gdb.COMMAND_DATA) def invoke(self, arg, from_tty): """GDB calls this to perform the command.""" do_enable_pretty_printer(arg, True) class DisablePrettyPrinter (gdb.Command): """GDB command to disable the specified pretty-printer. Usage: disable pretty-printer [OBJECT-REGEXP [NAME-REGEXP]] OBJECT-REGEXP is a regular expression matching the objects to examine. Objects are "global", the program space's file, and the objfiles within that program space. NAME-REGEXP matches the name of the pretty-printer. Individual printers in a collection are named as printer-name;subprinter-name.""" def __init__(self): super(DisablePrettyPrinter, self).__init__("disable pretty-printer", gdb.COMMAND_DATA) def invoke(self, arg, from_tty): """GDB calls this to perform the command.""" do_enable_pretty_printer(arg, False) def register_pretty_printer_commands(): """Call from a top level script to install the pretty-printer commands.""" InfoPrettyPrinter() EnablePrettyPrinter() DisablePrettyPrinter() register_pretty_printer_commands() PKPD4]ꊑͶgdb/command/__init__.pynu[# Copyright (C) 2010-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . PKPD4]UTJ))gdb/command/type_printers.pynu[# Type printer commands. # Copyright (C) 2010-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import copy import gdb """GDB commands for working with type-printers.""" class InfoTypePrinter(gdb.Command): """GDB command to list all registered type-printers. Usage: info type-printers""" def __init__ (self): super(InfoTypePrinter, self).__init__("info type-printers", gdb.COMMAND_DATA) def list_type_printers(self, type_printers): """Print a list of type printers.""" # A potential enhancement is to provide an option to list printers in # "lookup order" (i.e. unsorted). sorted_type_printers = sorted (copy.copy(type_printers), key = lambda x: x.name) for printer in sorted_type_printers: if printer.enabled: enabled = '' else: enabled = " [disabled]" print (" %s%s" % (printer.name, enabled)) def invoke(self, arg, from_tty): """GDB calls this to perform the command.""" sep = '' for objfile in gdb.objfiles(): if objfile.type_printers: print ("%sType printers for %s:" % (sep, objfile.filename)) self.list_type_printers(objfile.type_printers) sep = '\n' if gdb.current_progspace().type_printers: print ("%sType printers for program space:" % sep) self.list_type_printers(gdb.current_progspace().type_printers) sep = '\n' if gdb.type_printers: print ("%sGlobal type printers:" % sep) self.list_type_printers(gdb.type_printers) class _EnableOrDisableCommand(gdb.Command): def __init__(self, setting, name): super(_EnableOrDisableCommand, self).__init__(name, gdb.COMMAND_DATA) self.setting = setting def set_some(self, name, printers): result = False for p in printers: if name == p.name: p.enabled = self.setting result = True return result def invoke(self, arg, from_tty): """GDB calls this to perform the command.""" for name in arg.split(): ok = False for objfile in gdb.objfiles(): if self.set_some(name, objfile.type_printers): ok = True if self.set_some(name, gdb.current_progspace().type_printers): ok = True if self.set_some(name, gdb.type_printers): ok = True if not ok: print ("No type printer named '%s'" % name) def add_some(self, result, word, printers): for p in printers: if p.name.startswith(word): result.append(p.name) def complete(self, text, word): result = [] for objfile in gdb.objfiles(): self.add_some(result, word, objfile.type_printers) self.add_some(result, word, gdb.current_progspace().type_printers) self.add_some(result, word, gdb.type_printers) return result class EnableTypePrinter(_EnableOrDisableCommand): """GDB command to enable the specified type printer. Usage: enable type-printer NAME NAME is the name of the type-printer.""" def __init__(self): super(EnableTypePrinter, self).__init__(True, "enable type-printer") class DisableTypePrinter(_EnableOrDisableCommand): """GDB command to disable the specified type-printer. Usage: disable type-printer NAME NAME is the name of the type-printer.""" def __init__(self): super(DisableTypePrinter, self).__init__(False, "disable type-printer") InfoTypePrinter() EnableTypePrinter() DisableTypePrinter() PKPD4]$DhDhgdb/command/explore.pynu[# GDB 'explore' command. # Copyright (C) 2012-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Implementation of the GDB 'explore' command using the GDB Python API.""" import gdb import sys if sys.version_info[0] > 2: # Python 3 renamed raw_input to input raw_input = input class Explorer(object): """Internal class which invokes other explorers.""" # This map is filled by the Explorer.init_env() function type_code_to_explorer_map = { } _SCALAR_TYPE_LIST = ( gdb.TYPE_CODE_CHAR, gdb.TYPE_CODE_INT, gdb.TYPE_CODE_BOOL, gdb.TYPE_CODE_FLT, gdb.TYPE_CODE_VOID, gdb.TYPE_CODE_ENUM, ) @staticmethod def guard_expr(expr): length = len(expr) guard = False if expr[0] == '(' and expr[length-1] == ')': pass else: i = 0 while i < length: c = expr[i] if (c == '_' or ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z') or ('0' <= c and c <= '9')): pass else: guard = True break i += 1 if guard: return "(" + expr + ")" else: return expr @staticmethod def explore_expr(expr, value, is_child): """Main function to explore an expression value. Arguments: expr: The expression string that is being explored. value: The gdb.Value value of the expression. is_child: Boolean value to indicate if the expression is a child. An expression is a child if it is derived from the main expression entered by the user. For example, if the user entered an expression which evaluates to a struct, then when exploring the fields of the struct, is_child is set to True internally. Returns: No return value. """ type_code = value.type.code if type_code in Explorer.type_code_to_explorer_map: explorer_class = Explorer.type_code_to_explorer_map[type_code] while explorer_class.explore_expr(expr, value, is_child): pass else: print ("Explorer for type '%s' not yet available.\n" % str(value.type)) @staticmethod def explore_type(name, datatype, is_child): """Main function to explore a data type. Arguments: name: The string representing the path to the data type being explored. datatype: The gdb.Type value of the data type being explored. is_child: Boolean value to indicate if the name is a child. A name is a child if it is derived from the main name entered by the user. For example, if the user entered the name of struct type, then when exploring the fields of the struct, is_child is set to True internally. Returns: No return value. """ type_code = datatype.code if type_code in Explorer.type_code_to_explorer_map: explorer_class = Explorer.type_code_to_explorer_map[type_code] while explorer_class.explore_type(name, datatype, is_child): pass else: print ("Explorer for type '%s' not yet available.\n" % str(datatype)) @staticmethod def init_env(): """Initializes the Explorer environment. This function should be invoked before starting any exploration. If invoked before an exploration, it need not be invoked for subsequent explorations. """ Explorer.type_code_to_explorer_map = { gdb.TYPE_CODE_CHAR : ScalarExplorer, gdb.TYPE_CODE_INT : ScalarExplorer, gdb.TYPE_CODE_BOOL : ScalarExplorer, gdb.TYPE_CODE_FLT : ScalarExplorer, gdb.TYPE_CODE_VOID : ScalarExplorer, gdb.TYPE_CODE_ENUM : ScalarExplorer, gdb.TYPE_CODE_STRUCT : CompoundExplorer, gdb.TYPE_CODE_UNION : CompoundExplorer, gdb.TYPE_CODE_PTR : PointerExplorer, gdb.TYPE_CODE_REF : ReferenceExplorer, gdb.TYPE_CODE_RVALUE_REF : ReferenceExplorer, gdb.TYPE_CODE_TYPEDEF : TypedefExplorer, gdb.TYPE_CODE_ARRAY : ArrayExplorer } @staticmethod def is_scalar_type(type): """Checks whether a type is a scalar type. A type is a scalar type of its type is gdb.TYPE_CODE_CHAR or gdb.TYPE_CODE_INT or gdb.TYPE_CODE_BOOL or gdb.TYPE_CODE_FLT or gdb.TYPE_CODE_VOID or gdb.TYPE_CODE_ENUM. Arguments: type: The type to be checked. Returns: 'True' if 'type' is a scalar type. 'False' otherwise. """ return type.code in Explorer._SCALAR_TYPE_LIST @staticmethod def return_to_parent_value(): """A utility function which prints that the current exploration session is returning to the parent value. Useful when exploring values. """ print ("\nReturning to parent value...\n") @staticmethod def return_to_parent_value_prompt(): """A utility function which prompts the user to press the 'enter' key so that the exploration session can shift back to the parent value. Useful when exploring values. """ raw_input("\nPress enter to return to parent value: ") @staticmethod def return_to_enclosing_type(): """A utility function which prints that the current exploration session is returning to the enclosing type. Useful when exploring types. """ print ("\nReturning to enclosing type...\n") @staticmethod def return_to_enclosing_type_prompt(): """A utility function which prompts the user to press the 'enter' key so that the exploration session can shift back to the enclosing type. Useful when exploring types. """ raw_input("\nPress enter to return to enclosing type: ") class ScalarExplorer(object): """Internal class used to explore scalar values.""" @staticmethod def explore_expr(expr, value, is_child): """Function to explore scalar values. See Explorer.explore_expr and Explorer.is_scalar_type for more information. """ print ("'%s' is a scalar value of type '%s'." % (expr, value.type)) print ("%s = %s" % (expr, str(value))) if is_child: Explorer.return_to_parent_value_prompt() Explorer.return_to_parent_value() return False @staticmethod def explore_type(name, datatype, is_child): """Function to explore scalar types. See Explorer.explore_type and Explorer.is_scalar_type for more information. """ if datatype.code == gdb.TYPE_CODE_ENUM: if is_child: print ("%s is of an enumerated type '%s'." % (name, str(datatype))) else: print ("'%s' is an enumerated type." % name) else: if is_child: print ("%s is of a scalar type '%s'." % (name, str(datatype))) else: print ("'%s' is a scalar type." % name) if is_child: Explorer.return_to_enclosing_type_prompt() Explorer.return_to_enclosing_type() return False class PointerExplorer(object): """Internal class used to explore pointer values.""" @staticmethod def explore_expr(expr, value, is_child): """Function to explore pointer values. See Explorer.explore_expr for more information. """ print ("'%s' is a pointer to a value of type '%s'" % (expr, str(value.type.target()))) option = raw_input("Continue exploring it as a pointer to a single " "value [y/n]: ") if option == "y": deref_value = None try: deref_value = value.dereference() str(deref_value) except gdb.MemoryError: print ("'%s' a pointer pointing to an invalid memory " "location." % expr) if is_child: Explorer.return_to_parent_value_prompt() return False Explorer.explore_expr("*%s" % Explorer.guard_expr(expr), deref_value, is_child) return False option = raw_input("Continue exploring it as a pointer to an " "array [y/n]: ") if option == "y": while True: index = 0 try: index = int(raw_input("Enter the index of the element you " "want to explore in '%s': " % expr)) except ValueError: break element_expr = "%s[%d]" % (Explorer.guard_expr(expr), index) element = value[index] try: str(element) except gdb.MemoryError: print ("Cannot read value at index %d." % index) continue Explorer.explore_expr(element_expr, element, True) return False if is_child: Explorer.return_to_parent_value() return False @staticmethod def explore_type(name, datatype, is_child): """Function to explore pointer types. See Explorer.explore_type for more information. """ target_type = datatype.target() print ("\n%s is a pointer to a value of type '%s'." % (name, str(target_type))) Explorer.explore_type("the pointee type of %s" % name, target_type, is_child) return False class ReferenceExplorer(object): """Internal class used to explore reference (TYPE_CODE_REF) values.""" @staticmethod def explore_expr(expr, value, is_child): """Function to explore array values. See Explorer.explore_expr for more information. """ referenced_value = value.referenced_value() Explorer.explore_expr(expr, referenced_value, is_child) return False @staticmethod def explore_type(name, datatype, is_child): """Function to explore pointer types. See Explorer.explore_type for more information. """ target_type = datatype.target() Explorer.explore_type(name, target_type, is_child) return False class ArrayExplorer(object): """Internal class used to explore arrays.""" @staticmethod def explore_expr(expr, value, is_child): """Function to explore array values. See Explorer.explore_expr for more information. """ target_type = value.type.target() print ("'%s' is an array of '%s'." % (expr, str(target_type))) index = 0 try: index = int(raw_input("Enter the index of the element you want to " "explore in '%s': " % expr)) except ValueError: if is_child: Explorer.return_to_parent_value() return False element = None try: element = value[index] str(element) except gdb.MemoryError: print ("Cannot read value at index %d." % index) raw_input("Press enter to continue... ") return True Explorer.explore_expr("%s[%d]" % (Explorer.guard_expr(expr), index), element, True) return True @staticmethod def explore_type(name, datatype, is_child): """Function to explore array types. See Explorer.explore_type for more information. """ target_type = datatype.target() print ("%s is an array of '%s'." % (name, str(target_type))) Explorer.explore_type("the array element of %s" % name, target_type, is_child) return False class CompoundExplorer(object): """Internal class used to explore struct, classes and unions.""" @staticmethod def _print_fields(print_list): """Internal function which prints the fields of a struct/class/union. """ max_field_name_length = 0 for pair in print_list: if max_field_name_length < len(pair[0]): max_field_name_length = len(pair[0]) for pair in print_list: print (" %*s = %s" % (max_field_name_length, pair[0], pair[1])) @staticmethod def _get_real_field_count(fields): real_field_count = 0; for field in fields: if not field.artificial: real_field_count = real_field_count + 1 return real_field_count @staticmethod def explore_expr(expr, value, is_child): """Function to explore structs/classes and union values. See Explorer.explore_expr for more information. """ datatype = value.type type_code = datatype.code fields = datatype.fields() if type_code == gdb.TYPE_CODE_STRUCT: type_desc = "struct/class" else: type_desc = "union" if CompoundExplorer._get_real_field_count(fields) == 0: print ("The value of '%s' is a %s of type '%s' with no fields." % (expr, type_desc, str(value.type))) if is_child: Explorer.return_to_parent_value_prompt() return False print ("The value of '%s' is a %s of type '%s' with the following " "fields:\n" % (expr, type_desc, str(value.type))) has_explorable_fields = False choice_to_compound_field_map = { } current_choice = 0 print_list = [ ] for field in fields: if field.artificial: continue field_full_name = Explorer.guard_expr(expr) + "." + field.name if field.is_base_class: field_value = value.cast(field.type) else: field_value = value[field.name] literal_value = "" if type_code == gdb.TYPE_CODE_UNION: literal_value = ("" % (current_choice, str(field.type))) has_explorable_fields = True else: if Explorer.is_scalar_type(field.type): literal_value = ("%s .. (Value of type '%s')" % (str(field_value), str(field.type))) else: if field.is_base_class: field_desc = "base class" else: field_desc = "field" literal_value = ("" % (current_choice, field_desc, str(field.type))) has_explorable_fields = True choice_to_compound_field_map[str(current_choice)] = ( field_full_name, field_value) current_choice = current_choice + 1 print_list.append((field.name, literal_value)) CompoundExplorer._print_fields(print_list) print ("") if has_explorable_fields: choice = raw_input("Enter the field number of choice: ") if choice in choice_to_compound_field_map: Explorer.explore_expr(choice_to_compound_field_map[choice][0], choice_to_compound_field_map[choice][1], True) return True else: if is_child: Explorer.return_to_parent_value() else: if is_child: Explorer.return_to_parent_value_prompt() return False @staticmethod def explore_type(name, datatype, is_child): """Function to explore struct/class and union types. See Explorer.explore_type for more information. """ type_code = datatype.code type_desc = "" if type_code == gdb.TYPE_CODE_STRUCT: type_desc = "struct/class" else: type_desc = "union" fields = datatype.fields() if CompoundExplorer._get_real_field_count(fields) == 0: if is_child: print ("%s is a %s of type '%s' with no fields." % (name, type_desc, str(datatype))) Explorer.return_to_enclosing_type_prompt() else: print ("'%s' is a %s with no fields." % (name, type_desc)) return False if is_child: print ("%s is a %s of type '%s' " "with the following fields:\n" % (name, type_desc, str(datatype))) else: print ("'%s' is a %s with the following " "fields:\n" % (name, type_desc)) has_explorable_fields = False current_choice = 0 choice_to_compound_field_map = { } print_list = [ ] for field in fields: if field.artificial: continue if field.is_base_class: field_desc = "base class" else: field_desc = "field" rhs = ("" % (current_choice, field_desc, str(field.type))) print_list.append((field.name, rhs)) choice_to_compound_field_map[str(current_choice)] = ( field.name, field.type, field_desc) current_choice = current_choice + 1 CompoundExplorer._print_fields(print_list) print ("") if len(choice_to_compound_field_map) > 0: choice = raw_input("Enter the field number of choice: ") if choice in choice_to_compound_field_map: if is_child: new_name = ("%s '%s' of %s" % (choice_to_compound_field_map[choice][2], choice_to_compound_field_map[choice][0], name)) else: new_name = ("%s '%s' of '%s'" % (choice_to_compound_field_map[choice][2], choice_to_compound_field_map[choice][0], name)) Explorer.explore_type(new_name, choice_to_compound_field_map[choice][1], True) return True else: if is_child: Explorer.return_to_enclosing_type() else: if is_child: Explorer.return_to_enclosing_type_prompt() return False class TypedefExplorer(object): """Internal class used to explore values whose type is a typedef.""" @staticmethod def explore_expr(expr, value, is_child): """Function to explore typedef values. See Explorer.explore_expr for more information. """ actual_type = value.type.strip_typedefs() print ("The value of '%s' is of type '%s' " "which is a typedef of type '%s'" % (expr, str(value.type), str(actual_type))) Explorer.explore_expr(expr, value.cast(actual_type), is_child) return False @staticmethod def explore_type(name, datatype, is_child): """Function to explore typedef types. See Explorer.explore_type for more information. """ actual_type = datatype.strip_typedefs() if is_child: print ("The type of %s is a typedef of type '%s'." % (name, str(actual_type))) else: print ("The type '%s' is a typedef of type '%s'." % (name, str(actual_type))) Explorer.explore_type(name, actual_type, is_child) return False class ExploreUtils(object): """Internal class which provides utilities for the main command classes.""" @staticmethod def check_args(name, arg_str): """Utility to check if adequate number of arguments are passed to an explore command. Arguments: name: The name of the explore command. arg_str: The argument string passed to the explore command. Returns: True if adequate arguments are passed, false otherwise. Raises: gdb.GdbError if adequate arguments are not passed. """ if len(arg_str) < 1: raise gdb.GdbError("ERROR: '%s' requires an argument." % name) return False else: return True @staticmethod def get_type_from_str(type_str): """A utility function to deduce the gdb.Type value from a string representing the type. Arguments: type_str: The type string from which the gdb.Type value should be deduced. Returns: The deduced gdb.Type value if possible, None otherwise. """ try: # Assume the current language to be C/C++ and make a try. return gdb.parse_and_eval("(%s *)0" % type_str).type.target() except RuntimeError: # If assumption of current language to be C/C++ was wrong, then # lookup the type using the API. try: return gdb.lookup_type(type_str) except RuntimeError: return None @staticmethod def get_value_from_str(value_str): """A utility function to deduce the gdb.Value value from a string representing the value. Arguments: value_str: The value string from which the gdb.Value value should be deduced. Returns: The deduced gdb.Value value if possible, None otherwise. """ try: return gdb.parse_and_eval(value_str) except RuntimeError: return None class ExploreCommand(gdb.Command): """Explore a value or a type valid in the current context. Usage: explore ARG - ARG is either a valid expression or a type name. - At any stage of exploration, hit the return key (instead of a choice, if any) to return to the enclosing type or value.""" def __init__(self): super(ExploreCommand, self).__init__(name = "explore", command_class = gdb.COMMAND_DATA, prefix = True) def invoke(self, arg_str, from_tty): if ExploreUtils.check_args("explore", arg_str) == False: return # Check if it is a value value = ExploreUtils.get_value_from_str(arg_str) if value is not None: Explorer.explore_expr(arg_str, value, False) return # If it is not a value, check if it is a type datatype = ExploreUtils.get_type_from_str(arg_str) if datatype is not None: Explorer.explore_type(arg_str, datatype, False) return # If it is neither a value nor a type, raise an error. raise gdb.GdbError( ("'%s' neither evaluates to a value nor is a type " "in the current context." % arg_str)) class ExploreValueCommand(gdb.Command): """Explore value of an expression valid in the current context. Usage: explore value ARG - ARG is a valid expression. - At any stage of exploration, hit the return key (instead of a choice, if any) to return to the enclosing value.""" def __init__(self): super(ExploreValueCommand, self).__init__( name = "explore value", command_class = gdb.COMMAND_DATA) def invoke(self, arg_str, from_tty): if ExploreUtils.check_args("explore value", arg_str) == False: return value = ExploreUtils.get_value_from_str(arg_str) if value is None: raise gdb.GdbError( (" '%s' does not evaluate to a value in the current " "context." % arg_str)) return Explorer.explore_expr(arg_str, value, False) class ExploreTypeCommand(gdb.Command): """Explore a type or the type of an expression. Usage: explore type ARG - ARG is a valid expression or a type name. - At any stage of exploration, hit the return key (instead of a choice, if any) to return to the enclosing type.""" def __init__(self): super(ExploreTypeCommand, self).__init__( name = "explore type", command_class = gdb.COMMAND_DATA) def invoke(self, arg_str, from_tty): if ExploreUtils.check_args("explore type", arg_str) == False: return datatype = ExploreUtils.get_type_from_str(arg_str) if datatype is not None: Explorer.explore_type(arg_str, datatype, False) return value = ExploreUtils.get_value_from_str(arg_str) if value is not None: print ("'%s' is of type '%s'." % (arg_str, str(value.type))) Explorer.explore_type(str(value.type), value.type, False) return raise gdb.GdbError(("'%s' is not a type or value in the current " "context." % arg_str)) Explorer.init_env() ExploreCommand() ExploreValueCommand() ExploreTypeCommand() PKPD4]}wA A gdb/unwinder.pynu[# Copyright (C) 2015-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Unwinder class and register_unwinder function.""" import gdb class Unwinder(object): """Base class (or a template) for frame unwinders written in Python. An unwinder has a single method __call__ and the attributes described below. Attributes: name: The name of the unwinder. enabled: A boolean indicating whether the unwinder is enabled. """ def __init__(self, name): """Constructor. Args: name: An identifying name for the unwinder. """ self.name = name self.enabled = True def __call__(self, pending_frame): """GDB calls this method to unwind a frame. Arguments: pending_frame: gdb.PendingFrame instance. Returns: gdb.UnwindInfo instance. """ raise NotImplementedError("Unwinder __call__.") def register_unwinder(locus, unwinder, replace=False): """Register unwinder in given locus. The unwinder is prepended to the locus's unwinders list. Unwinder name should be unique. Arguments: locus: Either an objfile, progspace, or None (in which case the unwinder is registered globally). unwinder: An object of a gdb.Unwinder subclass replace: If True, replaces existing unwinder with the same name. Otherwise, raises exception if unwinder with the same name already exists. Returns: Nothing. Raises: RuntimeError: Unwinder name is not unique TypeError: Bad locus type """ if locus is None: if gdb.parameter("verbose"): gdb.write("Registering global %s unwinder ...\n" % unwinder.name) locus = gdb elif isinstance(locus, gdb.Objfile) or isinstance(locus, gdb.Progspace): if gdb.parameter("verbose"): gdb.write("Registering %s unwinder for %s ...\n" % (unwinder.name, locus.filename)) else: raise TypeError("locus should be gdb.Objfile or gdb.Progspace or None") i = 0 for needle in locus.frame_unwinders: if needle.name == unwinder.name: if replace: del locus.frame_unwinders[i] else: raise RuntimeError("Unwinder %s already exists." % unwinder.name) i += 1 locus.frame_unwinders.insert(0, unwinder) gdb.invalidate_cached_frames() PKPD4]E+E+gdb/xmethod.pynu[# Python side of the support for xmethods. # Copyright (C) 2013-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Utilities for defining xmethods""" import gdb import re import sys if sys.version_info[0] > 2: # Python 3 removed basestring and long basestring = str long = int class XMethod(object): """Base class (or a template) for an xmethod description. Currently, the description requires only the 'name' and 'enabled' attributes. Description objects are managed by 'XMethodMatcher' objects (see below). Note that this is only a template for the interface of the XMethodMatcher.methods objects. One could use this class or choose to use an object which supports this exact same interface. Also, an XMethodMatcher can choose not use it 'methods' attribute. In such cases this class (or an equivalent) is not used. Attributes: name: The name of the xmethod. enabled: A boolean indicating if the xmethod is enabled. """ def __init__(self, name): self.name = name self.enabled = True class XMethodMatcher(object): """Abstract base class for matching an xmethod. When looking for xmethods, GDB invokes the `match' method of a registered xmethod matcher to match the object type and method name. The `match' method in concrete classes derived from this class should return an `XMethodWorker' object, or a list of `XMethodWorker' objects if there is a match (see below for 'XMethodWorker' class). Attributes: name: The name of the matcher. enabled: A boolean indicating if the matcher is enabled. methods: A sequence of objects of type 'XMethod', or objects which have at least the attributes of an 'XMethod' object. This list is used by the 'enable'/'disable'/'info' commands to enable/disable/list the xmethods registered with GDB. See the 'match' method below to know how this sequence is used. This attribute is None if the matcher chooses not have any xmethods managed by it. """ def __init__(self, name): """ Args: name: An identifying name for the xmethod or the group of xmethods returned by the `match' method. """ self.name = name self.enabled = True self.methods = None def match(self, class_type, method_name): """Match class type and method name. In derived classes, it should return an XMethodWorker object, or a sequence of 'XMethodWorker' objects. Only those xmethod workers whose corresponding 'XMethod' descriptor object is enabled should be returned. Args: class_type: The class type (gdb.Type object) to match. method_name: The name (string) of the method to match. """ raise NotImplementedError("XMethodMatcher match") class XMethodWorker(object): """Base class for all xmethod workers defined in Python. An xmethod worker is an object which matches the method arguments, and invokes the method when GDB wants it to. Internally, GDB first invokes the 'get_arg_types' method to perform overload resolution. If GDB selects to invoke this Python xmethod, then it invokes it via the overridden '__call__' method. The 'get_result_type' method is used to implement 'ptype' on the xmethod. Derived classes should override the 'get_arg_types', 'get_result_type' and '__call__' methods. """ def get_arg_types(self): """Return arguments types of an xmethod. A sequence of gdb.Type objects corresponding to the arguments of the xmethod are returned. If the xmethod takes no arguments, then 'None' or an empty sequence is returned. If the xmethod takes only a single argument, then a gdb.Type object or a sequence with a single gdb.Type element is returned. """ raise NotImplementedError("XMethodWorker get_arg_types") def get_result_type(self, *args): """Return the type of the result of the xmethod. Args: args: Arguments to the method. Each element of the tuple is a gdb.Value object. The first element is the 'this' pointer value. These are the same arguments passed to '__call__'. Returns: A gdb.Type object representing the type of the result of the xmethod. """ raise NotImplementedError("XMethodWorker get_result_type") def __call__(self, *args): """Invoke the xmethod. Args: args: Arguments to the method. Each element of the tuple is a gdb.Value object. The first element is the 'this' pointer value. Returns: A gdb.Value corresponding to the value returned by the xmethod. Returns 'None' if the method does not return anything. """ raise NotImplementedError("XMethodWorker __call__") class SimpleXMethodMatcher(XMethodMatcher): """A utility class to implement simple xmethod mathers and workers. See the __init__ method below for information on how instances of this class can be used. For simple classes and methods, one can choose to use this class. For complex xmethods, which need to replace/implement template methods on possibly template classes, one should implement their own xmethod matchers and workers. See py-xmethods.py in testsuite/gdb.python directory of the GDB source tree for examples. """ class SimpleXMethodWorker(XMethodWorker): def __init__(self, method_function, arg_types): self._arg_types = arg_types self._method_function = method_function def get_arg_types(self): return self._arg_types def __call__(self, *args): return self._method_function(*args) def __init__(self, name, class_matcher, method_matcher, method_function, *arg_types): """ Args: name: Name of the xmethod matcher. class_matcher: A regular expression used to match the name of the class whose method this xmethod is implementing/replacing. method_matcher: A regular expression used to match the name of the method this xmethod is implementing/replacing. method_function: A Python callable which would be called via the 'invoke' method of the worker returned by the objects of this class. This callable should accept the object (*this) as the first argument followed by the rest of the arguments to the method. All arguments to this function should be gdb.Value objects. arg_types: The gdb.Type objects corresponding to the arguments that this xmethod takes. It can be None, or an empty sequence, or a single gdb.Type object, or a sequence of gdb.Type objects. """ XMethodMatcher.__init__(self, name) assert callable(method_function), ( "The 'method_function' argument to 'SimpleXMethodMatcher' " "__init__ method should be a callable.") self._method_function = method_function self._class_matcher = class_matcher self._method_matcher = method_matcher self._arg_types = arg_types def match(self, class_type, method_name): cm = re.match(self._class_matcher, str(class_type.unqualified().tag)) mm = re.match(self._method_matcher, method_name) if cm and mm: return SimpleXMethodMatcher.SimpleXMethodWorker( self._method_function, self._arg_types) # A helper function for register_xmethod_matcher which returns an error # object if MATCHER is not having the requisite attributes in the proper # format. def _validate_xmethod_matcher(matcher): if not hasattr(matcher, "match"): return TypeError("Xmethod matcher is missing method: match") if not hasattr(matcher, "name"): return TypeError("Xmethod matcher is missing attribute: name") if not hasattr(matcher, "enabled"): return TypeError("Xmethod matcher is missing attribute: enabled") if not isinstance(matcher.name, basestring): return TypeError("Attribute 'name' of xmethod matcher is not a " "string") if matcher.name.find(";") >= 0: return ValueError("Xmethod matcher name cannot contain ';' in it") # A helper function for register_xmethod_matcher which looks up an # xmethod matcher with NAME in LOCUS. Returns the index of the xmethod # matcher in 'xmethods' sequence attribute of the LOCUS. If NAME is not # found in LOCUS, then -1 is returned. def _lookup_xmethod_matcher(locus, name): for i in range(0, len(locus.xmethods)): if locus.xmethods[i].name == name: return i return -1 def register_xmethod_matcher(locus, matcher, replace=False): """Registers a xmethod matcher MATCHER with a LOCUS. Arguments: locus: The locus in which the xmethods should be registered. It can be 'None' to indicate that the xmethods should be registered globally. Or, it could be a gdb.Objfile or a gdb.Progspace object in which the xmethods should be registered. matcher: The xmethod matcher to register with the LOCUS. It should be an instance of 'XMethodMatcher' class. replace: If True, replace any existing xmethod matcher with the same name in the locus. Otherwise, if a matcher with the same name exists in the locus, raise an exception. """ err = _validate_xmethod_matcher(matcher) if err: raise err if not locus: locus = gdb if locus == gdb: locus_name = "global" else: locus_name = locus.filename index = _lookup_xmethod_matcher(locus, matcher.name) if index >= 0: if replace: del locus.xmethods[index] else: raise RuntimeError("Xmethod matcher already registered with " "%s: %s" % (locus_name, matcher.name)) if gdb.parameter("verbose"): gdb.write("Registering xmethod matcher '%s' with %s' ...\n") locus.xmethods.insert(0, matcher) PKPD4]yBffgdb/__init__.pynu[# Copyright (C) 2010-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import traceback import os import sys import _gdb if sys.version_info[0] > 2: # Python 3 moved "reload" from imp import reload from _gdb import * class _GdbFile (object): # These two are needed in Python 3 encoding = "UTF-8" errors = "strict" def close(self): # Do nothing. return None def isatty(self): return False def writelines(self, iterable): for line in iterable: self.write(line) def flush(self): flush() class _GdbOutputFile (_GdbFile): def write(self, s): write(s, stream=STDOUT) sys.stdout = _GdbOutputFile() class _GdbOutputErrorFile (_GdbFile): def write(self, s): write(s, stream=STDERR) sys.stderr = _GdbOutputErrorFile() # Default prompt hook does nothing. prompt_hook = None # Ensure that sys.argv is set to something. # We do not use PySys_SetArgvEx because it did not appear until 2.6.6. sys.argv = [''] # Initial pretty printers. pretty_printers = [] # Initial type printers. type_printers = [] # Initial xmethod matchers. xmethods = [] # Initial frame filters. frame_filters = {} # Initial frame unwinders. frame_unwinders = [] def _execute_unwinders(pending_frame): """Internal function called from GDB to execute all unwinders. Runs each currently enabled unwinder until it finds the one that can unwind given frame. Arguments: pending_frame: gdb.PendingFrame instance. Returns: gdb.UnwindInfo instance or None. """ for objfile in objfiles(): for unwinder in objfile.frame_unwinders: if unwinder.enabled: unwind_info = unwinder(pending_frame) if unwind_info is not None: return unwind_info for unwinder in current_progspace().frame_unwinders: if unwinder.enabled: unwind_info = unwinder(pending_frame) if unwind_info is not None: return unwind_info for unwinder in frame_unwinders: if unwinder.enabled: unwind_info = unwinder(pending_frame) if unwind_info is not None: return unwind_info return None def _execute_file(filepath): """This function is used to replace Python 2's PyRun_SimpleFile. Loads and executes the given file. We could use the runpy module, but its documentation says: "Furthermore, any functions and classes defined by the executed code are not guaranteed to work correctly after a runpy function has returned." """ globals = sys.modules['__main__'].__dict__ set_file = False # Set file (if not set) so that the imported file can use it (e.g. to # access file-relative paths). This matches what PyRun_SimpleFile does. if not hasattr(globals, '__file__'): globals['__file__'] = filepath set_file = True try: with open(filepath, 'rb') as file: # We pass globals also as locals to match what Python does # in PyRun_SimpleFile. compiled = compile(file.read(), filepath, 'exec') exec(compiled, globals, globals) finally: if set_file: del globals['__file__'] # Convenience variable to GDB's python directory PYTHONDIR = os.path.dirname(os.path.dirname(__file__)) # Auto-load all functions/commands. # Packages to auto-load. packages = [ 'function', 'command', 'printer' ] # pkgutil.iter_modules is not available prior to Python 2.6. Instead, # manually iterate the list, collating the Python files in each module # path. Construct the module name, and import. def _auto_load_packages(): for package in packages: location = os.path.join(os.path.dirname(__file__), package) if os.path.exists(location): py_files = filter(lambda x: x.endswith('.py') and x != '__init__.py', os.listdir(location)) for py_file in py_files: # Construct from foo.py, gdb.module.foo modname = "%s.%s.%s" % ( __name__, package, py_file[:-3] ) try: if modname in sys.modules: # reload modules with duplicate names reload(__import__(modname)) else: __import__(modname) except: sys.stderr.write (traceback.format_exc() + "\n") _auto_load_packages() def GdbSetPythonDirectory(dir): """Update sys.path, reload gdb and auto-load packages.""" global PYTHONDIR try: sys.path.remove(PYTHONDIR) except ValueError: pass sys.path.insert(0, dir) PYTHONDIR = dir # note that reload overwrites the gdb module without deleting existing # attributes reload(__import__(__name__)) _auto_load_packages() def current_progspace(): "Return the current Progspace." return selected_inferior().progspace def objfiles(): "Return a sequence of the current program space's objfiles." return current_progspace().objfiles() def solib_name (addr): """solib_name (Long) -> String.\n\ Return the name of the shared library holding a given address, or None.""" return current_progspace().solib_name(addr) def block_for_pc(pc): "Return the block containing the given pc value, or None." return current_progspace().block_for_pc(pc) def find_pc_line(pc): """find_pc_line (pc) -> Symtab_and_line. Return the gdb.Symtab_and_line object corresponding to the pc value.""" return current_progspace().find_pc_line(pc) try: from pygments import formatters, lexers, highlight def colorize(filename, contents): # Don't want any errors. try: lexer = lexers.get_lexer_for_filename(filename, stripnl=False) formatter = formatters.TerminalFormatter() return highlight(contents, lexer, formatter) except: return None except: def colorize(filename, contents): return None PK1]3,xexe6libstdcxx/v6/__pycache__/printers.cpython-36.opt-1.pycnu[PK1]e0elibstdcxx/v6/__pycache__/xmethods.cpython-36.pycnu[PK1] B666$libstdcxx/v6/__pycache__/__init__.cpython-36.opt-1.pycnu[PK1]3,xexe0libstdcxx/v6/__pycache__/printers.cpython-36.pycnu[PK1]e6]libstdcxx/v6/__pycache__/xmethods.cpython-36.opt-1.pycnu[PK1] B660libstdcxx/v6/__pycache__/__init__.cpython-36.pycnu[PK1]qqzlibstdcxx/v6/xmethods.pynu[PK1]ܯ}}`libstdcxx/v6/__init__.pynu[PK1]CBelibstdcxx/v6/printers.pynu[PK1]@JY3libstdcxx/__pycache__/__init__.cpython-36.opt-1.pycnu[PK1]@JY-libstdcxx/__pycache__/__init__.cpython-36.pycnu[PK1]2libstdcxx/__init__.pynu[PKk1] z distro.pynu[PKk1]:"8'__pycache__/kcsig_verify.cpython-36.pycnu[PKk1]xS!__pycache__/distro.cpython-36.pycnu[PKk1]k kcarectl/update_utils.pynu[PKk1]4ؓkcarectl/serverid.pynu[PKk1]eSjkcarectl/capabilities.pynu[PKk1][7 _ _kcarectl/doctor.pynu[PKk1] kcarectl/config.pynu[PKk1]Mq)kcarectl/py23.pynu[PKk1] ߬##&kcarectl/__main__.pynu[PKk1]{8ڞn)kcarectl/fetch.pynu[PKk1]gNgN*M=kcarectl/__pycache__/doctor.cpython-36.pycnu[PKk1]-kcarectl/__pycache__/constants.cpython-36.pycnu[PKk1]B0Xkcarectl/__pycache__/ipv6_support.cpython-36.pycnu[PKk1]w˕||+եkcarectl/__pycache__/anomaly.cpython-36.pycnu[PKk1]6ՌII+kcarectl/__pycache__/libcare.cpython-36.pycnu[PKk1]Q(kcarectl/__pycache__/py23.cpython-36.pycnu[PKk1]B, kcarectl/__pycache__/__main__.cpython-36.pycnu[PKk1] &&,[ kcarectl/__pycache__/serverid.cpython-36.pycnu[PKk1]{?++) kcarectl/__pycache__/kcare.cpython-36.pycnu[PKk1]˫ 1= kcarectl/__pycache__/process_utils.cpython-36.pycnu[PKk1]L'7 7 /J kcarectl/__pycache__/server_info.cpython-36.pycnu[PKk1]P;55)W kcarectl/__pycache__/utils.cpython-36.pycnu[PKk1]nAޥ *v kcarectl/__pycache__/errors.cpython-36.pycnu[PKk1]N` ` - kcarectl/__pycache__/log_utils.cpython-36.pycnu[PKk1]ff0Ύ kcarectl/__pycache__/capabilities.cpython-36.pycnu[PKk1]b%SS+ kcarectl/__pycache__/selinux.cpython-36.pycnu[PKk1]aa*B kcarectl/__pycache__/config.cpython-36.pycnu[PKk1]| . kcarectl/__pycache__/http_utils.cpython-36.pycnu[PKk1].  0 kcarectl/__pycache__/update_utils.cpython-36.pycnu[PKk1];'"3 kcarectl/__pycache__/config_handlers.cpython-36.pycnu[PKk1]W2ǔ0 kcarectl/__pycache__/delivery_kit.cpython-36.pycnu[PKk1]^;ѧ((2 kcarectl/__pycache__/platform_utils.cpython-36.pycnu[PKk1]""(* kcarectl/__pycache__/auth.cpython-36.pycnu[PKk1]ʠmm)L kcarectl/__pycache__/fetch.cpython-36.pycnu[PKk1]+,^ kcarectl/__pycache__/__init__.cpython-36.pycnu[PKk1]ץӒ&&3E kcarectl/config_handlers.pynu[PKk1]U/bbl kcarectl/libcare.pynu[PKk1]^uk// kcarectl/auth.pynu[PKk1]t*$ kcarectl/errors.pynu[PKk1]M((W kcarectl/platform_utils.pynu[PKk1]«++/ kcarectl/delivery_kit.pynu[PKk1]⢁EE [ kcarectl/http_utils.pynu[PKk1]/7~ ~ w kcarectl/log_utils.pynu[PKk1]Z kcarectl/selinux.pynu[PKk1]*[#[#Q kcarectl/utils.pynu[PKk1]l kcarectl/server_info.pynu[PKk1]u+)) kcarectl/kcare.pynu[PKk1]_) kcarectl/anomaly.pynu[PKk1]݌*:*:e kcarectl/__init__.pynu[PKk1]獅5kcarectl/ipv6_support.pynu[PKk1]xג44Rkcarectl/process_utils.pynu[PKk1])o[dkcarectl/constants.pynu[PKk1]r\\>jkcsig_verify.pynu[PK3]قpolicygenerators/libssh.pynu[PK3]R$$2policygenerators/nss.pynu[PK3]H‘#policygenerators/configgenerator.pynu[PK3]y!SSpolicygenerators/java.pynu[PK3]Ypolicygenerators/bind.pynu[PK3]ɨ5Kpolicygenerators/__pycache__/libreswan.cpython-36.pycnu[PK3]9 6policygenerators/__pycache__/java.cpython-36.opt-1.pycnu[PK3]9 0policygenerators/__pycache__/java.cpython-36.pycnu[PK3]/$~~2policygenerators/__pycache__/gnutls.cpython-36.pycnu[PK3]6!/policygenerators/__pycache__/nss.cpython-36.pycnu[PK3]˿;policygenerators/__pycache__/configgenerator.cpython-36.pycnu[PK3]1#G:policygenerators/__pycache__/__init__.cpython-36.opt-1.pycnu[PK3]oc772Kpolicygenerators/__pycache__/libssh.cpython-36.pycnu[PK3][9*policygenerators/__pycache__/openssl.cpython-36.opt-1.pycnu[PK3]˿A@policygenerators/__pycache__/configgenerator.cpython-36.opt-1.pycnu[PK3]6!5$Dpolicygenerators/__pycache__/nss.cpython-36.opt-1.pycnu[PK3]70Vpolicygenerators/__pycache__/bind.cpython-36.pycnu[PK3]b!3X_policygenerators/__pycache__/openssh.cpython-36.pycnu[PK3]F9006y~policygenerators/__pycache__/krb5.cpython-36.opt-1.pycnu[PK3]ɨ;policygenerators/__pycache__/libreswan.cpython-36.opt-1.pycnu[PK3]F9000zpolicygenerators/__pycache__/krb5.cpython-36.pycnu[PK3][3 policygenerators/__pycache__/openssl.cpython-36.pycnu[PK3]oc778policygenerators/__pycache__/libssh.cpython-36.opt-1.pycnu[PK3]/$~~8policygenerators/__pycache__/gnutls.cpython-36.opt-1.pycnu[PK3]76policygenerators/__pycache__/bind.cpython-36.opt-1.pycnu[PK3]1#G4policygenerators/__pycache__/__init__.cpython-36.pycnu[PK3]b!9@policygenerators/__pycache__/openssh.cpython-36.opt-1.pycnu[PK3]'ppgpolicygenerators/krb5.pynu[PK3]hiP policygenerators/gnutls.pynu[PK3] 6@N policygenerators/libreswan.pynu[PK3] v3policygenerators/openssh.pynu[PK3]I}Tpolicygenerators/openssl.pynu[PK3]Yb@EEjpolicygenerators/__init__.pynu[PK3])0!0!+nupdate-crypto-policies.pynuȯPK3]u>""7__pycache__/update-crypto-policies.cpython-36.opt-1.pycnu[PK3]ߺh0__pycache__/build-crypto-policies.cpython-36.pycnu[PK3]ߺh6__pycache__/build-crypto-policies.cpython-36.opt-1.pycnu[PK3]u>""1__pycache__/update-crypto-policies.cpython-36.pycnu[PK3]Hbuild-crypto-policies.pynuȯPK3]# CBCB X cryptopolicies/cryptopolicies.pynu[PK3]:E6..Kcryptopolicies/alg_lists.pynu[PK3]"~8d\cryptopolicies/__pycache__/__init__.cpython-36.opt-1.pycnu[PK3]>>>]cryptopolicies/__pycache__/cryptopolicies.cpython-36.opt-1.pycnu[PK3]U9cryptopolicies/__pycache__/alg_lists.cpython-36.opt-1.pycnu[PK3]q5]??8cryptopolicies/__pycache__/cryptopolicies.cpython-36.pycnu[PK3]U3cryptopolicies/__pycache__/alg_lists.cpython-36.pycnu[PK3]"~2=cryptopolicies/__pycache__/__init__.cpython-36.pycnu[PK3]c&cryptopolicies/validation/alg_lists.pynu[PK3]@qcryptopolicies/validation/__pycache__/rules.cpython-36.opt-1.pycnu[PK3]Xǭ @ cryptopolicies/validation/__pycache__/scope.cpython-36.opt-1.pycnu[PK3]nddC9cryptopolicies/validation/__pycache__/__init__.cpython-36.opt-1.pycnu[PK3]V&DBcryptopolicies/validation/__pycache__/general.cpython-36.opt-1.pycnu[PK3]Xǭ :!cryptopolicies/validation/__pycache__/scope.cpython-36.pycnu[PK3]V&D</cryptopolicies/validation/__pycache__/general.cpython-36.pycnu[PK3]:|3cryptopolicies/validation/__pycache__/rules.cpython-36.pycnu[PK3]BrooD;cryptopolicies/validation/__pycache__/alg_lists.cpython-36.opt-1.pycnu[PK3]Broo>@cryptopolicies/validation/__pycache__/alg_lists.cpython-36.pycnu[PK3]ndd=Ecryptopolicies/validation/__pycache__/__init__.cpython-36.pycnu[PK3]6F"mGcryptopolicies/validation/scope.pynu[PK3]gdb/function/strfns.pynu[PKPD4]H1gdb/function/__pycache__/as_string.cpython-36.pycnu[PKPD4]VB3__6bgdb/function/__pycache__/__init__.cpython-36.opt-1.pycnu[PKPD4]%`- .'gdb/function/__pycache__/strfns.cpython-36.pycnu[PKPD4]%`- 42gdb/function/__pycache__/strfns.cpython-36.opt-1.pycnu[PKPD4]H7Cgdb/function/__pycache__/as_string.cpython-36.opt-1.pycnu[PKPD4];gg1gdb/function/__pycache__/caller_is.cpython-36.pycnu[PKPD4];gg7tgdb/function/__pycache__/caller_is.cpython-36.opt-1.pycnu[PKPD4]VB3__0Bgdb/function/__pycache__/__init__.cpython-36.pycnu[PKPD4]P|Ngdb/function/__init__.pynu[PKPD4])ت((gdb/FrameDecorator.pynu[PKPD4]`;;4gdb/command/__pycache__/frame_filters.cpython-36.pycnu[PKPD4] GG3>gdb/command/__pycache__/prompt.cpython-36.opt-1.pycnu[PKPD4]|/0Dgdb/command/__pycache__/unwinders.cpython-36.pycnu[PKPD4]w,eOO47\gdb/command/__pycache__/explore.cpython-36.opt-1.pycnu[PKPD4]GQv##/gdb/command/__pycache__/xmethods.cpython-36.pycnu[PKPD4]