[PATCH 10/17] programs/winedbg: move bitfield extraction to extract_lgint

Eric Pouech eric.pouech at gmail.com
Tue Dec 7 11:46:15 CST 2021


(extraction is made on bitfield of width up to dbg_lgint_t size instead of
LONG)

Signed-off-by: Eric Pouech <eric.pouech at gmail.com>

---
 programs/winedbg/debugger.h |    2 +-
 programs/winedbg/expr.c     |    7 ++----
 programs/winedbg/memory.c   |   48 +++++++++++++++++++++++++++++++++++-------
 programs/winedbg/types.c    |   49 +++++++++++--------------------------------
 programs/winedbg/winedbg.c  |    6 +++--
 5 files changed, 58 insertions(+), 54 deletions(-)

diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h
index 8a8921cb685..2e316548511 100644
--- a/programs/winedbg/debugger.h
+++ b/programs/winedbg/debugger.h
@@ -487,7 +487,7 @@ extern dbg_lgint_t      types_extract_as_integer(const struct dbg_lvalue*);
 extern dbg_lgint_t      types_extract_as_lgint(const struct dbg_lvalue*, unsigned* psize, BOOL *pissigned);
 extern void             types_extract_as_address(const struct dbg_lvalue*, ADDRESS64*);
 extern BOOL             types_store_value(struct dbg_lvalue* lvalue_to, const struct dbg_lvalue* lvalue_from);
-extern BOOL             types_udt_find_element(struct dbg_lvalue* value, const char* name, ULONG *tmpbuf);
+extern BOOL             types_udt_find_element(struct dbg_lvalue* value, const char* name);
 extern BOOL             types_array_index(const struct dbg_lvalue* value, int index, struct dbg_lvalue* result);
 extern BOOL             types_get_info(const struct dbg_type*, IMAGEHLP_SYMBOL_TYPE_INFO, void*);
 extern BOOL             types_get_real_type(struct dbg_type* type, DWORD* tag);
diff --git a/programs/winedbg/expr.c b/programs/winedbg/expr.c
index e7c41094544..5d9ef30ad13 100644
--- a/programs/winedbg/expr.c
+++ b/programs/winedbg/expr.c
@@ -83,7 +83,6 @@ struct expr
         {
             struct expr*        exp1;
             const char*         element_name;
-            ULONG /* FIXME */   result;
         } structure;
 
         struct
@@ -361,8 +360,7 @@ struct dbg_lvalue expr_eval(struct expr* exp)
         if (exp1.type.id == dbg_itype_none || !types_array_index(&exp1, 0, &rtn) ||
             rtn.type.id == dbg_itype_none)
             RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
