I am using uVision 4.21 MDK_ARM to learn how to program C++ on MCB1700.
I have create a new project and add 2 files (startup_CPL17xx.s / system_LPCxx.c) to startup group. Then I add main.cpp to Sources Files group. The project options are:
Device: LPC 1768 Target: Default Output: Default Listing: Default User: Default C++: Default Asm: Default Linker: Default Debug: Use ULINK Cortex Debugger Utilities: Default
Then I change the startup_LPC17xx.s Stack Size: 0x0000 1000 Heap Size: 0x0000 1000
My main.cpp code:
#include <vector> #include <string> int main (void) { int i = 0; int sum = 0; std::vector<int> vInt; std::string str = "Hello, C++"; vInt.push_back(1); vInt.push_back(2); vInt.push_back(3); vInt.push_back(4); vInt.push_back(5); sum = vInt.size(); sum = 0; for(i=0; i<5; i++) { sum += vInt[i]; } while(1); //return 0; }
I build the project successfully and download it to MCB1700 board "OK". Then I hit "F9" to set break point at line "vInt.push_back(1);". After I select Debug->Start Debug Session, the break point is not reached even I hit "F5" many times. Why?
By the way, I find there are 2 windows: Disassembly Window and Code Window (for main.cpp). How could I step through the code on C++ source code level and how could I step through the code on Assembly level?
To answer your second question: set the cursor in the Disassembly window to step at the assembly level, set it in the source window to step at the source level. You can also close the Disassembly window and then it will step source.
The first question is hard to answer without seeing exactly what's going on in your debugger. One trap I fell in a few times is having simulation selected instead of the actual hardware debugger. Make sure "Use simulator" isn't selected in "Options|Debug".
Also, make sure no optimizations are switched on in "Options|C/C++" (-O0) - that makes it a lot easier to do source-level stepping.
Once you have that try stepping through your entire program instead of trying to set a breakpoint.
Also, I would set breakpoints after going into debug mode to be sure they really get set.
Andrew
Thank you for your reply.
After I read your post, I have tried your suggestion by start debugger first (set Run to main()) and then set the break point by "F9". I can see the break point is set. But when I hit "F5" or "F10", still can not see code run.
This time I remove the main.cpp, and add file main.c with all other same.
The main.c
int main (void) { int i = 0; int sum = 0; for(i=0; i<10; i++) { sum = sum + i; } i = sum; while(1); //return 0; }
I can reach the break point. But after I add variables "i" and "sum" to Watch 1 windows and hit "F10" to step over the code. I can not see the i/sum value (the value show "<out of scope>".
So my questions are: 1. Why C++ code can not run to the break point? 2. Why I can not see the variables value?
int main (void) { int i = 0; int sum = 0; for(i=0; i<10; i++) //*********************** { sum = sum + i; } i = sum; while(1); //return 0; } I can reach the break point. But after I add variables "i" and "sum" to Watch 1 windows and
hit "F10" to step over the code. I can not see the i/sum value (the value show "<out of scope>".
"the break point" is not very informative
can you see the values when stopped at '********'?
Erik
In the C++ case, when you try to run, does your assembly window look like this, with the PC register and the yellow arrow pointing to the BKPT instruction (in my case 0x0800149A)?
_sys_open: 0x0800148A B50E PUSH {r1-r3,lr} 0x0800148C E9CD0100 STRD r0,r1,[sp,#0] 0x08001490 F7FFF88E BL.W strlen (0x080005B0) 0x08001494 9002 STR r0,[sp,#0x08] 0x08001496 4669 MOV r1,sp 0x08001498 2001 MOVS r0,#0x01 0x0800149A BEAB BKPT 0xAB 0x0800149C BD0E POP {r1-r3,pc}
int main (void) { int i = 0; int sum = 0; for(i=0; i<10; i++) //***********************break point 1 { sum = sum + i; } i = sum;//break point 2 while(1); //return 0; }
Erik /////////////////////////////////////// No. I have set break point at break point 1 / 2. Both no value.
The Disassembly window :
0x00001482 BEAB BKPT 0xAB 0x00001484 BD0E POP (r1-r3,pc) 0x00001486 B508 PUSH (r3,1r) 0x00001488 4669 MOV r1,sp 0x0000148A 9000 STR r0, [sp,0x00] 0x0000148C 2002 MOVS r0, #0x02 0x0000148E BEAB BKPT 0xAB
with the PC register and the yellow arrow pointing to the BKPT instruction (0x00001482)
Aoso, For C++ case, after debug session started, I can not use "F5" to set break point and menu Debug->Inser/Remove Breakpoint is greyed out.
BKPT 0xAB is the "semi-hosting" interface.
You need to either use semi-hosting (sending I/O to your PC via the debugger) or retarget the stdio of your library (sending stdio through a UART or other interface). I added a dummy "retarget.c" to a sample project with your main.cpp and could get it to work.
Here are two links that explains the general idea:
Semi-hosting infocenter.arm.com/.../index.jsp
and retargeting infocenter.arm.com/.../index.jsp
In essence, what's going on is this: the C++ library eventually calls down to C functions to handle stdio. On a PC the output would go to the standard device defined by the OS but on an embedded system you have to bring your own. I usually send stdio to the trace port via the ULINK Pro or a serial port.
You can start with the retarget.c from here:
infocenter.arm.com/.../index.jsp
You'll need to supply a UART_write/UART_read or just define them as empty functions for starters.
Thank you for your reply. I will look at it.
By the way, for main.c case, why I can not watch the variables value? But I do find if I change the code to:
int i = 0; int sum = 0; int main (void) { // int i = 0; // int sum = 0; for(i=0; i<10; i++) { sum = sum + i; } i = sum; while(1); //return 0; }
Move i / sum outside of the main, then I can watch the value change. Weird.
You'll have to look at the assembly code the compiler produces. The debugger may not be able to tell how the variable is stored so it can't display it. It's probably just kept in a register for the duration of the loop.
Making variables global forces the compiler to store them in actual memory locations and then you can inspect them.
Usually switching optimisation off solves many of these types of problems but some optimisations are so basic the compiler will never avoid them.
Frequently programmers will use 'volatile' to force variables into memory but in the case of a local variable on the stack that's rarely a good idea.
Why can't it inspect variables in registers, then?
"some optimisations are so basic the compiler will never avoid them"
So debug tools should really be able to cope with them!
Thank you, Andrew.
After I twisted for awhile, my main.cpp can be run.
But again, I can not check the local variable value. This is not convenient for debugging the code.
Also, even worse, after I move string variable definition outside the main function. I still can not watch the string variable (its value always 0).
My C++ code:
#include <iostream> #include <vector> #include <string> int sum = 0; std::string str; int main (void) { int i = 0; std::vector<int> vInt; str = "Hello, C++"; vInt.push_back(1); vInt.push_back(2); vInt.push_back(3); vInt.push_back(4); vInt.push_back(5); sum = vInt.size(); sum = 0; for(i=0; i<5; i++) { sum += vInt[i]; } while(1); //return 0; }
I think now you're really running into limitations debugging C++ with uVision. The 0 value is obviously incorrect but even if you were able to put str in a watch window you'd just see the whole std::string class. A C++ "capable" debugger would give you the option of showing the C-style string that would be returned by c_str().