How solve this errors in avrstudio - avr
what can i do with this errors?
#ifndef WS2811_h
#define WS2811_h
#include <avr/io.h>
#include <util/delay.h>
#include <WS2811.h>
Error 1 unterminated #ifndef
typedef struct __attribute__ ((__packed__)) {
uint8_t r;
uint8_t g;
uint8_t b;
} RGB_t;
Error 2 expected ':', ',', ';', '}' or '__attribute__' before 'r'
please help me! thanks
thanks for your help but it not worked!!!
the main code is here:
/*
* WS2811 RGB LED driver.
*/
#include <stdio.h>
#include <stdint.h>
#ifndef WS2811_h
#define WS2811_h
#endif
#include <WS2811.h>
// RGB value structure.
typedef struct __attribute__ ((__packed__)) {
uint8_t r;
uint8_t g;
uint8_t b;
} RGB_t;
#ifndef ARRAYLEN
#define ARRAYLEN(A) (sizeof(A) / sizeof(A[0]))
#endif
/*
* Inline asm macro to output 24-bit RGB value in (G,R,B) order, MSBit first.
* 0 bits are 250ns hi, 1000ns lo, 1 bits are 1000ns hi, 250ns lo.
* r18 = red byte to be output
* r19 = green byte to be output
* r20 = blue byte to be output
* r26 = saved SREG
* r27 = inner loop counter
*/
#define WS2811(PORT, PIN, RGB, LEN) \
asm volatile( \
/* initialise */ \
" cp %A[len], r1 ; check len > 0, return immediately if it is\n" \
" cpc %B[len], r1\n" \
" brne 1f\n" \
" rjmp 16f\n" \
"1: ld r18, Z+ ; load in first red byte to be output\n" \
" ld r19, Z+ ; load in first green byte to be output\n" \
" ld r20, Z+ ; load in first blue byte to be output\n" \
" ldi r27, 8 ; load inner loop counter\n" \
" in r26, __SREG__ ; timing-critical, so no interrupts\n" \
" cli\n" \
/* green - loop over 8 bits */ \
"2: sbi %[port], %[pin] ; pin lo -> hi\n" \
" sbrc r19, 7 ; test hi bit clear\n" \
" rjmp 3f ; true, skip pin hi -> lo\n" \
" cbi %[port], %[pin] ; false, pin hi -> lo\n" \
"3: sbrc r19, 7 ; equalise delay of both code paths\n" \
" rjmp 4f\n" \
"4: nop ; pulse timing delay\n" \
" nop\n" \
" nop\n" \
" nop\n" \
" nop\n" \
" nop\n" \
" lsl r19 ; shift to next bit\n" \
" dec r27 ; decrement loop counter\n" \
" cbi %[port], %[pin] ; pin hi -> lo\n" \
" brne 2b\n ; loop if required\n" \
" ldi r27, 7 ; reload inner loop counter\n" \
/* red - loop over first 7 bits */ \
"5: sbi %[port], %[pin] ; pin lo -> hi\n" \
" sbrc r18, 7 ; test hi bit clear\n" \
" rjmp 6f ; true, skip pin hi -> lo\n" \
" cbi %[port], %[pin] ; false, pin hi -> lo\n" \
"6: sbrc r18, 7 ; equalise delay of both code paths\n" \
" rjmp 7f\n" \
"7: nop ; pulse timing delay\n" \
" nop\n" \
" nop\n" \
" nop\n" \
" nop\n" \
" nop\n" \
" lsl r18 ; shift to next bit\n" \
" dec r27 ; decrement inner loop counter\n" \
" cbi %[port], %[pin] ; pin hi -> lo\n" \
" brne 5b ; inner loop, if required\n" \
" nop ; equalise delay of both code paths\n" \
/* red, 8th bit - output & fetch next values */ \
" sbi %[port], %[pin] ; pin lo -> hi\n" \
" sbrc r18, 7 ; test hi bit clear\n" \
" rjmp 8f ; true, skip pin hi -> lo\n" \
" cbi %[port], %[pin] ; false, pin hi -> lo\n" \
"8: sbrc r18, 7 ; equalise delay of both code paths\n" \
" rjmp 9f\n" \
"9: nop ; pulse timing delay\n" \
" nop\n" \
" nop\n" \
" ld r18, Z+ ; load next red byte\n" \
" ld r19, Z+ ; load next green byte\n" \
" ldi r27, 7 ; reload inner loop counter\n" \
" cbi %[port], %[pin] ; pin hi -> lo\n" \
" nop ; pulse timing delay\n" \
" nop\n" \
/* blue - loop over first 7 bits */ \
"10: sbi %[port], %[pin] ; pin lo -> hi\n" \
" sbrc r20, 7 ; test hi bit clear\n" \
" rjmp 11f ; true, skip pin hi -> lo\n" \
" cbi %[port], %[pin] ; false, pin hi -> lo\n" \
"11: sbrc r20, 7 ; equalise delay of both code paths\n" \
" rjmp 12f\n" \
"12: nop ; pulse timing delay\n" \
" nop\n" \
" nop\n" \
" nop\n" \
" nop\n" \
" nop\n" \
" lsl r20 ; shift to next bit\n" \
" dec r27 ; decrement inner loop counter\n" \
" cbi %[port], %[pin] ; pin hi -> lo\n" \
" brne 10b ; inner loop, if required\n" \
" nop ; equalise delay of both code paths\n" \
/* blue, 8th bit - output & handle outer loop */ \
" sbi %[port], %[pin] ; pin lo -> hi\n" \
" sbrc r20, 7 ; test hi bit clear\n" \
" rjmp 13f ; true, skip pin hi -> lo\n" \
" cbi %[port], %[pin] ; false, pin hi -> lo\n" \
"13: sbrc r20, 7 ; equalise delay of both code paths\n" \
" rjmp 14f\n" \
"14: nop ; pulse timing delay\n" \
" nop\n" \
" ldi r27, 8 ; reload inner loop counter\n" \
" sbiw %A[len], 1 ; decrement outer loop counter\n" \
" breq 15f ; exit outer loop if zero\n" \
" ld r20, Z+ ; load in next blue byte\n" \
" cbi %[port], %[pin] ; pin hi -> lo\n" \
" rjmp 2b ; outer loop, if required\n" \
"15: nop ; pulse timing delay\n" \
" cbi %[port], %[pin] ; pin hi -> lo\n" \
" nop ; pulse timing delay\n" \
" nop\n" \
" out __SREG__, r26 ; reenable interrupts\n" \
"16:\n" \
: \
: [rgb] "z" (RGB), \
[len] "w" (LEN), \
[port] "I" (_SFR_IO_ADDR(PORT)), \
[pin] "I" (PIN) \
: "r18", "r19", "r20", "r26", "r27", "cc", "memory" \
)
/*
* Define a C function to wrap the inline WS2811 macro for a given port and pin.
*/
#define DEFINE_WS2811_FN(NAME, PORT, PIN) \
extern void NAME(const RGB_t *rgb, uint16_t len) __attribute__((noinline)); \
void NAME(const RGB_t *rgb, uint16_t len) { WS2811(PORT, PIN, rgb, len); }
#endif /* WS2811_h */
/*
* Copyright 2012 Alan Burlison, alan#bleaklow.com. All rights reserved.
* Use is subject to license terms.
*
* Demo of the WS2811 driver, driving 3 pixels.
*/
#include <avr/io.h>
#include <util/delay.h>
#define BIT(B) (0x01 << (uint8_t)(B))
#define SET_BIT_HI(V, B) (V) |= (uint8_t)BIT(B)
#define SET_BIT_LO(V, B) (V) &= (uint8_t)~BIT(B)
#define PAUSE 1000 // msec
#define DELAY 10 // msec
// Define the output function, using pin 0 on port b.
DEFINE_WS2811_FN(WS2811RGB, PORTB, 0)
// Drive the three pixels in an infinit loop.
void threepixeldemo(void)
{
// Configure pin for output.
SET_BIT_HI(DDRB, 0);
SET_BIT_LO(PORTB, 0);
// off->red, off->green, off->blue
RGB_t rgb[3] = {{0,0,0},{0,0,0},{0,0,0}};
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(PAUSE);
for (int i = 0; i < 255; i++) {
rgb[0].r += 1;
rgb[1].g += 1;
rgb[2].b += 1;
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(DELAY);
}
// loop forever.
for (;;) {
// red->yellow, green->cyan, blue->magenta
for (int i = 0; i < 255; i++) {
rgb[0].g += 1;
rgb[1].b += 1;
rgb[2].r += 1;
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(DELAY);
}
// yellow->green, cyan->blue, magenta->white
for (int i = 0; i < 255; i++) {
rgb[0].r -= 1;
rgb[1].g -= 1;
rgb[2].g += 1;
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(DELAY);
}
// green->cyan, blue->magenta, white->off
for (int i = 0; i < 255; i++) {
rgb[0].b += 1;
rgb[1].r += 1;
rgb[2].r -= 1;
rgb[2].g -= 1;
rgb[2].b -= 1;
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(DELAY);
}
// cyan->blue, magenta->white, off->red
for (int i = 0; i < 255; i++) {
rgb[0].g -= 1;
rgb[1].g += 1;
rgb[2].r += 1;
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(DELAY);
}
// blue->magenta, white->off, red->yellow
for (int i = 0; i < 255; i++) {
rgb[0].r += 1;
rgb[1].r -= 1;
rgb[1].g -= 1;
rgb[1].b -= 1;
rgb[2].g += 1;
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(DELAY);
}
// magenta->white, off->red, yellow->green
for (int i = 0; i < 255; i++) {
rgb[0].g += 1;
rgb[1].r += 1;
rgb[2].r -= 1;
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(DELAY);
}
// white->off, red->yellow, green->cyan
for (int i = 0; i < 255; i++) {
rgb[0].r -= 1;
rgb[0].g -= 1;
rgb[0].b -= 1;
rgb[1].g += 1;
rgb[2].b += 1;
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(DELAY);
}
// off->red, yellow->green, cyan->blue
for (int i = 0; i < 255; i++) {
rgb[0].r += 1;
rgb[1].r -= 1;
rgb[2].g -= 1;
WS2811RGB(rgb, ARRAYLEN(rgb));
_delay_ms(DELAY);
}
}
}
Add #include <stdint.h> to bring in the definition of uint8_t.
#ifndef WS2811_h
#define WS2811_h
/** missing an #endif here, (most likely) */
#include <avr/io.h>
#include <util/delay.h>
#include <WS2811.h>
The missing endif causes errors further down.
expected ':', ',', ';', '}' or '__attribute__' before 'r'
This type of error is usually caused by some earlier error, often with the #includes. You missed an #endif, but it can also happen when files include each other improperly. As with any macro errors, they are difficult to track down.
Related
Can't add reg expression for a #define in ctags
I can't figure out how to make ctags detect the __mrs_s definition. It doesn't add the search pattern so I can't find it in vi. $cat /tmp/qq.h int test(int i) { printf("Hello!"); return 0; } #define __mrs_s(v, r) \ DEFINE_MRS_S \ " mrs_s " v ", " __stringify(r) "\n" \ UNDEFINE_MRS_S $ctags --regex-C++='/^#define \([a-zA-Z_0-9]+\)([a-zA-Z,\ ]+)[\t ]+/\1/d/' -o - /tmp/qq.h __mrs_s /tmp/qq.h 7;" d test /tmp/qq.h /^int test(int i)$/;" f
Use --excmd=pattern option like: [root#localhost ~]# cat /tmp/qq.h int test(int i) { printf("Hello!"); return 0; } #define __mrs_s(v, r) \ DEFINE_MRS_S \ " mrs_s " v ", " __stringify(r) "\n" \ UNDEFINE_MRS_S [root#localhost ~]# ctags --excmd=pattern -o - /tmp/qq.h __mrs_s /tmp/qq.h /^#define __mrs_s(/;" d test /tmp/qq.h /^int test(int i)$/;" f
Can't use constexpr function in static_assert
tell me, please, why I can't use my constexpr recursive function to static_assert if string contains needed count of symbols? Constexpr function supposed to be a constant value, but VS2015 compiller tells me that expression did not evaluate to a constant (error C2131). constexpr const char* GetRequestStr = "GETVARS:_local_=I,I..8:1-1;NI,NI..8:1-1"; constexpr unsigned RequestedVars(const char* str, unsigned cnt=0){ return str[0] == 0 ? cnt+1 : RequestedVars(str+1, str[0] == ';' ? ++cnt : cnt); }; static_assert(RequestedVars(GetRequestStr) == 2, "Must be 2"); // C2131 here the result (translated into English): 1> d: \ cprojects \ logo \ exchlogo.h (43): error C2131: expression not defined by constant 1> d: \ cprojects \ logo \ exchlogo.h (43): note: the failure was caused by parsing an assignment operation 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 26, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 25, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 24, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 23, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 22, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (43): note: skipped intermediate calls: 16 (/ constexpr: backtrace <NUMBER>) 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 5, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 4, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 3, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 2, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (43): note: when calculating "RequestedVars ((" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 ") + 1, 0)" 1> d: \ cprojects \ logo \ exchlogo.h (45): note: when calculating "RequestedVars (" GETVARS: _local_ = I, I..8: 1-1; NI, NI..8: 1-1 " , 0) " 1> d: \ cprojects \ logo \ exchlogo.h (45): error C2131: expression not defined by constant 1> d: \ cprojects \ logo \ exchlogo.h (43): note: the failure was caused by parsing an assignment operation
QEMU gdb does not show instructions of firmware
I am trying to debug the bios.bin that comes with the QEMU emulator. I am starting QEMU as follows: qemu-system-x86_64 -bios bios.bin -s -S I then start start debugging with: gdb target remote localhost:1234 GDB is at the Intel handoff state 0xfffffff0 where now the firmware/BIOS should be. However there is nothing at this location in memory. Even if step through a more instructions via nexti it decodes as all zeros. What am I doing wrong or am I misunderstanding something? I basically want to get the first instruction the cpu calls and continue debugging from there.
QEMU isn't the problem here, but GDB is. I will start with a recommendations if you intend to use GDB to debug the BIOS: Do not use qemu-system-x86_64. Use qemu-system-i386 instead. This will avoid a packet too long problem and a pile of numbers being displayed. This may or may not happen to you depending on the version of GDB being used. With that being said, GDB's real problem is that it has no knowledge of real mode segment:offset addressing. When you boot QEMU it starts in 16-bit real mode to start executing the legacy BIOS. GDB's lack of real mode debugging support is the real issue. You can read more about it in another Stackoverflow answer I wrote. To summarize: Unfortunately by default gdb doesn't do segment:offset calculations and will use the value in EIP for breakpoints. You have to specify breakpoints as 32-bit addresses (EIP). When it comes to stepping through real mode code it can be cumbersome because gdb doesn't handle real mode segmentation. If you step into an interrupt handler you'll discover gdb will display the assembly code relative to EIP. Effectively gdb will be showing you disassembly of the wrong memory location since it didn't account for CS. Over the years changes to GDB have made debugging real mode code more involved and negotiating connections to remote hosts has become more problematic. Based on my answer above and the other 2 answers under the same question you may be able to get this working satisfactorily on old and new versions of GDB by trying the following: Make a file called target.xml with the following: <?xml version="1.0"?><!DOCTYPE target SYSTEM "gdb-target.dtd"> <target> <architecture>i8086</architecture> <xi:include href="i386-32bit.xml"/> </target> Create a file called i386-32bit.xml with the contents of this URL. Alternatively you can retrieve this file from the command line on Linux based OSes with: wget https://raw.githubusercontent.com/qemu/qemu/master/gdb-xml/i386-32bit.xml Create a script file called gdb_init_real_mode.txt with the following: # Special mode for GDB that allows to debug/disassemble REAL MODE x86 code # # It has been designed to be used with QEMU or BOCHS gdb-stub # # 08/2011 Hugo Mercier - GPL v3 license # # Freely inspired from "A user-friendly gdb configuration file" widely available # on the Internet set confirm off set verbose off set prompt \033[31mreal-mode-gdb$ \033[0m set output-radix 0d10 set input-radix 0d10 # These make gdb never pause in its output set height 0 set width 0 # Intel syntax set disassembly-flavor intel # Real mode #set architecture i8086 set $SHOW_CONTEXT = 1 set $REAL_MODE = 1 # By default A20 is present set $ADDRESS_MASK = 0x1FFFFF # nb of instructions to display set $CODE_SIZE = 10 define enable-a20 set $ADDRESS_MASK = 0x1FFFFF end define disable-a20 set $ADDRESS_MASK = 0x0FFFFF end # convert segment:offset address to physical address define r2p if $argc < 2 printf "Arguments: segment offset\n" else set $ADDR = (((unsigned long)$arg0 & 0xFFFF) << 4) + (((unsigned long)$arg1 & 0xFFFF) & $ADDRESS_MASK) printf "0x%05X\n", $ADDR end end document r2p Convert segment:offset address to physical address Set the global variable $ADDR to the computed one end # get address of Interruption define int_addr if $argc < 1 printf "Argument: interruption_number\n" else set $offset = (unsigned short)*($arg0 * 4) set $segment = (unsigned short)*($arg0 * 4 + 2) r2p $segment $offset printf "%04X:%04X\n", $segment, $offset end end document int_addr Get address of interruption end define compute_regs set $rax = ((unsigned long)$eax & 0xFFFF) set $rbx = ((unsigned long)$ebx & 0xFFFF) set $rcx = ((unsigned long)$ecx & 0xFFFF) set $rdx = ((unsigned long)$edx & 0xFFFF) set $rsi = ((unsigned long)$esi & 0xFFFF) set $rdi = ((unsigned long)$edi & 0xFFFF) set $rbp = ((unsigned long)$ebp & 0xFFFF) set $rsp = ((unsigned long)$esp & 0xFFFF) set $rcs = ((unsigned long)$cs & 0xFFFF) set $rds = ((unsigned long)$ds & 0xFFFF) set $res = ((unsigned long)$es & 0xFFFF) set $rss = ((unsigned long)$ss & 0xFFFF) set $rip = ((((unsigned long)$cs & 0xFFFF) << 4) + ((unsigned long)$eip & 0xFFFF)) & $ADDRESS_MASK set $r_ss_sp = ((((unsigned long)$ss & 0xFFFF) << 4) + ((unsigned long)$esp & 0xFFFF)) & $ADDRESS_MASK set $r_ss_bp = ((((unsigned long)$ss & 0xFFFF) << 4) + ((unsigned long)$ebp & 0xFFFF)) & $ADDRESS_MASK end define print_regs printf "AX: %04X BX: %04X ", $rax, $rbx printf "CX: %04X DX: %04X\n", $rcx, $rdx printf "SI: %04X DI: %04X ", $rsi, $rdi printf "SP: %04X BP: %04X\n", $rsp, $rbp printf "CS: %04X DS: %04X ", $rcs, $rds printf "ES: %04X SS: %04X\n", $res, $rss printf "\n" printf "IP: %04X EIP:%08X\n", ((unsigned short)$eip & 0xFFFF), $eip printf "CS:IP: %04X:%04X (0x%05X)\n", $rcs, ((unsigned short)$eip & 0xFFFF), $rip printf "SS:SP: %04X:%04X (0x%05X)\n", $rss, $rsp, $r_ss_sp printf "SS:BP: %04X:%04X (0x%05X)\n", $rss, $rbp, $r_ss_bp end document print_regs Print CPU registers end define print_eflags printf "OF <%d> DF <%d> IF <%d> TF <%d>",\ (($eflags >> 0xB) & 1), (($eflags >> 0xA) & 1), \ (($eflags >> 9) & 1), (($eflags >> 8) & 1) printf " SF <%d> ZF <%d> AF <%d> PF <%d> CF <%d>\n",\ (($eflags >> 7) & 1), (($eflags >> 6) & 1),\ (($eflags >> 4) & 1), (($eflags >> 2) & 1), ($eflags & 1) printf "ID <%d> VIP <%d> VIF <%d> AC <%d>",\ (($eflags >> 0x15) & 1), (($eflags >> 0x14) & 1), \ (($eflags >> 0x13) & 1), (($eflags >> 0x12) & 1) printf " VM <%d> RF <%d> NT <%d> IOPL <%d>\n",\ (($eflags >> 0x11) & 1), (($eflags >> 0x10) & 1),\ (($eflags >> 0xE) & 1), (($eflags >> 0xC) & 3) end document print_eflags Print eflags register. end # dump content of bytes in memory # arg0 : addr # arg1 : nb of bytes define _dump_memb if $argc < 2 printf "Arguments: address number_of_bytes\n" else set $_nb = $arg1 set $_i = 0 set $_addr = $arg0 while ($_i < $_nb) printf "%02X ", *((unsigned char*)$_addr + $_i) set $_i++ end end end # dump content of memory in words # arg0 : addr # arg1 : nb of words define _dump_memw if $argc < 2 printf "Arguments: address number_of_words\n" else set $_nb = $arg1 set $_i = 0 set $_addr = $arg0 while ($_i < $_nb) printf "%04X ", *((unsigned short*)$_addr + $_i) set $_i++ end end end # display data at given address define print_data if ($argc > 0) set $seg = $arg0 set $off = $arg1 set $raddr = ($arg0 << 16) + $arg1 set $maddr = ($arg0 << 4) + $arg1 set $w = 16 set $i = (int)0 while ($i < 4) printf "%08X: ", ($raddr + $i * $w) set $j = (int)0 while ($j < $w) printf "%02X ", *(unsigned char*)($maddr + $i * $w + $j) set $j++ end printf " " set $j = (int)0 while ($j < $w) set $c = *(unsigned char*)($maddr + $i * $w + $j) if ($c > 32) && ($c < 128) printf "%c", $c else printf "." end set $j++ end printf "\n" set $i++ end end end define context printf "---------------------------[ STACK ]---\n" _dump_memw $r_ss_sp 8 printf "\n" set $_a = $r_ss_sp + 16 _dump_memw $_a 8 printf "\n" printf "---------------------------[ DS:SI ]---\n" print_data $ds $rsi printf "---------------------------[ ES:DI ]---\n" print_data $es $rdi printf "----------------------------[ CPU ]----\n" print_regs print_eflags printf "---------------------------[ CODE ]----\n" set $_code_size = $CODE_SIZE # disassemble # first call x/i with an address # subsequent calls to x/i will increment address if ($_code_size > 0) x /i $rip set $_code_size-- end while ($_code_size > 0) x /i set $_code_size-- end end document context Print context window, i.e. regs, stack, ds:esi and disassemble cs:eip. end define hook-stop compute_regs if ($SHOW_CONTEXT > 0) context end end document hook-stop !!! FOR INTERNAL USE ONLY - DO NOT CALL !!! end # add a breakpoint on an interrupt define break_int set $offset = (unsigned short)*($arg0 * 4) set $segment = (unsigned short)*($arg0 * 4 + 2) break *$offset end define break_int_if_ah if ($argc < 2) printf "Arguments: INT_N AH\n" else set $addr = (unsigned short)*($arg0 * 4) set $segment = (unsigned short)*($arg0 * 4 + 2) break *$addr if ((unsigned long)$eax & 0xFF00) == ($arg1 << 8) end end document break_int_if_ah Install a breakpoint on INT N only if AH is equal to the expected value end define break_int_if_ax if ($argc < 2) printf "Arguments: INT_N AX\n" else set $addr = (unsigned short)*($arg0 * 4) set $segment = (unsigned short)*($arg0 * 4 + 2) break *$addr if ((unsigned long)$eax & 0xFFFF) == $arg1 end end document break_int_if_ax Install a breakpoint on INT N only if AX is equal to the expected value end define stepo ## we know that an opcode starting by 0xE8 has a fixed length ## for the 0xFF opcodes, we can enumerate what is possible to have set $lip = $rip set $offset = 0 # first, get rid of segment prefixes, if any set $_byte1 = *(unsigned char *)$rip # CALL DS:xx CS:xx, etc. if ($_byte1 == 0x3E || $_byte1 == 0x26 || $_byte1 == 0x2E || $_byte1 == 0x36 || $_byte1 == 0x3E || $_byte1 == 0x64 || $_byte1 == 0x65) set $lip = $rip + 1 set $_byte1 = *(unsigned char*)$lip set $offset = 1 end set $_byte2 = *(unsigned char *)($lip+1) set $_byte3 = *(unsigned char *)($lip+2) set $noffset = 0 if ($_byte1 == 0xE8) # call near set $noffset = 3 else if ($_byte1 == 0xFF) # A "ModR/M" byte follows set $_mod = ($_byte2 & 0xC0) >> 6 set $_reg = ($_byte2 & 0x38) >> 3 set $_rm = ($_byte2 & 7) #printf "mod: %d reg: %d rm: %d\n", $_mod, $_reg, $_rm # only for CALL instructions if ($_reg == 2 || $_reg == 3) # default offset set $noffset = 2 if ($_mod == 0) if ($_rm == 6) # a 16bit address follows set $noffset = 4 end else if ($_mod == 1) # a 8bit displacement follows set $noffset = 3 else if ($_mod == 2) # 16bit displacement set $noffset = 4 end end end end # end of _reg == 2 or _reg == 3 else # else byte1 != 0xff if ($_byte1 == 0x9A) # call far set $noffset = 5 else if ($_byte1 == 0xCD) # INTERRUPT CASE set $noffset = 2 end end end # end of byte1 == 0xff end # else byte1 != 0xe8 # if we have found a call to bypass we set a temporary breakpoint on next instruction and continue if ($noffset != 0) set $_nextaddress = $eip + $offset + $noffset printf "Setting BP to %04X\n", $_nextaddress tbreak *$_nextaddress continue # else we just single step else nexti end end document stepo Step over calls This function will set a temporary breakpoint on next instruction after the call so the call will be bypassed You can safely use it instead nexti since it will single step code if it's not a call instruction (unless you want to go into the call function) end define step_until_iret set $SHOW_CONTEXT=0 set $_found = 0 while (!$_found) if (*(unsigned char*)$rip == 0xCF) set $_found = 1 else stepo end end set $SHOW_CONTEXT=1 context end define step_until_ret set $SHOW_CONTEXT=0 set $_found = 0 while (!$_found) set $_p = *(unsigned char*)$rip if ($_p == 0xC3 || $_p == 0xCB || $_p == 0xC2 || $_p == 0xCA) set $_found = 1 else stepo end end set $SHOW_CONTEXT=1 context end define step_until_int set $SHOW_CONTEXT = 0 while (*(unsigned char*)$rip != 0xCD) stepo end set $SHOW_CONTEXT = 1 context end # Find a pattern in memory # The pattern is given by a string as arg0 # If another argument is present it gives the starting address (0 otherwise) define find_in_mem if ($argc >= 2) set $_addr = $arg1 else set $_addr = 0 end set $_found = 0 set $_tofind = $arg0 while ($_addr < $ADDRESS_MASK) && (!$_found) if ($_addr % 0x100 == 0) printf "%08X\n", $_addr end set $_i = 0 set $_found = 1 while ($_tofind[$_i] != 0 && $_found == 1) set $_b = *((char*)$_addr + $_i) set $_t = (char)$_tofind[$_i] if ($_t != $_b) set $_found = 0 end set $_i++ end if ($_found == 1) printf "Code found at 0x%05X\n", $_addr end set $_addr++ end end document find_in_mem Find a pattern in memory The pattern is given by a string as arg0 If another argument is present it gives the starting address (0 otherwise) end define step_until_code set $_tofind = $arg0 set $SHOW_CONTEXT = 0 set $_found = 0 while (!$_found) set $_i = 0 set $_found = 1 while ($_tofind[$_i] != 0 && $_found == 1) set $_b = *((char*)$rip + $_i) set $_t = (char)$_tofind[$_i] if ($_t != $_b) set $_found = 0 end set $_i++ end if ($_found == 0) stepo end end set $SHOW_CONTEXT = 1 context end This script provides features that allow a person to better debug real mode code. It will display the values of the segments and the registers and will attempt to resolve segment:offset addresses by properly computing a physical address to decode instructions from. Once you have the 3 files above you can attempt to debug the BIOS this way: qemu-system-i386 -bios bios.bin -s -S & gdb -ix gdb_init_real_mode.txt \ -ex 'set tdesc filename target.xml' \ -ex 'target remote localhost:1234' There are a number of additional commands added mentioned in my related answer linked to earlier. This script takes care of setting the architecture to i8086 and then hooks itself into gdb. It provides a number of new macros that can make stepping through 16 bit code easier: break_int : adds a breakpoint on a software interrupt vector (the way the good old MS DOS and BIOS expose their APIs) break_int_if_ah : adds a conditional breakpoint on a software interrupt. AH has to be equals to the given parameter. This is used to filter service calls of interrupts. For instance, you sometimes only wants to break when the function AH=0h of the interruption 10h is called (change screen mode). stepo : this is a kabalistic macro used to 'step-over' function and interrupt calls. How does it work ? The opcode of the current instruction is extracted and if it is a function or interrupt call, the "next" instruction address is computed, a temporary breakpoint is added on that address and the 'continue' function is called. step_until_ret : this is used to singlestep until we encounter a 'RET' instruction. step_until_iret : this is used to singlestep until we encounter an 'IRET' instruction. step_until_int : this is used to singlestep until we encounter an 'INT' instruction. If you use the command above to launch QEMU you should see something like: ---------------------------[ STACK ]--- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ---------------------------[ DS:SI ]--- 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ---------------------------[ ES:DI ]--- 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ----------------------------[ CPU ]---- AX: 0000 BX: 0000 CX: 0000 DX: 0663 SI: 0000 DI: 0000 SP: 0000 BP: 0000 CS: F000 DS: 0000 ES: 0000 SS: 0000 IP: FFF0 EIP:0000FFF0 CS:IP: F000:FFF0 (0xFFFF0) SS:SP: 0000:0000 (0x00000) SS:BP: 0000:0000 (0x00000) OF <0> DF <0> IF <0> TF <0> SF <0> ZF <0> AF <0> PF <0> CF <0> ID <0> VIP <0> VIF <0> AC <0> VM <0> RF <0> NT <0> IOPL <0> ---------------------------[ CODE ]---- 0xffff0: jmp 0xf000:0xe05b 0xffff5: xor BYTE PTR ds:0x322f,dh 0xffff9: xor bp,WORD PTR [bx] 0xffffb: cmp WORD PTR [bx+di],di 0xffffd: add ah,bh 0xfffff: add BYTE PTR [bx+si],al 0x100001: add BYTE PTR [bx+si],al 0x100003: add BYTE PTR [bx+si],al 0x100005: add BYTE PTR [bx+si],al 0x100007: add BYTE PTR [bx+si],al 0x0000fff0 in ?? () real-mode-gdb$ As you can see it prints out part of the data at the top of the stack, some memory regions common to real mode programs, the segment registers and the regular registers. The instructions have been properly decoded from the right place in memory. You should see the program starting to execute at 0xffff0. Some BIOSes might have a different first instruction but one of the first few instructions will be a FAR JMP to another place in the BIOS: 0xffff0: jmp 0xf000:0xe05b
gcc 8.2: error: invalid 'asm': invalid address mode
The following statement is taken from iPXE. It compiles fine with gcc 7.3 but fails with gcc 8.2 on the aarch64 architecture. Here I get an error error: invalid 'asm': invalid address mode The macro argument einfo is a list of 5 parameters. #define __einfo_error( einfo ) ( { __asm__ ( ".section \".einfo\", \"\", " PROGBITS_OPS "\n\t" \ ".align 8\n\t" \ "\n1:\n\t" \ ".long ( 4f - 1b )\n\t" \ ".long %a0\n\t" \ ".long ( 2f - 1b )\n\t" \ ".long ( 3f - 1b )\n\t" \ ".long %a1\n\t" \ "\n2:\t.asciz \"" __einfo_desc ( einfo ) "\"\n\t" \ "\n3:\t.asciz \"" __FILE__ "\"\n\t" \ ".align 8\n\t" \ "\n4:\n\t" \ ".previous\n\t" : : \ "i" ( __einfo_errno ( einfo ) ), \ "i" ( __LINE__ ) ); \ From where does .long %a0 take its value? What is the "i" statement doing? Where is a reference for this syntax? - Has it changed with gcc 8.2?
Embedding resource using inline assembly
I tried to use this trick together to embed a resource into an executable file: #define INCLUDE_BINARY(identifier,filename) \ asm("\t.data\n" \ "\t.local " #identifier "_begin\n" \ "\t.type " #identifier "_begin, #object\n" \ "\t.align 16\n" \ #identifier "_begin:\n" \ "\t.incbin \"" filename "\"\n\n" \ \ "\t.local " #identifier "_end\n" \ "\t.type " #identifier "_end, #object\n" \ "\t.align 1\n" \ #identifier "_end:\n" \ "\t.byte 0\n"); \ \ extern uint8_t identifier##_begin[];\ extern const uint8_t identifier##_end[] So that #include <herbs/include_binary/include_binary.h> #include <herbs/main/main.h> #include <cstdio> INCLUDE_BINARY(source,__FILE__); int MAIN(int argc,charsys_t* argv[]) { const uint8_t* begin=source_begin; while(begin!=source_end) { putchar(*begin); ++begin; } return 0; } will print itself. It works fine until I enable debug symbol generation. Then I get errors: /tmp/ccCfX7kc.s:103: Error: can't resolve `.data' {.data section} - `.Ltext0' {.text section} I guess the reason of failure is that -g adds stuff at the beginning of file: .text .Ltext0: Is there a way to add global symbols using inline assembly that does not interfere with debugging? Is asm undefined outside a function body?
You need to restore the section back to .text at the end of the inline asm. You could use .pushsection and .popsection todo so.