107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/*--------------------------------------------------------------------*/ 307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/*--- Obtaining information about an address. pub_tool_addrinfo.h ---*/ 407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/*--------------------------------------------------------------------*/ 507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/* 707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe This file is part of Valgrind, a dynamic binary instrumentation 807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe framework. 907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 10b3a1e4bffbdbbf38304f216af405009868f43628sewardj Copyright (C) 2000-2015 Julian Seward 1107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe jseward@acm.org 1207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 1307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe This program is free software; you can redistribute it and/or 1407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe modify it under the terms of the GNU General Public License as 1507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe published by the Free Software Foundation; either version 2 of the 1607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe License, or (at your option) any later version. 1707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 1807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe This program is distributed in the hope that it will be useful, but 1907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe WITHOUT ANY WARRANTY; without even the implied warranty of 2007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe General Public License for more details. 2207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 2307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe You should have received a copy of the GNU General Public License 2407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe along with this program; if not, write to the Free Software 2507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 2607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 02111-1307, USA. 2707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 2807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe The GNU General Public License is contained in the file COPYING. 2907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe*/ 3007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 3107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe#ifndef __PUB_TOOL_ADDRINFO_H 3207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe#define __PUB_TOOL_ADDRINFO_H 3307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 3407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe#include "pub_tool_basics.h" // VG_ macro 357463e49387b46e66b6612ff4b9683c612c92f804florian#include "pub_tool_aspacemgr.h" // SegKind 3607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 3707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/*====================================================================*/ 3807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/*=== Obtaining information about an address ===*/ 3907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/*====================================================================*/ 4007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 4107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// Different kinds of blocks. 4207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// Block_Mallocd is used by tools that maintain detailed information about 4307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// Client allocated heap blocks. 4407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// Block_Freed is used by tools such as memcheck that maintain a 'quarantine' 4507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// list of blocks freed by the Client but not yet physically freed. 4607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// Block_MempoolChunk and Block_UserG are used for mempool or user defined heap 4707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// blocks. 4807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// Block_ClientArenaMallocd and Block_ClientArenaFree are used when the tool 4907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// replaces the malloc/free/... functions but does not maintain detailed 5007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe// information about Client allocated heap blocks. 51fed894d33a94f840c013d1f127a6e819fd26ea2aphilippe// Block_ValgrindArenaMallocd and Block_ValgrindArenaFree are used for heap 52fed894d33a94f840c013d1f127a6e819fd26ea2aphilippe// blocks of Valgrind internal heap. 5307c08527f05caeb0062b42ca9a58ee774ec5fba1philippetypedef enum { 5407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Block_Mallocd = 111, 5507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Block_Freed, 5607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Block_MempoolChunk, 5707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Block_UserG, 5807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Block_ClientArenaMallocd, 5907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Block_ClientArenaFree, 6007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Block_ValgrindArenaMallocd, 6107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Block_ValgrindArenaFree, 6207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe} BlockKind; 6307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 6407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/* ------------------ Addresses -------------------- */ 6507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 6607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/* The classification of a faulting address. */ 6707c08527f05caeb0062b42ca9a58ee774ec5fba1philippetypedef 6807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe enum { 6907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Addr_Undescribed, // as-yet unclassified 7007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Addr_Unknown, // classification yielded nothing useful 7107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Addr_Block, // in malloc'd/free'd block 7207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Addr_Stack, // on a thread's stack 7307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Addr_DataSym, // in a global data sym 7407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe Addr_Variable, // variable described by the debug info 75f7ec77f53fd09a5682dbe6db049efe0746df7948philippe Addr_SectKind, // Section from a mmap-ed object file 76d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe Addr_BrkSegment, // address in brk data segment 77f7ec77f53fd09a5682dbe6db049efe0746df7948philippe Addr_SegmentKind // Client segment (mapped memory) 7807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe } 7907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe AddrTag; 8007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 817e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe/* For an address in a stack, gives the address position in this stack. */ 827e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippetypedef 837e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe enum { 847e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe StackPos_stacked, // Addressable and 'active' stack zone. 857e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe StackPos_below_stack_ptr, // Below stack ptr 867e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe StackPos_guard_page // In the guard page 877e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe } 887e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe StackPos; 897e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 907e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe 910c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe/* Note about ThreadInfo tid and tnr in various parts of _Addrinfo: 920c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe A tid is an index in the VG_(threads)[] array. The entries 930c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe in VG_(threads) array are re-used, so the tid in an 'old' _Addrinfo 940c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe might be misleading: if the thread that was using tid has been terminated 950c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe and the tid was re-used by another thread, the tid will very probably 960c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe be wrongly interpreted by the user. 970c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe So, such an _Addrinfo should be printed just after it has been produced, 980c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe before the tid could possibly be re-used by another thread. 990c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe 1000c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe A tool such as helgrind is uniquely/unambiguously identifying each thread 1010c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe by a number. If the tool sets tnr between the call to 1020c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe VG_(describe_addr) and the call to VG_(pp_addrinfo), then VG_(pp_addrinfo) 1030c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe will by preference print tnr instead of tid. 1040c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe Visually, a tid will be printed as thread %d 1050c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe while a tnr will be printed as thread #%d 1060c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe*/ 1070c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe 1080c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippetypedef 1090c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe struct _ThreadInfo { 1100c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe ThreadId tid; // 0 means thread not known. 1110c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe UInt tnr; // 0 means no tool specific thread nr, or not known. 1120c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe } ThreadInfo; 1130c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe 1140c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe/* Zeroes/clear all the fields of *tinfo. */ 1150c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippeextern void VG_(initThreadInfo) (ThreadInfo *tinfo); 1160c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe 11707c08527f05caeb0062b42ca9a58ee774ec5fba1philippetypedef 11807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe struct _AddrInfo 11907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe AddrInfo; 1200c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe 12107c08527f05caeb0062b42ca9a58ee774ec5fba1philippestruct _AddrInfo { 12207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe AddrTag tag; 12307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe union { 12407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe // As-yet unclassified. 12507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe struct { } Undescribed; 12607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 1270c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe // On a stack. tinfo indicates which thread's stack? 12818d6f4ec1b86057e1a906db1a1d31c89472fb1adphilippe // IP is the address of an instruction of the function where the 12918d6f4ec1b86057e1a906db1a1d31c89472fb1adphilippe // stack address was. 0 if not found. 13018d6f4ec1b86057e1a906db1a1d31c89472fb1adphilippe // frameNo is the frame nr of the call where the stack address was. 13118d6f4ec1b86057e1a906db1a1d31c89472fb1adphilippe // -1 if not found. 1327e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // stackPos describes the address 'position' in the stack. 1337e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // If stackPos is StackPos_below_stack_ptr or StackPos_guard_page, 1347e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // spoffset gives the offset from the thread stack pointer. 1357e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe // (spoffset will be negative, as stacks are assumed growing down). 13607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe struct { 1370c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe ThreadInfo tinfo; 13818d6f4ec1b86057e1a906db1a1d31c89472fb1adphilippe Addr IP; 13918d6f4ec1b86057e1a906db1a1d31c89472fb1adphilippe Int frameNo; 1407e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe StackPos stackPos; 1417e3b3f23b41ae75ceb6306ea3e15f110bbbf3dd6philippe PtrdiffT spoffset; 14207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe } Stack; 14307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 144fed894d33a94f840c013d1f127a6e819fd26ea2aphilippe // This covers heap blocks (normal and from mempools), user-defined 145fed894d33a94f840c013d1f127a6e819fd26ea2aphilippe // blocks and Arena blocks. 1460c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe // alloc_tinfo identifies the thread that has allocated the block. 1470c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe // This is used by tools such as helgrind that maintain 1480c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe // more detailed informations about client blocks. 14907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe struct { 15007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe BlockKind block_kind; 151fed894d33a94f840c013d1f127a6e819fd26ea2aphilippe const HChar* block_desc; // "block","mempool","user-defined",arena 15207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe SizeT block_szB; 15307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe PtrdiffT rwoffset; 15407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe ExeContext* allocated_at; // might be null_ExeContext. 1550c9ac8d0deca2f2a552fb2b0cab24efe6191bac7philippe ThreadInfo alloc_tinfo; // which thread did alloc this block. 15607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe ExeContext* freed_at; // might be null_ExeContext. 15707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe } Block; 15807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 15946cc04521acf2827eb33310fadc119bf2dc039e4florian // In a global .data symbol. This holds 16007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe // the variable's name (zero terminated), plus a (memory) offset. 16107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe struct { 16246cc04521acf2827eb33310fadc119bf2dc039e4florian HChar *name; 16307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe PtrdiffT offset; 16407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe } DataSym; 16507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 16607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe // Is described by Dwarf debug info. XArray*s of HChar. 16707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe struct { 16807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe XArray* /* of HChar */ descr1; 16907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe XArray* /* of HChar */ descr2; 17007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe } Variable; 17107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 17207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe // Could only narrow it down to be the PLT/GOT/etc of a given 17307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe // object. Better than nothing, perhaps. 17407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe struct { 175e08950b4ce5a3f5d75a7279548f975cd6207dc74florian HChar *objname; 17607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe VgSectKind kind; 17707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe } SectKind; 17807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 179d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe // Described address is or was in the brk data segment. 180d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe // brk_limit is the limit that was in force 181d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe // at the time address was described. 182d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe // If address is >= brk_limit, it means address is in a zone 183d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe // of the data segment that was shrinked. 184d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe struct { 185d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe Addr brk_limit; // limit in force when address was described. 186d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe } BrkSegment; 187d0da968735a4986e3a23f0832e9173fa9d58a1a3philippe 188f7ec77f53fd09a5682dbe6db049efe0746df7948philippe struct { 189f7ec77f53fd09a5682dbe6db049efe0746df7948philippe SegKind segkind; // SkAnonC, SkFileC or SkShmC. 190f7ec77f53fd09a5682dbe6db049efe0746df7948philippe HChar *filename; // NULL if segkind != SkFileC 191f7ec77f53fd09a5682dbe6db049efe0746df7948philippe Bool hasR; 192f7ec77f53fd09a5682dbe6db049efe0746df7948philippe Bool hasW; 193f7ec77f53fd09a5682dbe6db049efe0746df7948philippe Bool hasX; 194f7ec77f53fd09a5682dbe6db049efe0746df7948philippe } SegmentKind; 195f7ec77f53fd09a5682dbe6db049efe0746df7948philippe 19607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe // Classification yielded nothing useful. 19707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe struct { } Unknown; 19807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 19907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe } Addr; 20007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe}; 20107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 20207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 20307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/* Describe an address as best you can, putting the result in ai. 20407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe On entry, ai->tag must be equal to Addr_Undescribed. 20507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe This might allocate some memory, that can be cleared with 20607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe VG_(clear_addrinfo). */ 20707c08527f05caeb0062b42ca9a58ee774ec5fba1philippeextern void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai ); 20807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 20907c08527f05caeb0062b42ca9a58ee774ec5fba1philippeextern void VG_(clear_addrinfo) ( AddrInfo* ai); 21007c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 2110af05d465f338f7009ccb1172c61f00e06ddb58aphilippe/* Prints the AddrInfo ai describing a. 2120af05d465f338f7009ccb1172c61f00e06ddb58aphilippe Note that an ai with tag Addr_Undescribed will cause an assert.*/ 213518850bf0da07ed3e2244e307268ae0fd80e93a8florianextern void VG_(pp_addrinfo) ( Addr a, const AddrInfo* ai ); 21407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 21507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/* Same as VG_(pp_addrinfo) but provides some memcheck specific behaviour: 21607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe * maybe_gcc indicates Addr a was just below the stack ptr when the error 21707c08527f05caeb0062b42ca9a58ee774ec5fba1philippe with a was encountered. 21807c08527f05caeb0062b42ca9a58ee774ec5fba1philippe * the message for Unknown tag is slightly different, as memcheck 21907c08527f05caeb0062b42ca9a58ee774ec5fba1philippe has a recently freed list. */ 220518850bf0da07ed3e2244e307268ae0fd80e93a8florianextern void VG_(pp_addrinfo_mc) ( Addr a, const AddrInfo* ai, Bool maybe_gcc ); 22107c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 22207c08527f05caeb0062b42ca9a58ee774ec5fba1philippe#endif // __PUB_TOOL_ADDRINFO_H 22307c08527f05caeb0062b42ca9a58ee774ec5fba1philippe 22407c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/*--------------------------------------------------------------------*/ 22507c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/*--- end ---*/ 22607c08527f05caeb0062b42ca9a58ee774ec5fba1philippe/*--------------------------------------------------------------------*/ 227