0% found this document useful (0 votes)
32 views24 pages

Tools and Techniques For Debugging I

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views24 pages

Tools and Techniques For Debugging I

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

Module 7.

Tools and Techniques for Debugging I


Debugging is an essential skill for software developers, providing the means to find
and fix errors in code. With the right tools and techniques, debugging can be a
smooth process that enhances the efficiency and quality of a program. This module
offers a comprehensive look at integrated development environments (IDEs),
stand-alone debugging tools, and tracing code execution.

In this module, you will explore:

● Understand what IDEs are and how they facilitate software development,
including setting up and exploring an IDE through practical applications.
● Learn about various stand-alone debugging tools and how to use them
effectively, focusing on techniques like breakpoints and stepping-through
functions.
● Delve into tracing techniques that assist in debugging, such as using
"Assert," "Print," and "Stop."

To enhance your understanding, we have tailored specific learning activities:

● Setting up and exploring an IDE through a basic "Add Student" application


● Utilising debugging tools to set breakpoints, step into and over functions
● Implementing tracing techniques like "Assert," "Print," and "Stop" for
debugging

Subject Learning Outcomes

The material in this module relates to the following subject learning outcomes:

​ SLO 5: Gain hands-on experience with debugging through various tools,


including IDEs, and understand how to set breakpoints, inspect variables,
and trace code execution.

Student Expectations

During this module, you are expected to spend time working through the prescribed
material prior to attending class. This will enable a more valuable discussion to take
place in online tutorials or conferences, where you will be able to discuss concepts,
present ideas and explore information collaboratively in greater depth.

Accordingly, it is suggested that you allow:

4 hours for facilitated study. This includes guided facilitated study, watching or
attending course lectures (live or pre-recorded), responding to facilitator feedback.

8 hours for personal study. This includes reading through course material,
undertaking learning activities and exploring additional related resources.

Topic 1. Introduction to Integrated Development


Environments (IDEs)

Key takeaways from this topic...

1. IDEs provide an all-in-one environment for coding, debugging, and testing,


streamlining the development process.
2. Many IDEs come with powerful features like code completion, version control
integration, and built-in debugging tools.
3. IDEs are often highly customisable, allowing developers to tweak the
environment according to their workflow and preferences.

Learner Guide
The Learner Guide provides the core knowledge for this topic. Work through the
materials and be prepared to discuss these in your forums, tutorials or classes.

Expand All

Panels

Collapse All

Panels

Section 1: Introduction to Integrated Development Environments (IDEs)

An IDE is a powerful software suite that combines various features and utilities to
facilitate the seamless development of software applications. Essentially, it is a
one-stop solution that aids programmers in writing, testing, and deploying code more
efficiently, effectively shortening the development cycle and enhancing productivity.

Catering to Diverse Developer Needs

IDEs cater to a broad spectrum of developers, from novices to seasoned


professionals. For beginners, IDEs provide a supportive environment where they can
learn coding principles without getting bogged down by the complexities of setup and
configuration.

For experienced developers, the extensive features and customisation options


available in IDEs enable them to work at peak efficiency, tailoring the environment to
suit their specific project requirements.

The Impact on Modern Programming

Today, IDEs are central to the software development landscape. They have not only
simplified coding but also fostered collaboration and innovation, allowing teams to
work cohesively and leverage each other's expertise to build complex and
sophisticated software solutions. Through features like debugging, code completion,
and collaboration tools, IDEs have truly transformed the way programmers approach
software development.

Section 2: Core Features and Customisation Opportunities within IDEs

Explore the core functionalities of an IDE and understand the diverse customisation
opportunities that they offer to cater to individual project needs.

Features of an IDE

a. Text Editor: A central feature that facilitates code writing.


b. Compiler: This utility translates your written script into a format ready for
execution.
c. Debugger: A critical feature to help identify and correct errors in your code.
d. Auto-completion: Proposes code suggestions as you type, expediting the
coding process.
e. Syntax Highlighting: Differentiates elements of the code through coloured
text, enhancing readability and comprehension.
Customisation and Extensions

Most IDEs provide extensive personalisation options, allowing for the addition of
extensions that support different languages, debuggers, or version control systems.
For example, Visual Studio Code maintains a marketplace for a variety of extensions
to accommodate diverse needs.

