⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mc-tech-docs.html

📁 memory checking tool 源代码valgrind-3.2.1.tar.gz 这是英文使用手册
💻 HTML
📖 第 1 页 / 共 5 页
字号:
    All <code class="function">malloc</code>,    <code class="function">free</code>, etc calls that the    client program makes are eventually routed to a call to    <code class="function">vg_trap_here</code>, and Valgrind    does its own special thing with these calls.  In effect this    provides a trapdoor, by which Valgrind can intercept certain    calls on the simulated CPU, run the call as it sees fit    itself (on the real CPU), and return the result to the    simulated CPU, quite transparently to the client    program.</p></li></ul></div><p>Valgrind intercepts the client's<code class="function">malloc</code>,<code class="function">free</code>, etc, calls, so that it canstore additional information.  Each block<code class="function">malloc</code>'d by the client givesrise to a shadow block in which Valgrind stores the call stack atthe time of the <code class="function">malloc</code> call.When the client calls <code class="function">free</code>,Valgrind tries to find the shadow block corresponding to theaddress passed to <code class="function">free</code>, andemits an error message if none can be found.  If it is found, theblock is placed on the freed blocks queue<code class="computeroutput">vg_freed_list</code>, it is marked asinaccessible, and its shadow block now records the call stack atthe time of the <code class="function">free</code> call.Keeping <code class="computeroutput">free</code>'d blocks in thisqueue allows Valgrind to spot all (presumably invalid) accessesto them.  However, once the volume of blocks in the free queueexceeds <code class="function">VG_(clo_freelist_vol)</code>,blocks are finally removed from the queue.</p><p>Keeping track of <code class="literal">A</code> and<code class="literal">V</code> bits (note: if you don't know what theseare, you haven't read the user guide carefully enough) for memoryis done in <code class="filename">vg_memory.c</code>.  This implements asparse array structure which covers the entire 4G address spacein a way which is reasonably fast and reasonably space efficient.The 4G address space is divided up into 64K sections, eachcovering 64Kb of address space.  Given a 32-bit address, the top16 bits are used to select one of the 65536 entries in<code class="function">VG_(primary_map)</code>.  The resulting"secondary" (<code class="computeroutput">SecMap</code>) holds A andV bits for the 64k of address space chunk corresponding to thelower 16 bits of the address.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="mc-tech-docs.design"></a>1.1.3.燚esign decisions</h3></div></div></div><p>Some design decisions were motivated by the need to makeValgrind debuggable.  Imagine you are writing a CPU simulator.It works fairly well.  However, you run some large program, likeNetscape, and after tens of millions of instructions, it crashes.How can you figure out where in your simulator the bug is?</p><p>Valgrind's answer is: cheat.  Valgrind is designed so thatit is possible to switch back to running the client program onthe real CPU at any point.  Using the<code class="option">--stop-after= </code> flag, you can askValgrind to run just some number of basic blocks, and then runthe rest of the way on the real CPU.  If you are searching for abug in the simulated CPU, you can use this to do a binary search,which quickly leads you to the specific basic block which iscausing the problem.</p><p>This is all very handy.  It does constrain the design incertain unimportant ways.  Firstly, the layout of memory, whenviewed from the client's point of view, must be identicalregardless of whether it is running on the real or simulated CPU.This means that Valgrind can't do pointer swizzling -- well, nogreat loss -- and it can't run on the same stack as the client --again, no great loss.  Valgrind operates on its own stack,<code class="function">VG_(stack)</code>, which it switches toat startup, temporarily switching back to the client's stack whendoing system calls for the client.</p><p>Valgrind also receives signals on its own stack,<code class="computeroutput">VG_(sigstack)</code>, but for differentgruesome reasons discussed below.</p><p>This nice cleanswitch-back-to-the-real-CPU-whenever-you-like story is muddied bysignals.  Problem is that signals arrive at arbitrary times andtend to slightly perturb the basic block count, with the resultthat you can get close to the basic block causing a problem butcan't home in on it exactly.  My kludgey hack is to define<code class="computeroutput">SIGNAL_SIMULATION</code> to 1 towardsthe bottom of <code class="filename">vg_syscall_mem.c</code>, so thatsignal handlers are run on the real CPU and don't change the BBcounts.</p><p>A second hole in the switch-back-to-real-CPU story is thatValgrind's way of delivering signals to the client is differentfrom that of the kernel.  Specifically, the layout of the signaldelivery frame, and the mechanism used to detect a sighandlerreturning, are different.  So you can't expect to make thetransition inside a sighandler and still have things working, butin practice that's not much of a restriction.</p><p>Valgrind's implementation of<code class="function">malloc</code>,<code class="function">free</code>, etc, (in<code class="filename">vg_clientmalloc.c</code>, not the low-level stuffin <code class="filename">vg_malloc2.c</code>) is somewhat complicated bythe need to handle switching back at arbitrary points.  It doeswork tho.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="mc-tech-docs.correctness"></a>1.1.4.燙orrectness</h3></div></div></div><p>There's only one of me, and I have a Real Life (tm) as wellas hacking Valgrind [allegedly :-].  That means I don't have timeto waste chasing endless bugs in Valgrind.  My emphasis istherefore on doing everything as simply as possible, withcorrectness, stability and robustness being the number onepriority, more important than performance or functionality.  As aresult:</p><div class="itemizedlist"><ul type="disc"><li><p>The code is absolutely loaded with assertions, and    these are <span><strong class="command">permanently enabled.</strong></span> I have no    plan to remove or disable them later.  Over the past couple    of months, as valgrind has become more widely used, they have    shown their worth, pulling up various bugs which would    otherwise have appeared as hard-to-find segmentation    faults.</p><p>I am of the view that it's acceptable to spend 5% of    the total running time of your valgrindified program doing    assertion checks and other internal sanity checks.</p></li><li><p>Aside from the assertions, valgrind contains various    sets of internal sanity checks, which get run at varying    frequencies during normal operation.    <code class="function">VG_(do_sanity_checks)</code> runs    every 1000 basic blocks, which means 500 to 2000 times/second    for typical machines at present.  It checks that Valgrind    hasn't overrun its private stack, and does some simple checks    on the memory permissions maps.  Once every 25 calls it does    some more extensive checks on those maps.  Etc, etc.</p><p>The following components also have sanity check code,    which can be enabled to aid debugging:</p><div class="itemizedlist"><ul type="circle"><li><p>The low-level memory-manager        (<code class="computeroutput">VG_(mallocSanityCheckArena)</code>).        This does a complete check of all blocks and chains in an        arena, which is very slow.  Is not engaged by default.</p></li><li><p>The symbol table reader(s): various checks to        ensure uniqueness of mappings; see        <code class="function">VG_(read_symbols)</code> for a        start.  Is permanently engaged.</p></li><li><p>The A and V bit tracking stuff in        <code class="filename">vg_memory.c</code>.  This can be compiled        with cpp symbol        <code class="computeroutput">VG_DEBUG_MEMORY</code> defined,        which removes all the fast, optimised cases, and uses        simple-but-slow fallbacks instead.  Not engaged by        default.</p></li><li><p>Ditto        <code class="computeroutput">VG_DEBUG_LEAKCHECK</code>.</p></li><li><p>The JITter parses x86 basic blocks into sequences        of UCode instructions.  It then sanity checks each one        with <code class="function">VG_(saneUInstr)</code> and        sanity checks the sequence as a whole with        <code class="function">VG_(saneUCodeBlock)</code>.        This stuff is engaged by default, and has caught some        way-obscure bugs in the simulated CPU machinery in its        time.</p></li><li><p>The system call wrapper does        <code class="function">VG_(first_and_last_secondaries_look_plausible)</code>        after every syscall; this is known to pick up bugs in the        syscall wrappers.  Engaged by default.</p></li><li><p>The main dispatch loop, in        <code class="function">VG_(dispatch)</code>, checks        that translations do not set        <code class="computeroutput">%ebp</code> to any value        different from        <code class="computeroutput">VG_EBP_DISPATCH_CHECKED</code>        or <code class="computeroutput">&amp; VG_(baseBlock)</code>.        In effect this test is free, and is permanently        engaged.</p></li><li><p>There are a couple of ifdefed-out consistency        checks I inserted whilst debugging the new register        allocater,        <code class="computeroutput">vg_do_register_allocation</code>.</p></li></ul></div></li><li><p>I try to avoid techniques, algorithms, mechanisms, etc,    for which I can supply neither a convincing argument that    they are correct, nor sanity-check code which might pick up    bugs in my implementation.  I don't always succeed in this,    but I try.  Basically the idea is: avoid techniques which    are, in practice, unverifiable, in some sense.  When doing    anything, always have in mind: "how can I verify that this is    correct?"</p></li></ul></div><p>Some more specific things are:</p><div class="itemizedlist"><ul type="disc"><li><p>Valgrind runs in the same namespace as the client, at    least from <code class="filename">ld.so</code>'s point of view, and it    therefore absolutely had better not export any symbol with a    name which could clash with that of the client or any of its    libraries.  Therefore, all globally visible symbols exported    from <code class="filename">valgrind.so</code> are defined using the    <code class="computeroutput">VG_</code> CPP macro.  As you'll    see from <code class="filename">vg_constants.h</code>, this appends    some arbitrary prefix to the symbol, in order that it be, we    hope, globally unique.  Currently the prefix is    <code class="computeroutput">vgPlain_</code>.  For convenience    there are also <code class="computeroutput">VGM_</code>,    <code class="computeroutput">VGP_</code> and    <code class="computeroutput">VGOFF_</code>.  All locally defined    symbols are declared <code class="computeroutput">static</code>    and do not appear in the final shared object.</p><p>To check this, I periodically do <code class="computeroutput">nm    valgrind.so | grep " T "</code>, which shows you    all the globally exported text symbols.  They should all have    an approved prefix, except for those like    <code class="function">malloc</code>,    <code class="function">free</code>, etc, which we    deliberately want to shadow and take precedence over the same    names exported from <code class="filename">glibc.so</code>, so that    valgrind can intercept those calls easily.  Similarly,    <code class="computeroutput">nm valgrind.so | grep " D "</code>    allows you to find any rogue data-segment symbol    names.</p></li><li><p>Valgrind tries, and almost succeeds, in being    completely independent of all other shared objects, in    particular of <code class="filename">glibc.so</code>.  For example, we    have our own low-level memory manager in    <code class="filename">vg_malloc2.c</code>, which is a fairly standard

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -