The following notes illustrate debugging a linked list implementation with gdb.

Similar documents
Linked Lists. C Linked List

Here is a C function that will print a selected block of bytes from such a memory block, using an array-based view of the necessary logic:

Here is a C function that will print a selected block of bytes from such a memory block, using an array-based view of the necessary logic:

1. A student is testing an implementation of a C function; when compiled with gcc, the following x86-32 assembly code is produced:

int32_t Buffer[BUFFSZ] = {-1, -1, -1, 1, -1, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, -1, -1, -1, -1, -1}; int32_t* A = &Buffer[5];

Pointer Casts and Data Accesses

CS 11 C track: lecture 6

Creating a String Data Type in C

gcc o driver std=c99 -Wall driver.c bigmesa.c

The assignment requires solving a matrix access problem using only pointers to access the array elements, and introduces the use of struct data types.

Both parts center on the concept of a "mesa", and make use of the following data type:

Accessing Data in Memory

Instructions: Submit your answers to these questions to the Curator as OQ02 by the posted due date and time. No late submissions will be accepted.

CS 2505 Computer Organization I Test 2. Do not start the test until instructed to do so! printed

CS 2505 Computer Organization I Test 2. Do not start the test until instructed to do so! printed

Pointer Accesses to Memory and Bitwise Manipulation

Simple C Dynamic Data Structure

Malloc Lab & Midterm Solutions. Recitation 11: Tuesday: 11/08/2016

Pointer Accesses to Memory and Bitwise Manipulation

CS-211 Fall 2017 Test 2 Version A November 29, Name:

CprE 288 Introduction to Embedded Systems Exam 1 Review. 1

Dynamic Memory Management. Bin Li Assistant Professor Dept. of Electrical, Computer and Biomedical Engineering University of Rhode Island

Recitation #11 Malloc Lab. November 7th, 2017

Memory and Addresses. Pointers in C. Memory is just a sequence of byte-sized storage devices.

Pointer Accesses to Memory and Bitwise Manipulation

EL2310 Scientific Programming

CS 2505 Computer Organization I Test 2. Do not start the test until instructed to do so! printed

CS107 Handout 13 Spring 2008 April 18, 2008 Computer Architecture: Take II

C mini reference. 5 Binary numbers 12

Introduction to C: Pointers

Motivation was to facilitate development of systems software, especially OS development.

malloc(), calloc(), realloc(), and free()

Debugging Techniques. CEFET Engineering Week

CSE351 Spring 2010 Final Exam (9 June 2010)

CSCI 350 Pintos Intro. Mark Redekopp

Stack overflow exploitation

Short Notes of CS201

Programming in C - Part 2

CSE351 Spring 2010 Final Exam (9 June 2010)

CS201 - Introduction to Programming Glossary By

Pointers, Dynamic Data, and Reference Types

CS 2505 Computer Organization I Test 2. Do not start the test until instructed to do so! printed

CS32 Discussion Sec.on 1B Week 2. TA: Zhou Ren

ECE 2400 Computer Systems Programming, Fall 2018 PA2: List and Vector Data Structures

Data Storage. August 9, Indiana University. Geoffrey Brown, Bryce Himebaugh 2015 August 9, / 19

C Programming, Autumn 2013, Exercises for the Second Week

Do not start the test until instructed to do so!

1 A Brief Introduction To GDB

Cpt S 122 Data Structures. Data Structures

Here's how you declare a function that returns a pointer to a character:

#ifndef DOUBLE_LIST /* this string SHOULD NOT previously exist */ #define DOUBLE_LIST

CS 610: Intermediate Programming: C/C++ Making Programs General An Introduction to Linked Lists

Introduction to Programming Using Java (98-388)

Ricardo Rocha. Department of Computer Science Faculty of Sciences University of Porto

A short session with gdb verifies a few facts; the student has made notes of some observations:

Compiling Your Code and Running the Tests

Motivation was to facilitate development of systems software, especially OS development.

We are built to make mistakes, coded for error. Lewis Thomas

Dynamic Allocation in C

QUIZ. 1. Explain the meaning of the angle brackets in the declaration of v below:

static CS106L Spring 2009 Handout #21 May 12, 2009 Introduction

Advanced Pointer & Data Storage

1. A student is testing an implementation of a C function; when compiled with gcc, the following x86-64 assembly code is produced:

CS 220: Introduction to Parallel Computing. Arrays. Lecture 4

C Language Advanced Concepts. Microcomputer Architecture and Interfacing Colorado School of Mines Professor William Hoff

My malloc: mylloc and mhysa. Johan Montelius HT2016

When you add a number to a pointer, that number is added, but first it is multiplied by the sizeof the type the pointer points to.

Using a debugger. Segmentation fault? GDB to the rescue!