Advanced Utilities and Collaborative Features

● Integrated Terminal
An attribute that optimises your workflow by enabling shell commands
execution directly within the IDE.
● Code Profiling
Certain IDEs offer built-in tools for measuring various metrics such as
memory usage and CPU consumption.
● Database Management
Some IDEs incorporate features for executing SQL queries and managing
databases directly within the platform.
● Dependency Management
Facilitates easy addition, update, or removal of external libraries that your
project relies upon.
● Code Review Tools
These facilitate team members to comment on each other’s code, propose
changes, and merge pull requests directly within the IDE.
● Support for Multiple Languages
Most IDEs are versatile, offering support for a range of programming
languages.
● Collaboration Features
Modern IDEs come equipped with features to foster team collaboration,
including functionalities like pair programming, code sharing, and real-time
coding sessions. Visual Studio, for instance, hosts a feature named “Live
Share” for this purpose.

Further Reading
What is an IDE?

Links to an external site.

Explore the IDE concept further and discover the different types such as Desktop
IDEs, Cloud IDEs, Mobile App Development IDEs, and Database-Specific IDEs.
Learn how to choose an IDE based on factors like programming language, operating
system, pricing model, and features.

Reference: Geeks for Geeks, n.d., 'What is an IDE?', Geeks for Geeks, accessed 31 January 2024,
<https://www.geeksforgeeks.org/what-is-ide/>

Section 3: Case Study - Leveraging Integrated Tools for Scientific Research

In this case study, we examine a real-world scenario where a team of data scientists
at a prominent research institution leveraged the power of an Integrated
Development Environment (IDE) to streamline their research process and enhance
the quality of their work.

Scenario

A group of data scientists were tasked with developing complex machine learning
models to analyse vast datasets for a critical research project. The team faced
challenges in managing code, data, and computational resources efficiently, with
their workflow involving coding, data analysis, and version control.

The Selection of JupyterLab

To address these challenges, the team opted for JupyterLab, a web-based IDE
specifically tailored for scientific computing and data science workflows. JupyterLab
offers an integrated environment that encompasses text editors, terminals, data file
viewers, and other tools essential for data analysis and scientific computing.

Implementation and Workflow

With JupyterLab, the team could centralise all their tools and resources in one place.
They were able to write code, perform data analysis, and manage version control, all
within a single platform. The following features of JupyterLab were particularly
beneficial:

1. Interactive Computing
The team could create and share documents that contained live code,
equations, visualizations, and narrative text, fostering collaborative analysis
and data exploration.
2. Extensibility
JupyterLab offered the team the flexibility to customize and extend their
environment with additional tools and features, aligning with the specific
requirements of their project.
3. Integrated Tools for Data Visualisation
The IDE provided powerful tools for data visualisation, enabling the team to
generate insightful graphs and charts that facilitated data interpretation and
reporting.
4. Version Control
JupyterLab's integration with version control systems allowed the team to
manage changes to their codebase efficiently, tracking revisions and
maintaining a history of modifications.
Outcome

The implementation of JupyterLab dramatically improved the team's overall


productivity and research quality. The centralised, integrated environment facilitated
smoother collaboration and communication among team members, enabling them to
work more cohesively and achieve their project objectives with increased efficiency
and effectiveness.

Moreover, the platform's user-friendly interface and powerful tools for data analysis
and visualisation helped the team to glean more insightful findings from their data,
contributing to the success of their research project.

Topic 2. Using Stand-Alone Debugging Tools

Key takeaways from this topic...

1. Stand-alone debugging tools can offer specialised features not found in IDEs,
making them useful for targeted debugging scenarios.
2. Features like setting breakpoints and stepping into/over functions are
essential for thorough debugging.
3. Some stand-alone debugging tools work across multiple platforms and
languages, offering more flexibility.

Learner Guide

The Learner Guide provides the core knowledge for this topic. Work through the
materials and be prepared to discuss these in your forums, tutorials or classes.

Expand All
Panels

Collapse All

Panels

Section 1: Stand-Alone Debugging Tools

Debugging is an essential step in the software development process, where errors or


