Jump to content

Linux Applications Debugging Techniques/Appendices

From Wikibooks, open books for an open world

Tools

[edit | edit source]

Things to watch for

[edit | edit source]
Interrupted calls
[edit | edit source]

A number of API functions return an error code if the call was interrupted by a signal. Usually this is not an error by itself and the call should be restarted. For instance:

int raccept( int s, struct sockaddr *addr, socklen_t *addrlen )
{
     int rc;
     
     do {
         rc = accept( s, addr, addrlen );
     } while ( rc == -1 && errno == EINTR );
     
     return rc;
}

The list of interruptible function differs from Unix-like platform to platform. For Linux see signal(7). Note that sem_wait() & co. are on list.


Spurious wake-ups
[edit | edit source]

Threads waiting on a pthreads condition variable can be waken up even if the condition hs not been met. Upon waking up, the condition should be explicitly checked and return waiting if it is not met.


Code review checklist

[edit | edit source]
  1. Functional impact
    1. Which modules are affected; which functionality is impacted.
    2. Which modules & functionality is consumed by the changed code.
    3. Which modules/functionality is using it.
    4. Side effects.
  2. Architecture
    1. Scalability
    2. Stability
    3. Functionality
    4. Robustness
  3. Technicalities
    1. Generic
      1. First pass: logic. Correctness. What does it (tries to) do.
        1. Side effects.
        2. Why is code there?
      2. Second pass: error handling & odd conditions.
        1. Side effects.
        2. Are returned codes checked. Can the code handle them.
        3. Arguments:
          1. Border/out of bounds/strange values handled.
          2. Arg type: convenient?
          3. Where is the data coming from? Three levels upstream.
          4. Where are the outputs going? Three levels downstream.
            1. What are the possible/permitted outputs? Are all handled downstream?
        4. Variables: initialized?
        5. (over/under)flows:
          1. buffers.
          2. integral types.
        6. Asserted invariants & assumptions.
        7. Loops: off-by-one? infinite?
        8. Recursion: base case?
      3. Third pass: thread safety.
      4. Localization?
      5. Duplicate information?
      6. Math:
        1. Small values processed first?
        2. NaN checks/std::isnan & friends.
        3. Division by zero.
    2. C
      1. return: resource handling.
      2. Use the N functions (ex. s'n'printf vs. sprintf).
      3. printf & friends: do formatters match type and number of arguments?
      4. Non re-entrant/non thread-safe API
      5. Unsafe/race condition afflicted API ( mktemp() )
      6. enums:
        1. all cases handled?
        2. default returns/logs/throws error
      7. Unspecified/undefined/implementation-defined/non-standard behavior or extensions
    3. C++
      1. Fourth pass: exception handling:
        1. In destructors.
        2. Exception catching boundaries?
        3. Are resources RAII guarded.
      2. Fifth pass: performance.
        1. C++11: perfect forwarding & temporaries.
        2. How does it scale?
      3. Initialized data members.
      4. The big 6 (default constructor, destructor, copy/move constructors/operators).
      5. Virtual destructor?
      6. Resource handling: RAII.
      7. Where is created & destructed? Lifetime management?
      8. Thorough const & volatile.
      9. Are predicates stateless.
      10. Use size_t for std::string positions.
      11. Why casts?
      12. Do not trace under lock
      13. Do not destroy objects under lock
  4. Platform specific
    1. POSIX/SUS
      1. Interrupted calls.
      2. Spurious wake-ups.
      3. Calls known to have race conditions.


Tools
[edit | edit source]
[edit | edit source]

/proc

[edit | edit source]

A pseudo-filesystem exposing information about running processes:

# tree /proc/26041
/proc/26041
...
|-- cmdline             # Command line
|-- cwd ->              /current/working/folder/for/PID
|-- environ             # Program environment variables
|-- exe -> /bin/su
|-- fd                  # Open files descriptors
|   |-- 0 -> /dev/pts/21
|   |-- 1 -> /dev/pts/21
|   |-- 2 -> /dev/pts/21
|   `-- 3 -> socket:[113497835]
|-- fdinfo
|   |-- 0
|   |-- 1
|   |-- 2
|   `-- 3
|-- latency
|-- limits
|-- maps
|-- mem
|-- mountinfo
|-- mounts
|-- mountstats
...

# cat /proc/26041/status
...
VmPeak:   103276 kB     # Max virtual memory reached
VmSize:   103196 kB     # Current VM
VmLck:         0 kB
VmHWM:      1492 kB
VmRSS:      1488 kB     # Live memory used
...
Threads:        1
...
References
[edit | edit source]
sysstat, sar
[edit | edit source]


Other tools

[edit | edit source]
addr2line
[edit | edit source]

Given an address in an executable or an offset in a section of a relocatable object, addr2line translates it into file name and line number.

c++filt
[edit | edit source]

A tool to demangle symbol names.

objdump
[edit | edit source]
  • Disassemble binary, with source code: objdump -C -S -r -R -l <binary>
Varia
[edit | edit source]
[edit | edit source]

Abbreviations

[edit | edit source]
  • HLE: Hardware Lock Elision
  • HT: Hyper Threading
  • RTM: Restricted Transactional Memory
  • TSX: Intel Transactional Synchronization Extension ([1], [2])