Part 1 SAS/C Development System User's Guide Volume 2: Debugger, Utilities, Assembler Version 6.0 SAS Institute Inc. SAS Campus Drive Cary, NC 27513The correct bibliographic citation for this manual is as follows: SAS Institute Inc., SAS/C Development System User's Guide, Volume 2: Debugger, Utilities, Assembler, Version 6.0, Cary, NC: SAS Institute Inc., 1992. 363 pp. SAS/C Development System User's Guide, Volume 2: Debugger, Utilities, Assembler, Version 6.0 Copyright 1992 by SAS Institute Inc., Cary, NC, USA. ISBN 1-55544-497-0 All rights reserved. Printed in the United States of America. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, photocopying, or otherwise, without the prior written permission of the publisher, SAS Institute Inc. 1st printing, June 1992 The SAS System is an integrated system of software providing complete control over data access, management, analysis, and presentation. Base SAS software is the foundation of the SAS System. Products within the SAS System include SAS/ACCESS, SAS/AF, SAS/ASSIST, SAS/CPE, SAS/DMI, SAS/ETS, SAS/FSP, SAS/GRAPH, SAS/IML, SAS/IMS-DL/I, SAS/OR, SAS/QC, SAS/REPLAY-CICS, SAS/SHARE, SAS/STAT, SAS/CALC, SAS/CONNECT, SAS/DB2, SAS/EIS, SAS/ENGLISH, SAS/INSIGHT, SAS/LAB; SAS/LOOKUP, SAS/NVISION, SAS/PH-Clinical, SAS/SQL-DS, SAS/TOOLKIT, and SAS/TUTOR software. Other SAS Institute products are SYSTEM 2000 Data Management Software, with basic SYSTEM 2000, CREATE, Multi-User, QueX, Screen Writer, and CICS interface software; NeoVisuals software; JMP, JMP IN, and JMP Serve software; SAS/RTERM software; and the SAS/CI Compiler and the SAS/CX Compiler. MultiVendor Architecture and MVA are trademarks of SAS Institute Inc. SAS Institute also offers SAS Consulting and On-Site Ambassador services. SAS Communications, SAS Training, SAS Views, the SASware Ballot, and Observations are published by SAS Institute Inc. All trademarks above are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. (r) indicates USA registration. The Institute is a private company devoted to the support and further development of its software and related services. Amiga Includes and Development Tools Version 2.0 Copyright (c) 1990 Commodore-Amiga, Inc. All rights reserved. Amiga Workbench Version 2.0 Copyright (c) 1988, 1990 Commodore-Amiga, Inc. All rights reserved. Installer Copyright(c) 1991-1992 Commodore-Amiga, Inc. All rights reserved. AmigaGuide and WDisplay Copyright(c) 1991-1992 Commodore-Amiga, Inc. All rights reserved. Distributed under license from Commodore. Amiga, AmigaDOS, Workbench, and AmigaGuide are registered trademarks or trademarks of Commodore-Amiga, Inc. Commodore is a registered trademark or trademark of Commodore Electronics Limited. Other brand and product names are registered trademarks or trademarks of their respective companies. Doc S17, Ver212.0, 062492 Contents vii Reference Aids ix Credits xi Acknowledgments xiii Using This Book Part 1 Using the SAS/C Debugger Page 3 Chapter 1 Introduction to CodeProbe 3 Introduction 4 CodeProbe Overview 9 Compiling and Linking Your Program 9 Running CodeProbe 12 CodeProbe Windowing Interface 16 Entering Commands 25 Chapter 2 Sample CodeProbe Session 25 Introduction 25 A Walk through a Typical Application 35 Chapter 3 Debugging Your Program 35 Introduction 37 Sample Program 1 39 Controlling Program Execution 53 Sample Program 2 57 Examining Data and Data Structures 73 Chapter 4 Setting Up the Debugging Environment 73 Introduction 77 Determining Source File Location 78 Choosing Command-line Options 81 CodeProbe Initialization 82 Setting and Showing Options within CodeProbe 89 Customizing Dialog Window Commands 95 Chapter 5 Working in Cross-Development Mode 95 Introduction 95 Why Debug in Cross-Development Mode? 96 Using the Cross Debuggeriv Contents 101 Chapter 6 Using AREXX Macros with CodeProbe 101 The AREXX Interface 101 Macros Provided by CodeProbe 102 Invoking Macros 103 Values Returned from CodeProbe Commands 105 Chapter 7 Debugging Resident Libraries 105 Introduction 105 Setting Breakpoints 106 The symload Command 106 The libraries.cpr AREXX Macro 106 Cautions 106 Limitations 106 Example 107 Chapter 8 Debugging Multitasking Programs 107 Introduction 108 Types of Tasks 108 How CodeProbe Handles Tasks 109 Commands Used to Control Tasks 113 Design Considerations for Debugger Compatibility 115 Chapter 9 Commands and Built-in Functions 115 Introduction 115 CodeProbe Commands 118 Special Parameters 126 Command Reference 202 Built-in Functions 203 Built-in Function Reference Part 2 Using the SAS/C Utilities 215 Chapter 10 Utility Reference Part 3 Using the SAS/C Macro Assembler 299 Chapter 11 Using Assembly Language with C Language 299 Introduction 300 Writing Assembly Language Functions 314 Communicating between Assembly Language and C Language 323 Running the Assembler v Contents Part 4 Using the SAS/C opeimizer 329 Chapter 12 Optimizing Your Code 329 Introduction 329 The Global Optimizer 334 The Peephole Optimizer 334 Running the Optimizers Part 5 Appendix 341 Appendix diff File-Matching Algorithm 343 Index vi vii Reference Aids Displays 12 1.1 Initial CodeProbe Screen 13 1.2 CodeProbe Windows 28 2.1 Source Window Showing Mixed Mode 28 2.2 Source Window Showing Assembly Mode Figures 275 10.1 Example File Dependencies 317 11.1 The Stack after the func Module Is Called Tables 17 1.1 Command Line Editing Functions 18 1.2 Escape Sequences in Character Strings 19 1.3 Escape Sequences in Commands 20 1.4 Pull-down Menu Items 23 1.5 Function and Special Keys 24 1.6 Menu Accelerator Keys viii ix Credits Software The SAS/C Development System is designed, built, and tested through the combined effort of many people at SAS Institute. The AmigaDOS development group includes the following individuals: Principal Steve Krueger, Douglas Walker, Michael S. Developers Whitcher Testing and Twilah K. Blevins, Jim Cooper, Bob Patten, Technical Khristi Tomlinson Support These individuals continue to support future development of the SAS/C Development System. Others who have contributed to the SAS/C Development System are as follows: Development Edmund Burnette, Dave Frederick, Russell Gonsalves, Tony Hefner, loe Hutchinsoll, Glenn Musial, John Roth Testing and Alan R. Beale, John W. Gillikin, Charles Tudor Technical Support Documentation Composition Candy R. Farrell, Denise T. Jones, Pamela A. Troutman Graphic Design Creative Services Department Proofreading Patsy P. Blessis, Heather B. Dees, Laurie J. Medley, Karen A. Olander, Josephine P. Pope, Christian Schwoerke, Susan E. Willard Technical Review Elizabeth Brownrigg, Edmund Burnette, Jim Cooper, Steve Krueger, Johll Roth, Khristi Tomlinson, Douglas Walker, Michael S. Whitcher Writing and Jeanne Ferneyhough, Hanna lIicks, Keith Wagner, Editing Steve Krueger, Douglas Walker, Helen Weeks, Khristi Tomlinsorlx xi Acknowledgments Many people make significant and continuing contributions to the development of the SAS/C Development System. First among them is John A. Toebes VIII, who was instrumental in the development of Versions 4.0 and 5.0 and who directed the early development of Version 6.0. Others who have contributed to the development and testing of Version 6.0 of the SAS/C Development System include Ralph Babel, Bruce M. Drake, Nathan S. Fish, Maximilian Hantsch, Randell Jesup, David N. Junod, Andrew Kopp, Martin J. Laubach, Christian Ludwig, Andrew N. Mercier, Mike Meyer, Larry Rosenman, Carolyn Scheppner, Steve Shireman, Michael Sinz, Martin Taillefer, Steve Tibbett, John Wiederhirn, Loren Wilton, and Kenneth Yarnall. The final responsibility for the SAS/C Development System lies with SAS Institute alone. We hope that you will always let us know your feelings about our product and its documentation. It is through such communication that the progress of SAS software continues to be accomplished. Not to mention the two pirates who spent hours of their own time reproducing this document. Mikey The Bad & Deicide still live! xii xiii Using This Book Purpose SAS/C Development System User's Guide, Volume II: Debugger, Utilities, Assembler describes how to use some of the major tools available to the SAS/C programmer under AmigaDOS: the debugger, the macro assembler, the optimizer, and the various utilities that are part of the SAS/C Development System. "Using This Book" describes how you can best use this book. It describes the book's intended audience, the audience's prerequisite knowledge, the book's organization and its conventions, and additional documentation that is available to you. Audience The information in this book is written for experienced C programmers. This book assumes you have a working knowledge of the C language and the AmigaDOS operating system. To use the SAS/C Macro Assembler, you also need a working knowledge of assembly language. For a list of publications you can use to learn the C language or the AmigaDOS operating system, refer to the "Additional Documentation" section at the end of "Using This Book." How to Use This Book This section gives an overview of the book's organization and content. The book's chapters are described, followed by a section on how to use each chapter. Organization SAS/C Development System User's Guide, Volume II: Debugger, Utilities, Assembler is divided into four parts plus an appendix; the chapters contained in each part and the appendix are described here: Part 1: Using the SAS/C Debugger Part 1 contains nine chapters that discuss CodeProbe and how to use it to debug your program. Chapter 1, "Introduction to CodeProbe" explains what CodeProbe does, how it works, and what tasks are involved in debugging a program. This chapter also describes how to compile and link your program under CodeProbe control.xiv Using This Book Chapter 2, "Sample CodeProbe Session" contains a brief sample session using the lines.c program in the sc:examples drawer. You can follow this sample session to gain experience with the most commonly used debugger commands. Chapter 3, "Debugging Your Program" describes the CodeProbe commands most frequently used for stepping through your program, displaying code and data, and modifying code or data. Chapter 4, "Setting Up the Debugging Environment" describes the commands and options you can use to customize the environment in which you debug your program. Chapter 5, "Working in Cross-Development Mode" describes how to run your executable code from a serially- connected Amiga system. Chapter 6, "Using AREXX Macros with CodeProbe" describes how to use AREXX macros from inside CodeProbe. This chapter contains a list of valid AREXX commands. Chapter 7, "Debugging Resident Libraries" describes how to use CodeProbe to debug resident libraries. Chapter 8, "Debugging Multitasking Programs" describes how to use CodeProbe with applications that spawn additional tasks. Chapter 9, "Commands and Built In Functions" describes each CodeProbe command and built-in function in detail. Part 2: Using the SAS/C Utilities Part 2 contains only one chapter. This chapter discusses the SAS/C utilities. Chapter 10, "Utility Reference" describes each of the utilities (such as smake, scopts, and tb) provided by the SAS/C Development System. Part 3: Using the SAS/C Macro Assembler Part 3 contains only one chapter. This chapter discusses how to use assembly language with C language. Chapter 11, "Using Assembly Language with C Language" describes how to communicate between C language and the assembler. You can incorporate assembler routines as part of your C program or call C functions from assembly language.xv Using This Book Part 4: Using the SAS/C Optimizer Part 4 contains only one chapter. This chapter discusses how to use the SAS/C Optimizer. Chapter 12, "Optimizing Your Code" describes what the global and peephole optimizers do and how to run the optimizers during compilation. The appendix, "diff File-Matching Algorithm," describes the algorithm used by the diff utility to compare files. What you should read. The following table points you to specific chapters in this book for information on particular topics. For other references, refer to "Additional Documentation" later in this section. For information on You should read compiling, linking, and running your program Chapters 1 and 4 under the debugger using the most common debugger commands Chapters 2 and 3 customizing your debugging environment Chapter 4 running your program on one machine and Chapter 5 debugging it on another machine using AREXX macros Chapter 6 debugging resident libraries Chapter 7 debugging multitasking programs Chapter 8 Conventions This section covers the typographical and syntax conventions used in this book. Typographical Conventions The SAS/C books for AmigaDOS use special fonts to depict specific Conventions types of information. These typographical conventions are as follows: roman is the basic type style used for most text. monospace is used to show example statements or programs. Monospace is used also for items specific to the xvi Using this Book C language, such as the names of functions, header files, and keywords. obligue is used for arguments or variables whose values are supplied by the user; for example, you should enter an appropriate filename when you see filename. italic is used for terms that are defined. Italic is also used to indicate arguments for which you supply a value. Syntax Conventions This book uses the following conventions for syntax: monospace indicates commands, keywords, and switches that should be spelled exactly as shown. These arguments may or may not be optional, depending on whether they are enclosed in square brackets. italic indicates arguments for which you supply a value. [] indicate an optional argument when they surround the (square argument. brackets) . . . (ellipsis) indicates that you can repeat the argument or group of arguments preceding the ellipsis any number of times. | means to choose one item from a group of items (vertical bar) separated by the bars. The following example illustrates these syntax conventions: env [function | integer] env is a command name, so it appears in monospace type. function is a function for which you supply the name, so it appears in italic type. [function | integer] are both optional, so they are enclosed in square brackets. function | integer indicates that you can specify only one of the items separated by the vertical bar. xvii Using This Book Additional Documentation The following sections list documentation you may find helpful in using the SAS/C Development System. SAS Documentation If you are interested in SAS documentation, you need to contact the Book Sales department by writing to the following address or by calling the following number: SAS Institute Inc Book Sales Department SAS Campus Drive Cary, NC 27513 919-677-8000 SAS/C Development System This book is part of a set of publications for the SAS/C Development System. There are three other publications in the set: SAS/C Development System User's Guide, Volume I: Introduction, Compiler, Editor describes how to install the SAS/C Development System on your Amiga system use your development environment create files in the editor compile and link C files. SAS/C Development System Library Reference describes how to access libraries create your own libraries use header files to reduce the amount of time and space required by your program. SAS/C Development System Quick Reference, Version 6.0 contains reference tables for the library functions, compiler and linker options, and debugger commands. These volumes are sold together as a set. You can order them by specifying order #A56l85. Other Documentation The following sections list additional reference material specific to the C language, Amiga and AmigaDOS programrning, and the Motorola 68xxx microprocessor.xviii Using This Book C Language The following books describe the C programming language: American National Standards Committee (1990), American National Standard for Information Systems--Programming Language C, Document Number X3J11/90-013, Washington, D.C.: X3 Secretariat: Computer and Business Equipment Manufacturers Association. Harbison, Samuel P. and Steele, Guy L., Jr. (1990), C: A Reference Manual, Third Edition, Englewood Cliffs, NJ: Prentice-Hall, Inc. Kernighan, Brian W. and Ritchie, Dennis M. (1988), The C Programming Language, Second Edition, Englewood Cliffs, NJ: Prentice-Hall, Inc. Amiga and AmigaDOS The following books provide information specifically about programming on the Amiga system. Most of the examples in these books are written in the C or assembler languages. Commodore-Amiga, Inc. (1991), Amiga Hardware Reference Manual, 3rd Edition, Reading, MA: Addison-Wesley Publishing Company. Commodore-Amiga, Inc. (1991), Amiga ROM Kernal Reference Manual: Devices, 3rd Edition, Reading, MA: Addison-Wesley Publishing Company. Commodore-Amiga, Inc. (1991), Amiga ROM Kernal Reference Manual: Includes and Autodocs, 3rd Edition, Reading, MA: Addison-Wesley Publishing Company. Commodore-Amiga, Inc. (1991), Amiga User Interface Style Guide, Reading, MA: Addison-Wesley Publishing Company. Commodore-Amiga, Inc. (1991), The AmigaDOS Manual, 3rd Edition, New York, NY: Bantam Books. Commodore-Amiga, Inc. (1992), Amiga ROM Kernal Reference Manual: Libraries, 3rd Edition, Reading, MA: Addison-Wesley Publishing Company. Motorola 68xxx The following books contain information specifically about programming the Motorola 68xxx microprocessor. Motorola, Inc. (1987), MC68881/MC68882 Floating-Point Coprocessor User's Manual, First Edition, Englewood Cliffs, NJ: Prentice-Hall, Inc. Motorola, Inc. (1989), MC68030 Enhanced 32-Bit Microprocessor User's Manual, Second Edition, Englewood Cliffs, NJ: Prentice-Hall, Inc. Motorola, Inc. (1989), Programmer's Reference Manual, Phoenix, AZ: Motorola Literature Distribution.xix Using This Book Contacting CATS You can contact Commodore Application and Technical Support at the following address: 1200 Wilson Drive West Chester, PA 19380 215-429-0643 1 Part 1 Using the SAS/C Debugger Chapters 1 Introduction to CodeProbe 2 Sample CodeProbe Session 3 Debugging Your Program 4 Setting Up the Debugging Environment S Working in Cross-Development Mode 6 Using AREXX Macros with CodeProbe 7 Debugging Resident Libraries 8 Debugging Multitasking Programs 9 Commands and Built-in Functions2 3 1 Introduction to CodeProbe 3 Introduction 4 CodeProbe Overview 4 Basic Features 4 Multitasking Features S Summary of Changes and Enhancements for Version 6.0 of the CodeProbe Debugger 5 Terminology 7 How CodeProbe Works 9 Compiling and Linking Your Program 9 Running CodeProbe 9 The cpr Command 10 The quit Command 10 Workbench Support 11 Line Mode 12 CodeProbe Windowing Interface 12 Screen Layout 14 CodeProbe Windows 16 Entering Commands 16 Command Line 20 Pull-Down Menus 22 Function and Special Keys 23 Menu Accelerator Keys Introduction CodeProbe is a powerful source-level debugger that enables you to monitor, line by line, the behavior of programs written in C language, assembly language, or a combination of the two. CodeProbe has many useful features and commands designed to aid you in tracking down your program's problems. Some of these aids provide the ability to examine and modify variables, address and data registers, and user- specified memory locations. CodeProbe gives you absolute control over the execution of your program by enabling you to stop execution at any point. It also enables you to examine both the C source and the (Throughout this manual, the terms CodeProbe and the debugger are used interchallgeably to refer to this debugger program.) 4 Chapter 1 assembler generated for your program at the same time so you can see what is really occurring at the assembly language level. This chapter explains what CodeProbe does, how it works, and what is involved in debugging a program. CodeProbe Overview CodeProbe implements a number of commands and features specifically designed to ease the debugging of C programs. In addition to a command-line interface, the debugger provides you with a sophisticated, screen-oriented interface where you can take advantage of multiple windows and pull-down menus. Shortcuts that are built into the program enable you to issue commands with a couple of keystrokes or mouse clicks. Basic Features As a source-level debugger, CodeProbe allows you to single-step through programs either in C source code or the generated assembler code set breakpoints on C source lines, or an individual assembly language statement continue program execution until a specified function or line number is reached, or until a variable contains a specified value or its value changes examine variables and code at the C language level display C data types--including structures, unions, arrays, enums, typedefs, and bit fields--in their C formats display memory dumps in a variety of formats continuously watch any C variable, array element, or structure member assign a value to a C variable fill an area of memory copy one C array or structure to another copy a string from one place to another view and manipulate register data access storage classes of data, including automatic, static, and register as well as external. Multitasking Features CodeProbe allows you to debug multitasking programs. Any new tasks or processes created by a program that is being debugged are automatically under debugger control. The following multitasking features are provided: Breakpoints can be set and trapped for any task generated under debugger control.5 Introduction to CodeProbe The state of any task in a multitasking application can be displayed including the stack and registers. Tasks can be started and stopped selectively. Tasks that are executing independently of the debugger can be intercepted and attached to the debugger. This can be useful if a process enters an infinite loop or waits indefinitely on a message port. Summary of Changes and Enhancements for Version 6.0 of CodeProbe Debugger The following changes and enhancements are introduced with Version 6.0 of the CodeProbe debugger: Cross debugger support IS provided via the serial port or a communications network. Debugging of shared libraries and devices has been simplified. C expression parsing is allowed with most debugger commands. The ability to display ranges within arrays is provided. The alias and define commands provide greater flexibility. 68881 floating-point registers are supported. Motorola fast floating-point format (ffp) display is provided. The env and where commands enable you to look back up the function call chain. The args command displays arguments to the current function. More compact debugging format saves space on disk. The AmigaDos Version 2.0 look and feel is provided, including public screens and three-dimensional look. The call command enables you to call application functions directly from the debugger. The source command enables you to specify the new name of a source file. The symbol, shell, and window commands have been added. Calls, Modules, and Memory windows have been added. Enhanced AREXX support is provided. Cross-referenced online help is provided in a separate window. The log command provides a Dialog window command logging capability. The jump command provides the ability to change the current location. Terminology This book frequently uses terms that you may not be familiar with. The following definitions are new or have unique meanings to the CodeProbe documentation: breakpoint is an address used to control program execution. Program execution is suspended when the breakpoint address is reached.6 Chapter 1 call frame is the stack area associated with a function's formal parameters, automatic variables, temporaries, saved registers, and the return address. There is one call frame per function invocation. cross-debugging is a debugging technique that uses two machines that are linked together. CodeProbe runs on one machine, and the application runs on the other. (See host machine and target machine later in this list.) environment in CodeProbe documentation, environment means the state of the machine. The state of the machine consists of the contents of memory, the contents of the registers, the contents of the stack, and the point of execution in the source code. The run environment is the actual environment at which you are stopped. The user environment is the last environment set with the env command. This environment is used when displaying registers and variables. It is reset to the run environment after a go command or any of the commands that step the program. host machine when cross-debugging, the host machine is the machine that is used to display the CodeProbe user interface. The actual debugging session takes place on this machine. (See cross-debugging earlier in this list.) image is an executable program, an AmigaDOS shared library, or an AmigaDOS device. The name of the image is the same as the name of the disk file from which the image is loaded. An image can be specified with several CodeProbe commands as part of the location parameter. line boundary is the imaginary boundary in the machine code that specifies the end of the code generated for a C source line. log file is a file created by CodeProbe that contains details of all of the activity that occurred in the Dialog window. A log session can be turned off and on with the log command. By default, the log file is turned off.7 Introduction to CodeProbe module is all code generated by a single C source file. The name of the module is the same as the name of the C source file that generated pass count is the number of times that a line has been executed. The after parameter is used with commands such as go and break to specify a pass count. symbol is a series of letters and numbers that specify a function, memory location, or a variable. target machine when cross-debugging, the target machine is the machine used to run the application. (See cross-debugging earlier in this list.) How CodeProbe Works CodeProbe requires debugging information to be present in the executable files before you can use most of its powerful debugging features. This means that if you want to run CodeProbe and view the C source file while it is running, you must compile that C source file with one of the debugging options, such as line, full, or symbol. The compiler will then include information in the executable files that will enable CodeProbe to reflect accurately the state of your application program in the Source window. The compiler supports several debugging options specifying the amount of debugging information that is passed on to the linker. The linker (slink) also allows you to add symbolic debugging information to modules compiled without debugging information or to strip all debugging information from the executable file. Refer to Chapter 4, "Setting Up the Debugging Environment," for a complete discussion of debugging options. When CodeProbe runs your program, it uses debugging information present in executable files to keep track of which C source lines correspond to which assembler instructions. When you specify one of the debug options to the compiler, the compiler generates debugging information in the form of H_DEBUG hunks that get placed into the object module for that source. The compiler can generate two different types of H_DEBUG hunks, line and symbolic. It also can vary the amount of information that goes into the symbolic H_DEBUG hunks based on the debug option. Hunks and H_DEBUG hunks are explained in Chapter 12, "How the Compiler Works," in the SAS/C Development System User's Guide, Volume I: Introduction, Compiler, Editor.8 Chapter 1 If you specify debug=line, then the compiler generates an H_DEBUG hunk that contains the source filename and a table of source line numbers to address offset pairs. CodeProbe uses this table to match up the line numbers for the source with the assembly instructions as your program is executing. In addition to debug=line, if you specify the addsym option to the linker (slink), then slink generates an H_SYMBOL hunk in the final executable file. The H_SYMBOL hunk contains a table of global symbols and their offsets into the data section. If you compile and link using the sc command, the addsym option is added automatically to the slink command line, provided that you specify any debug option except nodebug. Using the global symbol information, CodeProbe can locate the start of the symbol but not its size or type. CodeProbe assumes all such symbols are of type long. This feature can be useful if you are debugging large projects on small machines where there might not be enough memory to load symbolic debugging information. If you specify the debug=symbol or debug=full options to the compiler, then the compiler generates an H_DEBUG hunk containing high-level symbolic debugging information for the source. This includes information for external identifiers, information for structure or union tags and typedefs, local variables, and so on. CodeProbe searches this information when trying to display an item in C source mode. Controlling CodeProbe Among CodeProbe's controls are pull-down menus, Intuition-based windows, and mouse support. The debugger also has powerful commands that can be entered in the Dialog window. In addition, CodeProbe offers a number of special functions and keyboard shortcuts, including programmed function and menu accelerator keys to maximize efficiency. Debugging a Program Debugging a program using CodeProbe involves three basic steps: 1. Compile with debug information. (Use one of the debug= options with the sc command.) 2. Invoke the debugger. 3. Execute the program under debugger control. The next two sections of this chapter present the basic information you need to perform these steps.9 Introduction to CodeProbe Compiling and Linking Your Program Before invoking CodeProbe you must compile and link your program as described in Chapter 8, "Compiling and Linking Your Program," of the SAS/C Development System User's Guide, Volume I: Introduction, Compiler, Editor. The degree to which the debugger can access symbols defined in any module is determined by the compiler and linker options. Refer to Chapter 4, "Setting Up the Debugging Environment," to determine which options you need to use. In most cases, the debug=symbol flush option to the sc command specifies sufficient information to debug your program. A typical way to compile and link your program is with the following commands: sc debug=symbolflush link filename.c The sc command invokes the compiler, and debug=symbo 1 f lush (or debug=sf) causes the compiler to generate line number information, generate symbolic debugging information for variables in that module, and make sure those variables are flushed back to memory at line boundaries. The link option causes sc to invoke the linker. The addsym option is automatically passed to the linker because of the inclusion of a debug option. The addsym option forces slink to generate symbolic information for global symbols in libraries and for any file that does not have debug information. The filename.c argument specifies the source file. Running CodeProbe This section describes how to use the cpr command to invoke CodeProbe from the Shell use the quit command to stop the debugger at any time use CodeProbe to run applications from either a Shell or Workbench screen run CodeProbe as a line-mode debugger. The cpr Command The cpr command is invoked from a Shell to start CodeProbe for the first time during your debugging session. The cpr command uses the following syntax: cpr [cpr-options]application-name [application-arguments]10 Chapter 1 The application-name and application-arguments parameters are determined by your application. You can specify any of the following cpr-options: -buffer -noprofile-wdialog -cli -screen -wregister -command -startup -wsource -i-w-wwatch -line-wb -cli Each of these options is discussed in the section "Choosing Command-line Options" in Chapter 4. When the cpr command is invoked, CodeProbe makes the following assumptions: The program specified on the command line exists in the current directory or somewhere on the command search path, as specified by the AmigaDOS path command. The modules making up the program to be debugged have been compiled with one or more of the debugging options discussed earlier and have been linked using the addsym option of the linker. Source files for modules that you will be accessing exist in either the current directory, your special source path list (as specified by the opt search command), or the directory in which the module was compiled. The quit Command The quit command can be issued from the Dialog window to stop the debugger at any time. However, you should allow your program to run to completion before using the quit command. While CodeProbe will attempt to do some cleanup for your program by calling the normal C exit routine, you should allow your program to do its own cleanup. Refer to Chapter 9 for more information about the quit command. Workbench Support CodeProbe can be run from the Amiga system's Workbench screen as well as from a Shell. Furthermore, CodeProbe itself can run applications in either a Shell or Workbench environment from either location. By default, CodeProbe runs its application in the same type of environment that invoked the debugger.11 Introduction to CodeProbe The following options to the cpr command are used to change the default environment: -cli forces the application to run under the debugger as if it were invoked from a Shell. -wb forces the application to run under the debugger as if it were invoked from the Workbench screen. To facilitate debugging from the Workbench screen, a small stub tool called DEBUG can be placed in a project directory along with a corresponding tool icon. Both the tool and its icon may be found in the sc:starter_project drawer. DEBUG invokes CodeProbe and passes to it all Workbench startup messages. The SCSETUP utility automatically copies DEBUG and its icon into your project directories. To invoke CodeProbe from the Workbench screen, click once on the cpr or debug icon. Then, while holding down the Shift key, double- click on the icon for the application's executable. To set up CodeProbe command-line options, use the Workbench screen's Information menu item on the cpr or debug icon from the Workbench menu. Place the debugger command-line options in the ToolTypes field of the icon. The debugger will parse the options as if they were entered on the command line. The options may be placed on one ToolType edit line or they can be spread across several lines. To invoke CodeProbe on a program requiring command-line options, edit the debug icon the same way that you would edit it to set up CodeProbe command-line options. Add the -cli option as the last cpr option and follow it with the name of the executable file followed by its command-line options. By default debug invokes sc: c/cpr. If you rename or move cpr, DEBUG can find it if you assign the full pathname of the debugger to the environment variable sc/cprpath. This is done easily using the AmigaDOS setenv command as follows: setenv sc/cprpath pathname Line Mode You also can run CodeProbe as a line-mode debugger by starting it with the -line option. In line mode the debugger displays its output in the current Shell window. The -line option can be used to start the debugger from a remote Shell that has been started from an rlogin or from a Shell started across a serial line. For information about starting a Shell over a serial line, see the description of the AUX: device in The AmigaDOS Manual, 3rd Edition.12 Chapter 1 CodeProbe Windowing Interface CodeProbe provides a sophisticated windowing interface with multiple windows and pull-down menus. Windows are used to issue debugger commands, to receive output from CodeProbe commands, or to browse through the source code for your program. Screen Layout CodeProbe starts with the Source and Dialog windows open, as shown in Display 1.1. (BUY THE PROGRAM!) 13 Introduction to CodeProbe Once CodeProbe is running, you can opell, close, move, and resize windows. Display 1.2 is a sample CodeProbe screen showing the following windows: Source window Dialog window Memory window Register window Watch window.14 Chapter 1 CodeProbe Windows CodeProbe has 11 types of windows. You control the actual number of windows open during a debugging session. No matter how many windows are displayed, one of them will be the active window that is currently receiving, or waiting for, input. The title bar of the active window is highlighted (AmigaDOS Version 2.0 changes the color, and Version 1.3 ghosts the title bar when a window is not activated). The following list explains the function of each type of window: Calls window displays a stack traceback showing the calling sequence for the program being debugged. Each level of the traceback represents the state of the machine when a function was called. The state of the machine is also known as its environment. By double-clicking on a desired traceback entry in the Calls window, you can return CodeProbe to a previous environment. You will then see the code that was being executed at that time in the Source window, and you can see the contents of the registers as they were before the call in the Register window. The state of memory cannot be replicated for previous environments, so the Memory window reflects your current environment. A message is also displayed in the Dialog window informing you of your current location. As an example, suppose you have a main function that calls a function named s ort, which in turn calls a function named swap. When the execution of your program reaches the swap function, the calling sequence main, sort, swap is displayed in the Calls window. By double-clicking on the entry for the main function, you can return the machine to the state it was in when ma in called sort. You will see the source code that was executed and be able to view what was in the registers at the point at which ma in called sort; however, your program will still be executing at the same point in the swap function. Therefore, you can examine local variables, and they will have the values they had when main called sort, but global variables may have changed. If you single-step through the program, the code displayed in the Source window returns back to the last line executed in swap, and execution continues. Dialog window enables you to enter commands and review the results of those commands. Many of the same commands available through the pull- down menus can be invoked directly at the command line in the Dialog window. Help window displays help information for each of the CodeProbe commands as well as other selected topics.15 Introduction to CodeProbe Input window automatically opens to request input for a task you are performing. Input windows allow you to enter data, such as selecting a value for the default number of lines to be displayed by the list command. You can exit out of an Input window without entering input by pressing the escape (Esc) key. Memory window displays a dump of memory in both character and hexadecimal format or disassembles code. Message window displays text passed to it by the wmsg command. Modules window displays a list of all the modules within the application program. Output window displays output that is directed to the terminal by your C program from functions such as printf. The Output window is the initial Shell if the program is run from the Shell, or the Shell Workbench window opened by the startup code otherwise. Register window displays the contents of the registers. This window is most useful to assembly-level programmers. It is also valuable for checking registerized variables defined in C source code. Once opened, it displays the current contents of all registers and the current values of the processor flags. Any registers that have been modified since the last breakpoint are highlighted. The Register window can be opened by pressing the F4 key. Source window displays the source code for the module currently being executed. As execution proceeds, the Source window is continually updated to reflect the current position. The Source window highlights the current position (the line about to be executed) and any breakpoints. Watch window watches and displays the value of variables. For installce, you can set a watch break such that the application will be stopped as SOOII as the watch variable changes value. The Watch window can be opened by pressing the Fl key. Opening Windows With the exceptions of the Input and Message windows, you can use the View menu to open any window. (See "Pull-Down Menus" later in16 Chapter 1 this chapter.) Input windows open automatically when user input is required. The Message window is used to display messages from scripts and is opened automatically to display output from the wmsg command. The Help window can be opened with the Help icon or the help command, as well as from the menu. You can also use the window command to open any of the windows. Entering Commands You can issue debugger commands in several different ways. The methods of issuing commands are presented in the following order: entering commands from the Dialog window using pull-down menus to enter commands using special function keys to enter commands using menu accelerator keys to enter commands. Command Line The most flexible method of entering debugger commands is by typing them in at the command line of the Dialog window. The command line is marked by the > prompt. You can enter any of the debugger commands described in Chapter 9 in this manner. Command Syntax In order to understand the individual command descriptions, you must first understand the syntax conventions described in the "Using This Book" section. Command Name Shortcuts Command names need not be entered in their entirety. Generally, only the minimum number of characters necessary to uniquely identify a command is required. The Help menu, which is displayed in the Dialog window when you enter the help command, shows required keys in caps for command names while the rest are shown in lowercase. For example, RETurn in the Help menu indicates that only the first three letters of the command are required, but typing in return or retur would work also. The syntax conventions used in this book show the optional portion of a command in square brackets [ ]. Command-line Editing CodeProbe commands can be typed on the command line of the Dialog window in either uppercase or lowercase. The following command-line editing techniques are useful when entering commands in this manner.17 Introduction to CodeProbe Determining Editing Modes The editing mode affects tne way characters are typed on the commarld line as well as the functioning of the numeric keypad. The current editing mode can be determined by examining the left end of the Dialog window's title bar. The first character in the title bar will be an I if in insert mode or C if in overwrite mode. When you are in insert mode, any characters you type on the command line are inserted between existing characters. Wherl you are in overwrite mode, any characters you type overwrite any existing characters. The Ins key on the numeric keypad is used to switch between insert and overwrite mode. (Use the zero key to switch between insert and overwrite modes on the A1000.) The second character in the title bar is always a slash (/), and the third character will be an F if tne numeric keypad is in functiorl mode or an N if in numeric mode. The keypad must be in functiorl mode to use the editing functions described in the next section. I o toggle between the numeric and function modes, press F10. Editing Function Keys Three control key sequences in function mode and the numeric keypad are used to perform command-line editing functions. In order to perform these functions you must be editing in function mode. Table 1.1 describes the command-line editing functions. Table 1. 1 Command Line Editing Functions KeysDescription Ctrl X erases the current line Ctrl A toggles insert/overstrike Ctrl keypad-lerases from the cursor to the end of the line keypad-1moves the cursor to the end of the line keypad-7moves the cursor to the start of the line keypad-Ostarts inserting at the cursor keypad-. (Del) deletes the character urlder the cursor keypad-4moves the cursor left one position keypad-6moves the cursor right one position Shift keypad 4 moves the cursor left one word (continued)18 Chapter 1 Table 1.1 (continued) KeysDescription Shift keypad-6 moves the cursor right one word keypad-Entersends the line to the program as input keypad-8recalls the previous Dialog window command keypad-2goes to the next Dialog window command keypad-9 (PgUp) moves the page up keypad-3 (PgDn) moves the page down Extending Commands across Lines A command line can extend across several input lines by ending all but the last line with a backslash (\) followed immediately by a carriage return. A command line can be up to 256 characters in length. Using Escape Characters There are three places where you might want to use escape characters: in character strings in character constants in commands. C character strings consist of text surrounded by double quotes (""). Standard C escapes starting with the backslash character are supported as shown in Table 1.2. Table 1.2 Escape Sequences in Character Strings Escape Sequence Meaning \nnewline (0xOa) ttab (0xO9) bbackspace (0x08) \rreturn (0xOd) \fform feed (0xOc) \vvertical tab (0xOb) \NNNoctal constant (NNN is 3 octal digits.) \xNNhex constant (NN is 2 hexadecimal digits.)19 Introduction to CodeProbe In a character string, a backslash followed by any other character will be interpreted as itself. Therefore, "\\" is a string consisting of a single backslash, and " a \ " b " is three characters long, an " a ", a double quote, and a "b". C character constants consist of a single character surrounded by single quotes (' '). The standard C escape sequences shown in Table 1.2 can be used with character constants. Escape characters also can be used in CodeProbe commands. Table 1.3 lists escape characters that can be used outside of character strings and constants. Table 1.3 Escape Sequences in Commands Escape SequenceMeaning \\backslash \;command delimiter \,argument delimiter \"character string/constant delimiter \'constant delimiter/constant delimiter \(when or macro delimiters \)when or macro delimiters Outside of quotes, a backslash followed by any other character is not assigned any special meaning; it is interpreted as two distinct characters. Therefore, "b \mod\func" sets a breakpoint at function func of module mod, and not at a function called modfunc. Escape sequences are especially useful in the alias command, as in these examples: alias tb where;d x /* this is two commands */ alias tb where\;d x /* this is one command */ The first example runs an a 1 ias command followed by a display command; the second runs a single alias command. After executing the second example, tb is aliased to where;d x. Note, however, that these special escape sequences are not accepted in certain places that do not make sense. For example, you cannot use escape sequences in command and alias names.20 Chapter 1 Pull-Down Menus The most common debugger activities can be performed by using pull- down menus. As with other Amiga applications, you use the right mouse button to control menu functions. CodeProbe has seven pull- down menus that enable you to enter commands. Table 1.4 lists the menu items along with their command-line equivalents. Table 1.4 Pull-down Menu Items Menu ItemCommand-line Equivalent File Menu Module list \module Linelist [ line ] | [ address ] Find Current Line env Executeexecute [ script-name ] RefreshCtrl L Paste Quitquit Options Menu Source Modeopt source (c|asm|mixed) Radix Default opt radix ( hex | decimal) Context Lines opt context [integer] List Defaultopt list [integer] Unassemble Default opt unassemble [ integer] String Length opt strlen [ integer] Array Lengthopt arrdim [integer] Range Lengthopt rangelen [ integer] Autoswap Mode opt autoswap (on | off ) Echo Mode opt echo ( on | off ) (continued)21 Introduction to CodeProbe Table 1.4 (continued) Menu ItemCommand-line Equivalent Instruction Bytes opt ibytes (on | off) Ignore Pathopt ignorepath (on | off) Case Sensitivity opt case ( on | off) Maximum Bad Charactersopt badchar [ integer] Step Into ResLib opt reslib ( on | off ) Catch New Devices opt devices ( on | off ) Catch New Tasksopt catch ( on | off ) View Menu Calls window calls Moduleswindow modules Register window register Watch window watch Sourcewindow source Dialogwindow dialog Outputwindow output Memorywindow memory Help window help Run Menu Trace Into trace Proceed Overproceed Go go Go Untilgo [ location ] Return return [ value ] Startstart [command line] Break Menu Setbreak [ location ] (continued)22 Chapter 1 Table 1.4 (continued) Menu ItemCommand-line Equivalent Listblist Clear bclear [arguments] Enable benable [arguments] Disablebdisable [arguments] All Clear bclear * Watch Menu Setwatch [location] Breakw break [arguments] Listwlist Clear wclear [arguments] Enable wenable [arguments] Disablewdisable [arguments] All Clear wclear * Memory Menu Size (Long, Word, Byte) Display As (Data, Code) Base Address (Static, Dynamic) The File menu has two items called Line and Find Current Line that automatically list lines of source code in the Dialog window. These options are displayed as Address and Find Current Address when the debugger is in assembler mode. When prompted for an address after choosing the Address item, you should enter a hexadecimal va]ue. A '0x" prefix is not required. The Source window will disassemble code beginning at the specified address. Function and Spaecial Keys The actions of the function keys (F1 through F10) are indicated on the debugger screen title bar. In addition to the function keys, there are three keys with special functions: Help, Ctrl L, and Ctrl W. I hese keys23 Introduction to CodeProbe are not shown in the title bar. Table 1.5 explains the use of the function and special keys in more detail. Table 1.5 Function and Special Keys Key Action F1toggles for opening/closing the Watch window Shift F1 toggles for opening/closing the Source window F2zooms or unzooms the active window to the size of the screen F3recalls the last command * Shift F3 recalls the previous command * F4toggles for opening/closing the Register window F5re-executes the last command * F6activates the next window F7steps into a line/instruction (trace) F8steps over a line/instruction (proceed) F9toggles for swap screens between the debugger and application screens F10 toggles the numeric keypad mode Help executes the help command Ctrl Lrefreshes the screen Ctrl Wrefreshes the screen * The Dialog window must be active to recall or re-execute commands. Menu Accelerator Keys Menu accelerator keys are familiar to most Amiga system users. Menu items with shortcuts can be executed from the keyboard by striking the right-Amiga key in combinatioIl with another specified key. If a menu item has an accelerator key, it is displayed on the menu after the item. The actions performed by the menu accelerator keys are shown in Table 1.6.24 Chapter 1 Table 1.6 Menu Accelerator Keys KeyMenu Action A Break Clears all breaks B Break Sets a breakpoint C Break Clears a breakpoint D Break Disables a breakpoint E Break Enables a breakpoint F File Refreshes the screen G RunExecutes the go command H File Finds the current line L Break Lists the breakpoints M File Changes the currellt module N File Finds the line/address P RunProceeds (steps over the current line/instruction) Q File Quits the debugger R RunReturns from the current function S RunStarts (restarts the program with same command line) T RunTraces (steps into the current line/instruction) W RunWhere (displays stack frame backtrace) X File Executes a debugger command script from a file 25 2Sample CodeProbe Session 25 Introduction 25 A Walk through a Typical Application 25 Starting the Debugger 26 Using the go and restart Commands 26 Using Online Help 27 Controlling the Debugging Session 34 Quitting the Debugger Introduction The best way to understand how to use CodeProbe is to walk through a sample debugging session. This chapter provides an example session that demonstrates several debugger commands and options. It also explains how to maneuver in the debugger's windows. The chapters that follow this one provide the necessary details to help you get the most out of CodeProbe. A Walk through a Typical Application The source code for the sample program, l ines . c, used in this chapter is located in the s c: e x amp 1 e s drawer. Starting the Debugger To start your debugging session you must first compile and link the application program and then invoke the debugger. This chapter provides instructions for performing these tasks with the sample program, lines.c. Additional information about compiling, linking, and invoking the debugger is located in Chapter 1, "Introduction to CodeProbe," and Chapter 4, "Setting Up the Debugging ~nvironment." Compiling and Linking the Program To compile the sample program, lines.c, invoke the compiler, SC, with the debug=symbolf lush (sf) option. This option outputs full debugging information for those symbols and structures referenced by the program. The link option invokes the linker automatically. sc debug=sf link lines.c26 Chapter 2 Invoking the Debugger To start the debugger, type in c pr followed by the executable program's filename. cpr lines Note that the Dialog window and the Source window open by default. The Dialog window highlights the current edit line. In the same manner, the Source window highlights the next line of the program's source code to be executed. Using the go and restart Commands In order to use the debugger efficiently, you need to become familiar with both the go and the restart commands. The go command begins execution of your application program, which runs until a breakpoint is hit or the program exits. The restart command causes the application program to be reloaded and execute up to the first line of the main function. Both of these commands are described in Chapter 9, "Commands and Built-in Functions." When you invoke CodeProbe, a go main command is automatically issued unless you specified the -startup option when you invoked the debugger. This initial go command causes your application to run to the first line of the main function. You can always return to this point by entering as many go commands as necessary to cause your application program to run to completion and then issuing a single restart command. Using the restart command incorrectly can crash your machine. You can issue a restart command at any point in your program, which causes execution to jump back to the beginning of your code and run up to the first line of the main function. However, restart does not finish executing the rest of your program before it returns to the beginning, and cleanup procedures located at the end of a program are not executed. These cleanup procedures return memory and registers to a state expected by the operating system and other programs. Failing to complete execution of your program before restarting or exiting CodeProbe may leave the machine in an unacceptable state that will later cause a crash. Using Online Help At any point in your debugging session, you can use the help command to get online help regarding debugger commands and other CodeProbe features. The help command can be issued from the command line using either of the following forms: h[elp] [command] ? [command] Sample CodeProbe Session 27 The optional command parameter specifies the debugger command for which help information is to be displayed. A brief description, a summary of command syntax, some sample uses, and references to other commands is provided. If you enter the help command without the command parameter, a list of debugger commands is displayed along with other topics for which online help is available. To make a selection from the list, double-click the mouse pointer on one of these commands or topics. Controlling the Debugging Session After you have invoked the debugger, you control your debugging session by entering debugger commands as described in Chapter 1, "Introduction to CodeProbe." Reference information for each of the debugger commands is provided in Chapter 9, "Commands and Built-in Functions." Setting the Source Mode The source mode controls the way the source code is displayed in the Source window. You can use a pull-down menu to change the source mode. Hold down the right mouse button and drag the pointer through the menu items under the Options menu. The Source Mode option appears as a menu item and indicates C as the default mode. When the Source Mode option is highlighted, three subitems are offered as choices: C, Asm, and Mixed. Modifying the selected choice alters the appearance of the lines in the Source window accordingly. For instance, Display 2.1 shows the results of selecting mixed mode, while Display 2.2 shows the results of selecting assembly mode. When debugging a C application, you should usually choose C mode. Refer to the section "Source Mode" in Chapter 4 for additional information.2829 Sample CodeProbe Session Activating Autoswap Mode You also can activate Autoswap mode from the options nlellu. ~-he autoswap mode is on, the screen containing the application's OlltpUt is pushed to the front each time CodeProbe gives cont1ol to the application. When a breakpoint is reached, the debugge1 screen is pushed again to the front. If autoswal) mode is not on, you must change to the output screen manually using functio1l key 19 or the keyboard shortcut left-Amiga-m. Regardless of what metllo(l yoll use to swap screens, you must activate each screen by first clicking the left mouse button before entering any input. Stepping Over Code One of most useful features of the debugger is the ability to step through code. The proceed command enables you to single step over function calls. If you need to step into a called functioll you can use the trace command. Since the proceed command is the most frequently used command, CodeProbe is designed so that pressing the Return key causes the proceed command to be executed. Step over the first few lines of code as follows: lines:\lines.c\main 71 > lines:\lines.c\main 72 > lines:\lines.c\main 73 > lines:\lines.c\main 74 Select the Options menu and turn Autoswap mode on. Now step over several more lines of code. Notice the qllick flashing due to the display of the application window (the initial Workben( 1l ( Ll window) during each step. lines:\lines.c\main 79 > lines:\lines.c\main 80 > lines:\lines.c\main 81 > lines:\lines.c\main 8230 Chapter 2 You will notice also that the debugger does not stop at every line. This is due to the fact that code is not generated for all lines. Code is not generally produced for lines that declare variables, such as lines 66-68, or lines that are blank or contain only comments. Continuing Execution If you do not want to take the time to execute each line individually, you can use the go command, which executes your application until it either encounters a breakpoint (a flag to stop execution) or the end of the program. You should always use go to complete execution of your program before quitting CodeProbe or using the restart command. Displaying a Structure Or an Array The display command, which can be abbreviated as d, allows you to display structures, arrays, and variables easily. For instance, to display the structure nw, issue the following command in the Dialog window: >display nw struct NewWindow { LeftEdge = 100 (0x64) TopEdge = 100 (0x64) Width = 300 (0x12C) Height = 100 (0x64) DetailPen = '\x02' 2 (0x02) BlockPen = '\x01' 1 (0x01) IDCMPFlags = 514 (0x202) Flags = 1039 (0x40F) FirstGadget = 0x0 CheckMark = 0x0 Title = 0x00226028 Screen = 0x0 BitMap = 0x0 MinWidth = 50 (0x32) MinHeight = 50 (0x32) MaxWidth = 640 (0x280) MaxHeight = 400 (0x190) Type = 1 (0x1) } Use F2 to zoom the Dialog window to full size so that the entire structure can be viewed at once. The value of the character pointer Title will probably be different on your screen, but the other values31 Sample CodeProbe Session should be the same. When you have finished viewing, press F2 to restore the Dialog window to its original size. To display the two-dimensional array ox, issue the following command from the Dialog window: > display ox { [0] = { [0] = 0 [1] = 0 [2] = 0 . . . Then press F2 again to zoom the Dialog window to full size. While the values are not noteworthy, you can get an idea of the format that is displayed. Notice that the entire array does not fit in a full-size window. To see the beginning values, use the mouse and the Dialog window's vertical scroll bar to scroll backwards. Individual members of structures and unions, as well as elements of arrays, can be displayed using the display command, as in the following examples: > display nw.Type 1 (0x1) > display xIl] 0 (0x0) > display w->RPort 0x07F000FC > display 0x[1][5] 0 (0x0) > display nw.Title 0x00226028 > dzero nw.Title "Nervous Lines" You probably will find different results for the third and fifth examples. Notice that the last command dzero indicates that nw . Title should be treated as a pointer to a null terminated string and its contents displayed rather than the pointer itself.32 Chapter 2 Setting a Breakpoint A breakpoint is an address at which program execution stops whenever encountered. To set a breakpoint, move the pointer to a given line of code in the Source window. Using the left mouse button, double-click on the line. This sets a breakpoint on the line, and the line is highlighted. If there is no code generated at the line, an error message is displayed in the Dialog window. The breakpoint can be removed easily by double-clicking again on the particular line of code. Executing up to a Breakpoint Use your mouse to scroll down to line 111 in the Source window and double-click on line 111 to set a breakpoint. Now execute the program up to the breakpoint by typing the go command on the command line. The breakpoint line is now highlighted in a different way to indicate that execution has proceeded to that point. Double-clicking on the line turns off the breakpoint. The line reverts back to normal, highlighting just the text, indicating this is the next line to be executed. Displaying the Value and Type of a Variable The debugger will display a variable's value and tell what type it is. Enter the following commands in the Dialog window: > display i 2 (0x2) > whatis i auto register variable in d7 (2 bytes) short i; > whatis x extern at 0022625E (8-byte array of 2 4-byte element(s)) int x[2]; > whatis nw extern at 00226036 (48 bytes) struct NewWindow nw; Notice that the whatis command can provide information about the location and attributes of any variable. This is particularly useful for keeping track of automatic variables, which may be placed in registers by the compiler, even though they were not explicitly declared as type register. Using the watch and watch break Commands A watch allows you to monitor a variable or area of memory to see when the value of the variable changes or when the area of memory is33 Sample CodeProbe Session altered. Create a watch for the variable x by issuing the following command: > watch x Open the Watch window by pressing the ~1 key. You may have to adjust the size of the Watch window to see the entire display. Note that the output shown in the Watch window is a hex dump of the variable x: 1 x : 00 00 00 51 00 00 00 The number 1 at the left of the display identifies the watch. It is used by other commands that manipulate the Watch window. A watch break is similar to a watch but acts as a breakpoint when the variable or area of memory is changed. Create a watch break for the variable y by issuing the following command: > wbreak y At this point the Watch window should appear as follows: 1 x : 00 00 00 51 00 00 00 2! y : 00 00 00 30 00 00 00 Notice that the watch break is highlighted and has an exclamation mark (!) following the watch break number. The exclamation mark indicates that it is a watch break and not simply a watch. Executing Until the Variable Changes Value The Watch window is updated when control is returned to you by the debugger, such as at a breakpoint, and the new values of the watched areas are displayed. Note that runrling with set watch breaks can be a slow process because the CPU executes the application in trace mode. This means that control returns to the debugger after every instruction. The debugger must then check the memory for all watch breaks before restarting the application. The watch break feature is a powerful tool, and it is particularly useful for locating obscure bugs that cause memory to be overwritten from unusual places in the code; however, it should not be used indiscriminantly. 34 Chapter 2 To see the effect of the watch break, click in the Dialog window and issue the go command: > go break (watch #2) 2! y: 00 00 00 38 00 00 00 lines:\lines.c\main 117 Notice that the debugger reports the watch break number that caused the breakpoint to occur. Also, notice that the line that modified the variable was actually the previous line. Line 116 is the next line to be executed. Clearing All Watches and Watch Breaks To clear watches and watch breaks, issue the following Dialog window command: > wclear * The asterisk (*) is a wild card representing all watch and watch break identifiers. Now that all watches and watch breaks have been cleared, issue the go command to start the program l ines . c. Notice that no breakpoints can be reached now, so the program will continue until completion. Standard input/output is written to the application window on the Workbench screen. To see the application as it is running, you can use the left-Amiga-m key sequence to swap screens. The demo will run until the close gadget is activated on the l ines.c application window. After closing the application window, swap screens back to CodeProbe. The Dialog window should now display the following: Program exited with code 0. The code value cited, 0 in this case, is the return code from the program. Quitting the Debugger To quit the debugger, issue the command quit at the command line, or use the pull-down menu item in the File menu.35 3 Debugging Your Program 35 Introduction 36 CodeProbe Commands 37 Sample Program 1 37 Source Code 39 Running Program 1 39 Controlling Program Execution 39 The go Command 44 Single Stepping 45 The trace Commands 46 The proceed Commands 47 Breakpoints 48 The break Command 53 Sample Program 2 54 Source Code 56 Running Program 2 57 Examining Data and Data Structures 57 The display Command 61 The dump Command 66 The register Command 68 The whatis Command 69 Walches and Watch Breaks 70 The watch and wbreak Commands Introduction This chapter explains the use of several common CodeProbe commands to perform the following tasks: control program execution examine data and data structures modify data use watches and watch breaks. The commands used to perform these tasks also are explained in this chapter because they can be complex to use effectively.36 Chapter 3 CodeProbe Commands This chapter introduces the following complex CodeProbe commands: breakgo watch display proceed wbreak dumptracewhatis There are additional commands that are not discussed here. For a complete listing of the commands and detailed reference information, refer to Chapter 9, "Commands and Built-in Functions." Commands for Running Sample Programs The following commands are useful when running the sample programs described in this chapter: bclear clears one or more breakpoints blist displays a list of all the breakpoints that have been set restart reloads your program and reinitializes your static data allowing you to start over from the top. Note: The restart command is an advanced command. Before using it to debug your programs, you should review carefully the restart command in Chapter 9. Additional Commands In addition to the commands described in this chapter, you should become familiar with the following commands, which are described in Chapter 9, to get the most out of CodeProbe: bdisablerflagwdisable benable set wenable callsymbol wlist jumpwhere return wclear37 Debugging Your Program Sample Program 1 To view the commands described in the first part of this chapter, you should compile, link, and debug Sample Program 1. It is a simple program consisting of three modules (smain.c, sort.c, and swap.c) that first initializes an array of integers from O to 9 and then sorts the array into reverse order. The examples in this chapter are designed so that you start CodeProbe only once, at the beginning of the section, and then run each example in order. Running the examples out of order can produce results that do not agree with the documentation. Extra go and restart commands are included with several of the examples to position the file back at its beginning. The same results can be achieved by entering go, quitting CodeProbe, and starting a new debug session with the same program. Note, however, that you should always allow your program to run to completion before restarting or quitting CodeProbe. Source Code The following source code for Sample Program 1 is provided in the sc:examples/debugger drawer: /* SMAIN.C */ (1) #define ASIZE 10 (2) (3) void init(int *, int); (4) int sort(int *, int); (5) (6) int array[ASIZE]; (7) (8) void main(void) (9) { (10)init(array,ASIZE); /* initialize array[] */ (11) (12)/* Keep swapping elements until sorted */ (13)while (sort(array,ASIZE) != 0) (14); (15)} /* SORT.C */ (1) void swap(int *, int *); (2) (3) void init(int *ip, int size)38 Chapter 3 (4) { (5)int i; (6)int *p; (7) (8)p = ip; (9)for (i = 0; i < size; i++) (10)*p++ = i; (11)} (12) (13)/* Reverse sort elements of an array */ (14) (l5)int sort(int *ip, int size) (16){ (17) int i, s; (18) int *p; (19) (20) p = ip; (21) s = 0; /* no swaps performed yet */ (22) (23) for (i=0; i < size - 1; i++) (24) if (p[i] < p[i+1] ) (25) { (26)swap(&p[i], &p[i+1] ); (27)s = 1; /* indicate a swap took place */ (28) } (29) (30)return(s); (31)} /* SWAP.C */ (1) void swap(int *x, int *y) (2) { (3)int tmp; (4) (5)tmp = *x; (6)*x = *y; (7)*y = tmp; (8) }39 Debugging Your Program Running Program 1 To run Sample Program 1, compile, link, and load it into the debugger as follows: 1. Compile and link Sample Program 1 using the following command: sc debug=sf link sort.c smain.c swap.c 2. Start CodeProbe by entering the following command: cpr sort Controlling Program Execution With CodeProbe you can exercise a high degree of control over program execution. You can single step through your program (at either the assembly or C source level), step over or into function calls, set breakpoints at source line or instruction addresses, or go to a specific location. This section describes the following Dialog window commands for controlling program execution: break sets a breakpoint at the specified location. go starts the execution of the program you are debugging and continues until it hits a breakpoint or the end of the program. Execution begins at the line highlighted in the Source window. proceed single steps through your program or steps through it a given number of times, stepping over function calls, unless they contain a breakpoint. trace single steps through your program or steps through it a given number of times breaking at a function call. The go Command The go command starts the execution of the program you are debugging. This command uses the following syntax: g[o] [location [after(integer)] [when(expression) ]]40 Chapter 3 The go command has three different parameters: location, after(integer), and when(expression). Note that the parentheses around the expression and integer parameters must be typed in. The optional location parameter indicates where execution should terminate. When the go command is used, the debugger sets a temporary (non-sticky) breakpoint at a specified location. This breakpoint is temporary in the sense that the breakpoint is deleted after it is encountered. If you already have a normal breakpoint at a particular location and execute the go command to that location, the original breakpoint is cleared. The after clause uses the integer parameter to specify the number of times that the line indicated by the location parameter should be executed. This is called a pass count and program execution stops after the line is passed the specified number of times. The when clause uses the expression parameter to specify the circumstances under which execution is suspended at location. In its most general form, the go command can be read as: go until location has been executed integer number of times and stop the next time location is reached when the expression is true. When used without parameters, the go command starts the execution of your program, which runs to normal completion if no active breakpoints are encountered. Specifying a Location The location parameter specifies the point in your program at which you want execution to stop. You can specify either an address or line number in a source file and a breakpoint will be set at that location. A location can take any of the following forms: address line function function line \module\function [line] image: function image: function [line] image:\module\function [line] The address form of the location parameter is used to specify an explicit address constant. This form is useful for setting breakpoints at specific addresses when debugging in assembly mode.41 Debugging Your Program The line parameter is usually a number referring to the line number where you want execution to stop. Other possibilities for line are the following: $ refers to the current line e[ntry] refers to the first instruction of the specified function, or the current function if none is specified r[eturn] refers to the last instruction of the specified function, or the current function if none is specified. A line number is always relative to the beginning of the module. The line parameter can be used in conjunction with the function parameter to describe a location. For instance, in the form function line line refers to the line number of the module containing function. If the specified line is not inside the specified function, an error is printed. If a function is specified without a line parameter, the entry point to the function is assumed. When the specified location is reached, a message is displayed describing the source filename, the function name, and the line number. If mixed or assembly mode has been specified, the information is preceded by the breakpoint address. For example, using Sample Program 1 shown earlier in this chapter, the session log displayed in the Dialog window would look as follows, if C mode is currently chosen: > go swap 5 sort:\swap.c\swap 5 > opt source mixed > go swap 7 at 0x38974C sort:\swap.c\swap 7 > opt source c > go program exited with code 0. > restart starting "sort" sort:\smain.c\main 1042 Chapter 3 Here execution has stopped after the second go command was issued, at line 7 of the file swap.c, and within the function swap. If the module is not specified, a search will be made among your modules, beginning with the current module, until function is found. In the unlikely event that you have defined two functions in separate modules with the same name and belonging to the same static storage class, then it is necessary to specify the module. If a function is not specified, the currently executing function is assumed. If an image parameter is specified, it refers to the name of a program or shared library that may or may not have been loaded. If it is not yet loaded, the debugger sets a deferred breakpoint in the library or program. When the library or program is loaded a breakpoint is set and program execution proceeds. If the debugger cannot find the debugging information for the image, it will halt when the image is loaded. At this point you can use the symload command to specify the location of the version to be debugged. For example, the following go command causes the program to execute until mylib.library is loaded, a breakpoint is then set at LIBmyfunc, and program execution continues. This example command will not work with Sample Program 1. go mylib.library:LIBmyfunc Specifying the after Clause As previously described, the after(integer) parameter is used to specify a pass count, which is the number of times that the line indicated by the location parameter should be executed. For example, if you enter the following command in the Dialog window after starting CodeProbe with Sample Program 1, execution will stop after the while statement on line 13 of the program has executed 5 times: > go 13 after(5) sort:\Work:examples/smain.c\main 13 Specifying the when Clause The when ( expression ) parameter is used to further control program execution. An expression can be any valid C expression. For example, any of the following expressions can be used with a when clause: i == 7 i < 12 || i > 5 i != 4 && strlen(string) != 743 Debugging Your Program Consider the following loop in the sort routine of Sample Program 1: for (i = 0; i < size - 1; i++) if (p[i] < p[i + 1]) You may want to stop at a point within the loop, but only after a certain number of iterations of the loop have been executed. Assuming that the f or statement is on line 23, this can be accomplished with the following go command: > go sort sort:\Work:examples/sort.c\20 > go 4 when (i == 7) sort:\Work:examples/sort.c\sort 4 This has the effect of planting a non-sticky breakpoint at line 24 of the current module. That is, the breakpoint will be triggered only if the when condition is true; otherwise execution will continue past the specified line. Note that the specified line is the line after the loop. This is because breakpoints are set at the beginning of a line, before the code on the line is executed. If the breakpoint had been set at the line on which the for statement occurs, the breakpoint would never have been encountered while the loop was executing. For example, if you give the following command the breakpoint would not be triggered, because i will never be less than 0 and the program will run to completion: > go 24 when (i == -1) program exited with code 0. Breakpoints are discussed in greater detail later in this section. If you make any mistakes in syntax when entering the condition, errors are not detected until the first time the specified location is reached and the debugger attempts to evaluate the condition. If the debugger cannot evaluate the condition, the breakpoint is triggered and an error message is displayed. The message indicates the position in the condition where syntax rules have been violated. For example, the44 Chapter 3 following message indicates that ! < violates rules governing permitted relational symbols: > restart > go sort > go 24 when (i !< 1) Processing the when clause: (i !< 1) ^-------------syntax error sort:\sort.c\sort 24 Examples The following are examples of ways to use the go command: go main goes until the entry point of function main go return goes until the end of the current function go 0xc80200 goes until the address 0xc80200 is reached go sort 24 when ( i==5 ) goes until line 24 of the sort function when i equals 5 go init 10 after(5) when (i>4) goes until pass 5 at line 10 in the init function when i is greater than 4 Single Stepping The proceed and trace commands can be used to single step your program. Each command has two variations: one to single step at the assembler level and the other to single step at the C source level. The difference between the two commands lies in their handling of function calls. The proceed commands step over function calls; if a function call is encountered during the execution of a proceed command, the function is executed without a break occurring (unless one has been deliberately set in the function), and then the next line after the function call is highlighted. Execution continues in the calling function. This is in contrast to a trace command, which steps into function calls, highlighting the first line of the function as the next line to be executed.45 Debugging Your Program The trace Command The trace commands, t and ts, are used to single step your program. The t command is for single stepping assembler instructiolls. The ts command stands for trace source and is used for single stepping C code. The syntax for the trace commands is as follows: t[racel [integer] ts [integer] The optional integer parameter indicates the number of steps to be executed; if absent, a single step is executed. A step is considered to be either one assembler instruction or a single line of C source code. Either trace command will step into any function calls encountered during the step. That is, the called function is entered and execution is suspended at its first instruction. The actions of these commands depend on the current source mode of the debugger. In C source mode, the two trace commands act identically, causing the execution of one line of C source code up to any imbedded function call. In assembly or mixed mode, t executes one machine instruction; ts always executes a single C source line. Both trace commands step into function calls. Regardless of the mode, if the current line contains a function call, then the first line of that function is executed and subsequent t commands execute lines within that function. In assembly mode, if the current line contains a JSR (Jump to SubRoutine) or a BSR (Branch to SubRoutine) instruction, then that instruction is executed and subsequent t commands execute instructions in the called function. Using Sample Program 1 given earlier in this chapter and starting over from main with the restart command, trace for several steps in source mode as shown here: > go program exited with code 0. > restart sort:\smain.c\main 10 > trace sort:\sort.c\init 4 > trace sort:\sort.c\init 8 > trace 3 sort:\sort.c\init 9 sort:\sort.c\init 9 (+0x2) sort:\sort.c\init 1046 Chapter 3 sort:\sort.c\init 9 (+0x2) sort:\sort.c\init 10 sort:\sort.c\init 9 (+0x2) The first trace command carries us to the init call in main. The second then moves us into the init function. The third illustrates the use of a numeric argument to execute several steps. To step by a single machine instruction, you can set the source to either asm or mixed. For instance, you can set your source mode to asm by using the pulldown Options menu or by issuing the following command: opt source asm Similarly, you can set your source to mixed with the following command: opt source mixed At this point, you can enter the trace command to step over an assembler instruction. If source mode is set to asm and no line information is available, using the ts command is regarded as an error, and an appropriate error message is displayed. In mixed mode, the trace command causes stepping by machine instruction while the ts command causes stepping by C source line. The proceed Commands The proceed commands, p and ps, also are used to single step your program or to step it a given number of times. Unlike trace, however, a proceed command steps over function calls rather than stepping into them. That is, if a call to a function is encountered in the process of the step, the function is not stepped into as in the trace commands. The syntax for the proceed commands is as follows: p[roceedl [integer] ps [integer]47 Debugging Your Program The integer parameter indicates the number of steps to be executed. The proceed and ps commands are analogous to the trace and ts commands with respect to source mode. Looking at the previous example, notice how the results of the proceed commands differ compared to the trace commands (C source mode is used again): > go program exited with code 0. > restart sort:\smain.c\main 10 > proceed sort:\smain.c\main 13 > proceed sort:\smain.c\main 14 > proceed sort:\smain.c\main 13 Here, a single step has been made for each source line of the function main. Function calls were made in the process of this stepping, but none of the called functions were entered. Pressing the Return key is equivalent to entering the p command. Continuing where the previous example left off, the following example demonstrates how this works: > sort:\smain.c\main 14 > sort:\smain.c\main 13 Using the ps command in assembly mode is regarded as an error if no source line information is available, while proceed can be used in mixed or assembly mode to single step by machine instruction. The ps command can be used in mixed mode to step by C source line in a manner similar to the ts command. Breakpoints A breakpoint is an address at which program execution stops. The break command enables you to suspend the execution of your program or to execute a set of debugger commands at any point you choose. By setting conditional breakpoints or by using a pass count to specify the number of times a program should pass a breakpoint before execution is stopped, you can suspend program execution at just the48 Chapter 3 right stage of your program. This means, for example, that you can set a breakpoint at a line within a loop so that the program stops after going through 500 iterations of the loop. By triggering a breakpoint in this way, you are able to easily reach the point in the program that you want to examine. Besides breakpoint setting, additional commands allow you to manage your breakpoint list. bc lear provides you with the ability to clear a breakpoint, bdisable temporarily disables a breakpoint, benable enables it again, and blist lists the current breakpoints. The break Command The break command enables you to specify a breakpoint. Breakpoints are used to suspend the execution of a program at any point or execute a set of debugger commands instead of suspending execution. You can also set and clear breakpoints by double-clicking the mouse on a line in C source mode or an assembly instruction in asm or mixed mode. The syntax of the break command has two forms: b[reak] $ b[reak]location[after(integer)][when(expression)] [tr[ace]] [q[uiet]] [te[mp]] [{cmd-list}] In the first form, a breakpoint is set at the current location (which in C source mode is the cutrent line). This is handy when you have stepped to a certain point in your program and want to set a breakpoint quickly at the current line. Here is an example: > go sort sort:\sort.c\sort 20 > sort:\sort.c\sort 21 > sort:\sort.c\sort 23 > break $ > go sort:\sort.c\sort 23 In this case we have single stepped twice by pressing Return (the same as a proceed command). When the breakpoint is set with the break command, line 23 in the Source window is highlighted. A breakpoint also can be easily and quickly set or removed by double-clicking on the line in the Source window where you want the breakpoint.49 Debugging Your Program The second form of the break command allows you to set a breakpoint at a specified line number and to ensure that the breakpoint is not triggered until that line has been executed a specified number of times. For example, suppose you want to set a breakpoint at the if statement in the sort routine, but you want the breakpoint triggered only after the fifth time that statement is executed. You can use the following commands: > break sort 24 after(5) > blist 1 0xC32DCA sort:\sort.c\sort 23 (1 hit) 2 0xC32DD4 sort:\sort.c\sort 24 after(5) > go sort:\sort.c\sort 24 > display i 4 (0x4) The fact that the value of i is 4 indicates that the loop has already executed five times. You will find the pass count feature to be especially useful in debugging programs containing loops that iterate many times. Conditional Breakpoints Although breakpoints with pass counts are a kind of conditional breakpoint, the break command also allows for a more generally useful kind of conditional breakpoint. Using the when option, you can specify a condition that depends upon the values of variables in your program. You might, for example, want to stop at the i f statement in sort when the value of p[i] is 8: > bclear * > break sort 26 when (p[i] == 8) > go sort:\sort.c\sort 26 > display p[i] 8 (0x8) Any valid C expression can be used as an argument in a when clause. Of course the after option can be used to specify a pass count in conjunction with the when clause. Both the pass count and the when50 Chapter 3 clause conditions must be met. You may, for example, want to see if there is an instance where the array element is equal to the array index after three or more executions of a given line: > bclear * > go program exited with return code 0. > restart > break sort 26 after (3) when(p[i]==i) > go sort:\sort.c\sort 26 > dump i decimal reg d6: 2 > dump plil decimal 00C28708 2 Attaching Actions to Breakpoints Instead of just stopping at a breakpoint, you may want to have the debugger perform one or more actions. You can do this with the cmd_list parameter. The cmd_list parameter is a sequence of debugger commands enclosed in braces ({}) and separated by semicolons (;). The following example shows how to use the cmd_list parameter to stop at line 25 of the sort function and have the debugger automatically display the value of p[i] and the value of i. > bclear * > break sort 26 {display "p[i] = ", p[i] ; display "i = ", i} > go sort:\sort.c\sort 26 p[i] = 2 (0x2) i = 3 (0x3) > go sort:\sort.c\sort 26 p[i] = 2 (0x2) i = 4 (0x4) > go sort:\sort.c\sort 26 p[i] = 2 (0x2) i = 5 (0x5)51 Debugging Your Program In fact, you can arrange for the debugger not to stop at the breakpoint but to continue by issuing the go command as the last command in your list, as in the following example: > bclear * > go program exited with code 0. > restart sort:\smain.c\main 10 > break sort 26 when (i < 3) {dump p L 4; go} > break sort 24 when (i >= 3) > blist 10 0xC32D4C sort:\sort.c\sort 26 when (i < 3) {dump p L 4; go} 11 0xC32D2C sort:\sort.c\sort 24 when (i >= 3) > go sort:\sort.c\sort 26 00C31260: 00000000 00000001 00000002 00000003 sort:\sort.c\sort 26 00C31260: 00000001 00000000 00000002 00000003 sort:\sort.c\sort 26 00C31260: 00000001 00000002 00000000 00000003 sort:\sort.c\sort 24 In this way, you can actually see the sort taking place and you do not need to type in the go command repeatedly. Using the trace option on the break command eliminates the need to include a final go in the command list parameter. This is demonstrated in the following example: > bclear * > break sort 26 when (i > 5) {dump p L 4; break sort 26 when (i == 8) trace; blist} > blist 12 0xC32D4C sort:\sort.c\sort 26 when (i > 5) {dump p L 4; break sort 26 when (i == 8) trace; blist} > go sort:\sort.c\sort 26 00C31260: 00000001 00000002 00000003 00000004 15 0xC32D4C sort:\sort.c\sort 26 when (i == 8) trace sort:\sort.c\sort 2652 Chapter 3 Here a breakpoint is set at line 26 of sort and is to be triggered when i has a value greater than 5. When triggered, the breakpoint action displays the first four elements (16 bytes) of the array referenced by p, sets a new breakpoint at the same line, lists the new breakpoint, and continues execution. The new breakpoint is then triggered when its when condition is satisfied. This nesting of breakpoints within action lists is a powerful feature of the debugger. Since nested breakpoints may become complex, you should take great care in using them or you may lose your place in the program when some breakpoints replace themselves with others. You must also be aware that a breakpoint with an action may have an effect (and perhaps an unexpected one) on program execution. To consider a simple case, suppose you set a breakpoint on line 26 of sort and attach to it an action that will alter the value of i: > bclear * > break sort 26 when (i == 5) [set i = 2] > go sort:\sort.c\sort 26 > dump i decimal reg d6:2 > go sort:\sort.c\sort 26 > dump i decimal reg d6:2 In this simple case you have managed to create an infinite loop by means of your breakpoint and action list. Such a simple mistake is easy to find, but if you have planted a number of breakpoints or if your breakpoints are deeply nested, the error might be very difficult to detect. This example also demonstrates that the action for a breakpoint is executed before control is returned to you; by the time you examine the value of i, it has already been set to its new value by the set command. You can also use the trace, quiet, and temp options with the break command. The trace option causes execution to continue after the breakpoint is hit, the quiet option suppresses the default message that is printed when the breakpoint is hit, and the temp53 Debugging Your Program option deletes the breakpoint after it is hit. The following example illustrates the use of these options: > go > restart > bclear * > break sort 26 trace quiet (display i) > break sort 30 temp > blist 1 0xC32D4C sort:\sort.c\sort 26 trace quiet (display i) 2 0xC32D66 sort:\sort.c\sort 30 temp > go 0 (0x0) 1 (0x1 ) 2 (0x2) 3 (0x3) 4 (0x4) 5 (0x5) 6 (0x6) 7 (0x7) 8 (0x8) sort:\sort.c\sort 30 > blist 1 0xC32D4C sort:\sort.c\sort 26 trace quiet (display i) Sample Program 2 To view the commands described in the second part of this chapter, you should compile, link, and debug Sample Program 2. It is a simple program consisting of one module (data.c). Sample Program 2 defines and initializes various data structures. It is intended only for exploring the data manipulatiorl fullctiolls of CodeProbe and has no practical use. The following sections use examples based on Sample Program 2 to explore various colnnlallds to display data and data structures.54 Chapter 3 Source Code The following source code for Sample Program 2 is provided in the sc:examples/debugger drawer: #inclUde void main (void) { struct X { int a; int b[3]; int c; } x; struct Y { int a; int b; } Y; typedef struct X *XPTR; struct W { int x; struct Y y[2]; int z; } w; struct Z { char c; struct Y d; int e; } z; struct X3D { int a; int b[2][3][2]; int c; } x3d; int i,j; int arrayl[0]; int *intptr;55 Debugging Your Program long lng; short shrt; float fl; double db; char *string = "Hello, World"; /* Initialize data structures.*/ i = 33; j = 44; intptr = &i; lng = 6456; shrt = 89; fl = 3.14; db = 33.5; array[O] = 5; array[1] = 15; array[2] = 25; array[3] = 35; array[4] = 45; array[5] = 55; array[6] = 65; array[7] = 75; array[3] = 89; array[9] = 95; x.a= 5; x.b[0] = 1; x.b[1]=2; x.b[2]=3; x.c=11; y.a=5; y.b=6; w.x= 4 ; w.y[0] = y; w.y[1] = y; w.z = 9;56 Chapter 3 z.c = 'r'; z.d = Y; z.e=3; intptr = &j; x3d.a=2; x3d.b[0][0][0] = 41; x3d.b[0][0][1] = 42; x3d.b[0][1][0] = 43; x3d.b[0][1][1] = 44; x3d.b[0][2][0] = 45; x3d.b[0][2][1] = 46; x3d.b[1][0][0] = 47; x3d.b[1][0][1] = 48; x3d.b[1][1][0] = 49; x3d.b[1][1][1] = 50; x3d.b[1][2][0] = 51; x3d.b[1][2][1] = 52; x3d.c=90; printf("%s!\n",string); } Running Program 2 To run sample program 2, compile, link, and load it into the debugger as follows: 1. Compile and link using the following command: sc debug=sf link math=standard noautoregister data.c 2. Start CodeProbe by entering the following command: cpr data57 Debugging Your Program Examining Data and Data Structures CodeProbe offers several commands that you can use to display the data referenced by your program. This section describes the following commands for examining data and data structures: display displays an object, area of memory, or the result of an expression dump examines the value of any variable in a program, an arbitrary range of memory, a register, or an expression register displays or modifies the current settings of the machine integer registers watch sets a variable or area of memory to be watched wbreak sets a breakpoint when a watched variable or area of memory changes whatis determines the type and address of a variable or the fundamental C type to which a typedef identifier resolves. The display Command The display command displays C data structures and objects and can display an object or area of memory interpreted as a specified type of object. The syntax of the display command is as follows: d[isplay] (expression["format"] | string)[,...] The expression parameter can be any C expression containing constants, variables, and function calls from the program being debugged except expressions involving the comma operator (,), the ?: operator, the various assignment operators (+=, -=, and so on), or the prefix and postfix operators (++ and --) To override the default format, a format specification like those used with the printf statement can be used after each expression. The forrnat parameter can contain up to two conversion operators for short and long types, but only one for all other types. No error checking is done on the format and strange results are possible. If an address is specified as the expression parameter, and it is an address constant, then, in the absence of a forrnat parameter, the address is assumed to be of type char *.58 Chapter 3 The string parameter can be any standard C string as described earlier in this chapter. The string is echoed in the Dialog window. The display command can accept multiple arguments, each of the following form: (expression["format"] | string) The arguments must be separated by commas. Given this information, the following are examples of the display command: > display i > display 0xC80FF8 > display i "i is equal to %d" > display a "a=%10.5e" > display p->d[5] + myfunction(3) > display x "X is %d", j "J is %d" Before using Sample Program 1 in the examples shown in this section, enter the following command to execute all of the data initialization code: > go 110 Now you can display the value of an integer variable as shown here: > display i 33 (0x21) To display its address, use the following command: > d &i 0xC309B8 Note that register variables do not have an address; if you try to use the and (&) operator on a register variable, you will get an error message. This is why the example program was compiled with the noautoregister option.59 Debugging Your Program It is equally simple to display an array element as follows: > d *array 5 (0X5) > d array[0] 5 (0x5) You can display an entire array as follows: > display array { [0] = 5 (0x5) [1] = 15 (0xF) [2] = 25 (0x19) [3] = 35 (0x23) [4] = 45 (0x2D) [5] = 55 (0x37) [6] = 65 (0x41) [7] = 75 (0x4B) [8] = 85 (0x55) [9] = 95 (0x5F) } Structures are also easy to analyze using the display command as follows: > d x struct X { a = 5 (0x5) b = { [0] = 1 (0x1) [1] = 2 (0x2) [2] = 3 (0x3) } c = 11 (oxB) }60 Chapter 3 > display z struct Z { c = 'r' 114 (0x72) d = struct Y { a = 5 (0x5) b = 6 (0x6) } e = 3 (0x3) } Multidimensional arrays are displayed in a format that enhances analysis as follows: > d x3d struct X3D { a = 2 (0x2) b= { [0] = { [0] = { [0] = 41 (0x29) [1] = 42 (0x2A) } [1] = { [0] = 43 (0x2B) [1] = 44 (0x2C) } [2] = { [0] = 45 (0x2D) [1] = 46 (0x2E) } } [1] = { [0] = { [0] = 47 (0x2F) [1] = 48 (0x30) } [1] = { [0] = 49 (0x31) [1] = 50 (0x32) }61 Debugging Your Program [2] = { [0] = 51 (0x33) [1] = 52 (0x34) } } c = 90 (0x5a) } A conversion string can also be used as a format parameter: > display i "i is equal to %d" i is equal to 33 The dump Command The dump command provides a simple way for yoll to examine the value of any variable in your program or to examille an arbitrary range of memory. The syntax of the dump comlllalld is as follows: du[mp] [variable | address | range ] [$] [style . . . ] The variable, address, or range parameter specifies the location to be dumped. The style parameter controls the format of the dulllp. I or complete details on usirlg the dump comman(t, see tne dump section in Chapter 9. Dumping a Variable In its simplest form, dump displays the melllory at the address (tile contents) of a variable. For example, the followillg comlrlall(t disl)lays memory starting at the address of i: > dump i 003c8466: 00000021 Note that the hexadecimal value 00000021 eqllals the decimal value 33, the value of i. By default, dump displays memory in the hexadecimal format. The number to the left of the hexadecimal value, 003C8466, is the address of i. Tlle dump comlllarld always displays the addresses of the memory blocks displayed. To display memory in decimal format, use the decimal option.62 Chapter 3 > dump i decimal 003C8466:33 0 0 0 003C8476:0 0 0 0 003C8486:0 0 0 0 003C8496:0 0 0 0 The variable parameter can be any valid C variable. When a variable parameter is specified, the amount of memory dumped is determined by the size of the object (or in the case of a pointer, the size of the object to which it points.) However, in the case of a character pointer or an address constant, 64 bytes of data are always displayed as follows: > dump string ascii 00394728: H e l l o , W o r l d \0 \0 % s 00394738: ! \n \0 \0 \0 \0 \0 \0 \0 \0 @ \0 \0 \0 \0 \0 00394748: \0 \0 \0 \0 \0 \0 \0 01 \0 \0 \0 \0 \0 \0 \0 \0 00394758: \0 \0 \0 01 \0 \0 \0 \0 \0 \0 \0 01 \0 \0 \0 01 Dumping an Address You can specify any valid address in the dump command, even addresses not under the control of your program. The following command specifies the address of the variable i. Note that the address parameter is preceded by a 0x. Here is an example: > dump 0x3c8466 decimal 003C8466:33000 003C8476:0000 003C8486:0000 003C8496:0000 Dumping a Range When a range parameter is specified, exactly that amount of data is displayed, unless the size of the range is not perfectly divisible by the size of the specified type of data items. For example, the following command specifies to dump 7 bytes of integer data starting at the first address: > dump 0x3c8466..0x3c846c decimal 0042D366: 33-749469637 The dump actually includes an additional 1 byte of data to make up the second 4-byte integer. The dump command automatically rounds 63 Debugging Your Program the range up to the size necessary to correctly display at least all of the memory specified as the data type specified. You can also specify ranges by indicating the number of elements of a data type to display, starting at a specified address or variable. The following command dumps the decimal value of the integer i and the next 12 bytes of memory (three additional integers of 4 bytes each): > dump i L 4 decimal 003C8466: 332 414 The amount of memory that is displayed with a range option of this type depends on the size of the data type. A command with a range of four elements of type decimal will display 16 bytes. The default length of f loat for the dump command is 8, so a command with a range of four elements of type float will display 32 bytes. Dumping a Pointer Dumping pointers and memory pointed to by pointers can be confusing. In the Sample Program 2 (data . c) the following variables are defined and initialized: int i; int *intptr; i = 33; intptr = &i; The following commands dump the contents of the variable i: > dump i decimal 003C8466: 33 > dump intptr decimal 003C8466: 33 212 003C8476:3 456 003C8486:7 89 10 003C8496: 11 12 97 1927282688 > dump *intptr decimal 003C8466: 3364 Chapter 3 > dump &i decimal 003C8466:332 12 003C8476:3 4 56 003C8486:7 8 910 003C8496:1112 97 1927282688 All of these commands are equivalent. The dump command treats variables that are addresses as already de-referenced. The dump command assumes that, if you specify a pointer, you want to look at what the pointer is pointing at. If you want to see the actual address contained in the pointer, you can look at the first address in the dump. You will note that all of the preceding dumps have O 0 3C8 4 6 6 as the address containing 33, which is the address of i. To dump the actual address of the pointer variable, use the following command: > dump &intptr 0064F676:003C8466 The address of the pointer is the first number displayed. Sometimes the compiler automatically stores a variable in a register. If this has occurred for a variable, the preceding command will yield the following result: > dump &intptr ^------cannot be applied to registers or constants Dumping Floating-Point Numbers The float option is used with the dump command to specify the format of floating-point numbers. The default number of bytes dumped by the float option is 8. This is equivalent to type double under C. Note that there is no double format specifier. To specify a 4-byte f loat, equivalent to type float under C, use the f loat4 option. Using the wrong format for a variable will cause the variable's value to appear incorrect. For example, compare the following commands and their results for the double variable db = 33.5 and the float variable f1 = 3.14: > dump db float4 004103FE: +3.0117187 > dump db float 004103FE: + 33.5Debugging Your Program 65 > dump f1 float4 00410406: +3.1400001 > dump f1 float 00410406: +49.92001667991304 Dumping Integers The decimal option is used with the dump command to specify the format of integers. The decimal option dumps 32-bit (4 byte) integers. This is equivalent to type long under C, and type int if the shortinteger compiler option was not used. Note that the dump command cannot distinguish between modules compiled with 16-bit integers (using the shortintegers option) and those compiled with 32-bit integers (using the default.) Using the wrong format for a variable will cause the variable's value to appear incorrect. The following commands will dump an integer, a long, and a short. Note the required format for the short: > dump i decimal 00410436:33 > dump lng decimal 00410402:6456 > dump shrt decimal 00410400: 5832704 > dump shrt decimal2 00410400: 89 Dumping Characters and Strings Characters and strings may be dumped in several ways. The simplest is to use the ASCII option as follows: > dump z.c ascii 00410472: r > dump string ascii 003BlB88: He l l o , W o r l d \0 \0 % s 003BlB98: ! \n \0 \0 \0 \0 \0 \0 \0 \0 @ \0 \0 F E4 003BlBA8: \0 \0 \0 \0 \0 \0 \0 01 \0 \0 \0 \0 \0 \0 \0 \0 003BlBB8: \0 \0 \0 01 \0 \0 \0 \0 \0 \0 \0 01 \0 \0 \0 0166 Chapter 3 When using the ASCII option, certain nonprintable characters appear as their usual C escape sequences: \b backspace \f formfeed \n new line \r carriage return \t horizontal tab \v vertical tab \o null byte (string terminator) Other characters are represented by the two-digit hexadecimal codes. You can also use the text option to display a block of data in character format. The text option displays the address of the data items on the left, the hexadecimal values in the middle, and the printable characters on the right. > dump string text 003BlB88: 48656C6C 6F2C2057 6F726C64 00002573 Hello, World..%s 003BlB98: 210A0000 00000000 00004000 0046E420 !.........@..F. 003BlBA8: 00000000 00000001 00000000 00000000 ................ 003BlBB8: 00000001 00000000 00000001 00000001 ................ The dzero command can also be used to display an ASCII text string terminated by a NULL character (\0) as shown here: > dzero string "Hello, World" The string at that location is displayed in double quotes. Normally you would use either a character pointer or an array name as the argument to this command. The register The register command has two forms, with and without parameters Command as follows: r[egister] r[egister] [register[ [=] expression ]]67 Debugging Your Program The first form of the register command displays the contellts of all the registers, while the second form results in the specified value being placed in the named register. Displaying the Contents of Registers If you use the register command without parameters, the current contents of the registers are displayed in hexadecimal followed by the current flag settings as shown here: > register dO=OOOOOOOl dl=00000002 d2=000003ED d3=00000000 d4=00000000 dS=OOOOOOOO d6=00000000 d7=00000000 aO=OOC2C102 al=000223BO a2=OOC25CCO a3=OOC2C106 a4=OOC28F08 a5=00000000 a6=OOCOB9C8 sp=000229A8 pc=OOC32E82 ccr=OOOOOOOO na pl nz nv nc sort:\smain.c\main 110 Registers dO through d7 and aO through a6 are labeled and displayed. Register a7 is the stack pointer and is labeled sp. I'he program counter is labeled pc, and the condition code register is labeled ccr and is summarized by the two-letter flag abbreviations immediately following. Note that the current source line number is displayed immediately after the display of the registers and flags. ~Itering the Contents of Registers The second form of the register command is similar to the set command. It allows you to alter the contents of registers. You can specify the value you want placed in a register as an expression. Here is an example: > register d0=00000001 d1=00000002 d2=000003ED d3=00000000 d4=00000000 d5=00000000 d6=00000000 d7=00000000 a0=00C2C102 a1=000223B0 a2=00C25CC0 a3=00C2C106 a4=00C2BF08 a5=00000000 a6=00C0B9C8 sp=000229A8 pc=00C32E82 ccr=00000000 na pl nz nv nc sort:\smain.c\main 110 > register d7=5 > register a2=0x24la4a > register d0=00000001 d1=00000002 d2=000003ED d3=00000000 d4=00000000 d5=00000000 d6=00000000 d7=00000005 a0=00C2C102 a1=000223B0 a2=00241A4A a3=00C2C106 a4=00C2BF08 a5=00000000 a6=00C0B9C868 Chapter 3 sp=000229A8 pc=00C32E82 ccr=00000000 na pl nz nv nc sort:\smain.c\main 110 You also can set a register by using a program variable or other expression: > display i 33 (0x21) > register d3=i > register dO=00000001 d1=00000002 d2=000003ED d3=00000021 d4=00000000 dS=00000000 d6=00000000 d7=00000005 a0=00C2C102 a1=000223B0 a2=00241A4A a3=00C2C106 a4=00C2BF08 a5=00000000 a6=00COB9C8 sp=000229A8 pc=00C32E82 ccr=00000000 na pl nz nv nc sort:\smain.c\main 110 To set floating-point registers, refer to the fregister command in Chapter 9. The whatis The whatis command is used to determine the type of an object or Command the configuration of a type of object. It has two forms: wha[tis] expression wha[tis] (type) The expression and type parameters can be any expression or data types, including structures and unions, provided by the C language. Sample Program 2 defines the following objects: struct X { int a; int b[3]; int c; } x; typedef struct X *XPTR; The whatis command yields the following: > whatis x auto at 00221FBC (20 bytes) struct X x;69 Debugging Your Program > whatis x.a object at 00221FBC (4 bytes) int a; > whatis x.b101 object at 00221FC0 (4 bytes) int > whatis (XPTR) typedef struct X { int a; int b[3]; int c; } *XPTR; > whatis (int) int > whatis (struct X) struct X { int a; int b[3]; int c; }; Notice that the typedefs are expanded in terms of the more fundamental types. Watches and Watch Breaks The watch commands allow you to set, list, disable, enable, and clear watches and watch breaks. A watch (also called a watch point) allows you to monitor a variable, an address, or a range of memory in order to see when the value of the variable changes or the area of memory is altered. A watch break is similar to a watch but acts as a breakpoint if the variable or area of memory changes. Like breakpoints, watches and watch breaks remain in memory until you clear them or exit the debugger. You may restart the program being debugged and still retain these watch settings. This allows you to run through the program again and again without resetting the watches and watch breaks. Watches and watch breaks are displayed in the Watch window. This window is updated when the debugger returns control to the user (as at a breakpoint), at which point the new values of the watched areas are displayed. You can open the Watch window with the F1 function key. You also can display the values of the watched areas by using the wlist command. For example, if a watch break is set on the variable tmp in the function swap in Sample Program 1, then execution will70 Chapter 3 stop at line 6 of swap when the value of tmp changes. At this point, entering a wlist command will display the value of the watch as shown here: sort:\swap.c\swap 6 > wlist 1! tmp : 0 (0x0) The 1! refers to the numbered entry in the watch list. Watches provide a convenient way to watch memory on a continuing basis. It is often easier to examine the Watch window instead of entering a display or dump command after every step or breakpoint. You can also use the Memory window to keep track of an area of memory. Watch breaks can help you locate problem areas with precision. Often a variable or block of memory may be altered or corrupted at an unknown point in a program's execution. It can be very difficult to pinpoint the exact location where the corruption took place. By setting a watch break on the variable and executing the program, the problem can be isolated quickly. The watch and wbreak Commands The watch command is used to set watches, while the wbreak command is used to set watch breaks. The syntax of these commands is as follows: w[atch] variable | address | range [s[tatic] | d[ynamic]] wb[reak] variable | address | range [ s[tatic] | d[ynamic]] The variable, address, or range parameter specifies the location of the watch or watch break. The optional static or dynamic flag specifies the way in which the debugger evaluates the location of the object being watched. (See Chapter 9 for more information.) By default, watches are dynamic. This means that an expression being watched is re-evaluated whenever control is returned to the debugger. The static flag causes the address of a watched expression to be evaluated once when the watch is set. Conversely, watch breaks are static by default. The dynamic flag is used to specify that the address of a watch break should be re- evaluated every time control is returned to the debugger. With the watch command, the new value of the watched object is displayed in the Watch window whenever control is returned to youDebugging Your Program 71 (for example, at a breakpoint). If the Watch window is not open, you can use the wl i st command as a way of determining the new value. Watches (and watch breaks) can be set on structures or arrays by name. When this is done, the specification of the aggregate name is treated as an implicit range and a watch is set on that range. Assume the following declarations are in effect: struct x { int i; char a[20] ; double d; } x; char string[80] ; A watch can be set on ranges as follows: > watch x > watch string[5] L 10 > watch &string[17].. &string[19] Watches and watch breaks can be set on formal or automatic variables. In this case the watch is in effect only as long as the function-defining variable is executing. If you set a watch on a formal or automatic variable, the watch list displays the watch as not active when execution is taking place outside its defining function. When the function is re-entered, the watch is re-activated. You should, however, use caution when using variables to specify a range. For example, suppose that aut is an automatic variable and sta is a static variable. Issuing the following command sets a watch on the memory between the address of aut and the address of sta as follows: > watch &aut &sta Of course, the address of aut could change a number of times as its function is entered, executed, and exited. In the case of such artificial ranges the debugger translates the symbolic names into their current absolute address equivalents and sets the watch on the absolute address range. It is this absolute address range that is displayed in the watch list. In general, this sort of translation from symbolic range to absolute range takes place when the two variables you use to specify72 Chapter 3 the range do not resolve to addresses within the same aggregate (structure, union, or array). While watch breaks can be useful in monitoring program execution, they are expensive in terms of execution time. You should expect your program to execute hundreds of times more slowly when watch breaks are enabled. This is not true of watches since the information for these is updated only when control is returned to you by the debugger. Watch breaks should be disabled whenever possible to speed execution. One way you can do this is to enable and disable a watch break dynamically depending on program conditions as shown here: > wbreak i > wdisable 1 > break sort 9 {we 1; go sort 20; wd 1; go} This command sequence installs a watch break whose number in the example is assumed to be 1 and then it sets a breakpoint that automatically enables the watch break, executes up to a certain point, disables the watch break, and continues execution. In this way, you can force the watch break to be active only when a certain portion of your program is executing. 73 4Setting Up the Debugging Environment 73 Introduction 74 The debug= Options 76 Which Debugging Option To Use 77 Determining Source File Location 78 Choosing Command-line Options 81 CodeProbe Initialization 82 Setting and Showing Options within CodeProbe 83 Source Mode 84 Echo Mode 84 Instruction Bytes 85 Ignore Path 85 Case Sensitivity 85 Context 86 List Default 86 Unassemble Default 86 Radix Default 86 String Length 86 Array Dimension 87 Range Length 87 Maximum Bad Chars 87 Search Path: 88 Autoswap Mode 88 Catch New Devices 88 Step Into ResLib 89 Current Task 89 Catch New Tasks 89 Customizing Dialog Window Commands 89 The Alias Command 92 The Unalias Command 92 The Define Command 94 The Undefine Command Introduction To use CodeProbe efficiently, you need to know how to set up the optimal debugging environment for your particular application. This74 Chapter 4 involves choosing the best debugging option to use, determining where to locate source files, and selecting necessary command-line options. This chapter discusses these and other topics pertinent to customizing your debugging environment. This section also describes the command used to invoke CodeProbe, cpr. Selecting the correct options for CodeProbe can determine whether a debugging session will be productive and useful. The debug= Options The degree to which CodeProbe can access symbols defined in a module is determined by the compiler debugging option used in compiling that module. The debug= option can be used with any of the following keywords to activate the debugging mode of the SAS/C Compiler: line or l generates the line number/offset table only. symbol or s in addition to the line number/offset table, generates full debugging information for those symbols referenced in the module. symbolflush or sf in addition to the line number/offset table, generates full debugging information for those symbols referenced in the module. Also forces the code generator to flush all registers to variable locations at line boundaries. full or f in addition to the line number/offset table, generates full debugging information for all symbols declared in the module even if there is no reference to them in the generated code. fullflush or ff in addition to the line number/offset table, generates full debugging information for all symbols declared in the program even if there is no reference to them in the generated code. Also causes the code generator to flush all registers at line boundaries. Each of the debug= options is described in more detail later in this section. You can mix modules compiled with different levels of debugging in the same program. The nodebug option can be used to suppress the generation of debugging information. nodebug is the default. The addsym option can be used to tell the linker to add symbol information to files that are compiled without debugging information. If a file was compiled with debugging information, addsym is not required.75 Setting Up the Debugging Environment The debug=line Option Specifying the debug=line option causes the compiler to output the line number/offset table only. As a result of using the line option, the debugger can match the lines in a source file with the loaded code. This allows you to set breakpoints at source lines and step through the source code. In addition, some limited symbolic information is available for external variables and functions. Only the address of a symbol is available. There is no information about the symbol's attributes. For this reason, the debugger will attempt to display any variable as a long by default with the following warning message: > display fahr accessing extern with unknown attributes - assuming long 1101004800 (0x41A00000) To display a variable in its proper form, use a type cast with the display command as follows or use one of the dump commands. > display (float) fahr 20 See Chapter 9, "Commands and Built-in Functions," for details on the display and dump commands. While the line option provides limited information to the debugger, it is useful with large programs or when disk space is limited because it produces much smaller object files. The line option also provides all the information needed by the disassembler, omd. The debug=symbol Option Specifying debug=symbol causes the compiler to output full debugging information for all global and local variables, all functions, and all types referenced in the module, including s tructure, union, enum, and typedef types. If a module is compiled with this option, you can set breakpoints at source lines, display or alter data symbolically, set watches on variables or areas of memory, and list source code. The display command will properly format all data declared in the module. Debug information for a structure or union definition is generated only if it is used in a typedef declaration or as either a global or local variable. That is, if the structure or union is defined in a header file that is included by your program, but the tag associated with that structure or union is not used by your program, then no debug information will be generated for that tag. Most source modules use76 Chapter 4 numerous include files that contain definitions that are never actually used. By limiting debug information to include only referenced definitions, the output module size is greatly reduced. The compiler will often manipulate a variable's contents in registers over several lines of code without replacing the results in the variable. If a breakpoint is reached in this section of code, the debugger will display the value in memory, not in the register. If you suspect that the debugger is not displaying the proper values, the code can be inspected in mixed mode, or the file can be recompiled with the symbolflush option. Note that register variables (automatic and formal variables that are only assigned to registers) will always be found in their proper register. The debug=symbolflush Option Specifyillg debug=symbolflush causes the compiler to output full debugging information for all global and local variables, all functions, and all types referenced in the module, including structure, union, enum, and typedef types. It does not generate debugging information for types that are defined but not referenced in the module. The symbolflush option also causes the code generator to Tflush all registers to variable locations at C source line boundaries. This can be useful because the debugger takes the value of a variable from its memory location, not a temporary register. While this option is recommellded for use with the debugger, it causes inefficient code generation. Any module compiled with this option should be recompiled before it is placed into production. The debug=full Option The debug=full option is similar to the debug=symbol option except that inforrnation for all declarations and definitions is generated including those that are defined but not referenced in a module. The debug=fullflush Option The debug=fullflush option is similar to the symbolflush option except that information for all declarations and definitions is generated including those that are defined but not referenced in a module. Which Debugger Option to Use In order to make full use of the debugger's features, you should always use either the symbol, symbolflush, full, or fullflush option. If the cornpiler keeps the value of a variable in a register, as it may in order to eliminate unnecessary loading and storing of values in its77 Setting Up the Debugging Environment registers, then the true value of a variable at any given time may be in a register rather than in the variable's memory location. As a consequence, the value of the variable displayed by the debugger may not be its correct value. The s ymbolflush and fullflush options force the correct values of variables to be in the memory locations of the variables at line boundaries but at the cost of generating extra code required to store, and perhaps reload, the values. Only the symbolflush and fullflush options affect the quality of code generated by the compiler. The other options do not affect code generation and differ only in the amount of symbolic information they pass on to the linker. If you want to debug exactly the program you intend to use, you should use symbol or full rather than symbolflush or fullflush, and you should debug in mixed mode so that you can see the machine instructions corresponding to your C source lines. The opt source mixed command is used to specify mixed mode. When you do this, you will be able to tell if the value of a variable is being kept in a register rather than being flushed to memory, and you can then use the register command rather than the display or dump commands to determine the variable's value. See Chapter 9 for more details about these commands. To produce the final version of your program, use the stripdebug option of slink. For example, the following command will strip debugging information from an existing executable file, source-filename, and place it in a second file, destination-filename: slink from source-filename to destination-filename stripdebug If you are not concerned with debugging production quality code, you should use the symbolflush option, since the difference in generated code will have little effect. Even if you are attempting to create a piece of production software, you should begin your debugging by using the symbolflush option and then recompile with the symbol option when most of your bugs have been detected and repaired. Determining Source File Location If you have compiled your program with any of the debug= options, CodeProbe reads the name of the source file from the program being debugged. By default, this is the same name you passed to the compiler with the sc command. If you specify a full or partial pathname for your source file, the pathname is included. You can change the filename specification in the program's debugging information by using78 Chapter 4 the sourceis option when you compile your program. Refer to Chapter 8, "Compiling and Linking Your Program," in SAS/C Development System User's Guide, Volume I for more details. You may want to direct CodeProbe to look for source files on a different disk or at a different location on the same disk by using the opt search command described later in this section. If CodeProbe cannot find the source file for the function it is currently executing, it displays the following message: Error: error opening source file filename Your source code will be displayed as long as you have used some debugging option, other than the nodebug option, with the compiler. The CodeProbe source command can be used to override the filename specified in the debugging information. This new association is remembered by CodeProbe throughout the current session. This command can prove useful when the name of the source file has been changed since the program was compiled. Choosing Command-line Options The CodeProbe environment can be customized by including command- line options when invoking the debugger. The format of the command is as follows: cpr [cpr-options] application-name [application-arguments] For information on how to use command-line options with the program you are debugging, see Chapter 1, "Introduction to CodeProbe." If you invoke CodeProbe from the Workbench screen, you can use command-line options by adding them as tool types to the debug icon created by scsetup. To add tool types, click on the icon, then select Info from the Workbench menu under AmigaDOS Version 1.3, or Information from the Icons menu under AmigaDOS Version 2.0. You can use the following command-line options when invoking CodeProbe: -buffer specifies the size of the Dialog window buffer. By default the Dialog window saves the last 4096 bytes displayed so that you can scroll79 Setting Up the Debugging Environment backwards and review output. This size can be increased or decreased with this option. The syntax of the option is as follows: cpr -b[uffer] size The size parameter specifies the size of the buffer in bytes. -cli instructs CodeProbe to invoke the application as a CLI (Shell) process. CodeProbe passes arguments to the application through the normal command line interface. This option is the default if CodeProbe is invoked from a Shell. The option is necessary if CodeProbe is invoked from the Workbench screen, and you want your program to run as if invoked from a Shell. -command executes debugger commands at startup. The commands are executed after go main if the -startup option is not specified or after the profile script if it is specified. Profile scripts are discussed later in this section. For example, the commands cpr -command "proceed; display fahr" program-name would execute to main, step over 1 line of code, and display the variable fahr in the Dialog window before giving control to you. -i sets up a screen in interlace mode. By default, CodeProbe opens a new screen using the specifications set up by Preferences for Workbench screens. To force a screen to be opened in interlace mode, include the -i option before typing the application command name. -line starts CodeProbe in line mode. Line mode causes the debugger to run in the current Shell window. The equivalent of the Dialog window is provided, with no other windows available. Line mode is probably only useful for running from a script file, redirecting output using the Shell redirection facility, or running from a remote terminal over a communications port. -noprofile suppresses execution of the CodeProbe startup file. When CodeProbe is invoked, it automatically executes a script file named cprinit, which must be located in either the current directory or80 Chapter 4 ENV:sc. If the startup file is found in the current directory, ENV:sc iS not searched. -screen instructs CodeProbe to open its windows on the named public screen. The syntax of the command is as follows: -sc[reen] name By default, CodeProbe creates a new public screen when it is invoked. If this option is specified, CodeProbe looks for an existing public screen with the given name, and if one is found it uses that screen to display its windows. If a screen with the given name does not exist, a new one is created with that name. To use the Workbench screen, specify -screen workbench. Public screens are a feature of Intuition 2.0. For users of earlier versions of Intuition, this option is not generally useful. However, specifying -screen workbench causes CodeProbe to use the Workbench screen on older releases. -startup suppresses the automatic go main that is normally executed by the debugger on startup. This option is useful if your application redefines _main or c.a so that no main function exists, or if you want to step through such code. If this option is used, no initialization of any kind will have been performed by the application process before control is given to you. If the quit, start, or restart commands are invoked and an application process has not exited, the debugger normally calls exit to clean up any process resources that may not have been freed. However, if the -startup option was used, exit will not be called. -w runs CodeProbe on the Workbench screen. This is the same as specifying -screen workbench. -wb instructs CodeProbe to invoke the application as a Workbench process. It passes arguments to the application through a Workbench startup message. This option is the default if CodeProbe is invoked from a Workbench icon. The option is necessary if CodeProbe is invoked from a Shell, but you want the application to run as if invoked from the Workbench screen.81 Setting Up the Debugging Environment -wdialog, -wregister, -wsource, -wwatch specifies start up window coordinates for the Dialog, Register, Source, and Watch windows, respectively. Window coordinates are measured in character positions. A width or height of 0 causes the window to extend to the screen border on the right or bottom, respectively. The option names can be abbreviated to two letters: -wd[ialog]left top width height -wr[egister] left top width height -ws[ource]left top width height -ww[atch] left top width height Here is an example: cpr -ws 0 1 50 12 -wd 0 13 50 0 ftoc Note that the Register and Watch windows will not be displayed on startup; however, when they are opened by pressing the appropriate function key (either Fl or F4), they will open to the coordinates specified on the command line. -. suppresses the copyright banner that is displayed at startup. CodeProbe Initialization Since you will probably want CodeProbe to start the debugger with the same options most of the time, CodeProbe allows you to create a debugger command script file that is executed each time the debugger is invoked. The profile script, named cprinit, is executed after the initial go main but before any commands specified with the -command option are executed. CodeProbe first looks for cprinit in the current directory and then in the ENV: SC directory. Only one cprinit script will be run; therefore, if a script is located in both directories, the one in the current directory is used. The following are examples of scripts displayed from the Shell window using the AmigaDOS type command: 1> type cprinit /* This is the debugger startup profile */82 Chapter 4 opt search dh0:mysource, df0:mysource, ram: opt radix h opt ibytes off 1> type env:sc/cprinit /* This is a debugger profile script for a project */ opt source mixed proceed display argc, argv Note that C style comments can be placed in profile scripts as long as they exist on a single line. Setting and Showing Options within CodeProbe In addition to the command-line options discussed above, a number of options can be set from within CodeProbe to customize the way information is displayed or handled. Most of these options are modified with the opt command or through the Options menu. To see the default options while in the debugger, activate the Options menu or execute the opt command without any parameters as follows: > opt Source mode.........c Echo mode...........Off Instruction bytes...Off Ignore path.........Off Case sensitivity....Off Context.............2 lines List default........6 lines Unassemble default..4 lines Radix default.......Decimal String Length.......128 Array Dimension.....20 Range Length........64 Maximum Bad Chars...3 Search path: Autoswap mode.......Off Catch New Devices...No Step into ResLib....No Current Task........sort at 0001DC20 Catch New Tasks.....No83 Setting Up the Debugging Environment End Of Part 1