"bugs" in the code are identified and rectified. While IDEs often incorporate
debugging tools, at times, stand-alone debugging tools become indispensable. This
section provides a guide to these tools, highlighting their types and benefits.

What are Stand-Alone Debugging Tools?

These are specialised tools designed to function independently from an IDE, offering
functionalities like code inspection, breakpoint management, and sometimes reverse
engineering capabilities. These tools are versatile and can provide deep analysis
and insights into your code’s behavior, often more than what's possible with an
integrated debugger.

Popular Debugging Tools

1. GDB
2. Links to an external site.
3. (GNU Debugger)
A popular open-source debugger, accommodating numerous languages
including C and C++.

4. WinDbg
5. Links to an external site.
6.
A comprehensive debugger for Windows, facilitating both kernel-mode and
user-mode debugging.

7. Fiddler
8. Links to an external site.
9.
Predominantly used to debug HTTP transactions.

10. Wireshark
11. Links to an external site.
12.
A tool focused on network debugging, it captures and analyses network
packets.

13. Valgrind
14. Links to an external site.
15.
This tool is significant for memory debugging, leak detection, and profiling.

Section 2: Advantages and Usage of Stand-Alone Debugging Tools

Why Use Stand-Alone Debugging Tools?

Utilising stand-alone debugging tools presents several benefits, including advanced


features not found in IDEs, resource efficiency, flexibility, and the capacity for deeper
analysis, assisting in achieving a more detailed insight into your project.

How to Use Stand-Alone Debugging Tools


Understanding how to use these tools effectively can enhance your debugging skills
considerably. The process includes:

1. Installation
Download and set up the tool compatible with your OS and programming
language.
2. Code Configuration
Adjust your code to be debug-ready, typically by including debugging
information during compilation.
3. Launching the Debugger
Load your code into the opened debugger.
4. Setting Breakpoints
Establish points in the code where you wish to pause for inspection.
5. Start Debugging
Execute the debugger, which will run your code until a breakpoint is reached,
facilitating variable, memory, and CPU registers inspection.
6. Step Through Code
Further execute your code step-by-step to comprehend its behaviour in
various scenarios.

Further Reading

Debugging: A Basic Beginner's Guide

Links to an external site.

Further explore the intricacies and considerations of debugging in software


development and learn various debugging tools and techniques, including
debuggers, profilers, logging and tracing tools, memory debuggers, code analysis
tools, and unit testing frameworks.

Reference: Sonar staff, n.d. 'debugging: basic beginner's guide', Sonar, accessed 31 January 2024,
<https://www.sonarsource.com/learn/debugging/>
Section 3: Case Study - Debugging Memory Leaks in a Web Application

Background

In the fast-paced world of web development, a team is working tirelessly on a


complex web application designed to streamline business processes for a growing
company. As they approach the deployment phase, they encounter a persistent
issue: a memory leak that seems to be slowing down the application significantly.
The issue has started to affect the performance and stability of the application,
causing occasional crashes which were threatening to delay the project timeline.

Scenario

Despite having used the debugging functionalities integrated into their preferred IDE,
the team has struggled to pinpoint the source of the memory leak. The intermittent
nature of the issue and the vast codebase were making it increasingly difficult to
locate the exact point where the leak was occurring. The clock was ticking, and the
pressure to resolve the issue promptly was mounting.
Decision to Use Valgrind

Realising that a more specialised approach was needed, the team decided to utilise
Valgrind, a renowned stand-alone debugging tool. Valgrind is well-regarded in the
industry for its ability to provide detailed insights into memory usage and potential
leaks, often outperforming integrated debugging tools in this aspect.

Implementation and Process

The team initiated the process by configuring their codebase to include detailed
debugging information, making it compatible with Valgrind's analysis tools. After
setting up Valgrind, they ran the application through various scenarios, with Valgrind
monitoring the memory allocations and deallocations happening in the background.

Valgrind's memory error detector, Memcheck, proved to be particularly beneficial. It


helped the team to monitor the memory usage in real-time, flagging potential areas
of concern. The tool was able to point to the exact lines of code where memory
allocations were not being properly deallocated, leading to the memory leak.

Solution and Outcome