-        if (!types_udt_find_element(&rtn, exp->un.structure.element_name,
-                                    &exp->un.structure.result))
+        if (!types_udt_find_element(&rtn, exp->un.structure.element_name))
         {
             dbg_printf("%s\n", exp->un.structure.element_name);
             RaiseException(DEBUG_STATUS_NO_FIELD, 0, 0, NULL);
@@ -372,8 +370,7 @@ struct dbg_lvalue expr_eval(struct expr* exp)
         exp1 = expr_eval(exp->un.structure.exp1);
         if (exp1.type.id == dbg_itype_none) RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
         rtn = exp1;
-        if (!types_udt_find_element(&rtn, exp->un.structure.element_name,
-                                    &exp->un.structure.result))
+        if (!types_udt_find_element(&rtn, exp->un.structure.element_name))
         {
             dbg_printf("%s\n", exp->un.structure.element_name);
             RaiseException(DEBUG_STATUS_NO_FIELD, 0, 0, NULL);
diff --git a/programs/winedbg/memory.c b/programs/winedbg/memory.c
index 68c66db7270..fd8293687b6 100644
--- a/programs/winedbg/memory.c
+++ b/programs/winedbg/memory.c
@@ -237,15 +237,47 @@ BOOL memory_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
     /* size must fit in ret and be a power of two */
     if (size > sizeof(*ret) || (size & (size - 1))) return FALSE;
 
-    /* we are on little endian CPU */
-    memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
-    if (!memory_read_value(lvalue, size, ret)) return FALSE;
-
-    /* propagate sign information */
-    if (is_signed && size < 8 && (*ret >> (size * 8 - 1)) != 0)
+    if (lvalue->bitlen)
     {
-        dbg_lguint_t neg = -1;
-        *ret |= neg << (size * 8);
+        struct dbg_lvalue alt_lvalue = *lvalue;
+        dbg_lguint_t mask;
+        DWORD bt;
+        /* FIXME: this test isn't sufficient, depending on start of bitfield
+         * (ie a 64 bit field can spread across 9 bytes)
+         */
+        if (lvalue->bitlen > 8 * sizeof(dbg_lgint_t)) return FALSE;
+        alt_lvalue.addr.Offset += lvalue->bitstart >> 3;
+        /*
+         * Bitfield operation.  We have to extract the field.
+         */
+        if (!memory_read_value(&alt_lvalue, sizeof(*ret), ret)) return FALSE;
+        mask = ~(dbg_lguint_t)0 << lvalue->bitlen;
+        *ret >>= lvalue->bitstart & 7;
+        *ret &= ~mask;
+
+        /*
+         * OK, now we have the correct part of the number.
+         * Check to see whether the basic type is signed or not, and if so,
+         * we need to sign extend the number.
+         */
+        if (types_get_info(&lvalue->type, TI_GET_BASETYPE, &bt) &&
+            (bt == btInt || bt == btLong) && (*ret & (1 << (lvalue->bitlen - 1))))
+        {
+            *ret |= mask;
+        }
+    }
+    else
+    {
+        /* we are on little endian CPU */
+        memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
+        if (!memory_read_value(lvalue, size, ret)) return FALSE;
+
+        /* propagate sign information */
+        if (is_signed && size < 8 && (*ret >> (size * 8 - 1)) != 0)
+        {
+            dbg_lguint_t neg = -1;
+            *ret |= neg << (size * 8);
+        }
     }
     return TRUE;
 }
diff --git a/programs/winedbg/types.c b/programs/winedbg/types.c
index de1fee9f84b..8f16a535606 100644
--- a/programs/winedbg/types.c
+++ b/programs/winedbg/types.c
@@ -68,6 +68,7 @@ dbg_lgint_t types_extract_as_lgint(const struct dbg_lvalue* lvalue,
     {
         return (LONG_PTR)memory_to_linear_addr(&lvalue->addr);
     }
+    if (tag != SymTagBaseType && lvalue->bitlen) dbg_printf("Unexpected bitfield on tag %d\n", tag);
 
     if (psize) *psize = 0;
     if (issigned) *issigned = FALSE;
@@ -180,15 +181,11 @@ BOOL types_store_value(struct dbg_lvalue* lvalue_to, const struct dbg_lvalue* lv
  *
  * Implement a structure derefencement
  */
-static BOOL types_get_udt_element_lvalue(struct dbg_lvalue* lvalue, 
-                                         const struct dbg_type* type, ULONG *tmpbuf)
+static BOOL types_get_udt_element_lvalue(struct dbg_lvalue* lvalue, const struct dbg_type* type)
 {
     DWORD       offset, bitoffset;
-    DWORD       bt;
     DWORD64     length;
 
-    unsigned    mask;
-
     types_get_info(type, TI_GET_TYPE, &lvalue->type.id);
     lvalue->type.module = type->module;
     if (!types_get_info(type, TI_GET_OFFSET, &offset)) return FALSE;
@@ -197,38 +194,17 @@ static BOOL types_get_udt_element_lvalue(struct dbg_lvalue* lvalue,
     if (types_get_info(type, TI_GET_BITPOSITION, &bitoffset))
     {
         types_get_info(type, TI_GET_LENGTH, &length);
-        /* FIXME: this test isn't sufficient, depending on start of bitfield
-         * (ie a 32 bit field can spread across 5 bytes)
-         */
-        if (length > 8 * sizeof(*tmpbuf)) return FALSE;
-        lvalue->addr.Offset += bitoffset >> 3;
-        /*
-         * Bitfield operation.  We have to extract the field and store
-         * it in a temporary buffer so that we get it all right.
-         */
-        if (!memory_read_value(lvalue, sizeof(*tmpbuf), tmpbuf)) return FALSE;
-        mask = 0xffffffff << (DWORD)length;
-        *tmpbuf >>= bitoffset & 7;
-        *tmpbuf &= ~mask;
-
-        lvalue->in_debuggee = 0;
-        lvalue->addr.Offset = (ULONG_PTR)tmpbuf;
-
-        /*
-         * OK, now we have the correct part of the number.
-         * Check to see whether the basic type is signed or not, and if so,
-         * we need to sign extend the number.
-         */
-        if (types_get_info(&lvalue->type, TI_GET_BASETYPE, &bt) && 
-            bt == btInt && (*tmpbuf & (1 << ((DWORD)length - 1))))
+        lvalue->bitlen = length;
+        lvalue->bitstart = bitoffset;
+        if (lvalue->bitlen != length || lvalue->bitstart != bitoffset)
         {
-            *tmpbuf |= mask;
+            dbg_printf("too wide bitfields\n"); /* shouldn't happen */
+            return FALSE;
         }
     }
     else
-    {
-        if (!memory_read_value(lvalue, sizeof(*tmpbuf), tmpbuf)) return FALSE;
-    }
+        lvalue->bitlen = lvalue->bitstart = 0;
+
     return TRUE;
 }
 
@@ -236,7 +212,7 @@ static BOOL types_get_udt_element_lvalue(struct dbg_lvalue* lvalue,
  *		types_udt_find_element
  *
  */
-BOOL types_udt_find_element(struct dbg_lvalue* lvalue, const char* name, ULONG *tmpbuf)
+BOOL types_udt_find_element(struct dbg_lvalue* lvalue, const char* name)
 {
     DWORD                       tag, count;
     char                        buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
@@ -266,7 +242,7 @@ BOOL types_udt_find_element(struct dbg_lvalue* lvalue, const char* name, ULONG *
                         WideCharToMultiByte(CP_ACP, 0, ptr, -1, tmp, sizeof(tmp), NULL, NULL);
                         HeapFree(GetProcessHeap(), 0, ptr);
                         if (!strcmp(tmp, name))
-                            return types_get_udt_element_lvalue(lvalue, &type, tmpbuf);
+                            return types_get_udt_element_lvalue(lvalue, &type);
                     }
                 }
             }
@@ -475,7 +451,6 @@ void print_value(const struct dbg_lvalue* lvalue, char format, int level)
             char                        buffer[sizeof(TI_FINDCHILDREN_PARAMS) + 256 * sizeof(DWORD)];
             TI_FINDCHILDREN_PARAMS*     fcp = (TI_FINDCHILDREN_PARAMS*)buffer;
             WCHAR*                      ptr;
-            ULONG                       tmpbuf;
             struct dbg_type             sub_type;
 
             dbg_printf("{");
@@ -493,7 +468,7 @@ void print_value(const struct dbg_lvalue* lvalue, char format, int level)
                         dbg_printf("%ls=", ptr);
                         HeapFree(GetProcessHeap(), 0, ptr);
                         lvalue_field = *lvalue;
-                        if (types_get_udt_element_lvalue(&lvalue_field, &sub_type, &tmpbuf))
+                        if (types_get_udt_element_lvalue(&lvalue_field, &sub_type))
                         {
                             print_value(&lvalue_field, format, level + 1);
                         }
diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c
index 283b126ba84..dab5fbd85a3 100644
--- a/programs/winedbg/winedbg.c
+++ b/programs/winedbg/winedbg.c
@@ -44,9 +44,9 @@
  * - type management:
  *      + some bits of internal types are missing (like type casts and the address
  *        operator)
- *      + all computations should be made on long long
- *              o expr computations are in int:s
- *              o bitfield size is on a 4-bytes
+ *      + all computations should be made on 64bit
+ *              o bitfield spreading on more bytes than dbg_lgint_t isn't supported
+ *                (can happen on 128bit integers, of an ELF build...)
  * - execution:
  *      + set a better fix for gdb (proxy mode) than the step-mode hack
  *      + implement function call in debuggee




More information about the wine-devel mailing list