CS 261 Fall C Introduction. Variables, Memory Model, Pointers, and Debugging. Mike Lam, Professor

For this assignment, you will implement a collection of C functions to support a classic data encoding scheme.

CS201 Some Important Definitions

CS107 Handout 08 Spring 2007 April 9, 2007 The Ins and Outs of C Arrays

Sequential Containers Cont'd

Structures and Unions in C

Exercise Session 6 Computer Architecture and Systems Programming

UW CSE 351, Winter 2013 Final Exam

Linked List using a Sentinel

Memory and Pointers written by Cathy Saxton

15-122: Principles of Imperative Computation, Spring Due: Thursday, March 10, 2016 by 22:00

Contract Programming For C++0x

11 'e' 'x' 'e' 'm' 'p' 'l' 'i' 'f' 'i' 'e' 'd' bool equal(const unsigned char pstr[], const char *cstr) {

CSCI-243 Exam 1 Review February 22, 2015 Presented by the RIT Computer Science Community

0x0d2C May your signals all trap May your references be bounded All memory aligned Floats to ints round. remember...

Supporting Class / C++ Lecture Notes

CSE 220: Systems Programming

Kurt Schmidt. October 30, 2018

However, in C we can group related variables together into something called a struct.

CS107, Lecture 9 C Generics Function Pointers

Slide 1 CS 170 Java Programming 1 The Switch Duration: 00:00:46 Advance mode: Auto

Pointers. Memory. void foo() { }//return

C for C++ Programmers

A Capacity: 10 Usage: 4 Data:

Chapter 1 Getting Started

Assignment 1: grid. Due November 20, 11:59 PM Introduction

CS 61C: Great Ideas in Computer Architecture Introduction to C

struct Properties C struct Types

Midterm Review. CS 211 Fall 2018

Object-Oriented Programming

Lesson 8: Linked List Deque

CS61, Fall 2012 Section 2 Notes

Transcription:

Payload Type The following notes illustrate debugging a linked list implementation with. The example makes use of the following payload type: struct _WordRecord { char* Word; // zero-terminated C-string uint32_t Freq; // number of occurrences in }; typedef struct _WordRecord WordRecord; 1 void WordRecord_Init(WordRecord* const pwr, const char* const pword, uint32_t Frequency); char* WordRecord_Word(const WordRecord* const pwr); uint32_t WordRecord_Frequency(const WordRecord* const pwr); bool WordRecord_Increment(WordRecord* const pwr); bool bool WordRecord_Decrement(WordRecord* const pwr); WordRecord_equals(const WordRecord* const pleft, const WordRecord* const pright); void WordRecord_Clear(WordRecord* const pwr); void WordRecord_Print(const WordRecord* const pwr, FILE *fp); The source code for the payload type is probably available on the course website.

"Duct-tape" Wrapper 2 The example uses the following "duct-tape" wrapper type to attach payload values to list nodes: struct _WordRecordDT { WordRecord WR; DNode node; }; typedef struct _WordRecordDT WordRecordDT; void WordRecordDT_Init(WordRecordDT* const ple, const WordRecord* const pwr);

List Interface 3 The list is fully generic and uses the following interface (which you've seen before): struct _DNode { struct _DNode *prev; // pointer to previous list element struct _DNode *next; // pointer to next list element }; struct _DList { struct _DNode head; // List head sentinel struct _DNode tail; // List tail sentinel }; typedef struct _DNode DNode; typedef struct _DList DList; #define DList_Entry(LIST_ELEM, STRUCT, MEMBER) \ ((STRUCT *) ((uint8_t *) (LIST_ELEM) \ offsetof (STRUCT, MEMBER)))

List Interface The list is fully generic and uses the following interface: void DList_Init(DList* pl); void DList_PushFront(DList* pl, DNode* node); void DList_PushBack(DList* list, DNode* elem); void DList_Insert(DNode* before, DNode* elem); DNode* DList_Remove(DNode* elem); DNode* DList_PopFront(DList* list); DNode* DList_PopBack(DList* list); bool DList_Empty(DList* list); 4

List Interface The list is fully generic and uses the following interface: DNode* DList_Begin(DList* pl); DNode* DList_Next(DNode* elem); DNode* DList_End(DList* list); DNode* DList_RBegin(DList* list); DNode* DList_Prev(DNode* elem); DNode* DList_REnd(DList* list); DNode* DList_Head(DList* list); DNode* DList_Tail(DList* list); DNode* DList_Front(DList* list); DNode* DList_Back(DList* list); 5

Driver v1 Here is one version of the driver code: int main() { char* Words[NUMWORDS]; Words[0] = "zero"; Words[1] = "one"; Words[2] = "two"; Words[3] = "three"; Words[4] = "four"; DList mylist; DList_Init(&myList); 6

Driver v1 Here is one version of the driver code: WordRecord WR; 7 for (int i = 0; i < NUMWORDS; i++) { WordRecordDT *pwrdt = malloc( sizeof(wordrecorddt) ); assert( pwrdt!= NULL ); WordRecord_Init(&WR, Words[i], i); WordRecordDT_Init(pWRDT, &WR); } DList_PushBack(&myList, &pwrdt->node); printlist(&mylist, stdout); fprintf(stdout, "\n"); } return 0;

Examining Execution We'll compile the code for examination under : 8 gcc -o driver -std=c99 -Wall -O0 -static -m32 g3 driver.c WordRecord.c WordRecordDT.c DList.o Note: I'm posting an object file for the implementation of DList. Start a session; some uninformative output has been clipped and some formatting has been altered for clarity. 2001: session1 > driver () break driver.c:22 Breakpoint 1 at 0x80482f1: file driver.c, line 22. () run Starting program: /home/williammcquain/2505//dlist/session1/driver Breakpoint 1, main () at driver.c:23 23 DList_Init(&myList);

Examining Execution 9 Breakpoint 1, main () at driver.c:23 23 DList_Init(&myList); () print Words OK, we've reached the breakpoint; let's examine the array Words[ ] $1 = {0x80af348 "zero", 0x80af34d "one", 0x80af351 "two", 0x80af355 "three", 0x80af35b "four"} How would you explain the data shown here?

Fine Points These are the values stored in the array Words[ ]. So, these are pointers to the strings. 10 $1 = {0x80af348 "zero", 0x80af34d "one", 0x80af351 "two", 0x80af355 "three", 0x80af35b "four"} Do those pointer values make sense? Remember how strings are stored in C.

Examining Execution Breakpoint 1, main () at driver.c:23 23 DList_Init(&myList); () n OK, let's execute the call to DList_Init() 11 27 for (int i = 0; i < NUMWORDS; i++) { And, examine the DList variable () print mylist $2 = {head = {prev = 0xffffd800, next = 0xffffd808}, tail = {prev = 0xffffd800, next = 0xffffd808}} How can we determine whether these values make sense?

Examining Execution () print mylist $2 = {head = {prev = 0xffffd800, next = 0xffffd808}, tail = {prev = 0xffffd800, next = 0xffffd808}} We can display the addresses of mylist.head and mylist.tail () print &mylist.head $3 = (struct _DNode *) 0xffffd800 12 () print &mylist.tail $4 = (struct _DNode *) 0xffffd808 Now do the contents of mylist appear to be correct?

Fine Points () print mylist $2 = {head = {prev = 0xffffd800, next = 0xffffd808}, tail = {prev = 0xffffd800, next = 0xffffd808}} 13 () print &mylist.head $3 = (struct _DNode *) 0xffffd800 () print &mylist.tail $4 = (struct _DNode *) 0xffffd808 Yep. Compare the addresses of the two node objects to the values of their prev and next pointers. at: 0xFFFFD800 at: 0xFFFFD808 Head prev: 0xFFFFD800 Tail prev: 0xFFFFD800 next: 0xFFFFD808 next: 0xFFFFD808 mylist

Examining Execution 14 27 for (int i = 0; i < NUMWORDS; i++) { Let's create our first WordRecord and WordRecordDT objects: () n 28 WordRecordDT *pwrdt = malloc( sizeof(wordrecorddt) ); () n 29 assert( pwrdt!= NULL ); () n 31 WordRecord_Init(&WR, Words[i], i); () n () print WR $5 = {Word = 0x80d42b0 "zero", Freq = 0} Is the WordRecord object as expected?

Examining Execution 15 32 WordRecordDT_Init(pWRDT, &WR); () n () print *pwrdt $6 = {WR = {Word = 0x80d42c0 "zero", Freq = 0}, node = {prev = 0x0, next = 0x0}} () print &(pwrdt->wr) $9 = (WordRecord *) 0x80d42d0 OK, we've initialized a wrapper object. Let's examine its structure: Let's see where the parts are stored in memory: () print &(pwrdt->node) $10 = (DNode *) 0x80d42d8 What does that tell us?

Fine Points () print &(pwrdt->wr) $9 = (WordRecord *) 0x80d42d0 () print &(pwrdt->node) $10 = (DNode *) 0x80d42d8 16 This tells us the memory layout of this WordRecordDT object: 0x80D42D0 0x80D42D8 WordRecord member DNode member And, therefore, the layout of every WordRecordDT object: offset 0 offset 8 WordRecord member DNode member

Examining Execution 17 34 DList_PushBack(&myList, &pwrdt->node); () n Let's insert the first object into the list: 27 for (int i = 0; i < NUMWORDS; i++) { And examine mylist now: () print mylist $7 = {head = {prev = 0xffffd800, next = 0x80d42a0}, tail = {prev = 0x80d42a0, next = 0xffffd808}} And see what head.next points to: () print *mylist.head.next $8 = {prev = 0xffffd800, next = 0xffffd808} Does that look OK?

Examining Execution () print mylist $7 = {head = {prev = 0xffffd800, next = 0x80d42a0}, tail = {prev = 0x80d42a0, next = 0xffffd808}} 18 () print *mylist.head.next $8 = {prev = 0xffffd800, next = 0xffffd808} Now we'll get sneaky. Here's a nice use of pointer arithmetic and typecasting to access the payload relative to the node object within the wrapper: () print *(WordRecord*)((uint8_t*)myList.head.next-8) $16 = {Word = 0x80d42c0 "zero", Freq = 0} Does that look OK?

Fine Points 19 () print *(WordRecord*)((uint8_t*)myList.head.next - 8) $16 = {Word = 0x80d42c0 "zero", Freq = 0} The pointer manipulation logic is: mylist.head.next points to the DNode object within a wrapper object But that pointer is of type Dnode* (uint8_t*) mylist.head.next also points to that DNode object But this (nameless) pointer has a 1-byte target (uint8_t*) mylist.head.next 8 points to the beginning of the wrapper And hence to the WordRecord object within the wrapper But that pointer has a 1-byte target (WordRecord*) ((uint8_t*) mylist.head.next 8) has a WordRecord target *(WordRecord*) ((uint8_t*) mylist.head.next 8) is that target!

Summary OK, now you know how to do the following things: - display and interpret the contents of struct variables - display and interpret pointer values - display and interpret targets of pointers - use C syntax in specifying pointer expressions - apply pointer arithmetic 20

Driver v2 Now we will add the following loop to the original driver: while (!DList_Empty(&myList) ) { 21 } DNode* current = DList_PopBack(&myList); WordRecordDT *pwrdt = DList_Entry(current, WordRecordDT, node); WordRecord_Print(&pWRDT->WR, stdout); fprintf(stdout, "\n"); } return 0;

Error 22 When we run the driver, it should create and display the contents of a list with 5 data nodes. Which it does. Then, it should delete the last data node and display the corresponding payload until the list is empty. What it actually does is fall into an infinite loop, repeatedly printing the same value. We'll examine this behavior in

Examining Execution 23 We'll set a breakpoint at the new while loop and run to that line: 2031: session2 > driver () break driver.c:40 Breakpoint 1 at 0x80483ca: file driver.c, line 40. () run Starting program: /home/williammcquain/2505//dlist/session2/driver 0: zero 1: one 2: two 3: three 4: four OK, the list that was created by the first loop displayed correctly that's something at least Breakpoint 1, main () at driver.c:40 40 while (!DList_Empty(&myList) ) {

Examining Execution 24 40 while (!DList_Empty(&myList) ) { () n 42 DNode* current = DList_PopBack(&myList); () n 43 WordRecordDT *pwrdt = DList_Entry(current, WordRecordDT, node); () n 44 WordRecord_Print(&pWRDT->WR, stdout); () n 45 fprintf(stdout, "\n"); () n 4: four 40 while (!DList_Empty(&myList) ) { OK, the correct value was displayed after popping the original final record from the list.

Examining Execution We'll set a breakpoint at the new while loop and run to that line: 40 while (!DList_Empty(&myList) ) { 25 Look at the contents of mylist; doesn't tell us much () print mylist $1 = {head = {prev = 0xffffd7f8, next = 0x80d42a0}, tail = {prev = 0x80d4380, next = 0xffffd800}} Look at the preceding node; next is OK () print *mylist.tail.prev $2 = {prev = 0x80d4348, next = 0xffffd800} () print *(WordRecord*)((uint8_t*)myList.tail.prev-8) $3 = {Word = 0x80d43a0 "four", Freq = 4}

Examining Execution We'll set a breakpoint at the new while loop and run to that line: () print *mylist.tail.prev $2 = {prev = 0x80d4348, next = 0xffffd800} Let's check the current last payload: 26 () print *(WordRecord*)((uint8_t*)myList.tail.prev-8) $3 = {Word = 0x80d43a0 "four", Freq = 4} Well, that's not good that should have been gone. Looks like PopBack() didn't do its job.

DList_PopBack() DNode* DList_PopBack(DList* list) { DNode* back = DList_Back(list); DList_Remove (back); return back; } 27 That looks OK, as far as it goes, but this depends on the implementations of two other DList functions. DNode* DList_Remove(DNode* elem) { elem->prev->next = elem->next; return elem->next; } That looks suspicious. Shouldn't this be resetting two pointers instead of one? You'd better check the logic.