After a series of rigorous sessions with Valgrind, the team successfully identified the
issue: a complex data structure was not being cleared properly, leading to gradual
memory buildup over time. Armed with this detailed information, they were able to
address the issue at its root, optimizing the code to prevent memory leaks and
improving the overall stability of the application.

Now, the application ran smoother, with significantly reduced chances of crashes due
to memory leaks. The team also documented their experience with Valgrind, creating
a guideline for leveraging stand-alone debugging tools for future projects, fostering a
culture of continuous learning and adaptation.
Topic 3. Tracing Code Execution

Key takeaways from this topic...

1. Tracing techniques such as assert, print, and stop provide real-time insights
into how the code is being executed.
2. Tracing is invaluable for quickly identifying the origins of errors or unexpected
behaviours in code.
3. Some tracing methods allow for conditional monitoring, executing only when
specific conditions are met, thus providing focused debugging.

Learner Guide

The Learner Guide provides the core knowledge for this topic. Work through the
materials and be prepared to discuss these in your forums, tutorials or classes.

Expand All

Panels

Collapse All

Panels

Section 1: Understanding Tracing Code Execution

What is Tracing Code Execution?


Tracing is essentially following the path that a program takes during its execution. It
allows you to see the order in which functions are called, where variables change
their values, and what output is generated at each step.

Methods for Tracing Code Execution

● Manual Tracing
Involves going through the code line-by-line manually, keeping track of
variables and flow of execution.
● Print Statements
Inserting print statements at key points to display the current state or value
of variables.
● Built-in Debuggers in IDEs
These allow you to pause execution, step through code one line at a time,
inspect the state, and even change variables in mid-execution.
● Profiling Tools
Specialised tools that offer in-depth statistics about resource consumption
of functions.
● Tracing Software
Designed to track the execution of code and report back in various
formats.

Section 2: Implementing Tracing

In this section, we delve deeper into each method of tracing code execution,
providing a comprehensive guide on how to use them effectively, alongside their
advantages and disadvantages.

Manual Tracing

Manual tracing is a fundamental method where developers follow the flow of


execution by inspecting each line of code manually.
How to Use
Begin by displaying the code on screen or taking a printout. Use a pen or a cursor to
trace each line, jotting down the state of variables at each step, which helps in
keeping track of the program’s progression.

Advantages
It’s a straightforward method that doesn’t require any additional tools, providing a
raw understanding of the code's flow.

Disadvantages
Can be quite time-consuming and prone to human error, especially for complex code
with numerous lines and functions.

Print Statements

This technique involves inserting print statements at key points in the code to
monitor the state or value of variables as the program runs.

How to Use
Depending on the programming language, use functions like print() in Python or
System.out.println() in Java to insert messages that will display the current
state at various stages in the code.

Advantages
It offers a quick way to monitor the code’s behaviour in real-time.

Disadvantages
Can clutter the code, making it less readable, and may not provide in-depth
information for complex debugging scenarios.

Built-in Debuggers in IDEs


Most Integrated Development Environments (IDEs) offer built-in debuggers that
allow developers to comprehensively inspect the flow of code execution.

How to Use
Configure the debugger in your IDE and set breakpoints at critical points in the code.
Once the debugger is running, you can inspect variables and the flow of execution
as it hits these breakpoints. Additionally, you have the flexibility to modify variables
during runtime to test different scenarios.

Advantages
These debuggers are powerful, offering extensive features that facilitate a deep
analysis of code behaviour.

Disadvantages
May have a steep learning curve, particularly for beginners, and integrating them into
the workflow can sometimes be complex.

Profiling Tools

Profiling tools are specialised utilities that provide detailed statistics on the resource
consumption of various functions in your code, helping to identify bottlenecks and
optimize performance.

How to Use
Run these tools alongside your code. They generate a report outlining aspects like
time-consuming functions and memory usage, offering insights into the areas where
optimisation is necessary.

Advantages
These are excellent resources for optimising code, providing deep insights into the
performance characteristics of your application.
Disadvantages
While great for performance optimisation, they might not be the best tools for
identifying logic errors or understanding complex algorithmic flows.

Tracing Software

Tracing software is designed to meticulously track the execution of code and report
the findings in different formats, offering real-time insights into the program’s
behaviour.

