This chapter is not about building kernel extensions (KEXTs). There are a number of good KEXT tutorials on Apples developer documentation site ( http://developer.apple.com/documentation ). This chapter is about adding new in-kernel modules (optional parts of the kernel), building kernels, and debugging kernel and kernel extension builds.
Gdb Mac Os X Brew
Gdb For Mac Os X 10.13
Gdb For Mac Os X64
Gdb For Mac Os X 10.8
Download Gdb For Mac Os X
Gdb For Mac Os X 10.10
The Mac OS X Debugging Magic Technote contains a wealth of information about various debugging options built in to macOS. IMPORTANT: By default, Xcode has the 'Load Symbols Lazily' preference set. As a result, any symbols not in the main static library (99. If you prefer watching videos to reading articles, Cody Henrichsen has created a video walkthrough of this procedure. With its new OS release, Apple has discontinued the use of GDB in OS X. Since 2005 Apple has steadily been moving away from the GNU toolchain in favor of LLVM.This means that Xcode now uses LLDB instead. LLDB looks to be a very nice replacement for GDB, and I hope to use it.
The discussion is divided into three sections. The first, Adding New Files or Modules , describes how to add new functionality into the kernel itself. You should only add files into the kernel when the use of a KEXT is not possible (for example, when adding certain low-level motherboard hardware support).
The second section, Building Your First Kernel , describes how to build a kernel, including how to build a kernel with debugger support, how to add new options, and how to obtain sources that are of similar vintage to those in a particular version of OS X or Darwin.
The third section, When Things Go Wrong: Debugging the Kernel , tells how to debug a kernel or kernel module using ddb and gdb . This is a must-read for anyone doing kernel development. Adding New Files or Modules
In this context, the term module is used loosely to refer to a collection of related files in the kernel that are controlled by a single config option at compile time. It does not refer to loadable modules (KEXTs). This section describes how to add additional files that will be compiled into the kernel, including how to add a new config option for an additional module. Modifying the Configuration Files
The details of adding a new file or module into the kernel differ according to what portion of the kernel contains the file. If you are adding a new file or module into the Mach portion of the kernel, you need to list it in various files in xnu/osfmk/conf . For the BSD portion of the kernel, you should list it in various files in xnu/bsd/conf . In either case, the procedure is basically the same, just in a different directory.
This section is divided into two subsections. The first describes adding the module itself and the second describes enabling the module. Adding the Files or Modules
In the appropriate conf directory, you need to add your files or modules into various files. The files MASTER , MASTER.ppc , and MASTER.i386 contain the list of configuration options that should be built into the kernel for all architectures, PowerPC, and i386, respectively.
These are supplemented by files , files.ppc , and files.i386 , which contain associations between compile options and the files that are related to them for their respective architectures.
The format for these two files is relatively straightforward. If you are adding a new module, you should first choose a name for that module. For example, if your module is called mach_foo , you should then add a new option line near the top of files that is whitespace (space or tab) delimited and looks like this:
The first part defines the name of the module as it will be used in if statements in the code. (See Modifying the Source Code Files for more information.) The second part is always the word optional. The third part tells the name of the option as used to turn it on or off in a MASTER file. Any line with mach_foo in the last field will be enabled only if there is an appropriate line in a MASTER file.
Then, later in the file, you add
and so on, for each new file associated with that module. This also applies if you are adding a file to an existing module. If you are adding a file that is not associated with any module at all, you add a line that looks like the following to specify that this file should always be included:
If you are not adding any modules, then youre done. Otherwise, you also need to enable your option in one of the MASTER files. Enabling Module Options
To enable a module option (as described in the files files), you must add an entry for that option into one of the MASTER files. If your code is not a BSD pseudo-device, you should add something like the following:
Otherwise, you should add something like this:
In the case of a pseudo-device (for example, /dev/random ), you can also add a number. When your code checks to see if it should be included, it can also check that number and allocate resources for more than one pseudo-device. The meaning of multiple pseudo-devices is device-dependent. An example of this is ppp , which allocates resources for two simultaneous PPP connections. Thus, in the MASTER.ppc file, it has the line: Modifying the Source Code Files
In the OS X kernel, all source code files are automatically compiled. It is the responsibility of the C file itself to determine whether its contents need to be included in the build or not.
In the example above, you created a module called mach_foo . Assume that you want this file to compile only on PowerPC-based computers. In that case, you should have included the option only in MASTER.ppc and not in MASTER.i386 . However, by default, merely specifying the file foo_main.c in files causes it to be compiled, regardless of compile options specified.
To make the code compile only when the option mach_foo is included in the configuration, you should begin each C source file with the lines
and end it with
If mach_foo is a pseudo-device and you need to check the number of mach_foo pseudo-devices included, you can do further tests of the value of MACH_FOO .
Note that the file mach_foo.h is not something you create. It is created by the makefiles themselves. You must run make exporthdrs before make all to generate these files. Building Your First Kernel
Before you can build a kernel, you must first obtain source code. Source code for the OS X kernel can be found in the Darwin xnu project on http://www.opensource.apple.com . To find out your current kernel version, use the command uname -a . If you run into trouble, search the archives of the darwin-kernel and darwin-development mailing lists for information. If that doesnt help, ask for assistance on either list. The list archives and subscription information can be found at http://www.lists.apple.com .
Note: Before you begin, make sure you extract the sources in a directory whose path does not contain any special characters (non-alphanumeric characters other than dash and underscore), as having such characters in the path leading up to the build directory can cause compiling to fail.
Also, make sure that /usr/local/bin is in your PATH environment variable as follows:
If you are using a csh derivative such as tcsh, you should add set path = (/usr/local/bin $path) to your .tcshrc file
If you are using a Bourne shell derivative, you should add export PATH=/usr/local/bin:$PATH to your .bashrc file.
Important: Once you have obtained and extracted the sources, before you begin compiling kernel support tools, you should configure your system to build using gcc 3.3. The OS X v10.4 kernel will not build using gcc 4.0. To do this, type:
Important: Before building anything, you should make sure you are running the latest version of OS X with the latest developer tools. The xnu compile process may reference various external headers from /System/Library/Frameworks . These headers are only installed as part of a developer tools installation, not as part of the normal OS X install process.
Next, you will need to compile several support tools. Get the bootstrap_cmds , Libstreams , kext_tools , IOKitUser , and cctools packages from http://www.opensource.apple.com . Extract the files from these .tar packages, then do the following:
In the cctools package, modify the Makefile , and change the COMMON_SUBDIRS line (including the continuation line after it) to read:
Finally, issue the following commands:
Now youre done with the cctools project. One final step remains: compiling kextsymboltool . To do this, extract the kext_tools tarball, then do the following:
Warning: If you do not use a version of kextsymboltool that is at least as current as your kernel, you will get serious compile failures. If you see the error message exported name not in import list, theres a good chance you arent using a current kextsymboltool .
Congratulations. You now have all the necessary tools, libraries, and header files to build a kernel.
The next step is to compile the kernel itself. First, change directories into the xnu directory. Next, you need to set a few environment variables appropriately. For your convenience, the kernel sources contain shell scripts to do this for you. If you are using sh, bash, zsh, or some other Bourne-compatible shell, issue the following command:
If you are using csh, tcsh, or a similar shell, use the following command:
Then, you should be able to type
and get a working kernel in BUILD/obj/RELEASE_PPC/mach_kernel (assuming you are building a RELEASE kernel for PowerPC, of course).
If things dont work, the darwin-kernel mailing list a good place to get help. Building an Alternate Kernel Configuration
When building a kernel, you may want to build a configuration other than the RELEASE configuration (the default shipping configuration). Additional configurations are RELEASE_TRACE , DEBUG , DEBUG_TRACE , and PROFILE . These configurations add various additional options (except PROFILE , which is reserved for future expansion, and currently maps onto RELEASE ).
The most useful and interesting configurations are RELEASE and DEBUG . The release configuration should be the same as a stock Apple-released kernel, so this is interesting only if you are building source that differs from that which was used to build the kernel you are already running. Compiling a kernel without specifying a configuration results in the RELEASE configuration being built.
The DEBUG configuration enables ddb , the in-kernel serial debugger. The ddb debugger is helpful to debug panics that occur early in boot or within certain parts of the Ethernet driver. It is also useful for debugging low-level interrupt handler routines that cannot be debugged by using the more traditional gdb .
To compile an alternate kernel configuration, you should follow the same basic procedure as outlined previously, changing the final make statement slightly. For example, to build the DEBUG configuration, instead of typing
you type
and wait.
To turn on additional compile options, you must modify one of the MASTER files. For information on modifying these files, see the section Enabling Module Options . When Things Go Wrong: Debugging the Kernel
No matter how careful your programming habits, sometimes things dont work right the first time. Kernel panics are simply a fact of life during development of kernel extensions or other in-kernel code.
There are a number of ways to track down problems in kernel code. In many cases, you can find the problem through careful use of printf or IOLog statements. Some people swear by this method, and indeed, given sufficient time and effort, any bug can be found and fixed without using a debugger.
Of course, the key words in that statement are given sufficient time and effort. For the rest of us, there are debuggers: gdb and ddb . Setting Debug Flags in Open Firmware
With the exception of kernel panics or calls to PE_enter_debugger , it is not possible to do remote kernel debugging without setting debug flags in Open Firmware. These flags are relevant to both gdb and ddb debugging and are important enough to warrant their own section.
To set these flags, you can either use the nvram program (from the OS X command line) or access your computers Open Firmware. You can access Open Firmware this by holding down Command-Option-O-F at boot time. For most computers, the default is for Open Firmware to present a commandline prompt on your monitor and accept input from your keyboard. For some older computers you must use a serial line at 38400, 8N1. (Technically, such computers are not supported by OS X, but some are usable under Darwin, and thus they are mentioned here for completeness.)
From an Open Firmware prompt, you can set the flags with the setenv command. From the OS X command line, you would use the nvram command. Note that when modifying these flags you should always look at the old value for the appropriate Open Firmware variables and add the debug flags.
For example, if you want to set the debug flags to 0x4 , you use one of the following commands. For computers with recent versions of Open Firmware, you would type
from Open Firmware or
from the command line (as root).
For older firmware versions, the interesting variable is boot-command . Thus, you might do something like
from Open Firmware or
from the command line (as root).
Of course, the more important issue is what value to choose for the debug flags. Table 20-1 lists the debugging flags that are supported in OS X. Table 20-1 Debugging flags
Symbolic name
Flag
Meaning
DB_HALT
0x01
Halt at boot-time and wait for debugger attach ( gdb ).
DB_PRT
0x02
Send kernel debugging printf output to console.
DB_NMI
0x04
Drop into debugger on NMI (CommandPower, Command-Option-Control-Shift-Escape, or interrupt switch).
DB_KPRT
0x08
Send kernel debugging kprintf output to serial port.
DB_KDB
0x10
Make ddb ( kdb ) the default debugger (requires a custom kernel).
DB_SLOG
0x20
Output certain diagnostic info to the system log.
DB_ARP
0x40
Allow debugger to ARP and route (allows debugging across routers and removes the need for a permanent ARP entry, but is a potential security hole)not available in all kernels.
DB_KDP_BP_DIS
0x80
Support old versions of gdb on newer systems.
DB_LOG_PI_SCRN
0x100
Disable graphical panic dialog.
The option DB_KDP_BP_DIS is not available on all systems, and should not be important if your target and host systems are running the same or similar versions of OS X with matching developer tools. The last option is only available in Mac OS 10.2 and later. Avoiding Watchdog Timer Problems
Macintosh computers have various watchdog timers designed to protect the system from certain types of failures. There are two primary watchdog timers in common use: the power management watchdog timer (not present on all systems) and the system crash watchdog timer. Both watchdogs are part of the power management hardware.
The first of these, the power management watchdog timer, is designed to restore the system to a known safe state in the event of unexpected communication loss between the power management hardware and the CPU. This timer is only present in G4 and earlier desktops and laptops and in early G5 desktops. More specifically, it is present only in machines containing a PMU (Power Management Unit) chip.
Under normal circumstances, when communication with the PMU chip is lost, the PMU driver will attempt to get back in sync with the PMU chip. With the possible exception of a momentary loss of keyboard and mouse control, you probably won't notice that anything has happened (and you should never even experience such a stall unless you are writing a device driver that disables interrupts for an extended period of time).
The problem occurs when the disruption in communication is caused by entering the debugger while the PMU chip is in one of these 'unsafe' states. If the chip is left in one of these 'unsafe' states for too long, it will shut the computer down to prevent overheating or other problems.
This problem can be significantly reduced by operating the PMU chip in polled mode. This prevents the watchdog timer from activating. You should only use this option when debugging, however, as it diminishes performance and a crashed system could overheat.
To disable this watchdog timer, add the argument pmuflags=1 to the kernel's boot arguments. See Setting Debug Flags in Open Firmware for information about how to add a boot argument.
The second type of watchdog timer is the system crash watchdog timer. This is normally only enabled in OS X Server. If your target machine is running OS X Server, your system will automatically reboot within seconds after a crash to maximize server uptime. You can disable this automatic reboot on crash feature in the server administration tool. Choosing a Debugger
There are two basic debugging environments supported by OS X: ddb and gdb . ddb is a built-in debugger that works over a serial line. By contrast, gdb is supported using a debugging shim built into the kernel, which allows a remote computer on the same physical network to attach after a panic (or sooner if you pass certain options to the kernel).
For problems involving network extensions or low-level operating system bringups, ddb is the only way to do debugging. For other bugs, gdb is generally easier to use. For completeness, this chapter describes how to use both ddb and gdb to do basic debugging. Since gdb itself is well documented and is commonly used for application programming, this chapter assumes at least a passing knowledge of the basics of using gdb and focuses on the areas where remote (kernel) gdb differs.
Note: Only systems with serial hardware support ddb . Thus, it is only possible to use ddb on PowerMac G4 and older systems. Using gdb for Kernel Debugging
gdb , short for the GNU Debugger, is a piece of software commonly used for debugging software on UNIX and Linux systems. This section assumes that you have used gdb before, and does not attempt to explain basic usage.
In standard OS X builds (and in your builds unless you compile with ddb support), gdb support is built into the system but is turned off except in the case of a kernel panic.
Of course, many software failures in the kernel do not result in a kernel panic but still cause aberrant behavior. For these reasons, you can pass additional flags to the kernel to allow you to attach to a remote computer early in boot or after a nonmaskable interrupt (NMI), or you can programmatically drop into the debugger in your code.
You can cause the test computer (the debug target) to drop into the debugger in the following ways:
debug on panic
debug on NMI
debug on boot
programmatically drop into the default debugger
The function PE_enter_debugger can be called from anywhere in the kernel, although if gdb is your default debugger, a crash will result if the network hardware is not initialized or if gdb cannot be used in that particular context. This call is described in the header pexpert/pexpert.h .
After you have decided what method to use for dropping into the debugger on the target, you must configure your debug host (the computer that will actually be running gdb ). Your debug host should be running a version of OS X that is comparable to the version running on your target host. However, it should not be running a customized kernel, since a debug host crash would be problematic, to say the least.
Note: It is possible to use a non-OS X system as your debug host. This is not a trivial exercise, however, and a description of building a cross- gdb is beyond the scope of this document.
When using gdb , the best results can be obtained when the source code for the customized kernel is present on your debug host. This not only makes debugging easier by allowing you to see the lines of code when you stop execution, it also makes it easier to modify those lines of code. Thus, the ideal situation is for your debug host to also be your build computer. This is not required, but it makes things easier. If you are debugging a kernel extension, it generally suffices to have the source for the kernel extension itself on your debug host. However, if you need to see kernel-specific structures, having the kernel sources on your debug host may also be helpful.
Once you have built a kernel using your debug host, you must then copy it to your target computer and reboot the target computer. At this point, if you are doing panic-only debugging, you should trigger the panic. Otherwise, you should tell your target computer to drop into the debugger by issuing an NMI (or by merely booting, in the case of debug=0x1 ).
Next, unless your kernel supports ARP while debugging (and unless you enabled it with the appropriate debug flag), you need to add a permanent ARP entry for the target. It will be unable to answer ARP requests while waiting for the debugger. This ensures that your connection wont suddenly disappear. The following example assumes that your target is target.foo.com with an IP number of 10.0.0.69 :
Now, you can begin debugging by doing the following:
Note that the mach kernel passed as an argument to gdb should be the symbolladen kernel file located in BUILD/obj/DEBUG_PPC/mach_kernel.sys (for debug kernel builds, RELEASE_PPC for non-debug builds), not the bootable kernel that you copied onto the debug target. Otherwise most of the gdb macros will fail. The correct kernel should be several times as large as a normal kernel.
You must do the p proc0 command and source the .gdbinit file (from the appropriate kernel sources) twice to work around a bug in gdb . Of course, if you do not need any of the macros in .gdbinit , you can skip those two instructions. The macros are mostly of interest to people debugging aspects of Mach, though they also provide ways of obtaining information about currently loaded KEXTs.
Warning: It may not be possible to detach in a way that the target computers kernel continues to run. If you detach, the target hangs until you reattach. It is not always possible to reattach, though the situation is improving in this area. Do not detach from the remote kernel!
If you are debugging a kernel module, you need to do some additional work to get debugging symbol information about the module. First, you need to know the load address for the module. You can get this information by running kextstat ( kmodstat on systems running OS X v10.1 or earlier) as root on the target.
If you are already in the debugger, then assuming the target did not panic, you should be able to use the continue function in gdb to revive the target, get this information, then trigger another NMI to drop back into the debugger.
If the target is no longer functional, and if you have a fully symbolladen kernel file on your debug host that matches the kernel on your debug target, you can use the showallkmods macro to obtain this information. Obtaining a fully symbolladen kernel generally requires compiling the kernel yourself.
Once you have the load address of the module in question, you need to create a symbol file for the module. You do this in different ways on different versions of OS X.
For versions 10.1 and earlier, you use the kmodsyms program to create a symbol file for the module. If your KEXT is called mykext and it is loaded at address 0xf7a4000, for example, you change directories to mykext.kext/Contents/MacOS and type:
Be sure to specify the correct path for the mach kernel that is running on your target (assuming it is not the same as the kernel running on your debug host).
For versions after 10.1, you have two options. If your KEXT does not crash the computer when it loads, you can ask kextload to generate the symbols at load time by passing it the following options:
It will then write the symbols for your kernel extension and its dependencies into files within the directory you specified. Of course, this only works if your target doesnt crash at or shortly after load time.
Alternately, if you are debugging an existing panic, or if your KEXT cant be loaded without causing a panic, you can generate the debugging symbols on your debug host. You do this by typing:
If will then prompt you for the load address of the kernel extension and the addresses of all its dependencies. As mentioned previously, you can find the addresses with kextstat (or kmodstat ) or by typing showallkmods inside gdb .
You should now have a file or files containing symbolic information that gdb can use to determine addresstoname mappings within the KEXT. To add the symbols from that KEXT, within gdb on your debug host, type the command
for each symbol file. You should now be able to see a human-readable representation of the addresses of functions, variables, and so on. Special gdb I/O Addressing Issues
As described in Address Spaces , some Macintosh hardware has a third addressing mode called I/O addressing which differs from both physical and virtual addressing modes. Most developers will not need to know about these modes in any detail.
Where some developers may run into problems is debugging PCI device drivers and attempting to access device memory/registers.
To allow I/O-mapped memory dumping, do the following:
To dump in physical mode, do the following:
For example:
If you experience problems accessing I/O addresses that are not corrected by this procedure, please contact Apple Developer Technical Support for additional assistance. Using ddb for Kernel Debugging
When doing typical debugging, gdb is probably the best solution. However, there are times when gdb cannot be used or where gdb can easily run into problems. Some of these include
drivers for built-in Ethernet hardware
interrupt handlers (the hardware variety, not handler threads)
early bootstrap before the network hardware is initialized
Find iphone on mac . See all your devices on a map. Is your iPad at home or back at the office? Use the map to get a full.
When gdb is not practical (or if youre curious), there is a second debug mechanism that can be compiled into OS X. This mechanism is called ddb , and is similar to the kdb debugger in most BSD UNIX systems. It is not quite as easy to use as gdb , mainly because of the hardware needed to use it.
Unlike gdb (which uses Ethernet for communication with a kernel stub), ddb is built into the kernel itself, and interacts directly with the user over a serial line. Also unlike gdb , using ddb requires building a custom kernel using the DEBUG configuration. For more information on building this kernel, see Building Your First Kernel .
Note: ddb requires an actual built-in hardware serial line on the debug target. Neither PCI nor USB serial adapters will work. In order to work reliably for interrupt-level debugging, ddb controls the serial ports directly with a polled-mode driver without the use of the I/O Kit.
If your debug target does not have a factory serial port, third-party adapter boards may be available that replace your internal modem with a serial port. Since these devices use the built-in serial controller, they should work for ddb . It is not necessary to install OS X drivers for these devices if you are using them only to support ddb debugging.
The use of these serial port adapter cards is not an officially supported configuration, and not all computers support the third-party adapter boards needed for ddb support. Consult the appropriate adapter board vendor for compatibility information.
If your target computer has two serial ports, ddb uses the modem port (SCC port 0). However, if your target has only one serial port, that port is probably attached to port 1 of the SCC cell, which means that you have to change the default port if you want to use ddb . To use this port (SCC port 1), change the line:
in osfmk/ppc/serial_console.c to read:
and recompile the kernel.
Once you have a kernel with ddb support, it is relatively easy to use. First, you need to set up a terminal emulator program on your debug host. If your debug host is running Mac OS 9, you might use ZTerm , for example. For OS X computers, or for computers running Linux or UNIX, minicom provides a good environment. Setting up these programs is beyond the scope of this document.
Important: Serial port settings for communicating with ddb must be 57600 8N1. Hardware handshaking may be on, but is not necessary.
Note: For targets whose Open Firmware uses the serial ports, remember that the baud rate for communicating with Open Firmware is 38400 and that hardware handshaking must be off .
Once you boot a kernel with ddb support, a panic will allow you to drop into the debugger, as will a call to PE_enter_debugger . If the DB_KDB flag is not set, you will have to press the D key on the keyboard to use ddb . Alternately, if both DB_KDB and DB_NMI are set, you should be able to drop into ddb by generating a nonmaskable interrupt (NMI). See Setting Debug Flags in Open Firmware for more information on debug flags.
To generate a nonmaskable interrupt, hold down the command, option, control, and shift keys and hit escape (OS X v10.4 and newer), hold down the command key while pressing the power key on your keyboard (on hardware with a power key), or press the interrupt button on your target computer. At this point, the system should hang, and you should see ddb output on the serial terminal. If you do not, check your configuration and verify that you have specified the correct serial port on both computers. Commands and Syntax of ddb
The ddb debugger is much more gdb -like than previous versions, but it still has a syntax that is very much its own (shared only with other ddb and kdb debuggers). Because ddb is substantially different from what most developers are used to using, this section outlines the basic commands and syntax.
The commands in ddb are generally in this form:
The switches can be one of those shown in Table 20-2 . Table 20-2 Switch options in ddb
Switch
Description
/A
Print the location with line number if possible
/I
Display as instruction with possible alternate machine-dependent format
/a
Print the location being displayed
/b
Display or process by bytes
/c
Display low 8 bits as a character (nonprinting characters as octal) or count instructions while executing (depends on instruction)
/d
Display as signed decimal
/h
Display or process by half word (16 bits)
/i
Display as an instruction
/l
Display or process by long word (32 bits)
/m
Display as unsigned hex with character dump for each line
/o Frpas .
Display in unsigned octal
/p
Print cumulative instruction count and call tree depth at each call or return statement
/r
Display in current radix, signed
/s
Display the null-terminated string at address (nonprinting as octal).
/u
Display in unsigned decimal or set breakpoint at a user space address (depending on command).
/x
Display in unsigned hex
/z
Display in signed hex
The ddb debugger has a rich command set that has grown over its lifetime. Its command set is similar to that of ddb and kdb on other BSD systems, and their manual pages provide a fairly good reference for the various commands. The command set for ddb includes the following commands: break[/u] addr
Set a breakpoint at the address specified by addr . Execution will stop when the breakpoint is reached. The /u switch means to set a breakpoint in user space. c or continue[/c]
Continue execution after reaching a breakpoint. The /c switch means to count instructions while executing. call
Call a function. cond
Set condition breakpoints. This command is not supported on PowerPC. cpu cpunum
Causes ddb to switch to run on a different CPU. d or delete [addr]
Delete a breakpoint. This takes a single argument that can be either an address or a breakpoint number. dk
Equivalent to running kextstat while the target computer is running. This lists loaded KEXTs, their load addresses, and various related information. dl vaddr
Dumps a range of memory starting from the address given. The parameter vaddr is a kernel virtual address. If vaddr is not specified, the last accessed address is used. See also dr , dv . dm
Displays mapping information for the last address accessed. dmacro name
Delete the macro called name . See macro . dp
Displays the currently active page table. dr addr
Dumps a range of memory starting from the address given. The parameter address is a physical address. If addr is not specified, the last accessed address is used. See also dl , dv . ds
Dumps save areas of all Mach tasks. dv [addr [vsid]]
Dumps a range of memory starting from the address given. The parameter addr is a virtual address in the address space indicated by vsid . If addr is not specified, the last accessed address is used. Similarly, if vsid is not specified, the last vsid is used. See also dl , dr . dwatch addr
Delete a watchpoint. See watch . dx
Displays CPU registers. examine
See print . gdb
Switches to gdb mode, allowing gdb to attach to the computer. lt
On PowerPC only: Dumps the PowerPC exception trace table. macro name command [ ; command . ]
Create a macro called name that executes the listed commands. You can show a macro with the command show macro name or delete it with dmacro name . match[/p]
Stop at the matching return instruction. If the /p switch is not specified, summary information is printed only at the final return. print[/AIabcdhilmorsuxz] addr1 [addr2 ..]
Print the values at the addresses given in the format specified by the switch. If no switch is given, the last used switch is assumed. Synonymous with examine and x . Note that some of the listed switches may work for examine and not for print . reboot
Reboots the computer. Immediately. Without doing any file-system unmounts or other cleanup. Do not do this except after a panic. s or step
Single step through instructions. search[/bhl] addr value [mask[,count]]
Search memory for value starting at addr . If the value is not found, this command can wreak havoc. This command may take other formatting values in addition to those listed. set $name [=] expr
Sets the value of the variable or register named by name to the value indicated by expr . show
Display system data. For a list of information that can be shown, type the show command by itself. Some additional options are available for certain options, particularly show all . For those suboptions, type show all by itself. trace[/u]
Prints a stack backtrace. If the /u flag is specified, the stack trace extends to user space if supported by architecture-dependent code. until[/p]
Stop at the next call or return. w or write[/bhl] addr expr1 [expr2 .. ]
Writes the value of expr1 to the memory location stored at addr in increments of a byte, half word, or long word. If additional expressions are specified, they are written to consecutive bytes, half words, or long words. watch addr[,size]
Sets a watchpoint on a particular address. Execution stops when the value stored at that address is modified. Watch points are not supported on PowerPC.
Warning Watching addresses in wired kernel memory may cause unrecoverable errors on i386. x
Short for examine . See print . xb
Examine backward. Execute the last examine command, but use the address previous to the last one used (jumping backward by increments of the last width displayed). xf
Examine forward. Execute the last examine command, but use the address following the last one used (jumping by increments of the last width displayed).
The ddb debugger should seem relatively familiar to users of gdb , and its syntax was changed radically from its predecessor, kdb , to be more gdb -like. However, it is still sufficiently different that you should take some time to familiarize yourself with its use before attempting to debug something with it. It is far easier to use ddb on a system whose memory hasnt been scribbled upon by an errant DMA request, for example.
Copyright 2002, 2013 Apple Inc. All Rights Reserved. Terms of Use Privacy Policy Updated: 2013-08-08
Creating a C++ application using the Standard Template Library and the CDT
This article, which is a follow-up to 'C/C++ development with the Eclipse Platform,' is intended for C++ developers who want to learn C++ development using the Eclipse CDT. A simple C++ application is developed in the article. The application makes use of the C++ STL. Readers should be familiar with the STL, as well as with basic object-oriented programming principles such as inheritance and polymorphism. A familiarity with Eclipse will be helpful, but is not required. Before we start
You need to install the following: Gdb Mac Os X Brew
Eclipse
We're using the CDT, which is a plug-in to Eclipse, so of course you need Eclipse. The article uses Eclipse V3.2.
Java Runtime Environment
We're building a C++ application, but we're using Eclipse. Eclipse is a Java application itself, so it needs a Java Runtime Environment (JRE). The article uses Eclipse V3.2, which requires a JRE of V1.4 or higher. If you want to also use Eclipse for Java development, you'll need a Java Development Kit (JDK).
Eclipse C/C++ Development Toolkit (CDT)
This article is about the CDT, so you'll need it, of course. For instructions on installing the CDT on early versions of Eclipse, read a 'C/C++ Development with the Eclipse Platform' (developerWorks 2003) .
Cygwin
If you're using Microsoft Windows, you will find Cygwin which provides a Linux-like environment on Windows helpful.
GNU C/C++ Development Tools
The CDT uses the standard GNU C/C++ tools for compiling your code, building your project, and debugging the applications. These tools are GNU Compiler Collection (GCC) for C++ (g++), make, and the GNU Project Debugger (GDB). If you're a programmer using Linux or Mac OS X, there's a pretty good chance these tools are installed on your machine. The article contains instructions for setting up these tools for Windows. The Eclipse CDT
The Eclipse CDT is an Eclipse plug-in that transforms Eclipse into a powerful C/C++ IDE. It was designed to bring many of the great features Eclipse enjoyed by Java developers to C/C++ developers, such as project management, integrated debugging, class wizards, automated builds, syntax coloring, and code completion. When Eclipse is used as a Java IDE, it leverages and integrates with the JDK. Similarly, the CDT leverages and integrates with standard C/C++ tools, such as g++, make, and GDB. This has lead to it becoming very popular on Linux, where those tools are readily available and used for most C++ development. The CDT can be set up on Windows to use the same tools. There is also an ongoing effort to get the CDT to work with Microsoft's C++ tools to make it even more attractive to Windows C++ developers. Installing the CDT
We start by assuming you installed Eclipse and can run it. If not, consult Eclipse's Web site for getting up and running. Let's install the CDT. The CDT is an Eclipse plug-in, so it uses Eclipse's Software Updates feature. Select Help Software Updates Find and Install . Figure 1. Eclipse Software Updates
Next, you'll want to choose Search for new features to install. Figure 2. Search for new features
If you're using a newer version of Eclipse, the Callisto or Europa discovery sites should be included. (Editor's note: Since this was written in April 2007, the Europa release was still in the planning stages. However, installing Europa is expected to be similar to Callisto.) Simply select it and click Finish . Figure 3. Callisto Discovery Site
Eclipse might ask you to choose from a list of mirror sites for the Callisto Discovery Site. Pick whatever one seems closest to you. You should see a list of plug-ins from the Callisto Discovery Site. You'll want to select C and C++ Development and click Next . Figure 4. Available Callisto plug-ins
You'll be asked to accept the license for the CDT. Once you've done that, you can click Next . You'll see a summary of what's going to be downloaded and installed. Simply click Finish . Figure 5. Download and installation summary
Eclipse's Update Manager will then download the CDT plug-in from the mirror site you selected earlier. The CDT is about 11 MB total, so this could take a few minutes, depending on your Internet connection speed. Once everything is downloaded, you'll be asked to confirm that you want to install the new features. Click Install All . Figure 6. Confirm installation
After you finish installing CDT, you'll be asked to restart Eclipse. Go ahead and do that. Once Eclipse restarts, the CDT will be ready to go. Windows configuration
If you're running Eclipse on Linux or Mac OS X, you're ready to start using the CDT to develop a C++ application. If you're on Windows, there might be a few more steps. As mentioned, CDT relies on the standard GNU C++ development tools: g++, make, and GDB. These are usually included on Linux or Mac OS X. They're usually not included with Windows. But don't worry. These tools can be easily installed on Windows. Perhaps the easiest way is to install Cygwin. Cygwin provides Linux-like environment on Windows (see Related topics). When installing Cygwin, you'll be asked to pick the packages you want to install. Make sure to go into the development section and select gcc: g++, make, and GDB. This will cause their prerequisites to be installed, too.
Once you're done installing Cygwin, you'll need to add g++, make, and GDB to your path. The easiest way to do this is to add Cygwin's bin directory to your path, since that's where g++, make, and GDB can be found. Once that's done, restart Eclipse. Playing the lottery
At this point, we should be ready to start developing our application with CDT. Let's pause to figure out what we want to develop. The sample application is a simple command-line program for generating lottery numbers. Many states have lotteries, and the rules vary quite a bit. We'll allow the user to pick which state lottery he wants to generate numbers for. This will provide us a good way to use C++'s support for polymorphic behavior. Creating the project
Eclipse uses the concepts of perspectives to allow for various plug-ins to customize their commands and views. Eclipse starts off by default in the Java perspective. CDT includes its own perspective, so we'll want to switch to that. To do that, select Window Open Perspective Other . You should see a list of perspectives available to you. Select the C/C++ perspective and click OK . Figure 7. Select C/C++ perspective
Eclipse should now look something like Figure 8. Figure 8. The C/C++ perspective
Eclipse organizes your code into projects, so we'll want to create a new project. Select File New Managed Make C++ Project . Figure 9. New C++ project
You might have noticed there were several different options for the project. We wanted a C++ project. We selected a 'Managed Make,' since that will allow Eclipse to create the make file for us. You could select a 'Standard Make' flavor and write your own make file. We should now be in the New Project wizard, where we'll name our project Lottery and click Finish .
This will create an empty project, which you should see in the C/C++ Projects window. Right-click on the project and select New Source Folder . This will bring up the 'New Source Folder' wizard, where we'll name our folder src and click Finish . Basic lottery
We're ready to start creating some code. We'll start by creating the executable of our application. Right-click on the source folder we just created and selected New Source File , as shown in Figure 10.
Let's create an empty main method for now. This is just a placeholder; we'll add more to this after we've created the rest of our project.
Save your project, and Eclipse will make it for you automatically. You should see some output in the console indicating that it compiled successfully.
We're ready to create our first class. Right-click on the source folder we just created and select New Class . Figure 10. New class
This should bring up the New Class wizard. We'll give our class a namespace lotto , and we'll call our class Lottery . Figure 11. Lottery class
Eclipse will now create stubs for your class. CDT does a lot of nice things for you. It generates the appropriate compiler directives in the header file. It encourages best practices by generating separate interface (Lottery.h) and implementation (Lottery.cpp) files. It encourages another best practice by making your class' destructor virtual. We can enter the source code for these classes as seen in Listings 1 and 2. Listing 1. Lottery.h
Listing 2 shows the implementation file for the Lottery class. Listing 2. Lottery.cpp
What's this code doing? Well, our Lottery class has two attributes. The ticketSize attribute is the number of numbers on the lottery ticket. The maxNum is the maximum number on the ticket. Later, we'll use the Florida state lottery as an example. There, you pick six numbers from 1 to 53, so ticketSize would be 6 and maxNum would be 53.
The generateNumbers method generates an array of numbers corresponding to the numbers on a lottery ticket. It uses the STL function rand() to generate numbers randomly. The allNums array is used to keep track of what numbers have been generated so far, so we can make sure we don't get a duplicate number on our ticket. Finally, the printTicket() creates a string representation of our ticket.
When you save the files, Eclipse builds your project automatically. Again, if you save the project, it should be compiled and you should see compilation messages in the console, as shown in Listing 3. Listing 3. Compiler output in console MegaLottery class
You might have noticed that we made the printTicket() method virtual when it was declared in the header file. That will allow us to subclass Lottery and override this method. We wanted to do that because some states have a lottery with a 'mega' number. This is a separately drawn number that any ticket must match in addition to the other numbers drawn. Let's create a MegaLottery class for these states that will subclass Lottery .
Once again, right-click on our source folder and select New Class , as we did earlier. This time in the New Class wizard, we'll declare our new class in the same namespace, but call it MegaLottery . Figure 12. MegaLottery class
To subclass Lottery , select the Add button next to the Base Classes section. This will bring up the Choose Base Class dialog. You can start typing the name of the class, and Eclipse will narrow the list of base class candidates quickly. You'll want to select Lottery and click OK . Figure 13. Choose base classes
We can enter the code for MegaLottery , as shown in Listings 4 and 5. Listing 4. MegaLottery.h
Listing 5 shows the implementation file for the MegaLottery class. Listing 5. MegaLottery.cpp
The main difference between Lottery and MegaLottery is that MegaLottery has an extra attribute maxMegaNum . This is the max value that the mega number can take. It overrides the printTicket() method. It uses the base class to generate the first part of the ticket, then it generates the mega number and appends it to the string representation of the ticket.
We just need a way to create the various lotteries. We'll use a class Factory Pattern to do this. We'll do this by adding a LotteryFactory class. We want all Lotteries to come from the same factory, so we'll make LotteryFactory a singleton. The code for it is in Listings 6 and 7. Listing 6. ifndef LOTTERYFACTORY_H_
Listing 7 shows the implementation file for the LotteryFactory class. Listing 7. LotteryFactory.cpp
The LotteryFactory has an enum of the different types of lotteries. We've only put in Florida and California in the example, but it shouldn't be hard to add as many as you want. The LotteryFactory 's constructor seeds the rand() function used by our lottery classes. We just need to implement our executable's main method. Listing 8. Main.cpp Running the program
We're ready to run our program. Select Run Run . Figure 14. Choose base classes
Select C/C++ Local Application and click the New button. Figure 15. New C/C++ run profile
This will bring up the Create run configuration interface for the Lottery project. You'll need to select its executable by clicking the Search Project button. Figure 16. Search project for executable
You can select the binary that Eclipse created for you and click OK . Figure 17. Search project for executable Gdb For Mac Os X 10.13
Just click Run , and the program should run in your console. The code below shows some sample output. Debugging the program
Our program should run fine, but let's take a look at debugging the application. First, create a breakpoint in our code. Pick a line and right-click next to it and select Toggle Breakpoint . Gdb For Mac Os X64 Figure 18. Create breakpoint
We need to create a debug configuration, much like we created a run configuration. Select Run Debug . Figure 19. Create debug configuration
This should bring up the Debug configuration. This is based on the Run configuration, and you shouldn't need to change anything. Just click Debug . Figure 20. Debug configuration
Once the debugger starts, it will prompt you to switch to the Debugger perspective. Do so. Notice that in the configuration we set things to break automatically at the startup of our main method. Thus, the debugger should break immediately and you should see a screen something like Figure 21. Gdb For Mac Os X 10.8 Figure 21. The debugger Download Gdb For Mac Os X Summary Gdb For Mac Os X 10.10
We've built and debugged our lottery application. You can easily add more lottery schemes to it. Some of these could involve additional subclasses. CDT makes it easier than ever to create these classes and class hierarchies, and to run and debug the application to test it. Downloadable resources Related topics
Integrate an external code checker into Eclipse CDT (Alex Ruiz, developerWorks): Learn how to execute C/C++ code analysis tools with Codan in Eclipse.
Get an overview of the CDT in 'C/C++ development with the Eclipse Platform.'
Dig deep into the CDT's architecture in the five-part series titled 'Building a CDT-based editor.'
As someone interested in C/C++ development, you might want to check out a trial of IBM's XL C/C++ compiler for Linux or AIX.
Windows developers can learn about migrating to the CDT in 'Migrate Visual Studio C and C++ projects to Eclipse CDT.'
Windows developers can also check out the CDT-MSVC project, a project for incorporating Microsoft's compiler and debugger with CDT.
Learn about MinGW, the GNU C/C++ tools for Windows included with Cygwin.
Download Cygwin a Linux-like environment for Windows. It consists of two parts: A DLL that acts as a Linux API emulation layer providing substantial Linux API functionality and a collection of tools that provide a Linux look and feel.
The Eclipse C/C++ Development Toolkit (CDT) download information contains the latest information about the available versions of CDT.
Check out the 'Recommended Eclipse reading list.'
For an introduction to the Eclipse platform, see 'Getting started with the Eclipse Platform.'
Gdb Mac Os X Brew
Gdb For Mac Os X 10.13
Gdb For Mac Os X64
Gdb For Mac Os X 10.8
Download Gdb For Mac Os X
Gdb For Mac Os X 10.10
The Mac OS X Debugging Magic Technote contains a wealth of information about various debugging options built in to macOS. IMPORTANT: By default, Xcode has the 'Load Symbols Lazily' preference set. As a result, any symbols not in the main static library (99. If you prefer watching videos to reading articles, Cody Henrichsen has created a video walkthrough of this procedure. With its new OS release, Apple has discontinued the use of GDB in OS X. Since 2005 Apple has steadily been moving away from the GNU toolchain in favor of LLVM.This means that Xcode now uses LLDB instead. LLDB looks to be a very nice replacement for GDB, and I hope to use it.
The discussion is divided into three sections. The first, Adding New Files or Modules , describes how to add new functionality into the kernel itself. You should only add files into the kernel when the use of a KEXT is not possible (for example, when adding certain low-level motherboard hardware support).
The second section, Building Your First Kernel , describes how to build a kernel, including how to build a kernel with debugger support, how to add new options, and how to obtain sources that are of similar vintage to those in a particular version of OS X or Darwin.
The third section, When Things Go Wrong: Debugging the Kernel , tells how to debug a kernel or kernel module using ddb and gdb . This is a must-read for anyone doing kernel development. Adding New Files or Modules
In this context, the term module is used loosely to refer to a collection of related files in the kernel that are controlled by a single config option at compile time. It does not refer to loadable modules (KEXTs). This section describes how to add additional files that will be compiled into the kernel, including how to add a new config option for an additional module. Modifying the Configuration Files
The details of adding a new file or module into the kernel differ according to what portion of the kernel contains the file. If you are adding a new file or module into the Mach portion of the kernel, you need to list it in various files in xnu/osfmk/conf . For the BSD portion of the kernel, you should list it in various files in xnu/bsd/conf . In either case, the procedure is basically the same, just in a different directory.
This section is divided into two subsections. The first describes adding the module itself and the second describes enabling the module. Adding the Files or Modules
In the appropriate conf directory, you need to add your files or modules into various files. The files MASTER , MASTER.ppc , and MASTER.i386 contain the list of configuration options that should be built into the kernel for all architectures, PowerPC, and i386, respectively.
These are supplemented by files , files.ppc , and files.i386 , which contain associations between compile options and the files that are related to them for their respective architectures.
The format for these two files is relatively straightforward. If you are adding a new module, you should first choose a name for that module. For example, if your module is called mach_foo , you should then add a new option line near the top of files that is whitespace (space or tab) delimited and looks like this:
The first part defines the name of the module as it will be used in if statements in the code. (See Modifying the Source Code Files for more information.) The second part is always the word optional. The third part tells the name of the option as used to turn it on or off in a MASTER file. Any line with mach_foo in the last field will be enabled only if there is an appropriate line in a MASTER file.
Then, later in the file, you add
and so on, for each new file associated with that module. This also applies if you are adding a file to an existing module. If you are adding a file that is not associated with any module at all, you add a line that looks like the following to specify that this file should always be included:
If you are not adding any modules, then youre done. Otherwise, you also need to enable your option in one of the MASTER files. Enabling Module Options
To enable a module option (as described in the files files), you must add an entry for that option into one of the MASTER files. If your code is not a BSD pseudo-device, you should add something like the following:
Otherwise, you should add something like this:
In the case of a pseudo-device (for example, /dev/random ), you can also add a number. When your code checks to see if it should be included, it can also check that number and allocate resources for more than one pseudo-device. The meaning of multiple pseudo-devices is device-dependent. An example of this is ppp , which allocates resources for two simultaneous PPP connections. Thus, in the MASTER.ppc file, it has the line: Modifying the Source Code Files
In the OS X kernel, all source code files are automatically compiled. It is the responsibility of the C file itself to determine whether its contents need to be included in the build or not.
In the example above, you created a module called mach_foo . Assume that you want this file to compile only on PowerPC-based computers. In that case, you should have included the option only in MASTER.ppc and not in MASTER.i386 . However, by default, merely specifying the file foo_main.c in files causes it to be compiled, regardless of compile options specified.
To make the code compile only when the option mach_foo is included in the configuration, you should begin each C source file with the lines
and end it with
If mach_foo is a pseudo-device and you need to check the number of mach_foo pseudo-devices included, you can do further tests of the value of MACH_FOO .
Note that the file mach_foo.h is not something you create. It is created by the makefiles themselves. You must run make exporthdrs before make all to generate these files. Building Your First Kernel
Before you can build a kernel, you must first obtain source code. Source code for the OS X kernel can be found in the Darwin xnu project on http://www.opensource.apple.com . To find out your current kernel version, use the command uname -a . If you run into trouble, search the archives of the darwin-kernel and darwin-development mailing lists for information. If that doesnt help, ask for assistance on either list. The list archives and subscription information can be found at http://www.lists.apple.com .
Note: Before you begin, make sure you extract the sources in a directory whose path does not contain any special characters (non-alphanumeric characters other than dash and underscore), as having such characters in the path leading up to the build directory can cause compiling to fail.
Also, make sure that /usr/local/bin is in your PATH environment variable as follows:
If you are using a csh derivative such as tcsh, you should add set path = (/usr/local/bin $path) to your .tcshrc file
If you are using a Bourne shell derivative, you should add export PATH=/usr/local/bin:$PATH to your .bashrc file.
Important: Once you have obtained and extracted the sources, before you begin compiling kernel support tools, you should configure your system to build using gcc 3.3. The OS X v10.4 kernel will not build using gcc 4.0. To do this, type:
Important: Before building anything, you should make sure you are running the latest version of OS X with the latest developer tools. The xnu compile process may reference various external headers from /System/Library/Frameworks . These headers are only installed as part of a developer tools installation, not as part of the normal OS X install process.
Next, you will need to compile several support tools. Get the bootstrap_cmds , Libstreams , kext_tools , IOKitUser , and cctools packages from http://www.opensource.apple.com . Extract the files from these .tar packages, then do the following:
In the cctools package, modify the Makefile , and change the COMMON_SUBDIRS line (including the continuation line after it) to read:
Finally, issue the following commands:
Now youre done with the cctools project. One final step remains: compiling kextsymboltool . To do this, extract the kext_tools tarball, then do the following:
Warning: If you do not use a version of kextsymboltool that is at least as current as your kernel, you will get serious compile failures. If you see the error message exported name not in import list, theres a good chance you arent using a current kextsymboltool .
Congratulations. You now have all the necessary tools, libraries, and header files to build a kernel.
The next step is to compile the kernel itself. First, change directories into the xnu directory. Next, you need to set a few environment variables appropriately. For your convenience, the kernel sources contain shell scripts to do this for you. If you are using sh, bash, zsh, or some other Bourne-compatible shell, issue the following command:
If you are using csh, tcsh, or a similar shell, use the following command:
Then, you should be able to type
and get a working kernel in BUILD/obj/RELEASE_PPC/mach_kernel (assuming you are building a RELEASE kernel for PowerPC, of course).
If things dont work, the darwin-kernel mailing list a good place to get help. Building an Alternate Kernel Configuration
When building a kernel, you may want to build a configuration other than the RELEASE configuration (the default shipping configuration). Additional configurations are RELEASE_TRACE , DEBUG , DEBUG_TRACE , and PROFILE . These configurations add various additional options (except PROFILE , which is reserved for future expansion, and currently maps onto RELEASE ).
The most useful and interesting configurations are RELEASE and DEBUG . The release configuration should be the same as a stock Apple-released kernel, so this is interesting only if you are building source that differs from that which was used to build the kernel you are already running. Compiling a kernel without specifying a configuration results in the RELEASE configuration being built.
The DEBUG configuration enables ddb , the in-kernel serial debugger. The ddb debugger is helpful to debug panics that occur early in boot or within certain parts of the Ethernet driver. It is also useful for debugging low-level interrupt handler routines that cannot be debugged by using the more traditional gdb .
To compile an alternate kernel configuration, you should follow the same basic procedure as outlined previously, changing the final make statement slightly. For example, to build the DEBUG configuration, instead of typing
you type
and wait.
To turn on additional compile options, you must modify one of the MASTER files. For information on modifying these files, see the section Enabling Module Options . When Things Go Wrong: Debugging the Kernel
No matter how careful your programming habits, sometimes things dont work right the first time. Kernel panics are simply a fact of life during development of kernel extensions or other in-kernel code.
There are a number of ways to track down problems in kernel code. In many cases, you can find the problem through careful use of printf or IOLog statements. Some people swear by this method, and indeed, given sufficient time and effort, any bug can be found and fixed without using a debugger.
Of course, the key words in that statement are given sufficient time and effort. For the rest of us, there are debuggers: gdb and ddb . Setting Debug Flags in Open Firmware
With the exception of kernel panics or calls to PE_enter_debugger , it is not possible to do remote kernel debugging without setting debug flags in Open Firmware. These flags are relevant to both gdb and ddb debugging and are important enough to warrant their own section.
To set these flags, you can either use the nvram program (from the OS X command line) or access your computers Open Firmware. You can access Open Firmware this by holding down Command-Option-O-F at boot time. For most computers, the default is for Open Firmware to present a commandline prompt on your monitor and accept input from your keyboard. For some older computers you must use a serial line at 38400, 8N1. (Technically, such computers are not supported by OS X, but some are usable under Darwin, and thus they are mentioned here for completeness.)
From an Open Firmware prompt, you can set the flags with the setenv command. From the OS X command line, you would use the nvram command. Note that when modifying these flags you should always look at the old value for the appropriate Open Firmware variables and add the debug flags.
For example, if you want to set the debug flags to 0x4 , you use one of the following commands. For computers with recent versions of Open Firmware, you would type
from Open Firmware or
from the command line (as root).
For older firmware versions, the interesting variable is boot-command . Thus, you might do something like
from Open Firmware or
from the command line (as root).
Of course, the more important issue is what value to choose for the debug flags. Table 20-1 lists the debugging flags that are supported in OS X. Table 20-1 Debugging flags
Symbolic name
Flag
Meaning
DB_HALT
0x01
Halt at boot-time and wait for debugger attach ( gdb ).
DB_PRT
0x02
Send kernel debugging printf output to console.
DB_NMI
0x04
Drop into debugger on NMI (CommandPower, Command-Option-Control-Shift-Escape, or interrupt switch).
DB_KPRT
0x08
Send kernel debugging kprintf output to serial port.
DB_KDB
0x10
Make ddb ( kdb ) the default debugger (requires a custom kernel).
DB_SLOG
0x20
Output certain diagnostic info to the system log.
DB_ARP
0x40
Allow debugger to ARP and route (allows debugging across routers and removes the need for a permanent ARP entry, but is a potential security hole)not available in all kernels.
DB_KDP_BP_DIS
0x80
Support old versions of gdb on newer systems.
DB_LOG_PI_SCRN
0x100
Disable graphical panic dialog.
The option DB_KDP_BP_DIS is not available on all systems, and should not be important if your target and host systems are running the same or similar versions of OS X with matching developer tools. The last option is only available in Mac OS 10.2 and later. Avoiding Watchdog Timer Problems
Macintosh computers have various watchdog timers designed to protect the system from certain types of failures. There are two primary watchdog timers in common use: the power management watchdog timer (not present on all systems) and the system crash watchdog timer. Both watchdogs are part of the power management hardware.
The first of these, the power management watchdog timer, is designed to restore the system to a known safe state in the event of unexpected communication loss between the power management hardware and the CPU. This timer is only present in G4 and earlier desktops and laptops and in early G5 desktops. More specifically, it is present only in machines containing a PMU (Power Management Unit) chip.
Under normal circumstances, when communication with the PMU chip is lost, the PMU driver will attempt to get back in sync with the PMU chip. With the possible exception of a momentary loss of keyboard and mouse control, you probably won't notice that anything has happened (and you should never even experience such a stall unless you are writing a device driver that disables interrupts for an extended period of time).
The problem occurs when the disruption in communication is caused by entering the debugger while the PMU chip is in one of these 'unsafe' states. If the chip is left in one of these 'unsafe' states for too long, it will shut the computer down to prevent overheating or other problems.
This problem can be significantly reduced by operating the PMU chip in polled mode. This prevents the watchdog timer from activating. You should only use this option when debugging, however, as it diminishes performance and a crashed system could overheat.
To disable this watchdog timer, add the argument pmuflags=1 to the kernel's boot arguments. See Setting Debug Flags in Open Firmware for information about how to add a boot argument.
The second type of watchdog timer is the system crash watchdog timer. This is normally only enabled in OS X Server. If your target machine is running OS X Server, your system will automatically reboot within seconds after a crash to maximize server uptime. You can disable this automatic reboot on crash feature in the server administration tool. Choosing a Debugger
There are two basic debugging environments supported by OS X: ddb and gdb . ddb is a built-in debugger that works over a serial line. By contrast, gdb is supported using a debugging shim built into the kernel, which allows a remote computer on the same physical network to attach after a panic (or sooner if you pass certain options to the kernel).
For problems involving network extensions or low-level operating system bringups, ddb is the only way to do debugging. For other bugs, gdb is generally easier to use. For completeness, this chapter describes how to use both ddb and gdb to do basic debugging. Since gdb itself is well documented and is commonly used for application programming, this chapter assumes at least a passing knowledge of the basics of using gdb and focuses on the areas where remote (kernel) gdb differs.
Note: Only systems with serial hardware support ddb . Thus, it is only possible to use ddb on PowerMac G4 and older systems. Using gdb for Kernel Debugging
gdb , short for the GNU Debugger, is a piece of software commonly used for debugging software on UNIX and Linux systems. This section assumes that you have used gdb before, and does not attempt to explain basic usage.
In standard OS X builds (and in your builds unless you compile with ddb support), gdb support is built into the system but is turned off except in the case of a kernel panic.
Of course, many software failures in the kernel do not result in a kernel panic but still cause aberrant behavior. For these reasons, you can pass additional flags to the kernel to allow you to attach to a remote computer early in boot or after a nonmaskable interrupt (NMI), or you can programmatically drop into the debugger in your code.
You can cause the test computer (the debug target) to drop into the debugger in the following ways:
debug on panic
debug on NMI
debug on boot
programmatically drop into the default debugger
The function PE_enter_debugger can be called from anywhere in the kernel, although if gdb is your default debugger, a crash will result if the network hardware is not initialized or if gdb cannot be used in that particular context. This call is described in the header pexpert/pexpert.h .
After you have decided what method to use for dropping into the debugger on the target, you must configure your debug host (the computer that will actually be running gdb ). Your debug host should be running a version of OS X that is comparable to the version running on your target host. However, it should not be running a customized kernel, since a debug host crash would be problematic, to say the least.
Note: It is possible to use a non-OS X system as your debug host. This is not a trivial exercise, however, and a description of building a cross- gdb is beyond the scope of this document.
When using gdb , the best results can be obtained when the source code for the customized kernel is present on your debug host. This not only makes debugging easier by allowing you to see the lines of code when you stop execution, it also makes it easier to modify those lines of code. Thus, the ideal situation is for your debug host to also be your build computer. This is not required, but it makes things easier. If you are debugging a kernel extension, it generally suffices to have the source for the kernel extension itself on your debug host. However, if you need to see kernel-specific structures, having the kernel sources on your debug host may also be helpful.
Once you have built a kernel using your debug host, you must then copy it to your target computer and reboot the target computer. At this point, if you are doing panic-only debugging, you should trigger the panic. Otherwise, you should tell your target computer to drop into the debugger by issuing an NMI (or by merely booting, in the case of debug=0x1 ).
Next, unless your kernel supports ARP while debugging (and unless you enabled it with the appropriate debug flag), you need to add a permanent ARP entry for the target. It will be unable to answer ARP requests while waiting for the debugger. This ensures that your connection wont suddenly disappear. The following example assumes that your target is target.foo.com with an IP number of 10.0.0.69 :
Now, you can begin debugging by doing the following:
Note that the mach kernel passed as an argument to gdb should be the symbolladen kernel file located in BUILD/obj/DEBUG_PPC/mach_kernel.sys (for debug kernel builds, RELEASE_PPC for non-debug builds), not the bootable kernel that you copied onto the debug target. Otherwise most of the gdb macros will fail. The correct kernel should be several times as large as a normal kernel.
You must do the p proc0 command and source the .gdbinit file (from the appropriate kernel sources) twice to work around a bug in gdb . Of course, if you do not need any of the macros in .gdbinit , you can skip those two instructions. The macros are mostly of interest to people debugging aspects of Mach, though they also provide ways of obtaining information about currently loaded KEXTs.
Warning: It may not be possible to detach in a way that the target computers kernel continues to run. If you detach, the target hangs until you reattach. It is not always possible to reattach, though the situation is improving in this area. Do not detach from the remote kernel!
If you are debugging a kernel module, you need to do some additional work to get debugging symbol information about the module. First, you need to know the load address for the module. You can get this information by running kextstat ( kmodstat on systems running OS X v10.1 or earlier) as root on the target.
If you are already in the debugger, then assuming the target did not panic, you should be able to use the continue function in gdb to revive the target, get this information, then trigger another NMI to drop back into the debugger.
If the target is no longer functional, and if you have a fully symbolladen kernel file on your debug host that matches the kernel on your debug target, you can use the showallkmods macro to obtain this information. Obtaining a fully symbolladen kernel generally requires compiling the kernel yourself.
Once you have the load address of the module in question, you need to create a symbol file for the module. You do this in different ways on different versions of OS X.
For versions 10.1 and earlier, you use the kmodsyms program to create a symbol file for the module. If your KEXT is called mykext and it is loaded at address 0xf7a4000, for example, you change directories to mykext.kext/Contents/MacOS and type:
Be sure to specify the correct path for the mach kernel that is running on your target (assuming it is not the same as the kernel running on your debug host).
For versions after 10.1, you have two options. If your KEXT does not crash the computer when it loads, you can ask kextload to generate the symbols at load time by passing it the following options:
It will then write the symbols for your kernel extension and its dependencies into files within the directory you specified. Of course, this only works if your target doesnt crash at or shortly after load time.
Alternately, if you are debugging an existing panic, or if your KEXT cant be loaded without causing a panic, you can generate the debugging symbols on your debug host. You do this by typing:
If will then prompt you for the load address of the kernel extension and the addresses of all its dependencies. As mentioned previously, you can find the addresses with kextstat (or kmodstat ) or by typing showallkmods inside gdb .
You should now have a file or files containing symbolic information that gdb can use to determine addresstoname mappings within the KEXT. To add the symbols from that KEXT, within gdb on your debug host, type the command
for each symbol file. You should now be able to see a human-readable representation of the addresses of functions, variables, and so on. Special gdb I/O Addressing Issues
As described in Address Spaces , some Macintosh hardware has a third addressing mode called I/O addressing which differs from both physical and virtual addressing modes. Most developers will not need to know about these modes in any detail.
Where some developers may run into problems is debugging PCI device drivers and attempting to access device memory/registers.
To allow I/O-mapped memory dumping, do the following:
To dump in physical mode, do the following:
For example:
If you experience problems accessing I/O addresses that are not corrected by this procedure, please contact Apple Developer Technical Support for additional assistance. Using ddb for Kernel Debugging
When doing typical debugging, gdb is probably the best solution. However, there are times when gdb cannot be used or where gdb can easily run into problems. Some of these include
drivers for built-in Ethernet hardware
interrupt handlers (the hardware variety, not handler threads)
early bootstrap before the network hardware is initialized
Find iphone on mac . See all your devices on a map. Is your iPad at home or back at the office? Use the map to get a full.
When gdb is not practical (or if youre curious), there is a second debug mechanism that can be compiled into OS X. This mechanism is called ddb , and is similar to the kdb debugger in most BSD UNIX systems. It is not quite as easy to use as gdb , mainly because of the hardware needed to use it.
Unlike gdb (which uses Ethernet for communication with a kernel stub), ddb is built into the kernel itself, and interacts directly with the user over a serial line. Also unlike gdb , using ddb requires building a custom kernel using the DEBUG configuration. For more information on building this kernel, see Building Your First Kernel .
Note: ddb requires an actual built-in hardware serial line on the debug target. Neither PCI nor USB serial adapters will work. In order to work reliably for interrupt-level debugging, ddb controls the serial ports directly with a polled-mode driver without the use of the I/O Kit.
If your debug target does not have a factory serial port, third-party adapter boards may be available that replace your internal modem with a serial port. Since these devices use the built-in serial controller, they should work for ddb . It is not necessary to install OS X drivers for these devices if you are using them only to support ddb debugging.
The use of these serial port adapter cards is not an officially supported configuration, and not all computers support the third-party adapter boards needed for ddb support. Consult the appropriate adapter board vendor for compatibility information.
If your target computer has two serial ports, ddb uses the modem port (SCC port 0). However, if your target has only one serial port, that port is probably attached to port 1 of the SCC cell, which means that you have to change the default port if you want to use ddb . To use this port (SCC port 1), change the line:
in osfmk/ppc/serial_console.c to read:
and recompile the kernel.
Once you have a kernel with ddb support, it is relatively easy to use. First, you need to set up a terminal emulator program on your debug host. If your debug host is running Mac OS 9, you might use ZTerm , for example. For OS X computers, or for computers running Linux or UNIX, minicom provides a good environment. Setting up these programs is beyond the scope of this document.
Important: Serial port settings for communicating with ddb must be 57600 8N1. Hardware handshaking may be on, but is not necessary.
Note: For targets whose Open Firmware uses the serial ports, remember that the baud rate for communicating with Open Firmware is 38400 and that hardware handshaking must be off .
Once you boot a kernel with ddb support, a panic will allow you to drop into the debugger, as will a call to PE_enter_debugger . If the DB_KDB flag is not set, you will have to press the D key on the keyboard to use ddb . Alternately, if both DB_KDB and DB_NMI are set, you should be able to drop into ddb by generating a nonmaskable interrupt (NMI). See Setting Debug Flags in Open Firmware for more information on debug flags.
To generate a nonmaskable interrupt, hold down the command, option, control, and shift keys and hit escape (OS X v10.4 and newer), hold down the command key while pressing the power key on your keyboard (on hardware with a power key), or press the interrupt button on your target computer. At this point, the system should hang, and you should see ddb output on the serial terminal. If you do not, check your configuration and verify that you have specified the correct serial port on both computers. Commands and Syntax of ddb
The ddb debugger is much more gdb -like than previous versions, but it still has a syntax that is very much its own (shared only with other ddb and kdb debuggers). Because ddb is substantially different from what most developers are used to using, this section outlines the basic commands and syntax.
The commands in ddb are generally in this form:
The switches can be one of those shown in Table 20-2 . Table 20-2 Switch options in ddb
Switch
Description
/A
Print the location with line number if possible
/I
Display as instruction with possible alternate machine-dependent format
/a
Print the location being displayed
/b
Display or process by bytes
/c
Display low 8 bits as a character (nonprinting characters as octal) or count instructions while executing (depends on instruction)
/d
Display as signed decimal
/h
Display or process by half word (16 bits)
/i
Display as an instruction
/l
Display or process by long word (32 bits)
/m
Display as unsigned hex with character dump for each line
/o Frpas .
Display in unsigned octal
/p
Print cumulative instruction count and call tree depth at each call or return statement
/r
Display in current radix, signed
/s
Display the null-terminated string at address (nonprinting as octal).
/u
Display in unsigned decimal or set breakpoint at a user space address (depending on command).
/x
Display in unsigned hex
/z
Display in signed hex
The ddb debugger has a rich command set that has grown over its lifetime. Its command set is similar to that of ddb and kdb on other BSD systems, and their manual pages provide a fairly good reference for the various commands. The command set for ddb includes the following commands: break[/u] addr
Set a breakpoint at the address specified by addr . Execution will stop when the breakpoint is reached. The /u switch means to set a breakpoint in user space. c or continue[/c]
Continue execution after reaching a breakpoint. The /c switch means to count instructions while executing. call
Call a function. cond
Set condition breakpoints. This command is not supported on PowerPC. cpu cpunum
Causes ddb to switch to run on a different CPU. d or delete [addr]
Delete a breakpoint. This takes a single argument that can be either an address or a breakpoint number. dk
Equivalent to running kextstat while the target computer is running. This lists loaded KEXTs, their load addresses, and various related information. dl vaddr
Dumps a range of memory starting from the address given. The parameter vaddr is a kernel virtual address. If vaddr is not specified, the last accessed address is used. See also dr , dv . dm
Displays mapping information for the last address accessed. dmacro name
Delete the macro called name . See macro . dp
Displays the currently active page table. dr addr
Dumps a range of memory starting from the address given. The parameter address is a physical address. If addr is not specified, the last accessed address is used. See also dl , dv . ds
Dumps save areas of all Mach tasks. dv [addr [vsid]]
Dumps a range of memory starting from the address given. The parameter addr is a virtual address in the address space indicated by vsid . If addr is not specified, the last accessed address is used. Similarly, if vsid is not specified, the last vsid is used. See also dl , dr . dwatch addr
Delete a watchpoint. See watch . dx
Displays CPU registers. examine
See print . gdb
Switches to gdb mode, allowing gdb to attach to the computer. lt
On PowerPC only: Dumps the PowerPC exception trace table. macro name command [ ; command . ]
Create a macro called name that executes the listed commands. You can show a macro with the command show macro name or delete it with dmacro name . match[/p]
Stop at the matching return instruction. If the /p switch is not specified, summary information is printed only at the final return. print[/AIabcdhilmorsuxz] addr1 [addr2 ..]
Print the values at the addresses given in the format specified by the switch. If no switch is given, the last used switch is assumed. Synonymous with examine and x . Note that some of the listed switches may work for examine and not for print . reboot
Reboots the computer. Immediately. Without doing any file-system unmounts or other cleanup. Do not do this except after a panic. s or step
Single step through instructions. search[/bhl] addr value [mask[,count]]
Search memory for value starting at addr . If the value is not found, this command can wreak havoc. This command may take other formatting values in addition to those listed. set $name [=] expr
Sets the value of the variable or register named by name to the value indicated by expr . show
Display system data. For a list of information that can be shown, type the show command by itself. Some additional options are available for certain options, particularly show all . For those suboptions, type show all by itself. trace[/u]
Prints a stack backtrace. If the /u flag is specified, the stack trace extends to user space if supported by architecture-dependent code. until[/p]
Stop at the next call or return. w or write[/bhl] addr expr1 [expr2 .. ]
Writes the value of expr1 to the memory location stored at addr in increments of a byte, half word, or long word. If additional expressions are specified, they are written to consecutive bytes, half words, or long words. watch addr[,size]
Sets a watchpoint on a particular address. Execution stops when the value stored at that address is modified. Watch points are not supported on PowerPC.
Warning Watching addresses in wired kernel memory may cause unrecoverable errors on i386. x
Short for examine . See print . xb
Examine backward. Execute the last examine command, but use the address previous to the last one used (jumping backward by increments of the last width displayed). xf
Examine forward. Execute the last examine command, but use the address following the last one used (jumping by increments of the last width displayed).
The ddb debugger should seem relatively familiar to users of gdb , and its syntax was changed radically from its predecessor, kdb , to be more gdb -like. However, it is still sufficiently different that you should take some time to familiarize yourself with its use before attempting to debug something with it. It is far easier to use ddb on a system whose memory hasnt been scribbled upon by an errant DMA request, for example.
Copyright 2002, 2013 Apple Inc. All Rights Reserved. Terms of Use Privacy Policy Updated: 2013-08-08
Creating a C++ application using the Standard Template Library and the CDT
This article, which is a follow-up to 'C/C++ development with the Eclipse Platform,' is intended for C++ developers who want to learn C++ development using the Eclipse CDT. A simple C++ application is developed in the article. The application makes use of the C++ STL. Readers should be familiar with the STL, as well as with basic object-oriented programming principles such as inheritance and polymorphism. A familiarity with Eclipse will be helpful, but is not required. Before we start
You need to install the following: Gdb Mac Os X Brew
Eclipse
We're using the CDT, which is a plug-in to Eclipse, so of course you need Eclipse. The article uses Eclipse V3.2.
Java Runtime Environment
We're building a C++ application, but we're using Eclipse. Eclipse is a Java application itself, so it needs a Java Runtime Environment (JRE). The article uses Eclipse V3.2, which requires a JRE of V1.4 or higher. If you want to also use Eclipse for Java development, you'll need a Java Development Kit (JDK).
Eclipse C/C++ Development Toolkit (CDT)
This article is about the CDT, so you'll need it, of course. For instructions on installing the CDT on early versions of Eclipse, read a 'C/C++ Development with the Eclipse Platform' (developerWorks 2003) .
Cygwin
If you're using Microsoft Windows, you will find Cygwin which provides a Linux-like environment on Windows helpful.
GNU C/C++ Development Tools
The CDT uses the standard GNU C/C++ tools for compiling your code, building your project, and debugging the applications. These tools are GNU Compiler Collection (GCC) for C++ (g++), make, and the GNU Project Debugger (GDB). If you're a programmer using Linux or Mac OS X, there's a pretty good chance these tools are installed on your machine. The article contains instructions for setting up these tools for Windows. The Eclipse CDT
The Eclipse CDT is an Eclipse plug-in that transforms Eclipse into a powerful C/C++ IDE. It was designed to bring many of the great features Eclipse enjoyed by Java developers to C/C++ developers, such as project management, integrated debugging, class wizards, automated builds, syntax coloring, and code completion. When Eclipse is used as a Java IDE, it leverages and integrates with the JDK. Similarly, the CDT leverages and integrates with standard C/C++ tools, such as g++, make, and GDB. This has lead to it becoming very popular on Linux, where those tools are readily available and used for most C++ development. The CDT can be set up on Windows to use the same tools. There is also an ongoing effort to get the CDT to work with Microsoft's C++ tools to make it even more attractive to Windows C++ developers. Installing the CDT
We start by assuming you installed Eclipse and can run it. If not, consult Eclipse's Web site for getting up and running. Let's install the CDT. The CDT is an Eclipse plug-in, so it uses Eclipse's Software Updates feature. Select Help Software Updates Find and Install . Figure 1. Eclipse Software Updates
Next, you'll want to choose Search for new features to install. Figure 2. Search for new features
If you're using a newer version of Eclipse, the Callisto or Europa discovery sites should be included. (Editor's note: Since this was written in April 2007, the Europa release was still in the planning stages. However, installing Europa is expected to be similar to Callisto.) Simply select it and click Finish . Figure 3. Callisto Discovery Site
Eclipse might ask you to choose from a list of mirror sites for the Callisto Discovery Site. Pick whatever one seems closest to you. You should see a list of plug-ins from the Callisto Discovery Site. You'll want to select C and C++ Development and click Next . Figure 4. Available Callisto plug-ins
You'll be asked to accept the license for the CDT. Once you've done that, you can click Next . You'll see a summary of what's going to be downloaded and installed. Simply click Finish . Figure 5. Download and installation summary
Eclipse's Update Manager will then download the CDT plug-in from the mirror site you selected earlier. The CDT is about 11 MB total, so this could take a few minutes, depending on your Internet connection speed. Once everything is downloaded, you'll be asked to confirm that you want to install the new features. Click Install All . Figure 6. Confirm installation
After you finish installing CDT, you'll be asked to restart Eclipse. Go ahead and do that. Once Eclipse restarts, the CDT will be ready to go. Windows configuration
If you're running Eclipse on Linux or Mac OS X, you're ready to start using the CDT to develop a C++ application. If you're on Windows, there might be a few more steps. As mentioned, CDT relies on the standard GNU C++ development tools: g++, make, and GDB. These are usually included on Linux or Mac OS X. They're usually not included with Windows. But don't worry. These tools can be easily installed on Windows. Perhaps the easiest way is to install Cygwin. Cygwin provides Linux-like environment on Windows (see Related topics). When installing Cygwin, you'll be asked to pick the packages you want to install. Make sure to go into the development section and select gcc: g++, make, and GDB. This will cause their prerequisites to be installed, too.
Once you're done installing Cygwin, you'll need to add g++, make, and GDB to your path. The easiest way to do this is to add Cygwin's bin directory to your path, since that's where g++, make, and GDB can be found. Once that's done, restart Eclipse. Playing the lottery
At this point, we should be ready to start developing our application with CDT. Let's pause to figure out what we want to develop. The sample application is a simple command-line program for generating lottery numbers. Many states have lotteries, and the rules vary quite a bit. We'll allow the user to pick which state lottery he wants to generate numbers for. This will provide us a good way to use C++'s support for polymorphic behavior. Creating the project
Eclipse uses the concepts of perspectives to allow for various plug-ins to customize their commands and views. Eclipse starts off by default in the Java perspective. CDT includes its own perspective, so we'll want to switch to that. To do that, select Window Open Perspective Other . You should see a list of perspectives available to you. Select the C/C++ perspective and click OK . Figure 7. Select C/C++ perspective
Eclipse should now look something like Figure 8. Figure 8. The C/C++ perspective
Eclipse organizes your code into projects, so we'll want to create a new project. Select File New Managed Make C++ Project . Figure 9. New C++ project
You might have noticed there were several different options for the project. We wanted a C++ project. We selected a 'Managed Make,' since that will allow Eclipse to create the make file for us. You could select a 'Standard Make' flavor and write your own make file. We should now be in the New Project wizard, where we'll name our project Lottery and click Finish .
This will create an empty project, which you should see in the C/C++ Projects window. Right-click on the project and select New Source Folder . This will bring up the 'New Source Folder' wizard, where we'll name our folder src and click Finish . Basic lottery
We're ready to start creating some code. We'll start by creating the executable of our application. Right-click on the source folder we just created and selected New Source File , as shown in Figure 10.
Let's create an empty main method for now. This is just a placeholder; we'll add more to this after we've created the rest of our project.
Save your project, and Eclipse will make it for you automatically. You should see some output in the console indicating that it compiled successfully.
We're ready to create our first class. Right-click on the source folder we just created and select New Class . Figure 10. New class
This should bring up the New Class wizard. We'll give our class a namespace lotto , and we'll call our class Lottery . Figure 11. Lottery class
Eclipse will now create stubs for your class. CDT does a lot of nice things for you. It generates the appropriate compiler directives in the header file. It encourages best practices by generating separate interface (Lottery.h) and implementation (Lottery.cpp) files. It encourages another best practice by making your class' destructor virtual. We can enter the source code for these classes as seen in Listings 1 and 2. Listing 1. Lottery.h
Listing 2 shows the implementation file for the Lottery class. Listing 2. Lottery.cpp
What's this code doing? Well, our Lottery class has two attributes. The ticketSize attribute is the number of numbers on the lottery ticket. The maxNum is the maximum number on the ticket. Later, we'll use the Florida state lottery as an example. There, you pick six numbers from 1 to 53, so ticketSize would be 6 and maxNum would be 53.
The generateNumbers method generates an array of numbers corresponding to the numbers on a lottery ticket. It uses the STL function rand() to generate numbers randomly. The allNums array is used to keep track of what numbers have been generated so far, so we can make sure we don't get a duplicate number on our ticket. Finally, the printTicket() creates a string representation of our ticket.
When you save the files, Eclipse builds your project automatically. Again, if you save the project, it should be compiled and you should see compilation messages in the console, as shown in Listing 3. Listing 3. Compiler output in console MegaLottery class
You might have noticed that we made the printTicket() method virtual when it was declared in the header file. That will allow us to subclass Lottery and override this method. We wanted to do that because some states have a lottery with a 'mega' number. This is a separately drawn number that any ticket must match in addition to the other numbers drawn. Let's create a MegaLottery class for these states that will subclass Lottery .
Once again, right-click on our source folder and select New Class , as we did earlier. This time in the New Class wizard, we'll declare our new class in the same namespace, but call it MegaLottery . Figure 12. MegaLottery class
To subclass Lottery , select the Add button next to the Base Classes section. This will bring up the Choose Base Class dialog. You can start typing the name of the class, and Eclipse will narrow the list of base class candidates quickly. You'll want to select Lottery and click OK . Figure 13. Choose base classes
We can enter the code for MegaLottery , as shown in Listings 4 and 5. Listing 4. MegaLottery.h
Listing 5 shows the implementation file for the MegaLottery class. Listing 5. MegaLottery.cpp
The main difference between Lottery and MegaLottery is that MegaLottery has an extra attribute maxMegaNum . This is the max value that the mega number can take. It overrides the printTicket() method. It uses the base class to generate the first part of the ticket, then it generates the mega number and appends it to the string representation of the ticket.
We just need a way to create the various lotteries. We'll use a class Factory Pattern to do this. We'll do this by adding a LotteryFactory class. We want all Lotteries to come from the same factory, so we'll make LotteryFactory a singleton. The code for it is in Listings 6 and 7. Listing 6. ifndef LOTTERYFACTORY_H_
Listing 7 shows the implementation file for the LotteryFactory class. Listing 7. LotteryFactory.cpp
The LotteryFactory has an enum of the different types of lotteries. We've only put in Florida and California in the example, but it shouldn't be hard to add as many as you want. The LotteryFactory 's constructor seeds the rand() function used by our lottery classes. We just need to implement our executable's main method. Listing 8. Main.cpp Running the program
We're ready to run our program. Select Run Run . Figure 14. Choose base classes
Select C/C++ Local Application and click the New button. Figure 15. New C/C++ run profile
This will bring up the Create run configuration interface for the Lottery project. You'll need to select its executable by clicking the Search Project button. Figure 16. Search project for executable
You can select the binary that Eclipse created for you and click OK . Figure 17. Search project for executable Gdb For Mac Os X 10.13
Just click Run , and the program should run in your console. The code below shows some sample output. Debugging the program
Our program should run fine, but let's take a look at debugging the application. First, create a breakpoint in our code. Pick a line and right-click next to it and select Toggle Breakpoint . Gdb For Mac Os X64 Figure 18. Create breakpoint
We need to create a debug configuration, much like we created a run configuration. Select Run Debug . Figure 19. Create debug configuration
This should bring up the Debug configuration. This is based on the Run configuration, and you shouldn't need to change anything. Just click Debug . Figure 20. Debug configuration
Once the debugger starts, it will prompt you to switch to the Debugger perspective. Do so. Notice that in the configuration we set things to break automatically at the startup of our main method. Thus, the debugger should break immediately and you should see a screen something like Figure 21. Gdb For Mac Os X 10.8 Figure 21. The debugger Download Gdb For Mac Os X Summary Gdb For Mac Os X 10.10
We've built and debugged our lottery application. You can easily add more lottery schemes to it. Some of these could involve additional subclasses. CDT makes it easier than ever to create these classes and class hierarchies, and to run and debug the application to test it. Downloadable resources Related topics
Integrate an external code checker into Eclipse CDT (Alex Ruiz, developerWorks): Learn how to execute C/C++ code analysis tools with Codan in Eclipse.
Get an overview of the CDT in 'C/C++ development with the Eclipse Platform.'
Dig deep into the CDT's architecture in the five-part series titled 'Building a CDT-based editor.'
As someone interested in C/C++ development, you might want to check out a trial of IBM's XL C/C++ compiler for Linux or AIX.
Windows developers can learn about migrating to the CDT in 'Migrate Visual Studio C and C++ projects to Eclipse CDT.'
Windows developers can also check out the CDT-MSVC project, a project for incorporating Microsoft's compiler and debugger with CDT.
Learn about MinGW, the GNU C/C++ tools for Windows included with Cygwin.
Download Cygwin a Linux-like environment for Windows. It consists of two parts: A DLL that acts as a Linux API emulation layer providing substantial Linux API functionality and a collection of tools that provide a Linux look and feel.
The Eclipse C/C++ Development Toolkit (CDT) download information contains the latest information about the available versions of CDT.
Check out the 'Recommended Eclipse reading list.'
For an introduction to the Eclipse platform, see 'Getting started with the Eclipse Platform.'