How to Use
Integrate the software into your development environment and run your code through
it. These tools provide a detailed trace of the execution, offering insights that can be
invaluable in debugging complex issues.

Advantages
Can provide real-time insights and comprehensive data about code execution,
facilitating deep analysis and understanding of code behaviour.

Disadvantages
May be an overkill for simple projects and can sometimes introduce a performance
overhead.

Further Reading

Tracing Code in C++

Links to an external site.


Learn more about tracing code in C++ for real-time insights and deep analysis of
code behaviour using tracing software.

Reference: Josh Weinstein 2020, 'Tracing Code in C++', Medium, accessed 31 January 2024,
<https://medium.com/swlh/tracing-code-in-c-fd9470e3bf5>

Section 3: Case Study - Debugging a Shopping Cart Issue Through Tracing

Identifying the Issue

Faced with a recurrent problem where items would mysteriously vanish from
customers' shopping carts, causing annoyance and a potential drop in sales, the
development team needed to pinpoint the underlying issue. The problem seemed
random and elusive, making the traditional approaches ineffective in diagnosing the
root cause.

Choosing Debugging Methods

To navigate this complex scenario, the team planned a meticulous approach by


combining various tracing code execution techniques:
● Print Statements
The team embedded print statements strategically within the code,
enabling real-time tracking of the shopping cart's status during various
critical stages, such as adding or removing items and initiating the
checkout process.
● IDE Debugging
Simultaneously, the powerful debugging features in their IDE were
employed to scrutinise variable states and logic flow at distinct
breakpoints, offering deeper insights into the code's functioning at pivotal
junctions.

Gathering Data

The data collection phase witnessed intensive efforts:

● Print Statements Data


This method recorded dynamic changes to the shopping cart's status.
These outputs illustrated the current items and their quantities at different
phases, painting a detailed picture of the cart's transitions.
● IDE Debugging Insights
The IDE debugger allowed the team to halt the code temporarily at
specific points, facilitating a deeper investigation into the states of various
variables and how the shopping cart's state was being altered during the
process.

Uncovering the Culprit

After numerous debugging sessions, the team unearthed the core of the problem: a
malfunction within the updateCart() function. This function, meant to adjust the
shopping cart's status when an item's quantity was altered, harboured a bug that
removed items under specific conditions - notably, when a customer had more than
five items in the cart and chose to modify the quantity of any item.
Implementing the Solution

Having identified the problem, the team embarked on a mission to rectify it:

● Modifying the UpdateCart() Function


The team reworked the function to handle all scenarios appropriately,
thereby preserving the shopping cart's stability during all operations.
● Testing the Solution
An extensive battery of tests was conducted before deploying the fixed
function, to ensure a fluid and error-free shopping experience for the
customers.

Outcome

The rigorous approach and the synergistic use of multiple debugging methods
yielded results, and the disappearing items issue was finally resolved. The proactive
response not only ensured a smoother user experience but also potentially saved
the business from significant revenue losses. This episode fortified the team's
confidence in the power of detailed code tracing and showcased how a multifaceted
approach could effectively untangle even the most perplexing issues in software
development.

Further Resources
The resources in this section are for further exploration, providing additional
information for deeper insights.

Expand All
Panels
Collapse All
Panels
Reading: C/C++ Debugging Tools
This article provides an overview of various debugging tools available for C/C++
applications. It covers different aspects of debugging, starting with the importance of
automated testing, including Test-Driven Development and unit test frameworks like
QTestLib, Google Test, and Catch.

C/C++ Debugging Tools

Links to an external site.

Reference: David Faure, 2022, 'C/C++ Debugging Tools', KDAB [online] url:
https://www.kdab.com/c-cpp-debugging-tools/ [Accessed 31 Jan. 2024]

Reading: Top Tips for Debugging C++


This article features Greg Law, the co-founder and CEO at Undo, sharing essential
debugging tips for C++ developers. His tips cover a range of topics, including the
importance of having a comprehensive set of debugging tools, utilizing conditional
breakpoints for efficient debugging, using watchpoints to track changes in variable
values, enhancing variable printing with pretty-printers, exploring Time Travel
Debugging to analyse program execution history, and utilising the find command in
GDB to search for specific byte sequences in memory.

Top Tips for Debugging C++

Links to an external site.

Reference: Anastasia Kazakova & Greg Law, 2021, 'Top Tips for Debugging C++', Jet Brains [online]
url: https://blog.jetbrains.com/clion/2021/06/7-top-tips-for-debugging-cpp/ [Accessed 31 Jan. 2024]

Video: A Guide to Debugging C++ Code - Practical Examples


We like to write code but—despite our best efforts—we make mistakes. Our program
will contain bugs. Sometimes, we don’t write what we mean to write, sometimes we
don’t understand an aspect of our programming language and at other times we
lack—or fail to consider—some critical information about our program’s system
environment. As a result, our program will not behave correctly. What do we do now?

In this talk, experienced developer Sebastian Theophil takes you through the entire
debugging process, starting with a program that crashes. What do we do next?
Which questions do we have to ask? What information do we need? What can we do
to find the cause of the crash? Which tools can help us in this quest, and, last but not
least, what can we do to make sure this bug never happens again?

A Guide to Debugging C++

Links to an external site.

(44:22)
Reference: Sebastian Theophil, 2023, 'A Guide to Debugging C++ Code: Practical and Interactive
Examples', YouTube [online video] url: https://youtu.be/Rc2hFf1HVow [Accessed 19 Jan, 2024]

Video: Back to Basics - Debugging in C++


In this talk from CppCon 2022, Mike Shah shows you how to debug C++ code,
starting from the very basics and then demonstrating how a debugger like GDB can
be used to help you track errors in CPU code. Learn about debugging techniques
(e.g. delta debugging), and several debugging tools (stepping through code,
capturing backtraces, conditional breakpoints, scripting, and even time traveling!).

Back to Basics: Debugging in C++

Links to an external site.

Reference: Mike Shah, 2022, 'Back to Basics: Debugging in C++', YouTube [online video] url:
https://youtu.be/YzIBwqWC6EM [Accessed 19 Jan. 2024]

Video: GDB Debugging - How to Debug a C/C++ Program


GDB is a powerful debugger that allows us to work with C/C++ code from inside the
operating system terminal. Mastering GDB will help you evolve as a programmer and
open doors to optimize your code and find potential errors.

This video explains what the GDB debugger can do, walking you through executing
the GDB tool step-by-step to demonstrate the most common commands to add
breakpoints, watch variables, and pause/resume the execution of C++ code.

GDB Debugging

Links to an external site.

(18:07)

Reference: pikuma, 2019, 'GDB Debugging: How to Debug a C/C++ program', YouTube [online video]
url: https://youtu.be/gFCQ37jVN3g [Accessed 19 Jan. 2024]

Reading: Debugging without an IDE - Using GDB


Debugging is clearly an important skill for any programmer in any language, with
C++ probably requiring better debugging skills than most popular languages, due to
its relative complexity. What’s more, the actual problems we solve with C++ tend to
be more complex, which may bring about unexpected results that require analysis
and debugging.
This post provides a step-by-step demonstration intended to teach just enough to
allow any programmer to debug code on the terminal alone, and to do so with more
ease than you may have thought possible.

Debugging without an IDE

Links to an external site.

Reference: Joseph Sibony, 2022, 'A Step-by-step Crash Course in C++ Debugging without IDE –
Empowering the terminal by using GDB', Incredibuild blog [online] url:
https://www.incredibuild.com/blog/a-step-by-step-crash-course-in-c-debugging-without-ide [Accessed
31 Jan. 2024]

Resources: Debugging C++ Code using Visual Studio


Following are a series of readings and videos that explain and demonstrate the
debugging features and abilities of Visual Studio.

● Learn to Debug C++ Code using Visual Studio (2022)


● Links to an external site.
● - Microsoft VS 2022 documentation
● Basic Debugging in Visual Studio (2024)
● Links to an external site.
● - LinkedIn Learning video (04:12)
● Visual Studio: Advanced Debugging Tools (2020)
● Links to an external site.
● - LinkedIn Learning course (2.5hrs)
● New Debugger Features in Visual Studio 2022
● Links to an external site.
● - video (09:47)

You might also like